xref: /freebsd/libexec/rpc.rstatd/rstat_proc.c (revision df7f5d4de4592a8948a25ce01e5bddfbb7ce39dc)
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$";
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 <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/dkstat.h>
44 #include <sys/errno.h>
45 #include <sys/socket.h>
46 #include <sys/sysctl.h>
47 #include <sys/time.h>
48 #include <sys/vmmeter.h>
49 
50 #include <fcntl.h>
51 #include <kvm.h>
52 #include <limits.h>
53 #include <nlist.h>
54 #include <signal.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <syslog.h>
59 
60 #include <net/if.h>
61 #include <net/if_mib.h>
62 
63 #include <rpc/rpc.h>
64 
65 #undef FSHIFT			 /* Use protocol's shift and scale values */
66 #undef FSCALE
67 #undef if_ipackets
68 #undef if_ierrors
69 #undef if_opackets
70 #undef if_oerrors
71 #undef if_collisions
72 #include <rpcsvc/rstat.h>
73 
74 struct nlist nl[] = {
75 #define	X_CPTIME	0
76 	{ "_cp_time" },
77 #define	X_CNT		1
78 	{ "_cnt" },
79 #define	X_DKXFER	2
80 	{ "_dk_xfer" },
81 #define	X_DKNDRIVE	3
82 	{ "_dk_ndrive" },
83 	{ "" },
84 };
85 int stats_service();
86 
87 extern int from_inetd;
88 int sincelastreq = 0;		/* number of alarms since last request */
89 extern int closedown;
90 
91 union {
92     struct stats s1;
93     struct statsswtch s2;
94     struct statstime s3;
95 } stats_all;
96 
97 void updatestat();
98 static stat_is_init = 0;
99 static kvm_t *kd;
100 extern int errno;
101 
102 static int	cp_time_xlat[RSTAT_CPUSTATES] = { CP_USER, CP_NICE, CP_SYS,
103 							CP_IDLE };
104 static long	bsd_cp_time[CPUSTATES];
105 
106 
107 #ifndef FSCALE
108 #define FSCALE (1 << 8)
109 #endif
110 
111 stat_init()
112 {
113     stat_is_init = 1;
114     setup();
115     updatestat();
116     (void) signal(SIGALRM, updatestat);
117     alarm(1);
118 }
119 
120 statstime *
121 rstatproc_stats_3()
122 {
123     if (! stat_is_init)
124         stat_init();
125     sincelastreq = 0;
126     return(&stats_all.s3);
127 }
128 
129 statsswtch *
130 rstatproc_stats_2()
131 {
132     if (! stat_is_init)
133         stat_init();
134     sincelastreq = 0;
135     return(&stats_all.s2);
136 }
137 
138 stats *
139 rstatproc_stats_1()
140 {
141     if (! stat_is_init)
142         stat_init();
143     sincelastreq = 0;
144     return(&stats_all.s1);
145 }
146 
147 u_int *
148 rstatproc_havedisk_3()
149 {
150     static u_int have;
151 
152     if (! stat_is_init)
153         stat_init();
154     sincelastreq = 0;
155     have = havedisk();
156 	return(&have);
157 }
158 
159 u_int *
160 rstatproc_havedisk_2()
161 {
162     return(rstatproc_havedisk_3());
163 }
164 
165 u_int *
166 rstatproc_havedisk_1()
167 {
168     return(rstatproc_havedisk_3());
169 }
170 
171 void
172 updatestat()
173 {
174 	int off, i, hz;
175 	struct clockinfo clockrate;
176 	struct vmmeter cnt;
177 	struct ifmibdata ifmd;
178 	double avrun[3];
179 	struct timeval tm, btm;
180 	int mib[6];
181 	size_t len;
182 	int ifcount;
183 
184 #ifdef DEBUG
185 	fprintf(stderr, "entering updatestat\n");
186 #endif
187 	if (sincelastreq >= closedown) {
188 #ifdef DEBUG
189                 fprintf(stderr, "about to closedown\n");
190 #endif
191                 if (from_inetd)
192                         exit(0);
193                 else {
194                         stat_is_init = 0;
195                         return;
196                 }
197 	}
198 	sincelastreq++;
199 
200 	mib[0] = CTL_KERN;
201 	mib[1] = KERN_CLOCKRATE;
202 	len = sizeof clockrate;
203 	if (sysctl(mib, 2, &clockrate, &len, 0, 0) < 0) {
204 		syslog(LOG_ERR, "sysctl(kern.clockrate): %m");
205 		exit(1);
206 	}
207 	hz = clockrate.hz;
208 
209 	if (kvm_read(kd, (long)nl[X_CPTIME].n_value, (char *)bsd_cp_time, sizeof(bsd_cp_time))
210 	    != sizeof(bsd_cp_time)) {
211 		syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n");
212 		exit(1);
213 	}
214 	for(i = 0; i < RSTAT_CPUSTATES ; i++)
215 		stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]];
216 
217         (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
218 
219 	stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
220 	stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
221 	stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
222 
223 	mib[0] = CTL_KERN;
224 	mib[1] = KERN_BOOTTIME;
225 	len = sizeof btm;
226 	if (sysctl(mib, 2, &btm, &len, 0, 0) < 0) {
227 		syslog(LOG_ERR, "sysctl(kern.boottime): %m");
228 		exit(1);
229 	}
230 
231 	stats_all.s2.boottime.tv_sec = btm.tv_sec;
232 	stats_all.s2.boottime.tv_usec = btm.tv_usec;
233 
234 
235 #ifdef DEBUG
236 	fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0],
237 	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
238 #endif
239 
240 	/* XXX - should use sysctl */
241  	if (kvm_read(kd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) != sizeof cnt) {
242 		syslog(LOG_ERR, "rstat: can't read cnt from kmem\n");
243 		exit(1);
244 	}
245 	stats_all.s1.v_pgpgin = cnt.v_vnodepgsin;
246 	stats_all.s1.v_pgpgout = cnt.v_vnodepgsout;
247 	stats_all.s1.v_pswpin = cnt.v_swappgsin;
248 	stats_all.s1.v_pswpout = cnt.v_swappgsout;
249 	stats_all.s1.v_intr = cnt.v_intr;
250 	gettimeofday(&tm, (struct timezone *) 0);
251 	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
252 	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
253 	stats_all.s2.v_swtch = cnt.v_swtch;
254 
255 	/* XXX - should use sysctl */
256  	if (kvm_read(kd, (long)nl[X_DKXFER].n_value, (char *)stats_all.s1.dk_xfer, sizeof (stats_all.s1.dk_xfer))
257 	    != sizeof (stats_all.s1.dk_xfer)) {
258 		syslog(LOG_ERR, "rstat: can't read dk_xfer from kmem\n");
259 		exit(1);
260 	}
261 
262 	mib[0] = CTL_NET;
263 	mib[1] = PF_LINK;
264 	mib[2] = NETLINK_GENERIC;
265 	mib[3] = IFMIB_SYSTEM;
266 	mib[4] = IFMIB_IFCOUNT;
267 	len = sizeof ifcount;
268 	if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) {
269 		syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m");
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 (i = 1; i <= ifcount; i++) {
279 		len = sizeof ifmd;
280 		mib[3] = IFMIB_IFDATA;
281 		mib[4] = i;
282 		mib[5] = IFDATA_GENERAL;
283 		if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) {
284 			syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)"
285 			       ": %m", i);
286 			exit(1);
287 		}
288 
289 		stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets;
290 		stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets;
291 		stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors;
292 		stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors;
293 		stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions;
294 	}
295 	gettimeofday((struct timeval *)&stats_all.s3.curtime,
296 		(struct timezone *) 0);
297 	alarm(1);
298 }
299 
300 setup()
301 {
302 	int off;
303 	char errbuf[_POSIX2_LINE_MAX];
304 
305 	int en;
306 
307 	if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) {
308 		syslog(LOG_ERR, "rpc.rstatd, %s", errbuf);
309 		exit(1);
310 	}
311 
312 	if ((en = kvm_nlist(kd, nl)) != 0) {
313 		syslog(LOG_ERR, "rstatd: Can't get namelist. %d", en);
314 		exit (1);
315         }
316 }
317 
318 /*
319  * returns true if have a disk
320  */
321 havedisk()
322 {
323 	int i, cnt;
324 	int dk_ndrive;
325 
326 	if (kvm_nlist(kd, nl) != 0) {
327 		syslog(LOG_ERR, "rstatd: Can't get namelist.(d)");
328 		exit (1);
329         }
330 
331 	if (kvm_read(kd, (long)nl[X_DKNDRIVE].n_value, (char *)&dk_ndrive,
332 		     sizeof dk_ndrive)!= sizeof dk_ndrive) {
333 		syslog(LOG_ERR, "rstat: can't read kmem\n");
334 		exit(1);
335 	}
336 	return (dk_ndrive != 0);
337 }
338 
339 void
340 rstat_service(rqstp, transp)
341 	struct svc_req *rqstp;
342 	SVCXPRT *transp;
343 {
344 	union {
345 		int fill;
346 	} argument;
347 	char *result;
348 	bool_t (*xdr_argument)(), (*xdr_result)();
349 	char *(*local)();
350 
351 	switch (rqstp->rq_proc) {
352 	case NULLPROC:
353 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
354 		goto leave;
355 
356 	case RSTATPROC_STATS:
357 		xdr_argument = xdr_void;
358 		xdr_result = xdr_statstime;
359                 switch (rqstp->rq_vers) {
360                 case RSTATVERS_ORIG:
361                         local = (char *(*)()) rstatproc_stats_1;
362                         break;
363                 case RSTATVERS_SWTCH:
364                         local = (char *(*)()) rstatproc_stats_2;
365                         break;
366                 case RSTATVERS_TIME:
367                         local = (char *(*)()) rstatproc_stats_3;
368                         break;
369                 default:
370                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
371                         goto leave;
372                         /*NOTREACHED*/
373                 }
374 		break;
375 
376 	case RSTATPROC_HAVEDISK:
377 		xdr_argument = xdr_void;
378 		xdr_result = xdr_u_int;
379                 switch (rqstp->rq_vers) {
380                 case RSTATVERS_ORIG:
381                         local = (char *(*)()) rstatproc_havedisk_1;
382                         break;
383                 case RSTATVERS_SWTCH:
384                         local = (char *(*)()) rstatproc_havedisk_2;
385                         break;
386                 case RSTATVERS_TIME:
387                         local = (char *(*)()) rstatproc_havedisk_3;
388                         break;
389                 default:
390                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
391                         goto leave;
392                         /*NOTREACHED*/
393                 }
394 		break;
395 
396 	default:
397 		svcerr_noproc(transp);
398 		goto leave;
399 	}
400 	bzero((char *)&argument, sizeof(argument));
401 	if (!svc_getargs(transp, xdr_argument, &argument)) {
402 		svcerr_decode(transp);
403 		goto leave;
404 	}
405 	result = (*local)(&argument, rqstp);
406 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
407 		svcerr_systemerr(transp);
408 	}
409 	if (!svc_freeargs(transp, xdr_argument, &argument)) {
410 		(void)fprintf(stderr, "unable to free arguments\n");
411 		exit(1);
412 	}
413 leave:
414         if (from_inetd)
415                 exit(0);
416 }
417