xref: /netbsd-src/libexec/rpc.rstatd/rstat_proc.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
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