xref: /netbsd-src/libexec/rpc.rstatd/rstat_proc.c (revision 5f7096188587a2c7c95fa3c69b78e1ec9c7923d0)
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.4 1993/09/23 18:42:39 jtc 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 <rpc/rpc.h>
46 #include <sys/socket.h>
47 #include <nlist.h>
48 #include <syslog.h>
49 #include <sys/errno.h>
50 #include <sys/param.h>
51 #ifdef BSD
52 #include <sys/vmmeter.h>
53 #include <sys/dkstat.h>
54 #else
55 #include <sys/dk.h>
56 #endif
57 #include <net/if.h>
58 
59 #undef FSHIFT			 /* Use protocol's shift and scale values */
60 #undef FSCALE
61 #include <rpcsvc/rstat.h>
62 
63 struct nlist nl[] = {
64 #define	X_CPTIME	0
65 	{ "_cp_time" },
66 #define	X_SUM		1
67 	{ "_sum" },
68 #define	X_IFNET		2
69 	{ "_ifnet" },
70 #define	X_DKXFER	3
71 	{ "_dk_xfer" },
72 #define	X_BOOTTIME	4
73 	{ "_boottime" },
74 #define X_HZ		5
75 	{ "_hz" },
76 #ifdef vax
77 #define	X_AVENRUN	6
78 	{ "_avenrun" },
79 #endif
80 	"",
81 };
82 int firstifnet, numintfs;	/* chain of ethernet interfaces */
83 int stats_service();
84 
85 extern int from_inetd;
86 int sincelastreq = 0;		/* number of alarms since last request */
87 extern int closedown;
88 
89 union {
90     struct stats s1;
91     struct statsswtch s2;
92     struct statstime s3;
93 } stats_all;
94 
95 void updatestat();
96 static stat_is_init = 0;
97 extern int errno;
98 
99 #ifndef FSCALE
100 #define FSCALE (1 << 8)
101 #endif
102 
103 #ifndef BSD
104 /*
105  * BSD has the kvm facility for getting info from the
106  * kernel. If you aren't on BSD, this surfices.
107  */
108 int kmem;
109 
110 kvm_read(off, addr, size)
111         unsigned long off, size;
112         char *addr;
113 {
114         int len;
115 	if (lseek(kmem, (long)off, 0) == -1)
116                 return(-1);
117 	return(read(kmem, addr, size));
118 }
119 
120 kvm_nlist(nl)
121         struct nlist *nl;
122 {
123 	int n = nlist("/vmunix", nl);
124 	if (nl[0].n_value == 0)
125                 return(n);
126 
127 	if ((kmem = open("/dev/kmem", 0)) < 0)
128                 return(-1);
129         return(0);
130 }
131 #endif
132 
133 stat_init()
134 {
135     stat_is_init = 1;
136     setup();
137     updatestat();
138     (void) signal(SIGALRM, updatestat);
139     alarm(1);
140 }
141 
142 statstime *
143 rstatproc_stats_3()
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()
153 {
154     if (! stat_is_init)
155         stat_init();
156     sincelastreq = 0;
157     return(&stats_all.s2);
158 }
159 
160 stats *
161 rstatproc_stats_1()
162 {
163     if (! stat_is_init)
164         stat_init();
165     sincelastreq = 0;
166     return(&stats_all.s1);
167 }
168 
169 u_int *
170 rstatproc_havedisk_3()
171 {
172     static u_int have;
173 
174     if (! stat_is_init)
175         stat_init();
176     sincelastreq = 0;
177     have = havedisk();
178 	return(&have);
179 }
180 
181 u_int *
182 rstatproc_havedisk_2()
183 {
184     return(rstatproc_havedisk_3());
185 }
186 
187 u_int *
188 rstatproc_havedisk_1()
189 {
190     return(rstatproc_havedisk_3());
191 }
192 
193 void
194 updatestat()
195 {
196 	int off, i, hz;
197 	struct vmmeter sum;
198 	struct ifnet ifnet;
199 	double avrun[3];
200 	struct timeval tm, btm;
201 
202 #ifdef DEBUG
203 	fprintf(stderr, "entering updatestat\n");
204 #endif
205 	if (sincelastreq >= closedown) {
206 #ifdef DEBUG
207                 fprintf(stderr, "about to closedown\n");
208 #endif
209                 if (from_inetd)
210                         exit(0);
211                 else {
212                         stat_is_init = 0;
213                         return;
214                 }
215 	}
216 	sincelastreq++;
217 
218 	if (kvm_read((long)nl[X_HZ].n_value, (char *)&hz, sizeof hz) != sizeof hz) {
219 		syslog(LOG_ERR, "rstat: can't read hz from kmem\n");
220 		exit(1);
221 	}
222  	if (kvm_read((long)nl[X_CPTIME].n_value, (char *)stats_all.s1.cp_time, sizeof (stats_all.s1.cp_time))
223 	    != sizeof (stats_all.s1.cp_time)) {
224 		syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n");
225 		exit(1);
226 	}
227 #ifdef vax
228  	if (kvm_read((long)nl[X_AVENRUN].n_value, (char *)avrun, sizeof (avrun)) != sizeof (avrun)) {
229 		syslog(LOG_ERR, "rstat: can't read avenrun from kmem\n");
230 		exit(1);
231 	}
232 #endif
233 #ifdef BSD
234         (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
235 #endif
236 	stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
237 	stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
238 	stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
239  	if (kvm_read((long)nl[X_BOOTTIME].n_value, (char *)&btm, sizeof (stats_all.s2.boottime))
240 	    != sizeof (stats_all.s2.boottime)) {
241 		syslog(LOG_ERR, "rstat: can't read boottime from kmem\n");
242 		exit(1);
243 	}
244 	stats_all.s2.boottime.tv_sec = btm.tv_sec;
245 	stats_all.s2.boottime.tv_usec = btm.tv_usec;
246 
247 
248 #ifdef DEBUG
249 	fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0],
250 	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
251 #endif
252 
253  	if (kvm_read((long)nl[X_SUM].n_value, (char *)&sum, sizeof sum) != sizeof sum) {
254 		syslog(LOG_ERR, "rstat: can't read sum from kmem\n");
255 		exit(1);
256 	}
257 	stats_all.s1.v_pgpgin = sum.v_pgpgin;
258 	stats_all.s1.v_pgpgout = sum.v_pgpgout;
259 	stats_all.s1.v_pswpin = sum.v_pswpin;
260 	stats_all.s1.v_pswpout = sum.v_pswpout;
261 	stats_all.s1.v_intr = sum.v_intr;
262 	gettimeofday(&tm, (struct timezone *) 0);
263 	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
264 	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
265 	stats_all.s2.v_swtch = sum.v_swtch;
266 
267  	if (kvm_read((long)nl[X_DKXFER].n_value, (char *)stats_all.s1.dk_xfer, sizeof (stats_all.s1.dk_xfer))
268 	    != sizeof (stats_all.s1.dk_xfer)) {
269 		syslog(LOG_ERR, "rstat: can't read dk_xfer from kmem\n");
270 		exit(1);
271 	}
272 
273 	stats_all.s1.if_ipackets = 0;
274 	stats_all.s1.if_opackets = 0;
275 	stats_all.s1.if_ierrors = 0;
276 	stats_all.s1.if_oerrors = 0;
277 	stats_all.s1.if_collisions = 0;
278 	for (off = firstifnet, i = 0; off && i < numintfs; i++) {
279 		if (kvm_read(off, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) {
280 			syslog(LOG_ERR, "rstat: can't read ifnet from kmem\n");
281 			exit(1);
282 		}
283 		stats_all.s1.if_ipackets += ifnet.if_ipackets;
284 		stats_all.s1.if_opackets += ifnet.if_opackets;
285 		stats_all.s1.if_ierrors += ifnet.if_ierrors;
286 		stats_all.s1.if_oerrors += ifnet.if_oerrors;
287 		stats_all.s1.if_collisions += ifnet.if_collisions;
288 		off = (int) ifnet.if_next;
289 	}
290 	gettimeofday((struct timeval *)&stats_all.s3.curtime,
291 		(struct timezone *) 0);
292 	alarm(1);
293 }
294 
295 setup()
296 {
297 	struct ifnet ifnet;
298 	int off;
299 
300 	if (kvm_nlist(nl) != 0) {
301 		syslog(LOG_ERR, "rstatd: Can't get namelist.");
302 		exit (1);
303         }
304 
305 	if (kvm_read((long)nl[X_IFNET].n_value, &firstifnet,
306                      sizeof(int)) != sizeof(int))  {
307 		syslog(LOG_ERR, "rstat: can't read firstifnet from kmem\n");
308 		exit(1);
309         }
310 
311 	numintfs = 0;
312 	for (off = firstifnet; off;) {
313 		if (kvm_read(off, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) {
314 			syslog(LOG_ERR, "rstat: can't read ifnet from kmem\n");
315 			exit(1);
316 		}
317 		numintfs++;
318 		off = (int) ifnet.if_next;
319 	}
320 }
321 
322 /*
323  * returns true if have a disk
324  */
325 havedisk()
326 {
327 	int i, cnt;
328 	long  xfer[DK_NDRIVE];
329 
330 	if (kvm_nlist(nl) != 0) {
331 		syslog(LOG_ERR, "rstatd: Can't get namelist.");
332 		exit (1);
333         }
334 
335 	if (kvm_read((long)nl[X_DKXFER].n_value, (char *)xfer, sizeof xfer)!= sizeof xfer) {
336 		syslog(LOG_ERR, "rstat: can't read kmem\n");
337 		exit(1);
338 	}
339 	cnt = 0;
340 	for (i=0; i < DK_NDRIVE; i++)
341 		cnt += xfer[i];
342 	return (cnt != 0);
343 }
344 
345 void
346 rstat_service(rqstp, transp)
347 	struct svc_req *rqstp;
348 	SVCXPRT *transp;
349 {
350 	union {
351 		int fill;
352 	} argument;
353 	char *result;
354 	bool_t (*xdr_argument)(), (*xdr_result)();
355 	char *(*local)();
356 
357 	switch (rqstp->rq_proc) {
358 	case NULLPROC:
359 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
360 		goto leave;
361 
362 	case RSTATPROC_STATS:
363 		xdr_argument = xdr_void;
364 		xdr_result = xdr_statstime;
365                 switch (rqstp->rq_vers) {
366                 case RSTATVERS_ORIG:
367                         local = (char *(*)()) rstatproc_stats_1;
368                         break;
369                 case RSTATVERS_SWTCH:
370                         local = (char *(*)()) rstatproc_stats_2;
371                         break;
372                 case RSTATVERS_TIME:
373                         local = (char *(*)()) rstatproc_stats_3;
374                         break;
375                 default:
376                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
377                         goto leave;
378                         /*NOTREACHED*/
379                 }
380 		break;
381 
382 	case RSTATPROC_HAVEDISK:
383 		xdr_argument = xdr_void;
384 		xdr_result = xdr_u_int;
385                 switch (rqstp->rq_vers) {
386                 case RSTATVERS_ORIG:
387                         local = (char *(*)()) rstatproc_havedisk_1;
388                         break;
389                 case RSTATVERS_SWTCH:
390                         local = (char *(*)()) rstatproc_havedisk_2;
391                         break;
392                 case RSTATVERS_TIME:
393                         local = (char *(*)()) rstatproc_havedisk_3;
394                         break;
395                 default:
396                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
397                         goto leave;
398                         /*NOTREACHED*/
399                 }
400 		break;
401 
402 	default:
403 		svcerr_noproc(transp);
404 		goto leave;
405 	}
406 	bzero((char *)&argument, sizeof(argument));
407 	if (!svc_getargs(transp, xdr_argument, &argument)) {
408 		svcerr_decode(transp);
409 		goto leave;
410 	}
411 	result = (*local)(&argument, rqstp);
412 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
413 		svcerr_systemerr(transp);
414 	}
415 	if (!svc_freeargs(transp, xdr_argument, &argument)) {
416 		(void)fprintf(stderr, "unable to free arguments\n");
417 		exit(1);
418 	}
419 leave:
420         if (from_inetd)
421                 exit(0);
422 }
423