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