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