rstat_proc.c revision 1.19 1 /* $NetBSD: rstat_proc.c,v 1.19 1997/07/19 20:25:44 fvdl 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.19 1997/07/19 20:25:44 fvdl 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 stats_all.s2.if_opackets = stats_all.s3.if_opackets;
148 return (&stats_all.s2);
149 }
150
151 stats *
152 rstatproc_stats_1_svc(arg, rqstp)
153 void *arg;
154 struct svc_req *rqstp;
155 {
156 if (!stat_is_init)
157 stat_init();
158 sincelastreq = 0;
159 stats_all.s1.if_opackets = stats_all.s3.if_opackets;
160 return (&stats_all.s1);
161 }
162
163 u_int *
164 rstatproc_havedisk_3_svc(arg, rqstp)
165 void *arg;
166 struct svc_req *rqstp;
167 {
168 static u_int have;
169
170 if (!stat_is_init)
171 stat_init();
172 sincelastreq = 0;
173 have = havedisk();
174 return (&have);
175 }
176
177 u_int *
178 rstatproc_havedisk_2_svc(arg, rqstp)
179 void *arg;
180 struct svc_req *rqstp;
181 {
182 return (rstatproc_havedisk_3_svc(arg, rqstp));
183 }
184
185 u_int *
186 rstatproc_havedisk_1_svc(arg, rqstp)
187 void *arg;
188 struct svc_req *rqstp;
189 {
190 return (rstatproc_havedisk_3_svc(arg, rqstp));
191 }
192
193 void
194 updatestat()
195 {
196 long off;
197 int i;
198 struct vmmeter cnt;
199 struct ifnet ifnet;
200 double avrun[3];
201 struct timeval tm, btm;
202 #ifdef BSD
203 int cp_time[BSD_CPUSTATES];
204 #endif
205
206 #ifdef DEBUG
207 syslog(LOG_DEBUG, "entering updatestat");
208 #endif
209 if (sincelastreq >= closedown) {
210 #ifdef DEBUG
211 syslog(LOG_DEBUG, "about to closedown");
212 #endif
213 if (from_inetd)
214 exit(0);
215 else {
216 stat_is_init = 0;
217 return;
218 }
219 }
220 sincelastreq++;
221
222 /*
223 * dkreadstats reads in the "disk_count" as well as the "disklist"
224 * statistics. It also retrieves "hz" and the "cp_time" array.
225 */
226 dkreadstats();
227 memset(stats_all.s3.dk_xfer, 0, sizeof(stats_all.s3.dk_xfer));
228 for (i = 0; i < dk_ndrive && i < DK_NDRIVE; i++)
229 stats_all.s3.dk_xfer[i] = cur.dk_xfer[i];
230
231 #ifdef BSD
232 for (i = 0; i < CPUSTATES; i++)
233 stats_all.s3.cp_time[i] = cur.cp_time[cp_xlat[i]];
234 #else
235 if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
236 (char *)stats_all.s3.cp_time,
237 sizeof (stats_all.s3.cp_time))
238 != sizeof (stats_all.s3.cp_time)) {
239 syslog(LOG_ERR, "can't read cp_time from kmem");
240 exit(1);
241 }
242 #endif
243 #ifdef BSD
244 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
245 #endif
246 stats_all.s3.avenrun[0] = avrun[0] * FSCALE;
247 stats_all.s3.avenrun[1] = avrun[1] * FSCALE;
248 stats_all.s3.avenrun[2] = avrun[2] * FSCALE;
249 if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value,
250 (char *)&btm, sizeof (stats_all.s3.boottime))
251 != sizeof (stats_all.s3.boottime)) {
252 syslog(LOG_ERR, "can't read boottime from kmem");
253 exit(1);
254 }
255 stats_all.s3.boottime.tv_sec = btm.tv_sec;
256 stats_all.s3.boottime.tv_usec = btm.tv_usec;
257
258
259 #ifdef DEBUG
260 syslog(LOG_DEBUG, "%d %d %d %d\n", stats_all.s3.cp_time[0],
261 stats_all.s3.cp_time[1], stats_all.s3.cp_time[2], stats_all.s3.cp_time[3]);
262 #endif
263
264 if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) !=
265 sizeof cnt) {
266 syslog(LOG_ERR, "can't read cnt from kmem");
267 exit(1);
268 }
269 stats_all.s3.v_pgpgin = cnt.v_pgpgin;
270 stats_all.s3.v_pgpgout = cnt.v_pgpgout;
271 stats_all.s3.v_pswpin = cnt.v_pswpin;
272 stats_all.s3.v_pswpout = cnt.v_pswpout;
273 stats_all.s3.v_intr = cnt.v_intr;
274 gettimeofday(&tm, (struct timezone *) 0);
275 stats_all.s3.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
276 hz*(tm.tv_usec - btm.tv_usec)/1000000;
277 stats_all.s3.v_swtch = cnt.v_swtch;
278
279 stats_all.s3.if_ipackets = 0;
280 stats_all.s3.if_opackets = 0;
281 stats_all.s3.if_ierrors = 0;
282 stats_all.s3.if_oerrors = 0;
283 stats_all.s3.if_collisions = 0;
284 for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) {
285 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
286 sizeof ifnet) {
287 syslog(LOG_ERR, "can't read ifnet from kmem");
288 exit(1);
289 }
290 stats_all.s3.if_ipackets += ifnet.if_data.ifi_ipackets;
291 stats_all.s3.if_opackets += ifnet.if_data.ifi_opackets;
292 stats_all.s3.if_ierrors += ifnet.if_data.ifi_ierrors;
293 stats_all.s3.if_oerrors += ifnet.if_data.ifi_oerrors;
294 stats_all.s3.if_collisions += ifnet.if_data.ifi_collisions;
295 off = (long)ifnet.if_list.tqe_next;
296 }
297 gettimeofday((struct timeval *)&stats_all.s3.curtime,
298 (struct timezone *) 0);
299 alarm(1);
300 }
301
302 setup()
303 {
304 struct ifnet ifnet;
305 long off;
306 char errbuf[_POSIX2_LINE_MAX];
307
308 kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
309 if (kfd == NULL) {
310 syslog(LOG_ERR, "%s", errbuf);
311 exit (1);
312 }
313
314 if (kvm_nlist(kfd, nl) != 0) {
315 syslog(LOG_ERR, "can't get namelist");
316 exit (1);
317 }
318
319 if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &ifnetq,
320 sizeof ifnetq) != sizeof ifnetq) {
321 syslog(LOG_ERR, "can't read ifnet queue head from kmem");
322 exit(1);
323 }
324
325 numintfs = 0;
326 for (off = (long)ifnetq.tqh_first; off;) {
327 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
328 sizeof ifnet) {
329 syslog(LOG_ERR, "can't read ifnet from kmem");
330 exit(1);
331 }
332 numintfs++;
333 off = (long)ifnet.if_list.tqe_next;
334 }
335 dkinit(0);
336 }
337
338 /*
339 * returns true if have a disk
340 */
341 int
342 havedisk()
343 {
344 return dk_ndrive != 0;
345 }
346
347 void
348 rstat_service(rqstp, transp)
349 struct svc_req *rqstp;
350 SVCXPRT *transp;
351 {
352 union {
353 int fill;
354 } argument;
355 char *result;
356 xdrproc_t xdr_argument, xdr_result;
357 char *(*local) __P((void *, struct svc_req *));
358
359 switch (rqstp->rq_proc) {
360 case NULLPROC:
361 (void)svc_sendreply(transp, xdr_void, (char *)NULL);
362 goto leave;
363
364 case RSTATPROC_STATS:
365 xdr_argument = (xdrproc_t)xdr_void;
366 xdr_result = (xdrproc_t)xdr_statstime;
367 switch (rqstp->rq_vers) {
368 case RSTATVERS_ORIG:
369 local = (char *(*) __P((void *, struct svc_req *)))
370 rstatproc_stats_1_svc;
371 break;
372 case RSTATVERS_SWTCH:
373 local = (char *(*) __P((void *, struct svc_req *)))
374 rstatproc_stats_2_svc;
375 break;
376 case RSTATVERS_TIME:
377 local = (char *(*) __P((void *, struct svc_req *)))
378 rstatproc_stats_3_svc;
379 break;
380 default:
381 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
382 goto leave;
383 }
384 break;
385
386 case RSTATPROC_HAVEDISK:
387 xdr_argument = (xdrproc_t)xdr_void;
388 xdr_result = (xdrproc_t)xdr_u_int;
389 switch (rqstp->rq_vers) {
390 case RSTATVERS_ORIG:
391 local = (char *(*) __P((void *, struct svc_req *)))
392 rstatproc_havedisk_1_svc;
393 break;
394 case RSTATVERS_SWTCH:
395 local = (char *(*) __P((void *, struct svc_req *)))
396 rstatproc_havedisk_2_svc;
397 break;
398 case RSTATVERS_TIME:
399 local = (char *(*) __P((void *, struct svc_req *)))
400 rstatproc_havedisk_3_svc;
401 break;
402 default:
403 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
404 goto leave;
405 }
406 break;
407
408 default:
409 svcerr_noproc(transp);
410 goto leave;
411 }
412 bzero((char *)&argument, sizeof(argument));
413 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
414 svcerr_decode(transp);
415 goto leave;
416 }
417 result = (*local)(&argument, rqstp);
418 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
419 svcerr_systemerr(transp);
420 }
421 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
422 (void)fprintf(stderr, "unable to free arguments\n");
423 exit(1);
424 }
425 leave:
426 if (from_inetd)
427 exit(0);
428 }
429