rstat_proc.c revision 1.22 1 /* $NetBSD: rstat_proc.c,v 1.22 1998/02/11 17:27:37 bad Exp $ */
2
3 /*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part. Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California 94043
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro";
36 static char sccsid[] = "from: @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC";
37 #else
38 __RCSID("$NetBSD: rstat_proc.c,v 1.22 1998/02/11 17:27:37 bad Exp $");
39 #endif
40 #endif
41
42 /*
43 * rstat service: built with rstat.x and derived from rpc.rstatd.c
44 *
45 * Copyright (c) 1984 by Sun Microsystems, Inc.
46 */
47
48 #include <sys/param.h>
49 #include <sys/errno.h>
50 #include <sys/socket.h>
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <signal.h>
56 #include <fcntl.h>
57 #include <kvm.h>
58 #include <limits.h>
59 #include <nlist.h>
60 #include <syslog.h>
61 #ifdef BSD
62 #if defined(UVM)
63 #include <sys/sysctl.h>
64 #include <vm/vm.h>
65 #include <uvm/uvm_extern.h>
66 #else
67 #include <sys/vmmeter.h>
68 #endif
69 #include <sys/dkstat.h>
70 #include "dkstats.h"
71 #else
72 #include <sys/dk.h>
73 #endif
74
75 #include <net/if.h>
76
77 /*
78 * XXX
79 *
80 * this is a huge hack to stop `struct pmap' being
81 * defined twice!
82 */
83 #define _RPC_PMAP_PROT_H_
84 #include <rpc/rpc.h>
85
86 #undef FSHIFT /* Use protocol's shift and scale values */
87 #undef FSCALE
88 #undef DK_NDRIVE
89 #undef CPUSTATES
90 #undef if_ipackets
91 #undef if_ierrors
92 #undef if_opackets
93 #undef if_oerrors
94 #undef if_collisions
95 #include <rpcsvc/rstat.h>
96
97 #ifdef BSD
98 #define BSD_CPUSTATES 5 /* Use protocol's idea of CPU states */
99 int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE };
100 #endif
101
102 struct nlist nl[] = {
103 #define X_IFNET 0
104 { "_ifnet" },
105 #define X_BOOTTIME 1
106 { "_boottime" },
107 #if !defined(UVM)
108 #define X_CNT 2
109 { "_cnt" },
110 #endif
111 { NULL },
112 };
113
114 extern int dk_ndrive; /* From dkstats.c */
115 extern struct _disk cur, last;
116 int hz;
117 char *memf = NULL, *nlistf = NULL;
118
119 struct ifnet_head ifnetq; /* chain of ethernet interfaces */
120 int numintfs;
121
122 extern int from_inetd;
123 int sincelastreq = 0; /* number of alarms since last request */
124 extern int closedown;
125 kvm_t *kfd;
126
127 union {
128 struct stats s1;
129 struct statsswtch s2;
130 struct statstime s3;
131 } stats_all;
132
133 extern void dkreadstats __P((void));
134 extern int dkinit __P((int));
135
136 void updatestat __P((int));
137 void setup __P((void));
138 void stat_init __P((void));
139 int havedisk __P((void));
140 void rstat_service __P((struct svc_req *, SVCXPRT *));
141
142 static stat_is_init = 0;
143 extern int errno;
144
145 #ifndef FSCALE
146 #define FSCALE (1 << 8)
147 #endif
148
149 void
150 stat_init()
151 {
152 stat_is_init = 1;
153 setup();
154 updatestat(0);
155 (void) signal(SIGALRM, updatestat);
156 alarm(1);
157 }
158
159 statstime *
160 rstatproc_stats_3_svc(arg, rqstp)
161 void *arg;
162 struct svc_req *rqstp;
163 {
164 if (!stat_is_init)
165 stat_init();
166 sincelastreq = 0;
167 return (&stats_all.s3);
168 }
169
170 statsswtch *
171 rstatproc_stats_2_svc(arg, rqstp)
172 void *arg;
173 struct svc_req *rqstp;
174 {
175 if (!stat_is_init)
176 stat_init();
177 sincelastreq = 0;
178 stats_all.s2.if_opackets = stats_all.s3.if_opackets;
179 return (&stats_all.s2);
180 }
181
182 stats *
183 rstatproc_stats_1_svc(arg, rqstp)
184 void *arg;
185 struct svc_req *rqstp;
186 {
187 if (!stat_is_init)
188 stat_init();
189 sincelastreq = 0;
190 stats_all.s1.if_opackets = stats_all.s3.if_opackets;
191 return (&stats_all.s1);
192 }
193
194 u_int *
195 rstatproc_havedisk_3_svc(arg, rqstp)
196 void *arg;
197 struct svc_req *rqstp;
198 {
199 static u_int have;
200
201 if (!stat_is_init)
202 stat_init();
203 sincelastreq = 0;
204 have = havedisk();
205 return (&have);
206 }
207
208 u_int *
209 rstatproc_havedisk_2_svc(arg, rqstp)
210 void *arg;
211 struct svc_req *rqstp;
212 {
213 return (rstatproc_havedisk_3_svc(arg, rqstp));
214 }
215
216 u_int *
217 rstatproc_havedisk_1_svc(arg, rqstp)
218 void *arg;
219 struct svc_req *rqstp;
220 {
221 return (rstatproc_havedisk_3_svc(arg, rqstp));
222 }
223
224 void
225 updatestat(dummy)
226 int dummy;
227 {
228 long off;
229 int i;
230 #if defined(UVM)
231 struct uvmexp uvmexp;
232 size_t len;
233 int mib[2];
234 #else
235 struct vmmeter cnt;
236 #endif
237 struct ifnet ifnet;
238 double avrun[3];
239 struct timeval tm, btm;
240
241 #ifdef DEBUG
242 syslog(LOG_DEBUG, "entering updatestat");
243 #endif
244 if (sincelastreq >= closedown) {
245 #ifdef DEBUG
246 syslog(LOG_DEBUG, "about to closedown");
247 #endif
248 if (from_inetd)
249 exit(0);
250 else {
251 stat_is_init = 0;
252 return;
253 }
254 }
255 sincelastreq++;
256
257 /*
258 * dkreadstats reads in the "disk_count" as well as the "disklist"
259 * statistics. It also retrieves "hz" and the "cp_time" array.
260 */
261 dkreadstats();
262 memset(stats_all.s3.dk_xfer, 0, sizeof(stats_all.s3.dk_xfer));
263 for (i = 0; i < dk_ndrive && i < DK_NDRIVE; i++)
264 stats_all.s3.dk_xfer[i] = cur.dk_xfer[i];
265
266 #ifdef BSD
267 for (i = 0; i < CPUSTATES; i++)
268 stats_all.s3.cp_time[i] = cur.cp_time[cp_xlat[i]];
269 #else
270 if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
271 (char *)stats_all.s3.cp_time,
272 sizeof (stats_all.s3.cp_time))
273 != sizeof (stats_all.s3.cp_time)) {
274 syslog(LOG_ERR, "can't read cp_time from kmem");
275 exit(1);
276 }
277 #endif
278 #ifdef BSD
279 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
280 #endif
281 stats_all.s3.avenrun[0] = avrun[0] * FSCALE;
282 stats_all.s3.avenrun[1] = avrun[1] * FSCALE;
283 stats_all.s3.avenrun[2] = avrun[2] * FSCALE;
284 if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value,
285 (char *)&btm, sizeof (stats_all.s3.boottime))
286 != sizeof (stats_all.s3.boottime)) {
287 syslog(LOG_ERR, "can't read boottime from kmem");
288 exit(1);
289 }
290 stats_all.s3.boottime.tv_sec = btm.tv_sec;
291 stats_all.s3.boottime.tv_usec = btm.tv_usec;
292
293
294 #ifdef DEBUG
295 syslog(LOG_DEBUG, "%d %d %d %d\n", stats_all.s3.cp_time[0],
296 stats_all.s3.cp_time[1], stats_all.s3.cp_time[2], stats_all.s3.cp_time[3]);
297 #endif
298
299 #if defined(UVM)
300 mib[0] = CTL_VM;
301 mib[1] = VM_UVMEXP;
302 len = sizeof(uvmexp);
303 if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0) {
304 syslog(LOG_ERR, "can't sysctl vm.uvmexp");
305 exit(1);
306 }
307 stats_all.s3.v_pgpgin = uvmexp.fltanget;
308 stats_all.s3.v_pgpgout = uvmexp.pdpageouts;
309 stats_all.s3.v_pswpin = uvmexp.swapins;
310 stats_all.s3.v_pswpout = uvmexp.swapouts;
311 stats_all.s3.v_intr = uvmexp.intrs;
312 stats_all.s3.v_swtch = uvmexp.swtch;
313 #else
314 if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) !=
315 sizeof cnt) {
316 syslog(LOG_ERR, "can't read cnt from kmem");
317 exit(1);
318 }
319 stats_all.s3.v_pgpgin = cnt.v_pgpgin;
320 stats_all.s3.v_pgpgout = cnt.v_pgpgout;
321 stats_all.s3.v_pswpin = cnt.v_pswpin;
322 stats_all.s3.v_pswpout = cnt.v_pswpout;
323 stats_all.s3.v_intr = cnt.v_intr;
324 stats_all.s3.v_swtch = cnt.v_swtch;
325 #endif
326 gettimeofday(&tm, (struct timezone *) 0);
327 stats_all.s3.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
328 hz*(tm.tv_usec - btm.tv_usec)/1000000;
329
330 stats_all.s3.if_ipackets = 0;
331 stats_all.s3.if_opackets = 0;
332 stats_all.s3.if_ierrors = 0;
333 stats_all.s3.if_oerrors = 0;
334 stats_all.s3.if_collisions = 0;
335 for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) {
336 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
337 sizeof ifnet) {
338 syslog(LOG_ERR, "can't read ifnet from kmem");
339 exit(1);
340 }
341 stats_all.s3.if_ipackets += ifnet.if_data.ifi_ipackets;
342 stats_all.s3.if_opackets += ifnet.if_data.ifi_opackets;
343 stats_all.s3.if_ierrors += ifnet.if_data.ifi_ierrors;
344 stats_all.s3.if_oerrors += ifnet.if_data.ifi_oerrors;
345 stats_all.s3.if_collisions += ifnet.if_data.ifi_collisions;
346 off = (long)ifnet.if_list.tqe_next;
347 }
348 gettimeofday((struct timeval *)&stats_all.s3.curtime,
349 (struct timezone *) 0);
350 alarm(1);
351 }
352
353 void
354 setup()
355 {
356 struct ifnet ifnet;
357 long off;
358 char errbuf[_POSIX2_LINE_MAX];
359
360 kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
361 if (kfd == NULL) {
362 syslog(LOG_ERR, "%s", errbuf);
363 exit (1);
364 }
365
366 if (kvm_nlist(kfd, nl) != 0) {
367 syslog(LOG_ERR, "can't get namelist");
368 exit (1);
369 }
370
371 if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &ifnetq,
372 sizeof ifnetq) != sizeof ifnetq) {
373 syslog(LOG_ERR, "can't read ifnet queue head from kmem");
374 exit(1);
375 }
376
377 numintfs = 0;
378 for (off = (long)ifnetq.tqh_first; off;) {
379 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
380 sizeof ifnet) {
381 syslog(LOG_ERR, "can't read ifnet from kmem");
382 exit(1);
383 }
384 numintfs++;
385 off = (long)ifnet.if_list.tqe_next;
386 }
387 dkinit(0);
388 }
389
390 /*
391 * returns true if have a disk
392 */
393 int
394 havedisk()
395 {
396 return dk_ndrive != 0;
397 }
398
399 void
400 rstat_service(rqstp, transp)
401 struct svc_req *rqstp;
402 SVCXPRT *transp;
403 {
404 union {
405 int fill;
406 } argument;
407 char *result;
408 xdrproc_t xdr_argument, xdr_result;
409 char *(*local) __P((void *, struct svc_req *));
410
411 switch (rqstp->rq_proc) {
412 case NULLPROC:
413 (void)svc_sendreply(transp, xdr_void, (char *)NULL);
414 goto leave;
415
416 case RSTATPROC_STATS:
417 xdr_argument = (xdrproc_t)xdr_void;
418 xdr_result = (xdrproc_t)xdr_statstime;
419 switch (rqstp->rq_vers) {
420 case RSTATVERS_ORIG:
421 local = (char *(*) __P((void *, struct svc_req *)))
422 rstatproc_stats_1_svc;
423 break;
424 case RSTATVERS_SWTCH:
425 local = (char *(*) __P((void *, struct svc_req *)))
426 rstatproc_stats_2_svc;
427 break;
428 case RSTATVERS_TIME:
429 local = (char *(*) __P((void *, struct svc_req *)))
430 rstatproc_stats_3_svc;
431 break;
432 default:
433 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
434 goto leave;
435 }
436 break;
437
438 case RSTATPROC_HAVEDISK:
439 xdr_argument = (xdrproc_t)xdr_void;
440 xdr_result = (xdrproc_t)xdr_u_int;
441 switch (rqstp->rq_vers) {
442 case RSTATVERS_ORIG:
443 local = (char *(*) __P((void *, struct svc_req *)))
444 rstatproc_havedisk_1_svc;
445 break;
446 case RSTATVERS_SWTCH:
447 local = (char *(*) __P((void *, struct svc_req *)))
448 rstatproc_havedisk_2_svc;
449 break;
450 case RSTATVERS_TIME:
451 local = (char *(*) __P((void *, struct svc_req *)))
452 rstatproc_havedisk_3_svc;
453 break;
454 default:
455 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
456 goto leave;
457 }
458 break;
459
460 default:
461 svcerr_noproc(transp);
462 goto leave;
463 }
464 bzero((char *)&argument, sizeof(argument));
465 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
466 svcerr_decode(transp);
467 goto leave;
468 }
469 result = (*local)(&argument, rqstp);
470 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
471 svcerr_systemerr(transp);
472 }
473 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
474 (void)fprintf(stderr, "unable to free arguments\n");
475 exit(1);
476 }
477 leave:
478 if (from_inetd)
479 exit(0);
480 }
481