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