1 /* $NetBSD: iostat.c,v 1.48 2006/02/12 22:11:54 dsl 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.48 2006/02/12 22:11:54 dsl 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 cpureadstats(); 200 dkreadstats(); 201 tpreadstats(); 202 ndrives = selectdrives(argc, argv); 203 if (ndrives == 0) { 204 /* No drives are selected. No need to show disk stats. */ 205 todo &= ~SHOW_STATS_ALL; 206 if (todo == 0) 207 errx(1, "no drives"); 208 } 209 if (ISSET(todo, SHOW_STATS_X)) 210 lines = ndrives; 211 else 212 lines = 1; 213 214 tv.tv_sec = interval; 215 tv.tv_nsec = 0; 216 217 /* print a new header on sigcont */ 218 (void)signal(SIGCONT, sig_header); 219 220 for (hdrcnt = 1;;) { 221 if (do_header || lines > 1 || (hdrcnt -= lines) <= 0) { 222 do_header = 0; 223 header(); 224 hdrcnt = winlines - 4; 225 } 226 227 if (!ISSET(todo, SHOW_TOTALS)) { 228 cpuswap(); 229 dkswap(); 230 tpswap(); 231 } 232 233 display(); 234 235 if (reps >= 0 && --reps <= 0) 236 break; 237 nanosleep(&tv, NULL); 238 cpureadstats(); 239 dkreadstats(); 240 tpreadstats(); 241 } 242 exit(0); 243 } 244 245 static void 246 sig_header(int signo) 247 { 248 do_header = 1; 249 } 250 251 static void 252 header() 253 { 254 int i; 255 256 /* Main Headers. */ 257 if (ISSET(todo, SHOW_STATS_X)) { 258 if (ISSET(todo, SHOW_TOTALS)) { 259 (void)printf( 260 "device read KB/t xfr time MB "); 261 (void)printf(" write KB/t xfr time MB\n"); 262 } else { 263 (void)printf( 264 "device read KB/t r/s time MB/s"); 265 (void)printf(" write KB/t w/s time MB/s\n"); 266 } 267 return; 268 } 269 270 if (ISSET(todo, SHOW_TTY)) 271 (void)printf(" tty"); 272 273 if (ISSET(todo, SHOW_STATS_1)) { 274 for (i = 0; i < dk_ndrive; i++) 275 if (cur.dk_select[i]) 276 (void)printf(" %9.9s ", cur.dk_name[i]); 277 for (i = 0; i < tp_ndrive; i++) 278 if (cur_tape.select[i]) 279 (void)printf(" %9.9s ", 280 cur_tape.name[i]); 281 } 282 283 if (ISSET(todo, SHOW_STATS_2)) { 284 for (i = 0; i < dk_ndrive; i++) 285 if (cur.dk_select[i]) 286 (void)printf(" %9.9s ", cur.dk_name[i]); 287 for (i = 0; i < tp_ndrive; i++) 288 if (cur_tape.select[i]) 289 (void)printf(" %9.9s ", 290 cur_tape.name[i]); 291 } 292 293 if (ISSET(todo, SHOW_CPU)) 294 (void)printf(" CPU"); 295 296 printf("\n"); 297 298 /* Sub-Headers. */ 299 if (ISSET(todo, SHOW_TTY)) 300 printf(" tin tout"); 301 302 if (ISSET(todo, SHOW_STATS_1)) { 303 for (i = 0; i < dk_ndrive; i++) 304 if (cur.dk_select[i]) { 305 if (ISSET(todo, SHOW_TOTALS)) 306 (void)printf(" KB/t xfr MB "); 307 else 308 (void)printf(" KB/t t/s MB/s "); 309 } 310 for (i = 0; i < tp_ndrive; i++) 311 if (cur_tape.select[i]) { 312 if (ISSET(todo, SHOW_TOTALS)) 313 (void)printf(" KB/t xfr MB "); 314 else 315 (void)printf(" KB/t t/s MB/s "); 316 } 317 } 318 319 if (ISSET(todo, SHOW_STATS_2)) { 320 for (i = 0; i < dk_ndrive; i++) 321 if (cur.dk_select[i]) 322 (void)printf(" KB xfr time "); 323 for (i = 0; i < tp_ndrive; i++) 324 if (cur_tape.select[i]) 325 (void)printf(" KB xfr time "); 326 } 327 328 if (ISSET(todo, SHOW_CPU)) 329 (void)printf(" us ni sy in id"); 330 printf("\n"); 331 } 332 333 static void 334 disk_stats(double etime) 335 { 336 int dn; 337 double atime, mbps; 338 339 for (dn = 0; dn < dk_ndrive; ++dn) { 340 if (!cur.dk_select[dn]) 341 continue; 342 /* average Kbytes per transfer. */ 343 if (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) 344 mbps = ((cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 345 1024.0) / (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]); 346 else 347 mbps = 0.0; 348 (void)printf(" %5.2f", mbps); 349 350 /* average transfers per second. */ 351 (void)printf(" %4.0f", 352 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime); 353 354 /* time busy in disk activity */ 355 atime = (double)cur.dk_time[dn].tv_sec + 356 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 357 358 /* Megabytes per second. */ 359 if (atime != 0.0) 360 mbps = (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 361 (double)(1024 * 1024); 362 else 363 mbps = 0; 364 (void)printf(" %5.2f ", mbps / etime); 365 } 366 } 367 368 static void 369 disk_stats2(double etime) 370 { 371 int dn; 372 double atime; 373 374 for (dn = 0; dn < dk_ndrive; ++dn) { 375 if (!cur.dk_select[dn]) 376 continue; 377 378 /* average kbytes per second. */ 379 (void)printf(" %5.0f", 380 (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 1024.0 / etime); 381 382 /* average transfers per second. */ 383 (void)printf(" %5.0f", 384 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime); 385 386 /* average time busy in disk activity */ 387 atime = (double)cur.dk_time[dn].tv_sec + 388 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 389 (void)printf(" %4.2f ", atime / etime); 390 } 391 } 392 393 static void 394 disk_statsx(double etime) 395 { 396 int dn; 397 double atime, kbps; 398 399 for (dn = 0; dn < dk_ndrive; ++dn) { 400 if (!cur.dk_select[dn]) 401 continue; 402 403 (void)printf("%-8.8s", cur.dk_name[dn]); 404 405 /* average read Kbytes per transfer */ 406 if (cur.dk_rxfer[dn]) 407 kbps = (cur.dk_rbytes[dn] / 1024.0) / cur.dk_rxfer[dn]; 408 else 409 kbps = 0.0; 410 (void)printf(" %8.2f", kbps); 411 412 /* average read transfers 413 (per second) */ 414 (void)printf(" %6.0f", cur.dk_rxfer[dn] / etime); 415 416 /* time read busy in disk activity */ 417 atime = (double)cur.dk_time[dn].tv_sec + 418 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 419 (void)printf(" %6.2f", atime / etime); 420 421 /* average read megabytes 422 (per second) */ 423 (void)printf(" %8.2f", 424 cur.dk_rbytes[dn] / (1024.0 * 1024) / etime); 425 426 427 /* average write Kbytes per transfer */ 428 if (cur.dk_wxfer[dn]) 429 kbps = (cur.dk_wbytes[dn] / 1024.0) / cur.dk_wxfer[dn]; 430 else 431 kbps = 0.0; 432 (void)printf(" %8.2f", kbps); 433 434 /* average write transfers 435 (per second) */ 436 (void)printf(" %6.0f", cur.dk_wxfer[dn] / etime); 437 438 /* time write busy in disk activity */ 439 atime = (double)cur.dk_time[dn].tv_sec + 440 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 441 (void)printf(" %6.2f", atime / etime); 442 443 /* average write megabytes 444 (per second) */ 445 (void)printf(" %8.2f\n", 446 cur.dk_wbytes[dn] / (1024.0 * 1024) / etime); 447 } 448 } 449 450 static void 451 tape_stats(double etime) 452 { 453 int dn; 454 double atime, mbps; 455 456 for (dn = 0; dn < tp_ndrive; ++dn) { 457 if (!cur_tape.select[dn]) 458 continue; 459 /* average Kbytes per transfer. */ 460 if (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) 461 mbps = ((cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) / 462 1024.0) / (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]); 463 else 464 mbps = 0.0; 465 (void)printf(" %5.2f", mbps); 466 467 /* average transfers per second. */ 468 (void)printf(" %4.0f", 469 (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) / etime); 470 471 /* time busy in disk activity */ 472 atime = (double)cur_tape.time[dn].tv_sec + 473 ((double)cur_tape.time[dn].tv_usec / (double)1000000); 474 475 /* Megabytes per second. */ 476 if (atime != 0.0) 477 mbps = (cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) / 478 (double)(1024 * 1024); 479 else 480 mbps = 0; 481 (void)printf(" %5.2f ", mbps / etime); 482 } 483 } 484 485 static void 486 tape_stats2(double etime) 487 { 488 int dn; 489 double atime; 490 491 for (dn = 0; dn < tp_ndrive; ++dn) { 492 if (!cur_tape.select[dn]) 493 continue; 494 495 /* average kbytes per second. */ 496 (void)printf(" %5.0f", 497 (cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) / 1024.0 / etime); 498 499 /* average transfers per second. */ 500 (void)printf(" %5.0f", 501 (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) / etime); 502 503 /* average time busy in disk activity */ 504 atime = (double)cur_tape.time[dn].tv_sec + 505 ((double)cur_tape.time[dn].tv_usec / (double)1000000); 506 (void)printf(" %4.2f ", atime / etime); 507 } 508 } 509 510 static void 511 tape_statsx(double etime) 512 { 513 int dn; 514 double atime, kbps; 515 516 for (dn = 0; dn < tp_ndrive; ++dn) { 517 if (!cur_tape.select[dn]) 518 continue; 519 520 (void)printf("%-8.8s", cur_tape.name[dn]); 521 522 /* average read Kbytes per transfer */ 523 if (cur.dk_rxfer[dn]) 524 kbps = (cur_tape.rbytes[dn] / 1024.0) / cur_tape.rxfer[dn]; 525 else 526 kbps = 0.0; 527 (void)printf(" %8.2f", kbps); 528 529 /* average read transfers 530 (per second) */ 531 (void)printf(" %6.0f", cur_tape.rxfer[dn] / etime); 532 533 /* time read busy in disk activity */ 534 atime = (double)cur_tape.time[dn].tv_sec + 535 ((double)cur_tape.time[dn].tv_usec / (double)1000000); 536 (void)printf(" %6.2f", atime / etime); 537 538 /* average read megabytes 539 (per second) */ 540 (void)printf(" %8.2f", 541 cur_tape.rbytes[dn] / (1024.0 * 1024) / etime); 542 543 544 /* average write Kbytes per transfer */ 545 if (cur_tape.wxfer[dn]) 546 kbps = (cur_tape.wbytes[dn] / 1024.0) / cur_tape.wxfer[dn]; 547 else 548 kbps = 0.0; 549 (void)printf(" %8.2f", kbps); 550 551 /* average write transfers 552 (per second) */ 553 (void)printf(" %6.0f", cur_tape.wxfer[dn] / etime); 554 555 /* time write busy in disk activity */ 556 atime = (double)cur_tape.time[dn].tv_sec + 557 ((double)cur_tape.time[dn].tv_usec / (double)1000000); 558 (void)printf(" %6.2f", atime / etime); 559 560 /* average write megabytes 561 (per second) */ 562 (void)printf(" %8.2f\n", 563 cur_tape.wbytes[dn] / (1024.0 * 1024) / etime); 564 } 565 } 566 567 static void 568 cpustats(void) 569 { 570 int state; 571 double time; 572 573 time = 0; 574 for (state = 0; state < CPUSTATES; ++state) 575 time += cur.cp_time[state]; 576 if (!time) 577 time = 1.0; 578 /* States are generally never 100% and can use %3.0f. */ 579 for (state = 0; state < CPUSTATES; ++state) 580 printf(" %2.0f", 100. * cur.cp_time[state] / time); 581 } 582 583 static void 584 usage(void) 585 { 586 587 (void)fprintf(stderr, "usage: iostat [-CdDITx] [-c count] [-M core] " 588 "[-N system] [-w wait] [drives]\n"); 589 exit(1); 590 } 591 592 static void 593 display(void) 594 { 595 double etime; 596 597 /* Sum up the elapsed ticks. */ 598 etime = cur.cp_etime; 599 600 /* 601 * If we're showing totals only, then don't divide by the 602 * system time. 603 */ 604 if (ISSET(todo, SHOW_TOTALS)) 605 etime = 1.0; 606 607 if (ISSET(todo, SHOW_STATS_X)) { 608 disk_statsx(etime); 609 tape_statsx(etime); 610 goto out; 611 } 612 613 if (ISSET(todo, SHOW_TTY)) 614 printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime); 615 616 if (ISSET(todo, SHOW_STATS_1)) { 617 disk_stats(etime); 618 tape_stats(etime); 619 } 620 621 622 if (ISSET(todo, SHOW_STATS_2)) { 623 disk_stats2(etime); 624 tape_stats2(etime); 625 } 626 627 628 if (ISSET(todo, SHOW_CPU)) 629 cpustats(); 630 631 (void)printf("\n"); 632 633 out: 634 (void)fflush(stdout); 635 } 636 637 static int 638 selectdrives(int argc, char *argv[]) 639 { 640 int i, maxdrives, ndrives, tried; 641 642 /* 643 * Choose drives to be displayed. Priority goes to (in order) drives 644 * supplied as arguments and default drives. If everything isn't 645 * filled in and there are drives not taken care of, display the first 646 * few that fit. 647 * 648 * The backward compatibility #ifdefs permit the syntax: 649 * iostat [ drives ] [ interval [ count ] ] 650 */ 651 652 #define BACKWARD_COMPATIBILITY 653 for (tried = ndrives = 0; *argv; ++argv) { 654 #ifdef BACKWARD_COMPATIBILITY 655 if (isdigit((unsigned char)**argv)) 656 break; 657 #endif 658 tried++; 659 for (i = 0; i < dk_ndrive; i++) { 660 if (strcmp(cur.dk_name[i], *argv)) 661 continue; 662 cur.dk_select[i] = 1; 663 ++ndrives; 664 } 665 666 for (i = 0; i < tp_ndrive; i++) { 667 if (strcmp(cur_tape.name[i], *argv)) 668 continue; 669 cur_tape.select[i] = 1; 670 ++ndrives; 671 } 672 } 673 674 if (ndrives == 0 && tried == 0) { 675 /* 676 * Pick up to defdrives (or all if -x is given) drives 677 * if none specified. 678 */ 679 maxdrives = (ISSET(todo, SHOW_STATS_X) || 680 (dk_ndrive + tp_ndrive) < defdrives) 681 ? (dk_ndrive + tp_ndrive) : defdrives; 682 for (i = 0; i < maxdrives; i++) { 683 if (i >= dk_ndrive) { 684 cur_tape.select[i - dk_ndrive] = 1; 685 } else { 686 cur.dk_select[i] = 1; 687 } 688 689 ++ndrives; 690 if (!ISSET(todo, SHOW_STATS_X) && ndrives == defdrives) 691 break; 692 } 693 } 694 695 #ifdef BACKWARD_COMPATIBILITY 696 if (*argv) { 697 interval = atoi(*argv); 698 if (*++argv) 699 reps = atoi(*argv); 700 } 701 #endif 702 703 if (interval) { 704 if (!reps) 705 reps = -1; 706 } else 707 if (reps) 708 interval = 1; 709 710 return (ndrives); 711 } 712