rstat_proc.c revision 1.49 1 /* $NetBSD: rstat_proc.c,v 1.49 2014/06/02 18:17:51 joerg 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
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: rstat_proc.c,v 1.49 2014/06/02 18:17:51 joerg Exp $");
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/param.h>
42 #include <sys/sched.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
45
46 #include <errno.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <signal.h>
51 #include <fcntl.h>
52 #include <limits.h>
53 #include <nlist.h>
54 #include <syslog.h>
55 #include <sys/sysctl.h>
56 #include <uvm/uvm_extern.h>
57 #include "drvstats.h"
58 #include <net/if.h>
59
60 /*
61 * XXX
62 *
63 * this is a huge hack to stop `struct pmap' being
64 * defined twice!
65 */
66 #define _RPC_PMAP_PROT_H_
67 #include <rpc/rpc.h>
68
69 #undef FSHIFT /* Use protocol's shift and scale values */
70 #undef FSCALE
71 #undef DK_NDRIVE
72 #undef CPUSTATES
73 #undef if_ipackets
74 #undef if_ierrors
75 #undef if_opackets
76 #undef if_oerrors
77 #undef if_collisions
78 #include <rpcsvc/rstat.h>
79
80 #define BSD_CPUSTATES 5 /* Use protocol's idea of CPU states */
81 int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE };
82
83 struct nlist nl[] = {
84 #define X_IFNET 0
85 { "_ifnet", 0, 0, 0, 0 },
86 { NULL, 0, 0, 0, 0 },
87 };
88
89 int hz;
90 char *memf = NULL, *nlistf = NULL;
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(int);
103 void stat_init(void);
104 int havedisk(void);
105 void rstat_service(struct svc_req *, SVCXPRT *);
106
107 static int stat_is_init = 0;
108
109 #ifndef FSCALE
110 #define FSCALE (1 << 8)
111 #endif
112
113 void
114 stat_init(void)
115 {
116 stat_is_init = 1;
117 drvinit(0);
118 updatestat(0);
119 (void) signal(SIGALRM, updatestat);
120 alarm(1);
121 }
122
123 statstime *
124 rstatproc_stats_3_svc(void *arg, struct svc_req *rqstp)
125 {
126 if (!stat_is_init)
127 stat_init();
128 sincelastreq = 0;
129 return (&stats_all.s3);
130 }
131
132 statsswtch *
133 rstatproc_stats_2_svc(void *arg, struct svc_req *rqstp)
134 {
135 if (!stat_is_init)
136 stat_init();
137 sincelastreq = 0;
138 stats_all.s2.if_opackets = stats_all.s3.if_opackets;
139 return (&stats_all.s2);
140 }
141
142 stats *
143 rstatproc_stats_1_svc(void *arg, struct svc_req *rqstp)
144 {
145 if (!stat_is_init)
146 stat_init();
147 sincelastreq = 0;
148 stats_all.s1.if_opackets = stats_all.s3.if_opackets;
149 return (&stats_all.s1);
150 }
151
152 u_int *
153 rstatproc_havedisk_3_svc(void *arg, struct svc_req *rqstp)
154 {
155 static u_int have;
156
157 if (!stat_is_init)
158 stat_init();
159 sincelastreq = 0;
160 have = havedisk();
161 return (&have);
162 }
163
164 u_int *
165 rstatproc_havedisk_2_svc(void *arg, struct svc_req *rqstp)
166 {
167 return (rstatproc_havedisk_3_svc(arg, rqstp));
168 }
169
170 u_int *
171 rstatproc_havedisk_1_svc(void *arg, struct svc_req *rqstp)
172 {
173 return (rstatproc_havedisk_3_svc(arg, rqstp));
174 }
175
176 void
177 updatestat(int dummy)
178 {
179 struct if_nameindex *ifps;
180 struct ifdatareq ifdr;
181 size_t i, len;
182 int mib[2], s;
183 struct uvmexp_sysctl uvmexp;
184 double avrun[3];
185 struct timeval tm, btm;
186
187 #ifdef DEBUG
188 syslog(LOG_DEBUG, "entering updatestat");
189 #endif
190 if (sincelastreq >= closedown) {
191 #ifdef DEBUG
192 syslog(LOG_DEBUG, "about to closedown");
193 #endif
194 if (from_inetd)
195 exit(0);
196 else {
197 stat_is_init = 0;
198 return;
199 }
200 }
201 sincelastreq++;
202
203 /*
204 * drvreadstats reads in the "disk_count" as well as the "disklist"
205 * statistics. It also retrieves "hz" and the "cp_time" array.
206 */
207 drvreadstats();
208 memset(stats_all.s3.dk_xfer, 0, sizeof(stats_all.s3.dk_xfer));
209 for (i = 0; i < ndrive && i < DK_NDRIVE; i++)
210 stats_all.s3.dk_xfer[i] = cur.rxfer[i] + cur.wxfer[i];
211
212 for (i = 0; i < CPUSTATES; i++)
213 stats_all.s3.cp_time[i] = cur.cp_time[cp_xlat[i]];
214 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
215 stats_all.s3.avenrun[0] = avrun[0] * FSCALE;
216 stats_all.s3.avenrun[1] = avrun[1] * FSCALE;
217 stats_all.s3.avenrun[2] = avrun[2] * FSCALE;
218 mib[0] = CTL_KERN;
219 mib[1] = KERN_BOOTTIME;
220 len = sizeof(btm);
221 if (sysctl(mib, 2, &btm, &len, NULL, 0) < 0) {
222 syslog(LOG_ERR, "can't sysctl kern.boottime");
223 exit(1);
224 }
225 stats_all.s3.boottime.tv_sec = btm.tv_sec;
226 stats_all.s3.boottime.tv_usec = btm.tv_usec;
227
228
229 #ifdef DEBUG
230 syslog(LOG_DEBUG, "%d %d %d %d %d\n", stats_all.s3.cp_time[0],
231 stats_all.s3.cp_time[1], stats_all.s3.cp_time[2],
232 stats_all.s3.cp_time[3], stats_all.s3.cp_time[4]);
233 #endif
234
235 mib[0] = CTL_VM;
236 mib[1] = VM_UVMEXP2;
237 len = sizeof(uvmexp);
238 if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0) {
239 syslog(LOG_ERR, "can't sysctl vm.uvmexp2");
240 exit(1);
241 }
242 stats_all.s3.v_pgpgin = uvmexp.fltanget;
243 stats_all.s3.v_pgpgout = uvmexp.pdpageouts;
244 stats_all.s3.v_pswpin = uvmexp.swapins;
245 stats_all.s3.v_pswpout = uvmexp.swapouts;
246 stats_all.s3.v_intr = uvmexp.intrs;
247 stats_all.s3.v_swtch = uvmexp.swtch;
248 gettimeofday(&tm, (struct timezone *) 0);
249 stats_all.s3.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
250 hz*(tm.tv_usec - btm.tv_usec)/1000000;
251
252 stats_all.s3.if_ipackets = 0;
253 stats_all.s3.if_opackets = 0;
254 stats_all.s3.if_ierrors = 0;
255 stats_all.s3.if_oerrors = 0;
256 stats_all.s3.if_collisions = 0;
257
258 ifps = if_nameindex();
259 if (ifps == NULL) {
260 syslog(LOG_ERR, "can't read interface list from kernel");
261 exit(1);
262 }
263 s = socket(AF_INET, SOCK_DGRAM, 0);
264 for (i = 0; s != -1 && ifps[i].if_name != NULL; ++i) {
265 strncpy(ifdr.ifdr_name, ifps[i].if_name, sizeof(ifdr.ifdr_name));
266 if (ioctl(s, SIOCGIFDATA, &ifdr) != 0)
267 continue;
268 stats_all.s3.if_ipackets += ifdr.ifdr_data.ifi_ipackets;
269 stats_all.s3.if_opackets += ifdr.ifdr_data.ifi_opackets;
270 stats_all.s3.if_ierrors += ifdr.ifdr_data.ifi_ierrors;
271 stats_all.s3.if_oerrors += ifdr.ifdr_data.ifi_oerrors;
272 stats_all.s3.if_collisions += ifdr.ifdr_data.ifi_collisions;
273 }
274 if (s != -1)
275 close(s);
276 if_freenameindex(ifps);
277
278 stats_all.s3.curtime.tv_sec = tm.tv_sec;
279 stats_all.s3.curtime.tv_usec = tm.tv_usec;
280 alarm(1);
281 }
282
283 /*
284 * returns true if have a disk
285 */
286 int
287 havedisk(void)
288 {
289 return ndrive != 0;
290 }
291
292 void
293 rstat_service(struct svc_req *rqstp, SVCXPRT *transp)
294 {
295 union {
296 int fill;
297 } argument;
298 char *result;
299 xdrproc_t xdr_argument, xdr_result;
300 char *(*local)(void *, struct svc_req *);
301
302 switch (rqstp->rq_proc) {
303 case NULLPROC:
304 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
305 goto leave;
306
307 case RSTATPROC_STATS:
308 xdr_argument = (xdrproc_t)xdr_void;
309 xdr_result = (xdrproc_t)xdr_statstime;
310 switch (rqstp->rq_vers) {
311 case RSTATVERS_ORIG:
312 local = (char *(*)(void *, struct svc_req *))
313 rstatproc_stats_1_svc;
314 break;
315 case RSTATVERS_SWTCH:
316 local = (char *(*)(void *, struct svc_req *))
317 rstatproc_stats_2_svc;
318 break;
319 case RSTATVERS_TIME:
320 local = (char *(*)(void *, struct svc_req *))
321 rstatproc_stats_3_svc;
322 break;
323 default:
324 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
325 goto leave;
326 }
327 break;
328
329 case RSTATPROC_HAVEDISK:
330 xdr_argument = (xdrproc_t)xdr_void;
331 xdr_result = (xdrproc_t)xdr_u_int;
332 switch (rqstp->rq_vers) {
333 case RSTATVERS_ORIG:
334 local = (char *(*)(void *, struct svc_req *))
335 rstatproc_havedisk_1_svc;
336 break;
337 case RSTATVERS_SWTCH:
338 local = (char *(*)(void *, struct svc_req *))
339 rstatproc_havedisk_2_svc;
340 break;
341 case RSTATVERS_TIME:
342 local = (char *(*)(void *, struct svc_req *))
343 rstatproc_havedisk_3_svc;
344 break;
345 default:
346 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
347 goto leave;
348 }
349 break;
350
351 default:
352 svcerr_noproc(transp);
353 goto leave;
354 }
355 memset((char *)&argument, 0, sizeof(argument));
356 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
357 svcerr_decode(transp);
358 goto leave;
359 }
360 result = (*local)(&argument, rqstp);
361 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
362 svcerr_systemerr(transp);
363 }
364 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
365 (void)fprintf(stderr, "unable to free arguments\n");
366 exit(1);
367 }
368 leave:
369 if (from_inetd)
370 exit(0);
371 }
372