Commit | Line | Data |
---|---|---|
43b57156 C |
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";*/ | |
90ba5b2c | 32 | static char rcsid[] = "$Id: rstat_proc.c,v 1.4 1993/09/23 18:42:39 jtc Exp $"; |
43b57156 C |
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 | ||
43b57156 | 41 | #include <stdio.h> |
90ba5b2c C |
42 | #include <stdlib.h> |
43 | #include <string.h> | |
44 | #include <signal.h> | |
43b57156 C |
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> | |
90ba5b2c C |
58 | |
59 | #undef FSHIFT /* Use protocol's shift and scale values */ | |
60 | #undef FSCALE | |
43b57156 C |
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 | } |