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