1 /* $NetBSD: iostat.c,v 1.46 2006/01/08 08:47:16 yamt 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. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 #include <sys/cdefs.h> 65 #ifndef lint 66 __COPYRIGHT("@(#) Copyright (c) 1986, 1991, 1993\n\ 67 The Regents of the University of California. All rights reserved.\n"); 68 #endif /* not lint */ 69 70 #ifndef lint 71 #if 0 72 static char sccsid[] = "@(#)iostat.c 8.3 (Berkeley) 4/28/95"; 73 #else 74 __RCSID("$NetBSD: iostat.c,v 1.46 2006/01/08 08:47:16 yamt Exp $"); 75 #endif 76 #endif /* not lint */ 77 78 #include <sys/types.h> 79 #include <sys/ioctl.h> 80 #include <sys/sched.h> 81 #include <sys/time.h> 82 83 #include <err.h> 84 #include <ctype.h> 85 #include <signal.h> 86 #include <stdio.h> 87 #include <stdlib.h> 88 #include <string.h> 89 #include <unistd.h> 90 91 #include "dkstats.h" 92 #include "tpstats.h" 93 94 /* Namelist and memory files. */ 95 char *nlistf, *memf; 96 97 int hz, reps, interval; 98 static int todo = 0; 99 static int defdrives; 100 static int winlines = 20; 101 static int wincols = 80; 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 sig_header(int); 117 static volatile int do_header; 118 static void header(void); 119 static void usage(void); 120 static void display(void); 121 static int selectdrives(int, char *[]); 122 123 int main(int, char *[]); 124 125 int 126 main(int argc, char *argv[]) 127 { 128 int ch, hdrcnt, ndrives, lines; 129 struct timespec tv; 130 struct ttysize ts; 131 132 while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:x")) != -1) 133 switch (ch) { 134 case 'c': 135 if ((reps = atoi(optarg)) <= 0) 136 errx(1, "repetition count <= 0."); 137 break; 138 case 'C': 139 todo |= SHOW_CPU; 140 break; 141 case 'd': 142 todo &= ~SHOW_STATS_ALL; 143 todo |= SHOW_STATS_1; 144 break; 145 case 'D': 146 todo &= ~SHOW_STATS_ALL; 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 'x': 166 todo &= ~SHOW_STATS_ALL; 167 todo |= SHOW_STATS_X; 168 break; 169 case '?': 170 default: 171 usage(); 172 } 173 argc -= optind; 174 argv += optind; 175 176 if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_ALL)) 177 todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1; 178 if (ISSET(todo, SHOW_STATS_X)) { 179 todo &= ~(SHOW_CPU | SHOW_TTY | SHOW_STATS_ALL); 180 todo |= SHOW_STATS_X; 181 } 182 183 if (ioctl(STDOUT_FILENO, TIOCGSIZE, &ts) != -1) { 184 if (ts.ts_lines) 185 winlines = ts.ts_lines; 186 if (ts.ts_cols) 187 wincols = ts.ts_cols; 188 } 189 190 defdrives = wincols; 191 if (ISSET(todo, SHOW_CPU)) 192 defdrives -= 16; /* XXX magic number */ 193 if (ISSET(todo, SHOW_TTY)) 194 defdrives -= 9; /* XXX magic number */ 195 defdrives /= 18; /* XXX magic number */ 196 197 dkinit(0); 198 tpinit(0); 199 dkreadstats(); 200 tpreadstats(); 201 ndrives = selectdrives(argc, argv); 202 if (ndrives == 0) { 203 /* No drives are selected. No need to show disk stats. */ 204 todo &= ~SHOW_STATS_ALL; 205 if (todo == 0) 206 errx(1, "no drives"); 207 } 208 if (ISSET(todo, SHOW_STATS_X)) 209 lines = ndrives; 210 else 211 lines = 1; 212 213 tv.tv_sec = interval; 214 tv.tv_nsec = 0; 215 216 /* print a new header on sigcont */ 217 (void)signal(SIGCONT, sig_header); 218 219 for (hdrcnt = 1;;) { 220 if (do_header || 221 ((hdrcnt -= lines) <= 0) || 222 ISSET(todo, SHOW_STATS_X)) { 223 do_header = 0; 224 header(); 225 hdrcnt = winlines - 4; 226 } 227 228 if (!ISSET(todo, SHOW_TOTALS)) { 229 dkswap(); 230 tpswap(); 231 } 232 233 display(); 234 235 if (reps >= 0 && --reps <= 0) 236 break; 237 nanosleep(&tv, NULL); 238 dkreadstats(); 239 tpreadstats(); 240 } 241 exit(0); 242 } 243 244 static void 245 sig_header(int signo) 246 { 247 do_header = 1; 248 } 249 250 static void 251 header() 252 { 253 int i; 254 255 /* Main Headers. */ 256 if (ISSET(todo, SHOW_STATS_X)) { 257 if (ISSET(todo, SHOW_TOTALS)) { 258 (void)printf( 259 "device read KB/t xfr time MB "); 260 (void)printf(" write KB/t xfr time MB\n"); 261 } else { 262 (void)printf( 263 "device read KB/t r/s time MB/s"); 264 (void)printf(" write KB/t w/s time MB/s\n"); 265 } 266 return; 267 } 268 269 if (ISSET(todo, SHOW_TTY)) 270 (void)printf(" tty"); 271 272 if (ISSET(todo, SHOW_STATS_1)) { 273 for (i = 0; i < dk_ndrive; i++) 274 if (cur.dk_select[i]) 275 (void)printf(" %9.9s ", cur.dk_name[i]); 276 for (i = 0; i < tp_ndrive; i++) 277 if (cur_tape.select[i]) 278 (void)printf(" %9.9s ", 279 cur_tape.name[i]); 280 } 281 282 if (ISSET(todo, SHOW_STATS_2)) { 283 for (i = 0; i < dk_ndrive; i++) 284 if (cur.dk_select[i]) 285 (void)printf(" %9.9s ", cur.dk_name[i]); 286 for (i = 0; i < tp_ndrive; i++) 287 if (cur_tape.select[i]) 288 (void)printf(" %9.9s ", 289 cur_tape.name[i]); 290 } 291 292 if (ISSET(todo, SHOW_CPU)) 293 (void)printf(" CPU"); 294 295 printf("\n"); 296 297 /* Sub-Headers. */ 298 if (ISSET(todo, SHOW_TTY)) 299 printf(" tin tout"); 300 301 if (ISSET(todo, SHOW_STATS_1)) { 302 for (i = 0; i < dk_ndrive; i++) 303 if (cur.dk_select[i]) { 304 if (ISSET(todo, SHOW_TOTALS)) 305 (void)printf(" KB/t xfr MB "); 306 else 307 (void)printf(" KB/t t/s MB/s "); 308 } 309 for (i = 0; i < tp_ndrive; i++) 310 if (cur_tape.select[i]) { 311 if (ISSET(todo, SHOW_TOTALS)) 312 (void)printf(" KB/t xfr MB "); 313 else 314 (void)printf(" KB/t t/s MB/s "); 315 } 316 } 317 318 if (ISSET(todo, SHOW_STATS_2)) { 319 for (i = 0; i < dk_ndrive; i++) 320 if (cur.dk_select[i]) 321 (void)printf(" KB xfr time "); 322 for (i = 0; i < tp_ndrive; i++) 323 if (cur_tape.select[i]) 324 (void)printf(" KB xfr time "); 325 } 326 327 if (ISSET(todo, SHOW_CPU)) 328 (void)printf(" us ni sy in id"); 329 printf("\n"); 330 } 331 332 static void 333 disk_stats(double etime) 334 { 335 int dn; 336 double atime, mbps; 337 338 for (dn = 0; dn < dk_ndrive; ++dn) { 339 if (!cur.dk_select[dn]) 340 continue; 341 /* average Kbytes per transfer. */ 342 if (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) 343 mbps = ((cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 344 1024.0) / (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]); 345 else 346 mbps = 0.0; 347 (void)printf(" %5.2f", mbps); 348 349 /* average transfers per second. */ 350 (void)printf(" %4.0f", 351 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime); 352 353 /* time busy in disk activity */ 354 atime = (double)cur.dk_time[dn].tv_sec + 355 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 356 357 /* Megabytes per second. */ 358 if (atime != 0.0) 359 mbps = (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 360 (double)(1024 * 1024); 361 else 362 mbps = 0; 363 (void)printf(" %5.2f ", mbps / etime); 364 } 365 } 366 367 static void 368 disk_stats2(double etime) 369 { 370 int dn; 371 double atime; 372 373 for (dn = 0; dn < dk_ndrive; ++dn) { 374 if (!cur.dk_select[dn]) 375 continue; 376 377 /* average kbytes per second. */ 378 (void)printf(" %5.0f", 379 (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 1024.0 / etime); 380 381 /* average transfers per second. */ 382 (void)printf(" %5.0f", 383 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime); 384 385 /* average time busy in disk activity */ 386 atime = (double)cur.dk_time[dn].tv_sec + 387 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 388 (void)printf(" %4.2f ", atime / etime); 389 } 390 } 391 392 static void 393 disk_statsx(double etime) 394 { 395 int dn; 396 double atime, kbps; 397 398 for (dn = 0; dn < dk_ndrive; ++dn) { 399 if (!cur.dk_select[dn]) 400 continue; 401 402 (void)printf("%-8.8s", cur.dk_name[dn]); 403 404 /* average read Kbytes per transfer */ 405 if (cur.dk_rxfer[dn]) 406 kbps = (cur.dk_rbytes[dn] / 1024.0) / cur.dk_rxfer[dn]; 407 else 408 kbps = 0.0; 409 (void)printf(" %8.2f", kbps); 410 411 /* average read transfers 412 (per second) */ 413 (void)printf(" %6.0f", cur.dk_rxfer[dn] / etime); 414 415 /* time read busy in disk activity */ 416 atime = (double)cur.dk_time[dn].tv_sec + 417 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 418 (void)printf(" %6.2f", atime / etime); 419 420 /* average read megabytes 421 (per second) */ 422 (void)printf(" %8.2f", 423 cur.dk_rbytes[dn] / (1024.0 * 1024) / etime); 424 425 426 /* average write Kbytes per transfer */ 427 if (cur.dk_wxfer[dn]) 428 kbps = (cur.dk_wbytes[dn] / 1024.0) / cur.dk_wxfer[dn]; 429 else 430 kbps = 0.0; 431 (void)printf(" %8.2f", kbps); 432 433 /* average write transfers 434 (per second) */ 435 (void)printf(" %6.0f", cur.dk_wxfer[dn] / etime); 436 437 /* time write busy in disk activity */ 438 atime = (double)cur.dk_time[dn].tv_sec + 439 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 440 (void)printf(" %6.2f", atime / etime); 441 442 /* average write megabytes 443 (per second) */ 444 (void)printf(" %8.2f\n", 445 cur.dk_wbytes[dn] / (1024.0 * 1024) / etime); 446 } 447 } 448 449 static void 450 tape_stats(double etime) 451 { 452 int dn; 453 double atime, mbps; 454 455 for (dn = 0; dn < tp_ndrive; ++dn) { 456 if (!cur_tape.select[dn]) 457 continue; 458 /* average Kbytes per transfer. */ 459 if (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) 460 mbps = ((cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) / 461 1024.0) / (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]); 462 else 463 mbps = 0.0; 464 (void)printf(" %5.2f", mbps); 465 466 /* average transfers per second. */ 467 (void)printf(" %4.0f", 468 (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) / etime); 469 470 /* time busy in disk activity */ 471 atime = (double)cur_tape.time[dn].tv_sec + 472 ((double)cur_tape.time[dn].tv_usec / (double)1000000); 473 474 /* Megabytes per second. */ 475 if (atime != 0.0) 476 mbps = (cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) / 477 (double)(1024 * 1024); 478 else 479 mbps = 0; 480 (void)printf(" %5.2f ", mbps / etime); 481 } 482 } 483 484 static void 485 tape_stats2(double etime) 486 { 487 int dn; 488 double atime; 489 490 for (dn = 0; dn < tp_ndrive; ++dn) { 491 if (!cur_tape.select[dn]) 492 continue; 493 494 /* average kbytes per second. */ 495 (void)printf(" %5.0f", 496 (cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) / 1024.0 / etime); 497 498 /* average transfers per second. */ 499 (void)printf(" %5.0f", 500 (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) / etime); 501 502 /* average time busy in disk activity */ 503 atime = (double)cur_tape.time[dn].tv_sec + 504 ((double)cur_tape.time[dn].tv_usec / (double)1000000); 505 (void)printf(" %4.2f ", atime / etime); 506 } 507 } 508 509 static void 510 tape_statsx(double etime) 511 { 512 int dn; 513 double atime, kbps; 514 515 for (dn = 0; dn < tp_ndrive; ++dn) { 516 if (!cur_tape.select[dn]) 517 continue; 518 519 (void)printf("%-8.8s", cur_tape.name[dn]); 520 521 /* average read Kbytes per transfer */ 522 if (cur.dk_rxfer[dn]) 523 kbps = (cur_tape.rbytes[dn] / 1024.0) / cur_tape.rxfer[dn]; 524 else 525 kbps = 0.0; 526 (void)printf(" %8.2f", kbps); 527 528 /* average read transfers 529 (per second) */ 530 (void)printf(" %6.0f", cur_tape.rxfer[dn] / etime); 531 532 /* time read busy in disk activity */ 533 atime = (double)cur_tape.time[dn].tv_sec + 534 ((double)cur_tape.time[dn].tv_usec / (double)1000000); 535 (void)printf(" %6.2f", atime / etime); 536 537 /* average read megabytes 538 (per second) */ 539 (void)printf(" %8.2f", 540 cur_tape.rbytes[dn] / (1024.0 * 1024) / etime); 541 542 543 /* average write Kbytes per transfer */ 544 if (cur_tape.wxfer[dn]) 545 kbps = (cur_tape.wbytes[dn] / 1024.0) / cur_tape.wxfer[dn]; 546 else 547 kbps = 0.0; 548 (void)printf(" %8.2f", kbps); 549 550 /* average write transfers 551 (per second) */ 552 (void)printf(" %6.0f", cur_tape.wxfer[dn] / etime); 553 554 /* time write busy in disk activity */ 555 atime = (double)cur_tape.time[dn].tv_sec + 556 ((double)cur_tape.time[dn].tv_usec / (double)1000000); 557 (void)printf(" %6.2f", atime / etime); 558 559 /* average write megabytes 560 (per second) */ 561 (void)printf(" %8.2f\n", 562 cur_tape.wbytes[dn] / (1024.0 * 1024) / etime); 563 } 564 } 565 566 static void 567 cpustats(void) 568 { 569 int state; 570 double time; 571 572 time = 0; 573 for (state = 0; state < CPUSTATES; ++state) 574 time += cur.cp_time[state]; 575 if (!time) 576 time = 1.0; 577 /* States are generally never 100% and can use %3.0f. */ 578 for (state = 0; state < CPUSTATES; ++state) 579 printf(" %2.0f", 100. * cur.cp_time[state] / time); 580 } 581 582 static void 583 usage(void) 584 { 585 586 (void)fprintf(stderr, "usage: iostat [-CdDITx] [-c count] [-M core] " 587 "[-N system] [-w wait] [drives]\n"); 588 exit(1); 589 } 590 591 static void 592 display(void) 593 { 594 double etime; 595 596 /* Sum up the elapsed ticks. */ 597 etime = cur.cp_etime; 598 599 /* 600 * If we're showing totals only, then don't divide by the 601 * system time. 602 */ 603 if (ISSET(todo, SHOW_TOTALS)) 604 etime = 1.0; 605 606 if (ISSET(todo, SHOW_STATS_X)) { 607 disk_statsx(etime); 608 tape_statsx(etime); 609 goto out; 610 } 611 612 if (ISSET(todo, SHOW_TTY)) 613 printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime); 614 615 if (ISSET(todo, SHOW_STATS_1)) { 616 disk_stats(etime); 617 tape_stats(etime); 618 } 619 620 621 if (ISSET(todo, SHOW_STATS_2)) { 622 disk_stats2(etime); 623 tape_stats2(etime); 624 } 625 626 627 if (ISSET(todo, SHOW_CPU)) 628 cpustats(); 629 630 (void)printf("\n"); 631 632 out: 633 (void)fflush(stdout); 634 } 635 636 static int 637 selectdrives(int argc, char *argv[]) 638 { 639 int i, maxdrives, ndrives, tried; 640 641 /* 642 * Choose drives to be displayed. Priority goes to (in order) drives 643 * supplied as arguments and default drives. If everything isn't 644 * filled in and there are drives not taken care of, display the first 645 * few that fit. 646 * 647 * The backward compatibility #ifdefs permit the syntax: 648 * iostat [ drives ] [ interval [ count ] ] 649 */ 650 651 #define BACKWARD_COMPATIBILITY 652 for (tried = ndrives = 0; *argv; ++argv) { 653 #ifdef BACKWARD_COMPATIBILITY 654 if (isdigit((unsigned char)**argv)) 655 break; 656 #endif 657 tried++; 658 for (i = 0; i < dk_ndrive; i++) { 659 if (strcmp(cur.dk_name[i], *argv)) 660 continue; 661 cur.dk_select[i] = 1; 662 ++ndrives; 663 } 664 665 for (i = 0; i < tp_ndrive; i++) { 666 if (strcmp(cur_tape.name[i], *argv)) 667 continue; 668 cur_tape.select[i] = 1; 669 ++ndrives; 670 } 671 } 672 673 if (ndrives == 0 && tried == 0) { 674 /* 675 * Pick up to defdrives (or all if -x is given) drives 676 * if none specified. 677 */ 678 maxdrives = (ISSET(todo, SHOW_STATS_X) || 679 (dk_ndrive + tp_ndrive) < defdrives) 680 ? (dk_ndrive + tp_ndrive) : defdrives; 681 for (i = 0; i < maxdrives; i++) { 682 if (i >= dk_ndrive) { 683 cur_tape.select[i - dk_ndrive] = 1; 684 } else { 685 cur.dk_select[i] = 1; 686 } 687 688 ++ndrives; 689 if (!ISSET(todo, SHOW_STATS_X) && ndrives == defdrives) 690 break; 691 } 692 } 693 694 #ifdef BACKWARD_COMPATIBILITY 695 if (*argv) { 696 interval = atoi(*argv); 697 if (*++argv) 698 reps = atoi(*argv); 699 } 700 #endif 701 702 if (interval) { 703 if (!reps) 704 reps = -1; 705 } else 706 if (reps) 707 interval = 1; 708 709 return (ndrives); 710 } 711