xref: /netbsd-src/libexec/rpc.rstatd/rstat_proc.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: rstat_proc.c,v 1.18 1997/02/22 01:41:35 thorpej 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.18 1997/02/22 01:41:35 thorpej 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 #include "dkstats.h"
60 #else
61 #include <sys/dk.h>
62 #endif
63 #include <net/if.h>
64 
65 #undef FSHIFT			 /* Use protocol's shift and scale values */
66 #undef FSCALE
67 #undef DK_NDRIVE
68 #undef CPUSTATES
69 #undef if_ipackets
70 #undef if_ierrors
71 #undef if_opackets
72 #undef if_oerrors
73 #undef if_collisions
74 #include <rpcsvc/rstat.h>
75 
76 #ifdef BSD
77 #define BSD_CPUSTATES	5	/* Use protocol's idea of CPU states */
78 int	cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE };
79 #endif
80 
81 struct nlist nl[] = {
82 #define	X_CNT		0
83 	{ "_cnt" },
84 #define	X_IFNET		1
85 	{ "_ifnet" },
86 #define	X_BOOTTIME	2
87 	{ "_boottime" },
88 	{ NULL },
89 };
90 
91 extern int dk_ndrive;		/* From dkstats.c */
92 extern struct _disk cur, last;
93 int hz;
94 char *memf = NULL, *nlistf = NULL;
95 
96 struct ifnet_head ifnetq;	/* chain of ethernet interfaces */
97 int numintfs;
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 stat_init()
120 {
121 	stat_is_init = 1;
122 	setup();
123 	updatestat();
124 	(void) signal(SIGALRM, updatestat);
125 	alarm(1);
126 }
127 
128 statstime *
129 rstatproc_stats_3_svc(arg, rqstp)
130 	void *arg;
131 	struct svc_req *rqstp;
132 {
133 	if (!stat_is_init)
134 	        stat_init();
135 	sincelastreq = 0;
136 	return (&stats_all.s3);
137 }
138 
139 statsswtch *
140 rstatproc_stats_2_svc(arg, rqstp)
141 	void *arg;
142 	struct svc_req *rqstp;
143 {
144 	if (!stat_is_init)
145 	        stat_init();
146 	sincelastreq = 0;
147 	return (&stats_all.s2);
148 }
149 
150 stats *
151 rstatproc_stats_1_svc(arg, rqstp)
152 	void *arg;
153 	struct svc_req *rqstp;
154 {
155 	if (!stat_is_init)
156 	        stat_init();
157 	sincelastreq = 0;
158 	return (&stats_all.s1);
159 }
160 
161 u_int *
162 rstatproc_havedisk_3_svc(arg, rqstp)
163 	void *arg;
164 	struct svc_req *rqstp;
165 {
166 	static u_int have;
167 
168 	if (!stat_is_init)
169 	        stat_init();
170 	sincelastreq = 0;
171 	have = havedisk();
172 	return (&have);
173 }
174 
175 u_int *
176 rstatproc_havedisk_2_svc(arg, rqstp)
177 	void *arg;
178 	struct svc_req *rqstp;
179 {
180 	return (rstatproc_havedisk_3_svc(arg, rqstp));
181 }
182 
183 u_int *
184 rstatproc_havedisk_1_svc(arg, rqstp)
185 	void *arg;
186 	struct svc_req *rqstp;
187 {
188 	return (rstatproc_havedisk_3_svc(arg, rqstp));
189 }
190 
191 void
192 updatestat()
193 {
194 	long off;
195 	int i;
196 	struct vmmeter cnt;
197 	struct ifnet ifnet;
198 	double avrun[3];
199 	struct timeval tm, btm;
200 #ifdef BSD
201 	int cp_time[BSD_CPUSTATES];
202 #endif
203 
204 #ifdef DEBUG
205 	syslog(LOG_DEBUG, "entering updatestat");
206 #endif
207 	if (sincelastreq >= closedown) {
208 #ifdef DEBUG
209                 syslog(LOG_DEBUG, "about to closedown");
210 #endif
211                 if (from_inetd)
212                         exit(0);
213                 else {
214                         stat_is_init = 0;
215                         return;
216                 }
217 	}
218 	sincelastreq++;
219 
220 	/*
221 	 * dkreadstats reads in the "disk_count" as well as the "disklist"
222 	 * statistics.  It also retrieves "hz" and the "cp_time" array.
223 	 */
224 	dkreadstats();
225 	memset(stats_all.s1.dk_xfer, 0, sizeof(stats_all.s1.dk_xfer));
226 	for (i = 0; i < dk_ndrive && i < DK_NDRIVE; i++)
227 		stats_all.s1.dk_xfer[i] = cur.dk_xfer[i];
228 
229 #ifdef BSD
230 	for (i = 0; i < CPUSTATES; i++)
231 		stats_all.s1.cp_time[i] = cur.cp_time[cp_xlat[i]];
232 #else
233  	if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
234 		     (char *)stats_all.s1.cp_time,
235 		     sizeof (stats_all.s1.cp_time))
236 	    != sizeof (stats_all.s1.cp_time)) {
237 		syslog(LOG_ERR, "can't read cp_time from kmem");
238 		exit(1);
239 	}
240 #endif
241 #ifdef BSD
242         (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
243 #endif
244 	stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
245 	stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
246 	stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
247  	if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value,
248 		     (char *)&btm, sizeof (stats_all.s2.boottime))
249 	    != sizeof (stats_all.s2.boottime)) {
250 		syslog(LOG_ERR, "can't read boottime from kmem");
251 		exit(1);
252 	}
253 	stats_all.s2.boottime.tv_sec = btm.tv_sec;
254 	stats_all.s2.boottime.tv_usec = btm.tv_usec;
255 
256 
257 #ifdef DEBUG
258 	syslog(LOG_DEBUG, "%d %d %d %d\n", stats_all.s1.cp_time[0],
259 	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
260 #endif
261 
262  	if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) !=
263 	    sizeof cnt) {
264 		syslog(LOG_ERR, "can't read cnt from kmem");
265 		exit(1);
266 	}
267 	stats_all.s1.v_pgpgin = cnt.v_pgpgin;
268 	stats_all.s1.v_pgpgout = cnt.v_pgpgout;
269 	stats_all.s1.v_pswpin = cnt.v_pswpin;
270 	stats_all.s1.v_pswpout = cnt.v_pswpout;
271 	stats_all.s1.v_intr = cnt.v_intr;
272 	gettimeofday(&tm, (struct timezone *) 0);
273 	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
274 	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
275 	stats_all.s2.v_swtch = cnt.v_swtch;
276 
277 	stats_all.s1.if_ipackets = 0;
278 	stats_all.s1.if_opackets = 0;
279 	stats_all.s1.if_ierrors = 0;
280 	stats_all.s1.if_oerrors = 0;
281 	stats_all.s1.if_collisions = 0;
282 	for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) {
283 		if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
284 		    sizeof ifnet) {
285 			syslog(LOG_ERR, "can't read ifnet from kmem");
286 			exit(1);
287 		}
288 		stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets;
289 		stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets;
290 		stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors;
291 		stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors;
292 		stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions;
293 		off = (long)ifnet.if_list.tqe_next;
294 	}
295 	gettimeofday((struct timeval *)&stats_all.s3.curtime,
296 		(struct timezone *) 0);
297 	alarm(1);
298 }
299 
300 setup()
301 {
302 	struct ifnet ifnet;
303 	long off;
304 	char errbuf[_POSIX2_LINE_MAX];
305 
306 	kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
307 	if (kfd == NULL) {
308 		syslog(LOG_ERR, "%s", errbuf);
309 		exit (1);
310 	}
311 
312 	if (kvm_nlist(kfd, nl) != 0) {
313 		syslog(LOG_ERR, "can't get namelist");
314 		exit (1);
315         }
316 
317 	if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &ifnetq,
318                      sizeof ifnetq) != sizeof ifnetq)  {
319 		syslog(LOG_ERR, "can't read ifnet queue head from kmem");
320 		exit(1);
321         }
322 
323 	numintfs = 0;
324 	for (off = (long)ifnetq.tqh_first; off;) {
325 		if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
326 		    sizeof ifnet) {
327 			syslog(LOG_ERR, "can't read ifnet from kmem");
328 			exit(1);
329 		}
330 		numintfs++;
331 		off = (long)ifnet.if_list.tqe_next;
332 	}
333 	dkinit(0);
334 }
335 
336 /*
337  * returns true if have a disk
338  */
339 int
340 havedisk()
341 {
342 	return dk_ndrive != 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 	xdrproc_t xdr_argument, xdr_result;
355 	char *(*local) __P((void *, struct svc_req *));
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 = (xdrproc_t)xdr_void;
364 		xdr_result = (xdrproc_t)xdr_statstime;
365                 switch (rqstp->rq_vers) {
366                 case RSTATVERS_ORIG:
367                         local = (char *(*) __P((void *, struct svc_req *)))
368 				rstatproc_stats_1_svc;
369                         break;
370                 case RSTATVERS_SWTCH:
371                         local = (char *(*) __P((void *, struct svc_req *)))
372 				rstatproc_stats_2_svc;
373                         break;
374                 case RSTATVERS_TIME:
375                         local = (char *(*) __P((void *, struct svc_req *)))
376 				rstatproc_stats_3_svc;
377                         break;
378                 default:
379                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
380                         goto leave;
381                 }
382 		break;
383 
384 	case RSTATPROC_HAVEDISK:
385 		xdr_argument = (xdrproc_t)xdr_void;
386 		xdr_result = (xdrproc_t)xdr_u_int;
387                 switch (rqstp->rq_vers) {
388                 case RSTATVERS_ORIG:
389                         local = (char *(*) __P((void *, struct svc_req *)))
390 				rstatproc_havedisk_1_svc;
391                         break;
392                 case RSTATVERS_SWTCH:
393                         local = (char *(*) __P((void *, struct svc_req *)))
394 				rstatproc_havedisk_2_svc;
395                         break;
396                 case RSTATVERS_TIME:
397                         local = (char *(*) __P((void *, struct svc_req *)))
398 				rstatproc_havedisk_3_svc;
399                         break;
400                 default:
401                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
402                         goto leave;
403                 }
404 		break;
405 
406 	default:
407 		svcerr_noproc(transp);
408 		goto leave;
409 	}
410 	bzero((char *)&argument, sizeof(argument));
411 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
412 		svcerr_decode(transp);
413 		goto leave;
414 	}
415 	result = (*local)(&argument, rqstp);
416 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
417 		svcerr_systemerr(transp);
418 	}
419 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
420 		(void)fprintf(stderr, "unable to free arguments\n");
421 		exit(1);
422 	}
423 leave:
424         if (from_inetd)
425                 exit(0);
426 }
427