rstat_proc.c revision 1.17 1 /* $NetBSD: rstat_proc.c,v 1.17 1996/10/01 04:01:52 cgd 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 #ifndef lint
32 /*static char sccsid[] = "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro";*/
33 /*static char sccsid[] = "from: @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC";*/
34 static char rcsid[] = "$NetBSD: rstat_proc.c,v 1.17 1996/10/01 04:01:52 cgd Exp $";
35 #endif
36
37 /*
38 * rstat service: built with rstat.x and derived from rpc.rstatd.c
39 *
40 * Copyright (c) 1984 by Sun Microsystems, Inc.
41 */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <signal.h>
47 #include <fcntl.h>
48 #include <kvm.h>
49 #include <limits.h>
50 #include <rpc/rpc.h>
51 #include <sys/socket.h>
52 #include <nlist.h>
53 #include <syslog.h>
54 #include <sys/errno.h>
55 #include <sys/param.h>
56 #ifdef BSD
57 #include <sys/vmmeter.h>
58 #include <sys/dkstat.h>
59 #else
60 #include <sys/dk.h>
61 #endif
62 #include <net/if.h>
63
64 #undef FSHIFT /* Use protocol's shift and scale values */
65 #undef FSCALE
66 #undef DK_NDRIVE
67 #undef CPUSTATES
68 #undef if_ipackets
69 #undef if_ierrors
70 #undef if_opackets
71 #undef if_oerrors
72 #undef if_collisions
73 #include <rpcsvc/rstat.h>
74
75 #ifdef BSD
76 #define BSD_CPUSTATES 5 /* Use protocol's idea of CPU states */
77 int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE };
78 #endif
79
80 #ifdef __NetBSD__
81 /*
82 * NetBSD does not (currently) support the rpc.rstatd functionality
83 * formerly provided by grabbing dk_xfer from kmem, since NetBSD's
84 * new disk attachment code makes the data harder to look up and the
85 * data is not usually used. If this becomes a problem, lookup via
86 * the new disk structures should be implemented.
87 */
88 #define NO_DK_XFER
89 #endif
90
91 struct nlist nl[] = {
92 #define X_CPTIME 0
93 { "_cp_time" },
94 #define X_CNT 1
95 { "_cnt" },
96 #define X_IFNET 2
97 { "_ifnet" },
98 #define X_BOOTTIME 3
99 { "_boottime" },
100 #define X_HZ 4
101 { "_hz" },
102 #ifndef NO_DK_XFER
103 #define X_DKXFER 5
104 { "_dk_xfer" },
105 #endif
106 { NULL },
107 };
108 struct ifnet_head ifnetq; /* chain of ethernet interfaces */
109 int numintfs;
110 int stats_service();
111
112 extern int from_inetd;
113 int sincelastreq = 0; /* number of alarms since last request */
114 extern int closedown;
115 kvm_t *kfd;
116
117 union {
118 struct stats s1;
119 struct statsswtch s2;
120 struct statstime s3;
121 } stats_all;
122
123 void updatestat();
124 static stat_is_init = 0;
125 extern int errno;
126
127 #ifndef FSCALE
128 #define FSCALE (1 << 8)
129 #endif
130
131 stat_init()
132 {
133 stat_is_init = 1;
134 setup();
135 updatestat();
136 (void) signal(SIGALRM, updatestat);
137 alarm(1);
138 }
139
140 statstime *
141 rstatproc_stats_3_svc(arg, rqstp)
142 void *arg;
143 struct svc_req *rqstp;
144 {
145 if (!stat_is_init)
146 stat_init();
147 sincelastreq = 0;
148 return (&stats_all.s3);
149 }
150
151 statsswtch *
152 rstatproc_stats_2_svc(arg, rqstp)
153 void *arg;
154 struct svc_req *rqstp;
155 {
156 if (!stat_is_init)
157 stat_init();
158 sincelastreq = 0;
159 return (&stats_all.s2);
160 }
161
162 stats *
163 rstatproc_stats_1_svc(arg, rqstp)
164 void *arg;
165 struct svc_req *rqstp;
166 {
167 if (!stat_is_init)
168 stat_init();
169 sincelastreq = 0;
170 return (&stats_all.s1);
171 }
172
173 u_int *
174 rstatproc_havedisk_3_svc(arg, rqstp)
175 void *arg;
176 struct svc_req *rqstp;
177 {
178 static u_int have;
179
180 if (!stat_is_init)
181 stat_init();
182 sincelastreq = 0;
183 have = havedisk();
184 return (&have);
185 }
186
187 u_int *
188 rstatproc_havedisk_2_svc(arg, rqstp)
189 void *arg;
190 struct svc_req *rqstp;
191 {
192 return (rstatproc_havedisk_3_svc(arg, rqstp));
193 }
194
195 u_int *
196 rstatproc_havedisk_1_svc(arg, rqstp)
197 void *arg;
198 struct svc_req *rqstp;
199 {
200 return (rstatproc_havedisk_3_svc(arg, rqstp));
201 }
202
203 void
204 updatestat()
205 {
206 long off;
207 int i, hz;
208 struct vmmeter cnt;
209 struct ifnet ifnet;
210 double avrun[3];
211 struct timeval tm, btm;
212 #ifdef BSD
213 int cp_time[BSD_CPUSTATES];
214 #endif
215
216 #ifdef DEBUG
217 syslog(LOG_DEBUG, "entering updatestat");
218 #endif
219 if (sincelastreq >= closedown) {
220 #ifdef DEBUG
221 syslog(LOG_DEBUG, "about to closedown");
222 #endif
223 if (from_inetd)
224 exit(0);
225 else {
226 stat_is_init = 0;
227 return;
228 }
229 }
230 sincelastreq++;
231
232 if (kvm_read(kfd, (long)nl[X_HZ].n_value, (char *)&hz, sizeof hz) !=
233 sizeof hz) {
234 syslog(LOG_ERR, "can't read hz from kmem");
235 exit(1);
236 }
237 #ifdef BSD
238 if (kvm_read(kfd, (long)nl[X_CPTIME].n_value, (char *)cp_time,
239 sizeof (cp_time))
240 != sizeof (cp_time)) {
241 syslog(LOG_ERR, "can't read cp_time from kmem");
242 exit(1);
243 }
244 for (i = 0; i < CPUSTATES; i++)
245 stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]];
246 #else
247 if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
248 (char *)stats_all.s1.cp_time,
249 sizeof (stats_all.s1.cp_time))
250 != sizeof (stats_all.s1.cp_time)) {
251 syslog(LOG_ERR, "can't read cp_time from kmem");
252 exit(1);
253 }
254 #endif
255 #ifdef BSD
256 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
257 #endif
258 stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
259 stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
260 stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
261 if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value,
262 (char *)&btm, sizeof (stats_all.s2.boottime))
263 != sizeof (stats_all.s2.boottime)) {
264 syslog(LOG_ERR, "can't read boottime from kmem");
265 exit(1);
266 }
267 stats_all.s2.boottime.tv_sec = btm.tv_sec;
268 stats_all.s2.boottime.tv_usec = btm.tv_usec;
269
270
271 #ifdef DEBUG
272 syslog(LOG_DEBUG, "%d %d %d %d\n", stats_all.s1.cp_time[0],
273 stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
274 #endif
275
276 if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) !=
277 sizeof cnt) {
278 syslog(LOG_ERR, "can't read cnt from kmem");
279 exit(1);
280 }
281 stats_all.s1.v_pgpgin = cnt.v_pgpgin;
282 stats_all.s1.v_pgpgout = cnt.v_pgpgout;
283 stats_all.s1.v_pswpin = cnt.v_pswpin;
284 stats_all.s1.v_pswpout = cnt.v_pswpout;
285 stats_all.s1.v_intr = cnt.v_intr;
286 gettimeofday(&tm, (struct timezone *) 0);
287 stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
288 hz*(tm.tv_usec - btm.tv_usec)/1000000;
289 stats_all.s2.v_swtch = cnt.v_swtch;
290
291 #ifdef NO_DK_XFER
292 memset(stats_all.s1.dk_xfer, 0, sizeof (stats_all.s1.dk_xfer));
293 #else
294 if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
295 (char *)stats_all.s1.dk_xfer,
296 sizeof (stats_all.s1.dk_xfer))
297 != sizeof (stats_all.s1.dk_xfer)) {
298 syslog(LOG_ERR, "can't read dk_xfer from kmem");
299 exit(1);
300 }
301 #endif
302
303 stats_all.s1.if_ipackets = 0;
304 stats_all.s1.if_opackets = 0;
305 stats_all.s1.if_ierrors = 0;
306 stats_all.s1.if_oerrors = 0;
307 stats_all.s1.if_collisions = 0;
308 for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) {
309 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
310 sizeof ifnet) {
311 syslog(LOG_ERR, "can't read ifnet from kmem");
312 exit(1);
313 }
314 stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets;
315 stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets;
316 stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors;
317 stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors;
318 stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions;
319 off = (long)ifnet.if_list.tqe_next;
320 }
321 gettimeofday((struct timeval *)&stats_all.s3.curtime,
322 (struct timezone *) 0);
323 alarm(1);
324 }
325
326 setup()
327 {
328 struct ifnet ifnet;
329 long off;
330 char errbuf[_POSIX2_LINE_MAX];
331
332 kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
333 if (kfd == NULL) {
334 syslog(LOG_ERR, "%s", errbuf);
335 exit (1);
336 }
337
338 if (kvm_nlist(kfd, nl) != 0) {
339 syslog(LOG_ERR, "can't get namelist");
340 exit (1);
341 }
342
343 if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &ifnetq,
344 sizeof ifnetq) != sizeof ifnetq) {
345 syslog(LOG_ERR, "can't read ifnet queue head from kmem");
346 exit(1);
347 }
348
349 numintfs = 0;
350 for (off = (long)ifnetq.tqh_first; off;) {
351 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
352 sizeof ifnet) {
353 syslog(LOG_ERR, "can't read ifnet from kmem");
354 exit(1);
355 }
356 numintfs++;
357 off = (long)ifnet.if_list.tqe_next;
358 }
359 }
360
361 /*
362 * returns true if have a disk
363 */
364 int
365 havedisk()
366 {
367 #ifdef NO_DK_XFER
368 return (0);
369 #else
370 int i, cnt;
371 long xfer[DK_NDRIVE];
372
373 if (kvm_nlist(kfd, nl) != 0) {
374 syslog(LOG_ERR, "can't get namelist");
375 exit (1);
376 }
377
378 if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
379 (char *)xfer, sizeof xfer) != sizeof xfer) {
380 syslog(LOG_ERR, "can't read dk_xfer from kmem");
381 exit(1);
382 }
383 cnt = 0;
384 for (i=0; i < DK_NDRIVE; i++)
385 cnt += xfer[i];
386 return (cnt != 0);
387 #endif
388 }
389
390 void
391 rstat_service(rqstp, transp)
392 struct svc_req *rqstp;
393 SVCXPRT *transp;
394 {
395 union {
396 int fill;
397 } argument;
398 char *result;
399 xdrproc_t xdr_argument, xdr_result;
400 char *(*local) __P((void *, struct svc_req *));
401
402 switch (rqstp->rq_proc) {
403 case NULLPROC:
404 (void)svc_sendreply(transp, xdr_void, (char *)NULL);
405 goto leave;
406
407 case RSTATPROC_STATS:
408 xdr_argument = (xdrproc_t)xdr_void;
409 xdr_result = (xdrproc_t)xdr_statstime;
410 switch (rqstp->rq_vers) {
411 case RSTATVERS_ORIG:
412 local = (char *(*) __P((void *, struct svc_req *)))
413 rstatproc_stats_1_svc;
414 break;
415 case RSTATVERS_SWTCH:
416 local = (char *(*) __P((void *, struct svc_req *)))
417 rstatproc_stats_2_svc;
418 break;
419 case RSTATVERS_TIME:
420 local = (char *(*) __P((void *, struct svc_req *)))
421 rstatproc_stats_3_svc;
422 break;
423 default:
424 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
425 goto leave;
426 }
427 break;
428
429 case RSTATPROC_HAVEDISK:
430 xdr_argument = (xdrproc_t)xdr_void;
431 xdr_result = (xdrproc_t)xdr_u_int;
432 switch (rqstp->rq_vers) {
433 case RSTATVERS_ORIG:
434 local = (char *(*) __P((void *, struct svc_req *)))
435 rstatproc_havedisk_1_svc;
436 break;
437 case RSTATVERS_SWTCH:
438 local = (char *(*) __P((void *, struct svc_req *)))
439 rstatproc_havedisk_2_svc;
440 break;
441 case RSTATVERS_TIME:
442 local = (char *(*) __P((void *, struct svc_req *)))
443 rstatproc_havedisk_3_svc;
444 break;
445 default:
446 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
447 goto leave;
448 }
449 break;
450
451 default:
452 svcerr_noproc(transp);
453 goto leave;
454 }
455 bzero((char *)&argument, sizeof(argument));
456 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
457 svcerr_decode(transp);
458 goto leave;
459 }
460 result = (*local)(&argument, rqstp);
461 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
462 svcerr_systemerr(transp);
463 }
464 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
465 (void)fprintf(stderr, "unable to free arguments\n");
466 exit(1);
467 }
468 leave:
469 if (from_inetd)
470 exit(0);
471 }
472