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