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