xref: /openbsd-src/libexec/rpc.rstatd/rstat_proc.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: rstat_proc.c,v 1.24 2003/07/29 18:39:23 deraadt 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[] = "$OpenBSD: rstat_proc.c,v 1.24 2003/07/29 18:39:23 deraadt 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 <sys/param.h>
44 #include <sys/vmmeter.h>
45 #include <sys/dkstat.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <net/if.h>
49 #include <uvm/uvm_extern.h>
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <signal.h>
55 #include <syslog.h>
56 #include <fcntl.h>
57 #include <limits.h>
58 #include <errno.h>
59 #include <ifaddrs.h>
60 #include "dkstats.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 int	cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE };
74 
75 extern int dk_ndrive;		/* from dkstats.c */
76 extern struct _disk cur, last;
77 char *memf = NULL, *nlistf = NULL;
78 int hz;
79 
80 extern int from_inetd;
81 int sincelastreq = 0;		/* number of alarms since last request */
82 extern int closedown;
83 
84 union {
85 	struct stats s1;
86 	struct statsswtch s2;
87 	struct statstime s3;
88 } stats_all;
89 
90 void	updatestat(void);
91 void	updatestatsig(int sig);
92 void	setup(void);
93 
94 volatile sig_atomic_t wantupdatestat;
95 
96 static int stat_is_init = 0;
97 
98 #ifndef FSCALE
99 #define FSCALE (1 << 8)
100 #endif
101 
102 static void
103 stat_init(void)
104 {
105 	stat_is_init = 1;
106 	setup();
107 	updatestat();
108 	(void) signal(SIGALRM, updatestatsig);
109 	alarm(1);
110 }
111 
112 statstime *
113 rstatproc_stats_3_svc(void *arg, struct svc_req *rqstp)
114 {
115 	if (!stat_is_init)
116 		stat_init();
117 	sincelastreq = 0;
118 	return (&stats_all.s3);
119 }
120 
121 statsswtch *
122 rstatproc_stats_2_svc(void *arg, struct svc_req *rqstp)
123 {
124 	if (!stat_is_init)
125 		stat_init();
126 	sincelastreq = 0;
127 	return (&stats_all.s2);
128 }
129 
130 stats *
131 rstatproc_stats_1_svc(void *arg, struct svc_req *rqstp)
132 {
133 	if (!stat_is_init)
134 		stat_init();
135 	sincelastreq = 0;
136 	return (&stats_all.s1);
137 }
138 
139 u_int *
140 rstatproc_havedisk_3_svc(void *arg, struct svc_req *rqstp)
141 {
142 	static u_int have;
143 
144 	if (!stat_is_init)
145 		stat_init();
146 	sincelastreq = 0;
147 	have = dk_ndrive != 0;
148 	return (&have);
149 }
150 
151 u_int *
152 rstatproc_havedisk_2_svc(void *arg, struct svc_req *rqstp)
153 {
154 	return (rstatproc_havedisk_3_svc(arg, rqstp));
155 }
156 
157 u_int *
158 rstatproc_havedisk_1_svc(void *arg, struct svc_req *rqstp)
159 {
160 	return (rstatproc_havedisk_3_svc(arg, rqstp));
161 }
162 
163 void
164 updatestatsig(int sig)
165 {
166 	wantupdatestat = 1;
167 }
168 
169 void
170 updatestat(void)
171 {
172 	int i, mib[2], save_errno = errno;
173 	struct uvmexp uvmexp;
174 	size_t len;
175 	struct if_data *ifdp;
176 	struct ifaddrs *ifaddrs, *ifa;
177 	double avrun[3];
178 	struct timeval tm, btm;
179 	long *cp_time = cur.cp_time;
180 
181 #ifdef DEBUG
182 	syslog(LOG_DEBUG, "entering updatestat");
183 #endif
184 	if (sincelastreq >= closedown) {
185 #ifdef DEBUG
186 		syslog(LOG_DEBUG, "about to closedown");
187 #endif
188 		if (from_inetd)
189 			_exit(0);
190 		else {
191 			stat_is_init = 0;
192 			errno = save_errno;
193 			return;
194 		}
195 	}
196 	sincelastreq++;
197 
198 	/*
199 	 * dkreadstats reads in the "disk_count" as well as the "disklist"
200 	 * statistics.  It also retrieves "hz" and the "cp_time" array.
201 	 */
202 	dkreadstats();
203 	memset(stats_all.s1.dk_xfer, '\0', sizeof(stats_all.s1.dk_xfer));
204 	for (i = 0; i < dk_ndrive && i < DK_NDRIVE; i++)
205 		stats_all.s1.dk_xfer[i] = cur.dk_xfer[i];
206 
207 	for (i = 0; i < CPUSTATES; i++)
208 		stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]];
209 	(void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
210 	stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
211 	stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
212 	stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
213 	mib[0] = CTL_KERN;
214 	mib[1] = KERN_BOOTTIME;
215 	len = sizeof(btm);
216 	if (sysctl(mib, 2, &btm, &len, NULL, 0) < 0) {
217 		syslog(LOG_ERR, "can't sysctl kern.boottime: %m");
218 		_exit(1);
219 	}
220 	stats_all.s2.boottime.tv_sec = btm.tv_sec;
221 	stats_all.s2.boottime.tv_usec = btm.tv_usec;
222 
223 
224 #ifdef DEBUG
225 	syslog(LOG_DEBUG, "%d %d %d %d", stats_all.s1.cp_time[0],
226 	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2],
227 	    stats_all.s1.cp_time[3]);
228 #endif
229 
230 	mib[0] = CTL_VM;
231 	mib[1] = VM_UVMEXP;
232 	len = sizeof(uvmexp);
233 	if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0) {
234 		syslog(LOG_ERR, "can't sysctl vm.uvmexp: %m");
235 		_exit(1);
236 	}
237 	stats_all.s1.v_pgpgin = uvmexp.fltanget;
238 	stats_all.s1.v_pgpgout = uvmexp.pdpageouts;
239 	stats_all.s1.v_pswpin = uvmexp.swapins;
240 	stats_all.s1.v_pswpout = uvmexp.swapouts;
241 	stats_all.s1.v_intr = uvmexp.intrs;
242 	stats_all.s2.v_swtch = uvmexp.swtch;
243 	gettimeofday(&tm, (struct timezone *) 0);
244 	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
245 	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
246 	stats_all.s1.if_ipackets = 0;
247 	stats_all.s1.if_opackets = 0;
248 	stats_all.s1.if_ierrors = 0;
249 	stats_all.s1.if_oerrors = 0;
250 	stats_all.s1.if_collisions = 0;
251 	if (getifaddrs(&ifaddrs) == -1) {
252 		syslog(LOG_ERR, "can't getifaddrs: %m");
253 		_exit(1);
254 	}
255 	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
256 		if (ifa->ifa_addr->sa_family != AF_LINK)
257 			continue;
258 		ifdp = (struct if_data *)ifa->ifa_data;
259 		stats_all.s1.if_ipackets += ifdp->ifi_ipackets;
260 		stats_all.s1.if_opackets += ifdp->ifi_opackets;
261 		stats_all.s1.if_ierrors += ifdp->ifi_ierrors;
262 		stats_all.s1.if_oerrors += ifdp->ifi_oerrors;
263 		stats_all.s1.if_collisions += ifdp->ifi_collisions;
264 	}
265 	freeifaddrs(ifaddrs);
266 	stats_all.s3.curtime.tv_sec = tm.tv_sec;
267 	stats_all.s3.curtime.tv_usec = tm.tv_usec;
268 
269 	alarm(1);
270 	errno = save_errno;
271 }
272 
273 void
274 setup(void)
275 {
276 	dkinit(0);
277 }
278 
279 void	rstat_service(struct svc_req *, SVCXPRT *);
280 
281 void
282 rstat_service(struct svc_req *rqstp, SVCXPRT *transp)
283 {
284 	char *(*local)(void *, struct svc_req *);
285 	xdrproc_t xdr_argument, xdr_result;
286 	union {
287 		int fill;
288 	} argument;
289 	char *result;
290 
291 	switch (rqstp->rq_proc) {
292 	case NULLPROC:
293 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
294 		return;
295 
296 	case RSTATPROC_STATS:
297 		xdr_argument = (xdrproc_t)xdr_void;
298 		xdr_result = (xdrproc_t)xdr_statstime;
299 		switch (rqstp->rq_vers) {
300 		case RSTATVERS_ORIG:
301 			local = (char *(*)(void *, struct svc_req *))
302 				rstatproc_stats_1_svc;
303 			break;
304 		case RSTATVERS_SWTCH:
305 			local = (char *(*)(void *, struct svc_req *))
306 				rstatproc_stats_2_svc;
307 			break;
308 		case RSTATVERS_TIME:
309 			local = (char *(*)(void *, struct svc_req *))
310 				rstatproc_stats_3_svc;
311 			break;
312 		default:
313 			svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
314 			return;
315 		}
316 		break;
317 
318 	case RSTATPROC_HAVEDISK:
319 		xdr_argument = (xdrproc_t)xdr_void;
320 		xdr_result = (xdrproc_t)xdr_u_int;
321 		switch (rqstp->rq_vers) {
322 		case RSTATVERS_ORIG:
323 			local = (char *(*)(void *, struct svc_req *))
324 				rstatproc_havedisk_1_svc;
325 			break;
326 		case RSTATVERS_SWTCH:
327 			local = (char *(*)(void *, struct svc_req *))
328 				rstatproc_havedisk_2_svc;
329 			break;
330 		case RSTATVERS_TIME:
331 			local = (char *(*)(void *, struct svc_req *))
332 				rstatproc_havedisk_3_svc;
333 			break;
334 		default:
335 			svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
336 			return;
337 		}
338 		break;
339 
340 	default:
341 		svcerr_noproc(transp);
342 		return;
343 	}
344 	bzero((char *)&argument, sizeof(argument));
345 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
346 		svcerr_decode(transp);
347 		return;
348 	}
349 	result = (*local)(&argument, rqstp);
350 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
351 		svcerr_systemerr(transp);
352 	}
353 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
354 		syslog(LOG_ERR, "unable to free arguments");
355 		exit(1);
356 	}
357 }
358