1 /* $NetBSD: iostat.c,v 1.24 2000/12/01 02:10:23 simonb 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 #include <sys/cdefs.h> 69 #ifndef lint 70 __COPYRIGHT("@(#) 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.3 (Berkeley) 4/28/95"; 77 #else 78 __RCSID("$NetBSD: iostat.c,v 1.24 2000/12/01 02:10:23 simonb Exp $"); 79 #endif 80 #endif /* not lint */ 81 82 #include <sys/types.h> 83 #include <sys/sched.h> 84 #include <sys/dkstat.h> 85 #include <sys/time.h> 86 87 #include <err.h> 88 #include <ctype.h> 89 #include <signal.h> 90 #include <stdio.h> 91 #include <stdlib.h> 92 #include <string.h> 93 #include <unistd.h> 94 95 #include "dkstats.h" 96 97 /* Namelist and memory files. */ 98 char *nlistf, *memf; 99 100 int hz, reps, interval; 101 static int todo = 0; 102 103 #define ISSET(x, a) ((x) & (a)) 104 #define SHOW_CPU 1<<0 105 #define SHOW_TTY 1<<1 106 #define SHOW_STATS_1 1<<2 107 #define SHOW_STATS_2 1<<3 108 #define SHOW_STATS_X 1<<4 109 #define SHOW_TOTALS 1<<7 110 #define SHOW_STATS_ALL (SHOW_STATS_1 | SHOW_STATS_2 | SHOW_STATS_X) 111 112 static void cpustats(void); 113 static void disk_stats(double); 114 static void disk_stats2(double); 115 static void disk_statsx(double); 116 static void header(int); 117 static void usage(void); 118 static void display(void); 119 static void selectdrives(int, char **); 120 121 int main(int, char **); 122 123 int 124 main(int argc, char *argv[]) 125 { 126 int ch, hdrcnt; 127 struct timeval tv; 128 gid_t egid = getegid(); 129 setegid(getgid()); 130 131 while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:x")) != -1) 132 switch(ch) { 133 case 'c': 134 if ((reps = atoi(optarg)) <= 0) 135 errx(1, "repetition count <= 0."); 136 break; 137 case 'C': 138 todo |= SHOW_CPU; 139 break; 140 case 'd': 141 todo &= ~SHOW_STATS_ALL; 142 todo |= SHOW_STATS_1; 143 break; 144 case 'D': 145 todo &= ~SHOW_STATS_ALL; 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 'x': 165 todo &= ~SHOW_STATS_ALL; 166 todo |= SHOW_STATS_X; 167 break; 168 case '?': 169 default: 170 usage(); 171 } 172 argc -= optind; 173 argv += optind; 174 175 if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_ALL)) 176 todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1; 177 if (ISSET(todo, SHOW_STATS_X)) { 178 todo &= ~(SHOW_CPU | SHOW_TTY | SHOW_STATS_ALL); 179 todo |= SHOW_STATS_X; 180 } 181 182 /* 183 * Discard setgid privileges if not the running kernel so that bad 184 * guys can't print interesting stuff from kernel memory. 185 */ 186 if (nlistf != NULL || memf != NULL) 187 setgid(getgid()); 188 189 dkinit(0, egid); 190 dkreadstats(); 191 selectdrives(argc, argv); 192 193 tv.tv_sec = interval; 194 tv.tv_usec = 0; 195 196 /* print a new header on sigcont */ 197 (void)signal(SIGCONT, header); 198 199 for (hdrcnt = 1;;) { 200 if (!--hdrcnt) { 201 header(0); 202 hdrcnt = 20; 203 } 204 205 if (!ISSET(todo, SHOW_TOTALS)) 206 dkswap(); 207 display(); 208 209 if (reps >= 0 && --reps <= 0) 210 break; 211 select(0, NULL, NULL, NULL, &tv); 212 dkreadstats(); 213 } 214 exit(0); 215 } 216 217 static void 218 header(int signo) 219 { 220 int i; 221 222 if (ISSET(todo, SHOW_STATS_X)) 223 return; 224 225 /* Main Headers. */ 226 if (ISSET(todo, SHOW_TTY)) 227 (void)printf(" tty"); 228 229 if (ISSET(todo, SHOW_STATS_1)) 230 for (i = 0; i < dk_ndrive; i++) 231 if (cur.dk_select[i]) 232 (void)printf( 233 " %7.7s ", cur.dk_name[i]); 234 235 if (ISSET(todo, SHOW_STATS_2)) 236 for (i = 0; i < dk_ndrive; i++) 237 if (cur.dk_select[i]) 238 (void)printf( 239 " %7.7s ", cur.dk_name[i]); 240 241 if (ISSET(todo, SHOW_CPU)) 242 (void)printf(" cpu"); 243 244 printf("\n"); 245 246 /* Sub-Headers. */ 247 if (ISSET(todo, SHOW_TTY)) 248 printf(" tin tout"); 249 250 if (ISSET(todo, SHOW_STATS_1)) { 251 for (i = 0; i < dk_ndrive; i++) 252 if (cur.dk_select[i]) { 253 if (ISSET(todo, SHOW_TOTALS)) 254 (void)printf(" KB/t xfr MB "); 255 else 256 (void)printf(" KB/t t/s MB/s "); 257 } 258 } 259 260 if (ISSET(todo, SHOW_STATS_2)) 261 for (i = 0; i < dk_ndrive; i++) 262 if (cur.dk_select[i]) 263 (void)printf(" KB xfr time "); 264 265 if (ISSET(todo, SHOW_CPU)) 266 (void)printf(" us ni sy in id"); 267 printf("\n"); 268 } 269 270 static void 271 disk_stats(double etime) 272 { 273 int dn; 274 double atime, mbps; 275 276 for (dn = 0; dn < dk_ndrive; ++dn) { 277 if (!cur.dk_select[dn]) 278 continue; 279 280 /* average Kbytes per transfer. */ 281 if (cur.dk_xfer[dn]) 282 mbps = (cur.dk_bytes[dn] / (1024.0)) / cur.dk_xfer[dn]; 283 else 284 mbps = 0.0; 285 (void)printf(" %5.2f", mbps); 286 287 /* average transfers per second. */ 288 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime); 289 290 /* time busy in disk activity */ 291 atime = (double)cur.dk_time[dn].tv_sec + 292 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 293 294 /* Megabytes per second. */ 295 if (atime != 0.0) 296 mbps = cur.dk_bytes[dn] / (double)(1024 * 1024); 297 else 298 mbps = 0; 299 (void)printf(" %4.2f ", mbps / etime); 300 } 301 } 302 303 static void 304 disk_stats2(double etime) 305 { 306 int dn; 307 double atime; 308 309 for (dn = 0; dn < dk_ndrive; ++dn) { 310 if (!cur.dk_select[dn]) 311 continue; 312 313 /* average kbytes per second. */ 314 (void)printf(" %4.0f", cur.dk_bytes[dn] / (1024.0) / etime); 315 316 /* average transfers per second. */ 317 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime); 318 319 /* average time busy in disk activity */ 320 atime = (double)cur.dk_time[dn].tv_sec + 321 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 322 (void)printf(" %4.2f ", atime / etime); 323 } 324 } 325 326 static void 327 disk_statsx(double etime) 328 { 329 int dn; 330 double atime, kbps; 331 332 if (ISSET(todo, SHOW_TOTALS)) 333 (void)printf("device KB/t xfr time MB"); 334 else 335 (void)printf("device KB/t t/s time MB/s"); 336 337 for (dn = 0; dn < dk_ndrive; ++dn) { 338 (void)printf("\n"); 339 (void)printf("%-8.8s", cur.dk_name[dn]); 340 341 /* average Kbytes per transfer */ 342 if (cur.dk_xfer[dn]) 343 kbps = (cur.dk_bytes[dn] / (1024.0)) / cur.dk_xfer[dn]; 344 else 345 kbps = 0.0; 346 (void)printf(" %8.2f", kbps); 347 348 /* average transfers (per second) */ 349 (void)printf(" %8.0f", cur.dk_xfer[dn] / etime); 350 351 /* time busy in disk activity */ 352 atime = (double)cur.dk_time[dn].tv_sec + 353 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 354 (void)printf(" %8.2f", atime / etime); 355 356 /* average megabytes (per second) */ 357 (void)printf(" %8.2f", 358 cur.dk_bytes[dn] / (1024.0 * 1024) / etime); 359 360 } 361 } 362 363 static void 364 cpustats(void) 365 { 366 int state; 367 double time; 368 369 time = 0; 370 for (state = 0; state < CPUSTATES; ++state) 371 time += cur.cp_time[state]; 372 if (!time) 373 time = 1.0; 374 /* States are generally never 100% and can use %3.0f. */ 375 for (state = 0; state < CPUSTATES; ++state) 376 printf(" %2.0f", 100. * cur.cp_time[state] / time); 377 } 378 379 static void 380 usage(void) 381 { 382 383 (void)fprintf(stderr, "usage: iostat [-CdDITx] [-c count] [-M core] \ 384 [-N system] [-w wait] [drives]\n"); 385 exit(1); 386 } 387 388 static void 389 display(void) 390 { 391 int i; 392 double etime; 393 394 /* Sum up the elapsed ticks. */ 395 etime = 0.0; 396 for (i = 0; i < CPUSTATES; i++) { 397 etime += cur.cp_time[i]; 398 } 399 if (etime == 0.0) 400 etime = 1.0; 401 /* Convert to seconds. */ 402 etime /= (float)hz; 403 404 /* If we're showing totals only, then don't divide by the 405 * system time. 406 */ 407 if (ISSET(todo, SHOW_TOTALS)) 408 etime = 1.0; 409 410 if (ISSET(todo, SHOW_TTY)) 411 printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime); 412 413 if (ISSET(todo, SHOW_STATS_1)) 414 disk_stats(etime); 415 416 if (ISSET(todo, SHOW_STATS_2)) 417 disk_stats2(etime); 418 419 if (ISSET(todo, SHOW_STATS_X)) 420 disk_statsx(etime); 421 422 if (ISSET(todo, SHOW_CPU)) 423 cpustats(); 424 425 (void)printf("\n"); 426 (void)fflush(stdout); 427 } 428 429 static void 430 selectdrives(int argc, char *argv[]) 431 { 432 int i, ndrives; 433 434 /* 435 * Choose drives to be displayed. Priority goes to (in order) drives 436 * supplied as arguments and default drives. If everything isn't 437 * filled in and there are drives not taken care of, display the first 438 * few that fit. 439 * 440 * The backward compatibility #ifdefs permit the syntax: 441 * iostat [ drives ] [ interval [ count ] ] 442 */ 443 if (ISSET(todo, SHOW_STATS_X)) { 444 for (i = 0; i < dk_ndrive; i++) 445 cur.dk_select[i] = 1; 446 } 447 448 #define BACKWARD_COMPATIBILITY 449 for (ndrives = 0; *argv; ++argv) { 450 #ifdef BACKWARD_COMPATIBILITY 451 if (isdigit(**argv)) 452 break; 453 #endif 454 if (!ISSET(todo, SHOW_STATS_X)) 455 for (i = 0; i < dk_ndrive; i++) { 456 if (strcmp(cur.dk_name[i], *argv)) 457 continue; 458 cur.dk_select[i] = 1; 459 ++ndrives; 460 } 461 } 462 #ifdef BACKWARD_COMPATIBILITY 463 if (*argv) { 464 interval = atoi(*argv); 465 if (*++argv) 466 reps = atoi(*argv); 467 } 468 #endif 469 470 if (interval) { 471 if (!reps) 472 reps = -1; 473 } else 474 if (reps) 475 interval = 1; 476 477 /* Pick up to 4 drives if none specified. */ 478 if (ndrives == 0) 479 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 480 if (cur.dk_select[i]) 481 continue; 482 cur.dk_select[i] = 1; 483 ++ndrives; 484 } 485 } 486