1 /* $NetBSD: iostat.c,v 1.12 1997/10/17 09:03:57 lukem 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.12 1997/10/17 09:03:57 lukem Exp $"); 79 #endif 80 #endif /* not lint */ 81 82 #include <sys/types.h> 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 int main __P((int, char **)); 125 126 int 127 main(argc, argv) 128 int argc; 129 char *argv[]; 130 { 131 int ch, hdrcnt; 132 struct timeval tv; 133 134 while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != -1) 135 switch(ch) { 136 case 'c': 137 if ((reps = atoi(optarg)) <= 0) 138 errx(1, "repetition count <= 0."); 139 break; 140 case 'C': 141 todo |= SHOW_CPU; 142 break; 143 case 'd': 144 todo |= SHOW_STATS_1; 145 break; 146 case 'D': 147 todo |= SHOW_STATS_2; 148 break; 149 case 'I': 150 todo |= SHOW_TOTALS; 151 break; 152 case 'M': 153 memf = optarg; 154 break; 155 case 'N': 156 nlistf = optarg; 157 break; 158 case 'T': 159 todo |= SHOW_TTY; 160 break; 161 case 'w': 162 if ((interval = atoi(optarg)) <= 0) 163 errx(1, "interval <= 0."); 164 break; 165 case '?': 166 default: 167 usage(); 168 } 169 argc -= optind; 170 argv += optind; 171 172 if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2)) 173 todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1; 174 175 /* 176 * Discard setgid privileges if not the running kernel so that bad 177 * guys can't print interesting stuff from kernel memory. 178 */ 179 if (nlistf != NULL || memf != NULL) 180 setgid(getgid()); 181 182 dkinit(0); 183 dkreadstats(); 184 selectdrives(argc, argv); 185 186 tv.tv_sec = interval; 187 tv.tv_usec = 0; 188 189 /* print a new header on sigcont */ 190 (void)signal(SIGCONT, header); 191 192 for (hdrcnt = 1;;) { 193 if (!--hdrcnt) { 194 header(0); 195 hdrcnt = 20; 196 } 197 198 if (!ISSET(todo, SHOW_TOTALS)) 199 dkswap(); 200 display(); 201 202 if (reps >= 0 && --reps <= 0) 203 break; 204 select(0, NULL, NULL, NULL, &tv); 205 dkreadstats(); 206 } 207 exit(0); 208 } 209 210 static void 211 header(signo) 212 int signo; 213 { 214 int i; 215 216 /* Main Headers. */ 217 if (ISSET(todo, SHOW_TTY)) 218 (void)printf(" tty"); 219 220 if (ISSET(todo, SHOW_STATS_1)) 221 for (i = 0; i < dk_ndrive; i++) 222 if (cur.dk_select[i]) 223 (void)printf(" %3.3s ", cur.dk_name[i]); 224 225 if (ISSET(todo, SHOW_STATS_2)) 226 for (i = 0; i < dk_ndrive; i++) 227 if (cur.dk_select[i]) 228 (void)printf(" %3.3s ", cur.dk_name[i]); 229 230 if (ISSET(todo, SHOW_CPU)) 231 (void)printf(" cpu"); 232 printf("\n"); 233 234 /* Sub-Headers. */ 235 if (ISSET(todo, SHOW_TTY)) 236 printf(" tin tout"); 237 238 if (ISSET(todo, SHOW_STATS_1)) 239 for (i = 0; i < dk_ndrive; i++) 240 if (cur.dk_select[i]) 241 if (ISSET(todo, SHOW_TOTALS)) 242 (void)printf(" KB/t xfr MB "); 243 else 244 (void)printf(" KB/t t/s MB/s "); 245 246 if (ISSET(todo, SHOW_STATS_2)) 247 for (i = 0; i < dk_ndrive; i++) 248 if (cur.dk_select[i]) 249 (void)printf(" KB xfr time "); 250 251 if (ISSET(todo, SHOW_CPU)) 252 (void)printf(" us ni sy in id"); 253 printf("\n"); 254 } 255 256 static void 257 disk_stats(etime) 258 double etime; 259 { 260 int dn; 261 double atime, mbps; 262 263 for (dn = 0; dn < dk_ndrive; ++dn) { 264 if (!cur.dk_select[dn]) 265 continue; 266 267 /* average Kbytes per transfer. */ 268 if (cur.dk_xfer[dn]) 269 mbps = (cur.dk_bytes[dn] / (1024.0)) / cur.dk_xfer[dn]; 270 else 271 mbps = 0.0; 272 (void)printf(" %5.2f", mbps); 273 274 /* average transfers per second. */ 275 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime); 276 277 /* time busy in disk activity */ 278 atime = (double)cur.dk_time[dn].tv_sec + 279 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 280 281 /* Megabytes per second. */ 282 if (atime != 0.0) 283 mbps = cur.dk_bytes[dn] / (double)(1024 * 1024); 284 else 285 mbps = 0; 286 (void)printf(" %4.2f ", mbps / etime); 287 } 288 } 289 290 static void 291 disk_stats2(etime) 292 double etime; 293 { 294 int dn; 295 double atime; 296 297 for (dn = 0; dn < dk_ndrive; ++dn) { 298 if (!cur.dk_select[dn]) 299 continue; 300 301 /* average kbytes per second. */ 302 (void)printf(" %4.0f", cur.dk_bytes[dn] / (1024.0) / etime); 303 304 /* average transfers per second. */ 305 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime); 306 307 /* average time busy in disk activity. */ 308 atime = (double)cur.dk_time[dn].tv_sec + 309 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 310 (void)printf(" %4.2f ", atime / etime); 311 } 312 } 313 314 static void 315 cpustats() 316 { 317 int state; 318 double time; 319 320 time = 0; 321 for (state = 0; state < CPUSTATES; ++state) 322 time += cur.cp_time[state]; 323 if (!time) 324 time = 1.0; 325 /* States are generally never 100% and can use %3.0f. */ 326 for (state = 0; state < CPUSTATES; ++state) 327 printf("%3.0f", 100. * cur.cp_time[state] / time); 328 } 329 330 static void 331 usage() 332 { 333 (void)fprintf(stderr, 334 "usage: iostat [-CdDIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n"); 335 exit(1); 336 } 337 338 static void 339 display() 340 { 341 int i; 342 double etime; 343 344 /* Sum up the elapsed ticks. */ 345 etime = 0.0; 346 for (i = 0; i < CPUSTATES; i++) { 347 etime += cur.cp_time[i]; 348 } 349 if (etime == 0.0) 350 etime = 1.0; 351 /* Convert to seconds. */ 352 etime /= (float)hz; 353 354 /* If we're showing totals only, then don't divide by the 355 * system time. 356 */ 357 if (ISSET(todo, SHOW_TOTALS)) 358 etime = 1.0; 359 360 if (ISSET(todo, SHOW_TTY)) 361 printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime); 362 363 if (ISSET(todo, SHOW_STATS_1)) 364 disk_stats(etime); 365 366 if (ISSET(todo, SHOW_STATS_2)) 367 disk_stats2(etime); 368 369 if (ISSET(todo, SHOW_CPU)) 370 cpustats(); 371 372 (void)printf("\n"); 373 (void)fflush(stdout); 374 } 375 376 static void 377 selectdrives(argc, argv) 378 int argc; 379 char *argv[]; 380 { 381 int i, ndrives; 382 383 /* 384 * Choose drives to be displayed. Priority goes to (in order) drives 385 * supplied as arguments and default drives. If everything isn't 386 * filled in and there are drives not taken care of, display the first 387 * few that fit. 388 * 389 * The backward compatibility #ifdefs permit the syntax: 390 * iostat [ drives ] [ interval [ count ] ] 391 */ 392 #define BACKWARD_COMPATIBILITY 393 for (ndrives = 0; *argv; ++argv) { 394 #ifdef BACKWARD_COMPATIBILITY 395 if (isdigit(**argv)) 396 break; 397 #endif 398 for (i = 0; i < dk_ndrive; i++) { 399 if (strcmp(cur.dk_name[i], *argv)) 400 continue; 401 cur.dk_select[i] = 1; 402 ++ndrives; 403 } 404 } 405 #ifdef BACKWARD_COMPATIBILITY 406 if (*argv) { 407 interval = atoi(*argv); 408 if (*++argv) 409 reps = atoi(*argv); 410 } 411 #endif 412 413 if (interval) { 414 if (!reps) 415 reps = -1; 416 } else 417 if (reps) 418 interval = 1; 419 420 /* Pick up to 4 drives if none specified. */ 421 if (ndrives == 0) 422 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 423 if (cur.dk_select[i]) 424 continue; 425 cur.dk_select[i] = 1; 426 ++ndrives; 427 } 428 } 429