Commit | Line | Data |
---|---|---|
ad787160 C |
1 | /* @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC */ |
2 | #ifndef lint | |
3 | static char sccsid[] = "@(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro"; | |
4 | #endif | |
5 | ||
6 | /* | |
7 | * Copyright (c) 1984 by Sun Microsystems, Inc. | |
8 | */ | |
9 | ||
10 | /* | |
11 | * Sun RPC is a product of Sun Microsystems, Inc. and is provided for | |
12 | * unrestricted use provided that this legend is included on all tape | |
13 | * media and as a part of the software program in whole or part. Users | |
14 | * may copy or modify Sun RPC without charge, but are not authorized | |
15 | * to license or distribute it to anyone else except as part of a product or | |
16 | * program developed by the user. | |
17 | * | |
18 | * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE | |
19 | * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR | |
20 | * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. | |
21 | * | |
22 | * Sun RPC is provided with no support and without any obligation on the | |
23 | * part of Sun Microsystems, Inc. to assist in its use, correction, | |
24 | * modification or enhancement. | |
25 | * | |
26 | * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE | |
27 | * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC | |
28 | * OR ANY PART THEREOF. | |
29 | * | |
30 | * In no event will Sun Microsystems, Inc. be liable for any lost revenue | |
31 | * or profits or other special, indirect and consequential damages, even if | |
32 | * Sun has been advised of the possibility of such damages. | |
33 | * | |
34 | * Sun Microsystems, Inc. | |
35 | * 2550 Garcia Avenue | |
36 | * Mountain View, California 94043 | |
37 | */ | |
38 | ||
39 | /* | |
40 | * rstat service: built with rstat.x and derived from rpc.rstatd.c | |
41 | */ | |
42 | ||
43 | #include <signal.h> | |
44 | #include <stdio.h> | |
45 | #include <rpc/rpc.h> | |
46 | #include <sys/socket.h> | |
47 | #include <nlist.h> | |
48 | #include <sys/dk.h> | |
49 | #include <sys/errno.h> | |
50 | #include <sys/vmmeter.h> | |
51 | #include <net/if.h> | |
52 | #include "rstat.h" | |
53 | ||
54 | struct nlist nl[] = { | |
55 | #define X_CPTIME 0 | |
56 | { "_cp_time" }, | |
57 | #define X_SUM 1 | |
58 | { "_sum" }, | |
59 | #define X_IFNET 2 | |
60 | { "_ifnet" }, | |
61 | #define X_DKXFER 3 | |
62 | { "_dk_xfer" }, | |
63 | #define X_BOOTTIME 4 | |
64 | { "_boottime" }, | |
65 | #define X_AVENRUN 5 | |
66 | { "_avenrun" }, | |
67 | #define X_HZ 6 | |
68 | { "_hz" }, | |
69 | "", | |
70 | }; | |
71 | int kmem; | |
72 | int firstifnet, numintfs; /* chain of ethernet interfaces */ | |
73 | int stats_service(); | |
74 | ||
75 | /* | |
76 | * Define EXIT_WHEN_IDLE if you are able to have this program invoked | |
77 | * automatically on demand (as from inetd). When defined, the service | |
78 | * will terminated after being idle for 20 seconds. | |
79 | */ | |
80 | int sincelastreq = 0; /* number of alarms since last request */ | |
81 | #ifdef EXIT_WHEN_IDLE | |
82 | #define CLOSEDOWN 20 /* how long to wait before exiting */ | |
83 | #endif /* def EXIT_WHEN_IDLE */ | |
84 | ||
85 | union { | |
86 | struct stats s1; | |
87 | struct statsswtch s2; | |
88 | struct statstime s3; | |
89 | } stats_all; | |
90 | ||
91 | int updatestat(); | |
92 | static stat_is_init = 0; | |
93 | extern int errno; | |
94 | ||
95 | #ifndef FSCALE | |
96 | #define FSCALE (1 << 8) | |
97 | #endif | |
98 | ||
99 | stat_init() | |
100 | { | |
101 | stat_is_init = 1; | |
102 | setup(); | |
103 | updatestat(); | |
104 | alarm(1); | |
105 | signal(SIGALRM, updatestat); | |
106 | sleep(1); /* allow for one wake-up */ | |
107 | } | |
108 | ||
109 | statstime * | |
110 | rstatproc_stats_3() | |
111 | { | |
112 | if (! stat_is_init) | |
113 | stat_init(); | |
114 | sincelastreq = 0; | |
115 | return(&stats_all.s3); | |
116 | } | |
117 | ||
118 | statsswtch * | |
119 | rstatproc_stats_2() | |
120 | { | |
121 | if (! stat_is_init) | |
122 | stat_init(); | |
123 | sincelastreq = 0; | |
124 | return(&stats_all.s2); | |
125 | } | |
126 | ||
127 | stats * | |
128 | rstatproc_stats_1() | |
129 | { | |
130 | if (! stat_is_init) | |
131 | stat_init(); | |
132 | sincelastreq = 0; | |
133 | return(&stats_all.s1); | |
134 | } | |
135 | ||
136 | u_int * | |
137 | rstatproc_havedisk_3() | |
138 | { | |
139 | static u_int have; | |
140 | ||
141 | if (! stat_is_init) | |
142 | stat_init(); | |
143 | sincelastreq = 0; | |
144 | have = havedisk(); | |
145 | return(&have); | |
146 | } | |
147 | ||
148 | u_int * | |
149 | rstatproc_havedisk_2() | |
150 | { | |
151 | return(rstatproc_havedisk_3()); | |
152 | } | |
153 | ||
154 | u_int * | |
155 | rstatproc_havedisk_1() | |
156 | { | |
157 | return(rstatproc_havedisk_3()); | |
158 | } | |
159 | ||
160 | updatestat() | |
161 | { | |
162 | int off, i, hz; | |
163 | struct vmmeter sum; | |
164 | struct ifnet ifnet; | |
165 | double avrun[3]; | |
166 | struct timeval tm, btm; | |
167 | ||
168 | #ifdef DEBUG | |
169 | fprintf(stderr, "entering updatestat\n"); | |
170 | #endif | |
171 | #ifdef EXIT_WHEN_IDLE | |
172 | if (sincelastreq >= CLOSEDOWN) { | |
173 | #ifdef DEBUG | |
174 | fprintf(stderr, "about to closedown\n"); | |
175 | #endif | |
176 | exit(0); | |
177 | } | |
178 | sincelastreq++; | |
179 | #endif /* def EXIT_WHEN_IDLE */ | |
180 | if (lseek(kmem, (long)nl[X_HZ].n_value, 0) == -1) { | |
181 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
182 | exit(1); | |
183 | } | |
184 | if (read(kmem, (char *)&hz, sizeof hz) != sizeof hz) { | |
185 | fprintf(stderr, "rstat: can't read hz from kmem\n"); | |
186 | exit(1); | |
187 | } | |
188 | if (lseek(kmem, (long)nl[X_CPTIME].n_value, 0) == -1) { | |
189 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
190 | exit(1); | |
191 | } | |
192 | if (read(kmem, (char *)stats_all.s1.cp_time, sizeof (stats_all.s1.cp_time)) | |
193 | != sizeof (stats_all.s1.cp_time)) { | |
194 | fprintf(stderr, "rstat: can't read cp_time from kmem\n"); | |
195 | exit(1); | |
196 | } | |
197 | if (lseek(kmem, (long)nl[X_AVENRUN].n_value, 0) ==-1) { | |
198 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
199 | exit(1); | |
200 | } | |
201 | #ifdef vax | |
202 | if (read(kmem, (char *)avrun, sizeof (avrun)) != sizeof (avrun)) { | |
203 | fprintf(stderr, "rstat: can't read avenrun from kmem\n"); | |
204 | exit(1); | |
205 | } | |
206 | stats_all.s2.avenrun[0] = avrun[0] * FSCALE; | |
207 | stats_all.s2.avenrun[1] = avrun[1] * FSCALE; | |
208 | stats_all.s2.avenrun[2] = avrun[2] * FSCALE; | |
209 | #endif | |
210 | if (lseek(kmem, (long)nl[X_BOOTTIME].n_value, 0) == -1) { | |
211 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
212 | exit(1); | |
213 | } | |
214 | if (read(kmem, (char *)&btm, sizeof (stats_all.s2.boottime)) | |
215 | != sizeof (stats_all.s2.boottime)) { | |
216 | fprintf(stderr, "rstat: can't read boottime from kmem\n"); | |
217 | exit(1); | |
218 | } | |
219 | stats_all.s2.boottime.tv_sec = btm.tv_sec; | |
220 | stats_all.s2.boottime.tv_usec = btm.tv_usec; | |
221 | ||
222 | ||
223 | #ifdef DEBUG | |
224 | fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0], | |
225 | stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); | |
226 | #endif | |
227 | ||
228 | if (lseek(kmem, (long)nl[X_SUM].n_value, 0) ==-1) { | |
229 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
230 | exit(1); | |
231 | } | |
232 | if (read(kmem, (char *)&sum, sizeof sum) != sizeof sum) { | |
233 | fprintf(stderr, "rstat: can't read sum from kmem\n"); | |
234 | exit(1); | |
235 | } | |
236 | stats_all.s1.v_pgpgin = sum.v_pgpgin; | |
237 | stats_all.s1.v_pgpgout = sum.v_pgpgout; | |
238 | stats_all.s1.v_pswpin = sum.v_pswpin; | |
239 | stats_all.s1.v_pswpout = sum.v_pswpout; | |
240 | stats_all.s1.v_intr = sum.v_intr; | |
241 | gettimeofday(&tm, (struct timezone *) 0); | |
242 | stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + | |
243 | hz*(tm.tv_usec - btm.tv_usec)/1000000; | |
244 | stats_all.s2.v_swtch = sum.v_swtch; | |
245 | ||
246 | if (lseek(kmem, (long)nl[X_DKXFER].n_value, 0) == -1) { | |
247 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
248 | exit(1); | |
249 | } | |
250 | if (read(kmem, (char *)stats_all.s1.dk_xfer, sizeof (stats_all.s1.dk_xfer)) | |
251 | != sizeof (stats_all.s1.dk_xfer)) { | |
252 | fprintf(stderr, "rstat: can't read dk_xfer from kmem\n"); | |
253 | exit(1); | |
254 | } | |
255 | ||
256 | stats_all.s1.if_ipackets = 0; | |
257 | stats_all.s1.if_opackets = 0; | |
258 | stats_all.s1.if_ierrors = 0; | |
259 | stats_all.s1.if_oerrors = 0; | |
260 | stats_all.s1.if_collisions = 0; | |
261 | for (off = firstifnet, i = 0; off && i < numintfs; i++) { | |
262 | if (lseek(kmem, (long)off, 0) == -1) { | |
263 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
264 | exit(1); | |
265 | } | |
266 | if (read(kmem, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) { | |
267 | fprintf(stderr, "rstat: can't read ifnet from kmem\n"); | |
268 | exit(1); | |
269 | } | |
270 | stats_all.s1.if_ipackets += ifnet.if_ipackets; | |
271 | stats_all.s1.if_opackets += ifnet.if_opackets; | |
272 | stats_all.s1.if_ierrors += ifnet.if_ierrors; | |
273 | stats_all.s1.if_oerrors += ifnet.if_oerrors; | |
274 | stats_all.s1.if_collisions += ifnet.if_collisions; | |
275 | off = (int) ifnet.if_next; | |
276 | } | |
277 | gettimeofday((struct timeval *)&stats_all.s3.curtime, | |
278 | (struct timezone *) 0); | |
279 | alarm(1); | |
280 | } | |
281 | ||
282 | static | |
283 | setup() | |
284 | { | |
285 | struct ifnet ifnet; | |
286 | int off; | |
287 | ||
288 | nlist("/vmunix", nl); | |
289 | if (nl[0].n_value == 0) { | |
290 | fprintf(stderr, "rstat: Variables missing from namelist\n"); | |
291 | exit (1); | |
292 | } | |
293 | if ((kmem = open("/dev/kmem", 0)) < 0) { | |
294 | fprintf(stderr, "rstat: can't open kmem\n"); | |
295 | exit(1); | |
296 | } | |
297 | ||
298 | off = nl[X_IFNET].n_value; | |
299 | if (lseek(kmem, (long)off, 0) == -1) { | |
300 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
301 | exit(1); | |
302 | } | |
303 | if (read(kmem, (char *)&firstifnet, sizeof(int)) != sizeof (int)) { | |
304 | fprintf(stderr, "rstat: can't read firstifnet from kmem\n"); | |
305 | exit(1); | |
306 | } | |
307 | numintfs = 0; | |
308 | for (off = firstifnet; off;) { | |
309 | if (lseek(kmem, (long)off, 0) == -1) { | |
310 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
311 | exit(1); | |
312 | } | |
313 | if (read(kmem, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) { | |
314 | fprintf(stderr, "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 | static | |
326 | havedisk() | |
327 | { | |
328 | int i, cnt; | |
329 | long xfer[DK_NDRIVE]; | |
330 | ||
331 | nlist("/vmunix", nl); | |
332 | if (nl[X_DKXFER].n_value == 0) { | |
333 | fprintf(stderr, "rstat: Variables missing from namelist\n"); | |
334 | exit (1); | |
335 | } | |
336 | if ((kmem = open("/dev/kmem", 0)) < 0) { | |
337 | fprintf(stderr, "rstat: can't open kmem\n"); | |
338 | exit(1); | |
339 | } | |
340 | if (lseek(kmem, (long)nl[X_DKXFER].n_value, 0) == -1) { | |
341 | fprintf(stderr, "rstat: can't seek in kmem\n"); | |
342 | exit(1); | |
343 | } | |
344 | if (read(kmem, (char *)xfer, sizeof xfer)!= sizeof xfer) { | |
345 | fprintf(stderr, "rstat: can't read kmem\n"); | |
346 | exit(1); | |
347 | } | |
348 | cnt = 0; | |
349 | for (i=0; i < DK_NDRIVE; i++) | |
350 | cnt += xfer[i]; | |
351 | return (cnt != 0); | |
352 | } |