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