xref: /netbsd-src/libexec/rpc.rstatd/rstat_proc.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
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.9 1994/05/25 19:40:40 pk 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 int firstifnet, numintfs;	/* chain of ethernet interfaces */
98 int stats_service();
99 
100 extern int from_inetd;
101 int sincelastreq = 0;		/* number of alarms since last request */
102 extern int closedown;
103 kvm_t *kfd;
104 
105 union {
106     struct stats s1;
107     struct statsswtch s2;
108     struct statstime s3;
109 } stats_all;
110 
111 void updatestat();
112 static stat_is_init = 0;
113 extern int errno;
114 
115 #ifndef FSCALE
116 #define FSCALE (1 << 8)
117 #endif
118 
119 #ifndef BSD
120 /*
121  * BSD has the kvm facility for getting info from the
122  * kernel. If you aren't on BSD, this surfices.
123  */
124 int kmem;
125 
126 kvm_read(kfd, off, addr, size)
127 	void *kfd;
128         unsigned long off, size;
129         char *addr;
130 {
131         int len;
132 	if (lseek(kmem, off, 0) == -1)
133                 return(-1);
134 	return(read(kmem, addr, size));
135 }
136 
137 kvm_nlist(kfd, nl)
138 	void *kfd;
139         struct nlist *nl;
140 {
141 	int n = nlist("/vmunix", nl);
142 	if (nl[0].n_value == 0)
143                 return(n);
144 
145 	if ((kmem = open("/dev/kmem", 0)) < 0)
146                 return(-1);
147         return(0);
148 }
149 #endif
150 
151 stat_init()
152 {
153     stat_is_init = 1;
154     setup();
155     updatestat();
156     (void) signal(SIGALRM, updatestat);
157     alarm(1);
158 }
159 
160 statstime *
161 rstatproc_stats_3()
162 {
163     if (! stat_is_init)
164         stat_init();
165     sincelastreq = 0;
166     return(&stats_all.s3);
167 }
168 
169 statsswtch *
170 rstatproc_stats_2()
171 {
172     if (! stat_is_init)
173         stat_init();
174     sincelastreq = 0;
175     return(&stats_all.s2);
176 }
177 
178 stats *
179 rstatproc_stats_1()
180 {
181     if (! stat_is_init)
182         stat_init();
183     sincelastreq = 0;
184     return(&stats_all.s1);
185 }
186 
187 u_int *
188 rstatproc_havedisk_3()
189 {
190     static u_int have;
191 
192     if (! stat_is_init)
193         stat_init();
194     sincelastreq = 0;
195     have = havedisk();
196 	return(&have);
197 }
198 
199 u_int *
200 rstatproc_havedisk_2()
201 {
202     return(rstatproc_havedisk_3());
203 }
204 
205 u_int *
206 rstatproc_havedisk_1()
207 {
208     return(rstatproc_havedisk_3());
209 }
210 
211 void
212 updatestat()
213 {
214 	int off, i, hz;
215 	struct vmmeter cnt;
216 	struct ifnet ifnet;
217 	double avrun[3];
218 	struct timeval tm, btm;
219 #ifdef BSD
220 	int cp_time[BSD_CPUSTATES];
221 #endif
222 
223 #ifdef DEBUG
224 	fprintf(stderr, "entering updatestat\n");
225 #endif
226 	if (sincelastreq >= closedown) {
227 #ifdef DEBUG
228                 fprintf(stderr, "about to closedown\n");
229 #endif
230                 if (from_inetd)
231                         exit(0);
232                 else {
233                         stat_is_init = 0;
234                         return;
235                 }
236 	}
237 	sincelastreq++;
238 
239 	if (kvm_read(kfd, (long)nl[X_HZ].n_value, (char *)&hz, sizeof hz) !=
240 	    sizeof hz) {
241 		syslog(LOG_ERR, "rstat: can't read hz from kmem\n");
242 		exit(1);
243 	}
244 #ifdef BSD
245  	if (kvm_read(kfd, (long)nl[X_CPTIME].n_value, (char *)cp_time,
246 		     sizeof (cp_time))
247 	    != sizeof (cp_time)) {
248 		syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n");
249 		exit(1);
250 	}
251 	for (i = 0; i < CPUSTATES; i++)
252 		stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]];
253 #else
254  	if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
255 		     (char *)stats_all.s1.cp_time,
256 		     sizeof (stats_all.s1.cp_time))
257 	    != sizeof (stats_all.s1.cp_time)) {
258 		syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n");
259 		exit(1);
260 	}
261 #endif
262 #ifdef vax
263  	if (kvm_read(kfd, (long)nl[X_AVENRUN].n_value, (char *)avrun,
264 		     sizeof (avrun)) != sizeof (avrun)) {
265 		syslog(LOG_ERR, "rstat: can't read avenrun from kmem\n");
266 		exit(1);
267 	}
268 #endif
269 #ifdef BSD
270         (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
271 #endif
272 	stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
273 	stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
274 	stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
275  	if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value,
276 		     (char *)&btm, sizeof (stats_all.s2.boottime))
277 	    != sizeof (stats_all.s2.boottime)) {
278 		syslog(LOG_ERR, "rstat: can't read boottime from kmem\n");
279 		exit(1);
280 	}
281 	stats_all.s2.boottime.tv_sec = btm.tv_sec;
282 	stats_all.s2.boottime.tv_usec = btm.tv_usec;
283 
284 
285 #ifdef DEBUG
286 	fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0],
287 	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
288 #endif
289 
290  	if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) !=
291 	    sizeof cnt) {
292 		syslog(LOG_ERR, "rstat: can't read cnt from kmem\n");
293 		exit(1);
294 	}
295 	stats_all.s1.v_pgpgin = cnt.v_pgpgin;
296 	stats_all.s1.v_pgpgout = cnt.v_pgpgout;
297 	stats_all.s1.v_pswpin = cnt.v_pswpin;
298 	stats_all.s1.v_pswpout = cnt.v_pswpout;
299 	stats_all.s1.v_intr = cnt.v_intr;
300 	gettimeofday(&tm, (struct timezone *) 0);
301 	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
302 	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
303 	stats_all.s2.v_swtch = cnt.v_swtch;
304 
305  	if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
306 		     (char *)stats_all.s1.dk_xfer,
307 		     sizeof (stats_all.s1.dk_xfer))
308 	    != sizeof (stats_all.s1.dk_xfer)) {
309 		syslog(LOG_ERR, "rstat: can't read dk_xfer from kmem\n");
310 		exit(1);
311 	}
312 
313 	stats_all.s1.if_ipackets = 0;
314 	stats_all.s1.if_opackets = 0;
315 	stats_all.s1.if_ierrors = 0;
316 	stats_all.s1.if_oerrors = 0;
317 	stats_all.s1.if_collisions = 0;
318 	for (off = firstifnet, i = 0; off && i < numintfs; i++) {
319 		if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
320 		    sizeof ifnet) {
321 			syslog(LOG_ERR, "rstat: can't read ifnet from kmem\n");
322 			exit(1);
323 		}
324 		stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets;
325 		stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets;
326 		stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors;
327 		stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors;
328 		stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions;
329 		off = (int) ifnet.if_next;
330 	}
331 	gettimeofday((struct timeval *)&stats_all.s3.curtime,
332 		(struct timezone *) 0);
333 	alarm(1);
334 }
335 
336 setup()
337 {
338 	struct ifnet ifnet;
339 	int off;
340 	char errbuf[_POSIX2_LINE_MAX];
341 
342 	kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
343 	if (kfd == NULL) {
344 		syslog(LOG_ERR, "rstat: %s", errbuf);
345 		exit (1);
346 	}
347 
348 	if (kvm_nlist(kfd, nl) != 0) {
349 		syslog(LOG_ERR, "rstatd: Can't get namelist.");
350 		exit (1);
351         }
352 
353 	if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &firstifnet,
354                      sizeof(int)) != sizeof(int))  {
355 		syslog(LOG_ERR, "rstat: can't read firstifnet from kmem\n");
356 		exit(1);
357         }
358 
359 	numintfs = 0;
360 	for (off = firstifnet; off;) {
361 		if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
362 		    sizeof ifnet) {
363 			syslog(LOG_ERR, "rstat: can't read ifnet from kmem\n");
364 			exit(1);
365 		}
366 		numintfs++;
367 		off = (int) ifnet.if_next;
368 	}
369 }
370 
371 /*
372  * returns true if have a disk
373  */
374 int
375 havedisk()
376 {
377 	int i, cnt;
378 	long  xfer[DK_NDRIVE];
379 
380 	if (kvm_nlist(kfd, nl) != 0) {
381 		syslog(LOG_ERR, "rstatd: Can't get namelist.");
382 		exit (1);
383         }
384 
385 	if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
386 		     (char *)xfer, sizeof xfer) != sizeof xfer) {
387 		syslog(LOG_ERR, "rstat: can't read kmem\n");
388 		exit(1);
389 	}
390 	cnt = 0;
391 	for (i=0; i < DK_NDRIVE; i++)
392 		cnt += xfer[i];
393 	return (cnt != 0);
394 }
395 
396 void
397 rstat_service(rqstp, transp)
398 	struct svc_req *rqstp;
399 	SVCXPRT *transp;
400 {
401 	union {
402 		int fill;
403 	} argument;
404 	char *result;
405 	bool_t (*xdr_argument)(), (*xdr_result)();
406 	char *(*local)();
407 
408 	switch (rqstp->rq_proc) {
409 	case NULLPROC:
410 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
411 		goto leave;
412 
413 	case RSTATPROC_STATS:
414 		xdr_argument = xdr_void;
415 		xdr_result = xdr_statstime;
416                 switch (rqstp->rq_vers) {
417                 case RSTATVERS_ORIG:
418                         local = (char *(*)()) rstatproc_stats_1;
419                         break;
420                 case RSTATVERS_SWTCH:
421                         local = (char *(*)()) rstatproc_stats_2;
422                         break;
423                 case RSTATVERS_TIME:
424                         local = (char *(*)()) rstatproc_stats_3;
425                         break;
426                 default:
427                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
428                         goto leave;
429                         /*NOTREACHED*/
430                 }
431 		break;
432 
433 	case RSTATPROC_HAVEDISK:
434 		xdr_argument = xdr_void;
435 		xdr_result = xdr_u_int;
436                 switch (rqstp->rq_vers) {
437                 case RSTATVERS_ORIG:
438                         local = (char *(*)()) rstatproc_havedisk_1;
439                         break;
440                 case RSTATVERS_SWTCH:
441                         local = (char *(*)()) rstatproc_havedisk_2;
442                         break;
443                 case RSTATVERS_TIME:
444                         local = (char *(*)()) rstatproc_havedisk_3;
445                         break;
446                 default:
447                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
448                         goto leave;
449                         /*NOTREACHED*/
450                 }
451 		break;
452 
453 	default:
454 		svcerr_noproc(transp);
455 		goto leave;
456 	}
457 	bzero((char *)&argument, sizeof(argument));
458 	if (!svc_getargs(transp, xdr_argument, &argument)) {
459 		svcerr_decode(transp);
460 		goto leave;
461 	}
462 	result = (*local)(&argument, rqstp);
463 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
464 		svcerr_systemerr(transp);
465 	}
466 	if (!svc_freeargs(transp, xdr_argument, &argument)) {
467 		(void)fprintf(stderr, "unable to free arguments\n");
468 		exit(1);
469 	}
470 leave:
471         if (from_inetd)
472                 exit(0);
473 }
474