iostat.c revision 1.10 1 /* $NetBSD: iostat.c,v 1.10 1996/10/25 18:21:58 scottr Exp $ */
2
3 /*
4 * Copyright (c) 1996 John M. Vinopal
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project
18 * by John M. Vinopal.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*-
36 * Copyright (c) 1986, 1991, 1993
37 * The Regents of the University of California. All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 * must display the following acknowledgement:
49 * This product includes software developed by the University of
50 * California, Berkeley and its contributors.
51 * 4. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 */
67
68 #ifndef lint
69 static char copyright[] =
70 "@(#) Copyright (c) 1986, 1991, 1993\n\
71 The Regents of the University of California. All rights reserved.\n";
72 #endif /* not lint */
73
74 #ifndef lint
75 #if 0
76 static char sccsid[] = "@(#)iostat.c 8.2 (Berkeley) 1/26/94";
77 #else
78 static char *rcsid = "$NetBSD: iostat.c,v 1.10 1996/10/25 18:21:58 scottr Exp $"
79 ;
80 #endif
81 #endif /* not lint */
82
83 #include <sys/dkstat.h>
84 #include <sys/time.h>
85
86 #include <err.h>
87 #include <ctype.h>
88 #include <signal.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <unistd.h>
93
94 #include "dkstats.h"
95
96 /* Defined in dkstats.c */
97 extern struct _disk cur;
98 extern int dk_ndrive;
99
100 /* Namelist and memory files. */
101 char *nlistf, *memf;
102
103 int hz, reps, interval;
104 static int todo = 0;
105
106 #define ISSET(x, a) ((x) & (a))
107 #define SHOW_CPU 0x0001
108 #define SHOW_TTY 0x0002
109 #define SHOW_STATS_1 0x0004
110 #define SHOW_STATS_2 0x0008
111 #define SHOW_TOTALS 0x0080
112
113 static void cpustats __P((void));
114 static void disk_stats __P((double));
115 static void disk_stats2 __P((double));
116 static void header __P((int));
117 static void usage __P((void));
118 static void display __P((void));
119 static void selectdrives __P((int, char **));
120
121 void dkswap __P((void));
122 void dkreadstats __P((void));
123 int dkinit __P((int));
124
125 int
126 main(argc, argv)
127 int argc;
128 char *argv[];
129 {
130 int ch, hdrcnt;
131 struct timeval tv;
132
133 while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != EOF)
134 switch(ch) {
135 case 'c':
136 if ((reps = atoi(optarg)) <= 0)
137 errx(1, "repetition count <= 0.");
138 break;
139 case 'C':
140 todo |= SHOW_CPU;
141 break;
142 case 'd':
143 todo |= SHOW_STATS_1;
144 break;
145 case 'D':
146 todo |= SHOW_STATS_2;
147 break;
148 case 'I':
149 todo |= SHOW_TOTALS;
150 break;
151 case 'M':
152 memf = optarg;
153 break;
154 case 'N':
155 nlistf = optarg;
156 break;
157 case 'T':
158 todo |= SHOW_TTY;
159 break;
160 case 'w':
161 if ((interval = atoi(optarg)) <= 0)
162 errx(1, "interval <= 0.");
163 break;
164 case '?':
165 default:
166 usage();
167 }
168 argc -= optind;
169 argv += optind;
170
171 if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2))
172 todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1;
173
174 /*
175 * Discard setgid privileges if not the running kernel so that bad
176 * guys can't print interesting stuff from kernel memory.
177 */
178 if (nlistf != NULL || memf != NULL)
179 setgid(getgid());
180
181 dkinit(0);
182 dkreadstats();
183 selectdrives(argc, argv);
184
185 tv.tv_sec = interval;
186 tv.tv_usec = 0;
187
188 /* print a new header on sigcont */
189 (void)signal(SIGCONT, header);
190
191 for (hdrcnt = 1;;) {
192 if (!--hdrcnt) {
193 header(0);
194 hdrcnt = 20;
195 }
196
197 if (!ISSET(todo, SHOW_TOTALS))
198 dkswap();
199 display();
200
201 if (reps >= 0 && --reps <= 0)
202 break;
203 select(0, NULL, NULL, NULL, &tv);
204 dkreadstats();
205 }
206 exit(0);
207 }
208
209 static void
210 header(signo)
211 int signo;
212 {
213 register int i;
214
215 /* Main Headers. */
216 if (ISSET(todo, SHOW_TTY))
217 (void)printf(" tty");
218
219 if (ISSET(todo, SHOW_STATS_1))
220 for (i = 0; i < dk_ndrive; i++)
221 if (cur.dk_select[i])
222 (void)printf(" %3.3s ", cur.dk_name[i]);
223
224 if (ISSET(todo, SHOW_STATS_2))
225 for (i = 0; i < dk_ndrive; i++)
226 if (cur.dk_select[i])
227 (void)printf(" %3.3s ", cur.dk_name[i]);
228
229 if (ISSET(todo, SHOW_CPU))
230 (void)printf(" cpu");
231 printf("\n");
232
233 /* Sub-Headers. */
234 if (ISSET(todo, SHOW_TTY))
235 printf(" tin tout");
236
237 if (ISSET(todo, SHOW_STATS_1))
238 for (i = 0; i < dk_ndrive; i++)
239 if (cur.dk_select[i])
240 if (ISSET(todo, SHOW_TOTALS))
241 (void)printf(" KB/t xfr MB ");
242 else
243 (void)printf(" KB/t t/s MB/s ");
244
245 if (ISSET(todo, SHOW_STATS_2))
246 for (i = 0; i < dk_ndrive; i++)
247 if (cur.dk_select[i])
248 (void)printf(" KB xfr time ");
249
250 if (ISSET(todo, SHOW_CPU))
251 (void)printf(" us ni sy in id");
252 printf("\n");
253 }
254
255 static void
256 disk_stats(etime)
257 double etime;
258 {
259 register int dn;
260 double atime, mbps;
261
262 for (dn = 0; dn < dk_ndrive; ++dn) {
263 if (!cur.dk_select[dn])
264 continue;
265
266 /* average Kbytes per transfer. */
267 if (cur.dk_xfer[dn])
268 mbps = (cur.dk_bytes[dn] / (1024.0)) / cur.dk_xfer[dn];
269 else
270 mbps = 0.0;
271 (void)printf(" %5.2f", mbps);
272
273 /* average transfers per second. */
274 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime);
275
276 /* time busy in disk activity */
277 atime = (double)cur.dk_time[dn].tv_sec +
278 ((double)cur.dk_time[dn].tv_usec / (double)1000000);
279
280 /* Megabytes per second. */
281 if (atime != 0.0)
282 mbps = cur.dk_bytes[dn] / (double)(1024 * 1024);
283 else
284 mbps = 0;
285 (void)printf(" %4.2f ", mbps / etime);
286 }
287 }
288
289 static void
290 disk_stats2(etime)
291 double etime;
292 {
293 register int dn;
294 double atime;
295
296 for (dn = 0; dn < dk_ndrive; ++dn) {
297 if (!cur.dk_select[dn])
298 continue;
299
300 /* average kbytes per second. */
301 (void)printf(" %4.0f", cur.dk_bytes[dn] / (1024.0) / etime);
302
303 /* average transfers per second. */
304 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime);
305
306 /* average time busy in disk activity. */
307 atime = (double)cur.dk_time[dn].tv_sec +
308 ((double)cur.dk_time[dn].tv_usec / (double)1000000);
309 (void)printf(" %4.2f ", atime / etime);
310 }
311 }
312
313 static void
314 cpustats()
315 {
316 register int state;
317 double time;
318
319 time = 0;
320 for (state = 0; state < CPUSTATES; ++state)
321 time += cur.cp_time[state];
322 if (!time)
323 time = 1.0;
324 /* States are generally never 100% and can use %3.0f. */
325 for (state = 0; state < CPUSTATES; ++state)
326 printf("%3.0f", 100. * cur.cp_time[state] / time);
327 }
328
329 static void
330 usage()
331 {
332 (void)fprintf(stderr,
333 "usage: iostat [-CdDIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n");
334 exit(1);
335 }
336
337 static void
338 display()
339 {
340 int i;
341 double etime;
342
343 /* Sum up the elapsed ticks. */
344 etime = 0.0;
345 for (i = 0; i < CPUSTATES; i++) {
346 etime += cur.cp_time[i];
347 }
348 if (etime == 0.0)
349 etime = 1.0;
350 /* Convert to seconds. */
351 etime /= (float)hz;
352
353 /* If we're showing totals only, then don't divide by the
354 * system time.
355 */
356 if (ISSET(todo, SHOW_TOTALS))
357 etime = 1.0;
358
359 if (ISSET(todo, SHOW_TTY))
360 printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime);
361
362 if (ISSET(todo, SHOW_STATS_1))
363 disk_stats(etime);
364
365 if (ISSET(todo, SHOW_STATS_2))
366 disk_stats2(etime);
367
368 if (ISSET(todo, SHOW_CPU))
369 cpustats();
370
371 (void)printf("\n");
372 (void)fflush(stdout);
373 }
374
375 static void
376 selectdrives(argc, argv)
377 int argc;
378 char *argv[];
379 {
380 int i, ndrives;
381
382 /*
383 * Choose drives to be displayed. Priority goes to (in order) drives
384 * supplied as arguments and default drives. If everything isn't
385 * filled in and there are drives not taken care of, display the first
386 * few that fit.
387 *
388 * The backward compatibility #ifdefs permit the syntax:
389 * iostat [ drives ] [ interval [ count ] ]
390 */
391 #define BACKWARD_COMPATIBILITY
392 for (ndrives = 0; *argv; ++argv) {
393 #ifdef BACKWARD_COMPATIBILITY
394 if (isdigit(**argv))
395 break;
396 #endif
397 for (i = 0; i < dk_ndrive; i++) {
398 if (strcmp(cur.dk_name[i], *argv))
399 continue;
400 cur.dk_select[i] = 1;
401 ++ndrives;
402 }
403 }
404 #ifdef BACKWARD_COMPATIBILITY
405 if (*argv) {
406 interval = atoi(*argv);
407 if (*++argv)
408 reps = atoi(*argv);
409 }
410 #endif
411
412 if (interval) {
413 if (!reps)
414 reps = -1;
415 } else
416 if (reps)
417 interval = 1;
418
419 /* Pick up to 4 drives if none specified. */
420 if (ndrives == 0)
421 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
422 if (cur.dk_select[i])
423 continue;
424 cur.dk_select[i] = 1;
425 ++ndrives;
426 }
427 }
428