WOrking disk statistics; NetBSD PR 2161
authortholo <tholo@openbsd.org>
Sun, 3 Mar 1996 02:52:32 +0000 (02:52 +0000)
committertholo <tholo@openbsd.org>
Sun, 3 Mar 1996 02:52:32 +0000 (02:52 +0000)
usr.sbin/iostat/Makefile
usr.sbin/iostat/iostat.8
usr.sbin/iostat/iostat.c

index 20ebf13..0dcd91c 100644 (file)
@@ -1,10 +1,16 @@
-#      @(#)Makefile    8.1 (Berkeley) 6/6/93
+#      $OpenBSD: Makefile,v 1.2 1996/03/03 02:52:32 tholo Exp $
+#      $NetBSD: Makefile,v 1.12 1995/12/22 08:04:27 jonathan Exp $
+#      from: @(#)Makefile      8.1 (Berkeley) 6/6/93
 
 PROG=  iostat
 .if (${MACHINE_ARCH} == "m68k")
-CFLAGS+=-D${MACHINE} -I${.CURDIR}/../../sys/arch
+CFLAGS+=-D${MACHINE}
 .endif
-CFLAGS+=-I${.CURDIR}/../../usr.bin/vmstat
+
+.PATH: ${.CURDIR}/../../usr.bin/vmstat
+
+CFLAGS+=-I${.CURDIR}/../../sys/arch -I${.CURDIR}/../../usr.bin/vmstat
+SRCS=  dkstats.c iostat.c
 MAN=   iostat.8
 DPADD= ${LIBKVM}
 LDADD= -lkvm
index b2c56cc..16f27ba 100644 (file)
@@ -1,3 +1,6 @@
+.\"    $OpenBSD: iostat.8,v 1.2 1996/03/03 02:52:33 tholo Exp $
+.\"    $NetBSD: iostat.8,v 1.8 1995/11/28 20:16:30 thorpej Exp $
+.\"
 .\" Copyright (c) 1985, 1991, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
 .\" SUCH DAMAGE.
 .\"
 .\"    from: @(#)iostat.8      8.1 (Berkeley) 6/6/93
-.\"    $Id: iostat.8,v 1.1.1.1 1995/10/18 08:47:37 deraadt Exp $
 .\"
-.Dd June 6, 1993
+.Dd Jan 18, 1996
 .Dt IOSTAT 8
-.Os BSD 4
+.Os NetBSD 1.1
 .Sh NAME
 .Nm iostat
 .Nd report
@@ -42,6 +44,7 @@
 statistics
 .Sh SYNOPSIS
 .Nm iostat
+.Op Fl CdDIT
 .Op Fl c Ar count
 .Op Fl M Ar core
 .Op Fl N Ar system
@@ -51,8 +54,19 @@ statistics
 .Nm Iostat
 displays kernel
 .Tn I/O
-statistics on terminal, disk and cpu
-operations.
+statistics on terminal, disk and cpu operations.  By default,
+.Nm iostat
+displays one line of statistics averaged over the machine's run time.
+The use of 
+.Fl c
+presents successive lines averaged over the
+.Ar wait
+period.
+The
+.Fl I
+option causes
+.Nm iostat
+to print raw, unaveraged values.
 .Pp
 The options are as follows:
 .Bl -tag -width flag
@@ -60,18 +74,44 @@ The options are as follows:
 Repeat the display
 .Ar count
 times.
-The first display is for the time since a reboot and each subsequent
-report is for the time period since the last display.
+Unless the
+.Fl I
+flag is in effect, the first display is for the time since a reboot and
+each subsequent report is for the time period since the last display.
 If no
 .Ar wait
 interval is specified, the default is 1 second.
+.It Fl C
+Show cpu statistics.  This is enabled by default unless the
+.Fl d, 
+.Fl D,
+or 
+.Fl T
+flags are used.
+.It Fl d
+Show disk statistics.  This is the default.  Displays kilobytes per
+transfer, number of transfers, and megabytes transfered.  Use of this
+flag disables display of cpu and tty statistics.
+.It Fl D
+Show alternate disk statistics.  Displays kilobytes transfered, number of 
+transfers, and time spent in transfers.  Use of this flag disables the
+default display.
+.It Fl I
+Show the running total values, rather than an average.
 .It Fl M
 Extract values associated with the name list from the specified core
 instead of the default
-.Dq Pa /dev/kmem .
+.Dq Pa /dev/mem .
 .It Fl N
 Extract the name list from the specified system instead of the default
 .Dq Pa /netbsd .
+.It Fl T
+Show tty statistics.  This is enabled by default unless the
+.Fl C, 
+.Fl d,
+or 
+.Fl D
+flags are used.
 .It Fl w
 Pause
 .Ar wait
@@ -92,7 +132,7 @@ characters read from terminals
 characters written to terminals
 .El
 .It disks
-Disk operations (this field is system dependent)
+Disk operations. 
 The header of the field is the disk name and unit number.
 If more than four disk drives are configured in the system,
 .Nm iostat
@@ -103,13 +143,24 @@ to display specific drives, their names may be supplied on the command
 line.
 .Pp
 .Bl -tag -width indent -compact
-.It sps
-sectors transferred per second
-.It tps
+.It K/t
+Kilobytes transferred per disk transfer
+.It t/s
 transfers per second
-.It msps
-milliseconds per average seek (including implied
-seeks and rotational latency)
+.It Mb/s
+Megabytes transferred per second
+.Pp
+.El
+The alternate display format, (selected with
+.Fl D
+), presents the following values.
+.Bl -tag -width indent -compact
+.It Kb
+Kilobytes transferred
+.It xfr
+Disk transfers
+.It time
+Seconds spent in disk activity
 .El
 .It cpu
 .Bl -tag -width indent -compact
@@ -124,10 +175,10 @@ seeks and rotational latency)
 .El
 .El
 .Sh FILES
-.Bl -tag -width /dev/kmem -compact
+.Bl -tag -width /dev/mem -compact
 .It Pa /netbsd
 Default kernel namelist.
-.It Pa /dev/kmem
+.It Pa /dev/mem
 Default memory file.
 .El
 .Sh SEE ALSO
index deaaaf6..a9313ed 100644 (file)
@@ -1,6 +1,41 @@
+/*     $OpenBSD: iostat.c,v 1.2 1996/03/03 02:52:34 tholo Exp $        */
+/*     $NetBSD: iostat.c,v 1.8 1995/11/28 20:16:31 thorpej Exp $       */
+
+/*
+ * Copyright (c) 1996 John M. Vinopal (banshee@resort.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the NetBSD Project
+ *      by John M. Vinopal.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 /*-
  * Copyright (c) 1986, 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -12,8 +47,8 @@
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
 #ifndef lint
 static char copyright[] =
 "@(#) Copyright (c) 1986, 1991, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n";
+        The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-/* from: static char sccsid[] = "@(#)iostat.c  8.2 (Berkeley) 1/26/94"; */
-static char *rcsid = "$Id: iostat.c,v 1.1.1.1 1995/10/18 08:47:37 deraadt Exp $";
+#if 0
+static char sccsid[] = "@(#)iostat.c    8.2 (Berkeley) 1/26/94";
+#else
+static char *rcsid = "$NetBSD: iostat.c,v 1.8 1995/11/28 20:16:31 thorpej Exp $"
+;
+#endif
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/buf.h>
 #include <sys/dkstat.h>
+#include <sys/time.h>
 
 #include <err.h>
 #include <ctype.h>
-#include <fcntl.h>
-#include <kvm.h>
-#include <limits.h>
-#include <nlist.h>
-#include <paths.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-struct nlist namelist[] = {
-#define        X_DK_TIME       0
-       { "_dk_time" },
-#define        X_DK_XFER       1
-       { "_dk_xfer" },
-#define        X_DK_WDS        2
-       { "_dk_wds" },
-#define        X_TK_NIN        3
-       { "_tk_nin" },
-#define        X_TK_NOUT       4
-       { "_tk_nout" },
-#define        X_DK_SEEK       5
-       { "_dk_seek" },
-#define        X_CP_TIME       6
-       { "_cp_time" },
-#define        X_DK_WPMS       7
-       { "_dk_wpms" },
-#define        X_HZ            8
-       { "_hz" },
-#define        X_STATHZ        9
-       { "_stathz" },
-#define        X_DK_NDRIVE     10
-       { "_dk_ndrive" },
-#define        X_END           10
-#if defined(hp300) || defined(luna68k)
-#define        X_HPDINIT       (X_END+1)
-       { "_hp_dinit" },
-#endif
-#ifdef mips
-#define        X_SCSI_DINIT    (X_END+1)
-       { "_scsi_dinit" },
-#endif
-#ifdef tahoe
-#define        X_VBDINIT       (X_END+1)
-       { "_vbdinit" },
-#endif
-#ifdef vax
-       { "_mbdinit" },
-#define X_MBDINIT      (X_END+1)
-       { "_ubdinit" },
-#define X_UBDINIT      (X_END+2)
-#endif
-       { NULL },
-};
-
-struct _disk {
-       long    cp_time[CPUSTATES];
-       long    *dk_time;
-       long    *dk_wds;
-       long    *dk_seek;
-       long    *dk_xfer;
-       long    tk_nin;
-       long    tk_nout;
-} cur, last;
-
-kvm_t   *kd;
-double   etime;
-long    *dk_wpms;
-int      dk_ndrive, *dr_select, hz, kmemfd, ndrives;
-char   **dr_name;
-
-#define nlread(x, v) \
-       kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
-
-#include "names.c"                             /* XXX */
-
-void cpustats __P((void));
-void dkstats __P((void));
-void phdr __P((int));
-void usage __P((void));
+#include "dkstats.h"
+
+/* Defined in dkstats.c */
+extern struct _disk cur;
+extern int     dk_ndrive;
+
+char   *nlistf = NULL;
+char   *memf = NULL;
+
+int            hz, reps, interval;
+static int     todo = 0;
+
+#define ISSET(x, a)    ((x) & (a))
+#define SHOW_CPU       0x0001
+#define SHOW_TTY       0x0002
+#define SHOW_STATS_1   0x0004
+#define SHOW_STATS_2   0x0008
+#define SHOW_TOTALS    0x0080
+
+static void cpustats __P((void));
+static void disk_stats __P((double));
+static void disk_stats2 __P((double));
+static void header __P((int));
+static void usage __P((void));
+static void display __P((void));
+static void selectdrives __P((int, char **));
+
+void dkswap __P((void));
+void dkreadstats __P((void));
+int dkinit __P((int));
 
 int
 main(argc, argv)
        int argc;
        char *argv[];
 {
-       register int i;
-       long tmp;
-       int ch, hdrcnt, reps, interval, stathz, ndrives;
-       char **cp, *memf, *nlistf, buf[30];
-        char errbuf[_POSIX2_LINE_MAX];
-
-       interval = reps = 0;
-       nlistf = memf = NULL;
-       while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF)
+       int ch, hdrcnt;
+       struct timeval  tv;
+
+       while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != EOF)
                switch(ch) {
                case 'c':
                        if ((reps = atoi(optarg)) <= 0)
                                errx(1, "repetition count <= 0.");
                        break;
+               case 'C':
+                       todo |= SHOW_CPU;
+                       break;
+               case 'd':
+                       todo |= SHOW_STATS_1;
+                       break;
+               case 'D':
+                       todo |= SHOW_STATS_2;
+                       break;
+               case 'I':
+                       todo |= SHOW_TOTALS;
+                       break;
                case 'M':
                        memf = optarg;
                        break;
                case 'N':
                        nlistf = optarg;
                        break;
+               case 'T':
+                       todo |= SHOW_TTY;
+                       break;
                case 'w':
                        if ((interval = atoi(optarg)) <= 0)
                                errx(1, "interval <= 0.");
@@ -166,6 +169,9 @@ main(argc, argv)
        argc -= optind;
        argv += optind;
 
+       if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2))
+               todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1;
+
        /*
         * Discard setgid privileges if not the running kernel so that bad
         * guys can't print interesting stuff from kernel memory.
@@ -173,203 +179,139 @@ main(argc, argv)
        if (nlistf != NULL || memf != NULL)
                setgid(getgid());
 
-        kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
-       if (kd == 0)
-               errx(1, "kvm_openfiles: %s", errbuf);
-       if (kvm_nlist(kd, namelist) == -1)
-               errx(1, "kvm_nlist: %s", kvm_geterr(kd));
-       if (namelist[X_DK_NDRIVE].n_type == 0)
-               errx(1, "dk_ndrive not found in namelist");
-       (void)nlread(X_DK_NDRIVE, dk_ndrive);
-       if (dk_ndrive <= 0)
-               errx(1, "invalid dk_ndrive %d\n", dk_ndrive);
-
-       cur.dk_time = calloc(dk_ndrive, sizeof(long));
-       cur.dk_wds = calloc(dk_ndrive, sizeof(long));
-       cur.dk_seek = calloc(dk_ndrive, sizeof(long));
-       cur.dk_xfer = calloc(dk_ndrive, sizeof(long));
-       last.dk_time = calloc(dk_ndrive, sizeof(long));
-       last.dk_wds = calloc(dk_ndrive, sizeof(long));
-       last.dk_seek = calloc(dk_ndrive, sizeof(long));
-       last.dk_xfer = calloc(dk_ndrive, sizeof(long));
-       dr_select = calloc(dk_ndrive, sizeof(int));
-       dr_name = calloc(dk_ndrive, sizeof(char *));
-       dk_wpms = calloc(dk_ndrive, sizeof(long));
-
-       for (i = 0; i < dk_ndrive; i++) {
-               (void)sprintf(buf, "dk%d", i);
-               dr_name[i] = strdup(buf);
-       }
-       if (!read_names())
-               exit(1);
-       (void)nlread(X_HZ, hz);
-       (void)nlread(X_STATHZ, stathz);
-       if (stathz)
-               hz = stathz;
-       (void)kvm_read(kd, namelist[X_DK_WPMS].n_value, dk_wpms,
-               dk_ndrive * sizeof(dk_wpms));
-
-       /*
-        * Choose drives to be displayed.  Priority goes to (in order) drives
-        * supplied as arguments and default drives.  If everything isn't
-        * filled in and there are drives not taken care of, display the first
-        * few that fit.
-        *
-        * The backward compatibility #ifdefs permit the syntax:
-        *      iostat [ drives ] [ interval [ count ] ]
-        */
-#define        BACKWARD_COMPATIBILITY
-       for (ndrives = 0; *argv; ++argv) {
-#ifdef BACKWARD_COMPATIBILITY
-               if (isdigit(**argv))
-                       break;
-#endif
-               for (i = 0; i < dk_ndrive; i++) {
-                       if (strcmp(dr_name[i], *argv))
-                               continue;
-                       dr_select[i] = 1;
-                       ++ndrives;
-               }
-       }
-#ifdef BACKWARD_COMPATIBILITY
-       if (*argv) {
-               interval = atoi(*argv);
-               if (*++argv)
-                       reps = atoi(*argv);
-       }
-#endif
-
-       if (interval) {
-               if (!reps)
-                       reps = -1;
-       } else
-               if (reps)
-                       interval = 1;
+       dkinit(0);
+       dkreadstats();
+       selectdrives(argc, argv);
 
-       for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
-               if (dr_select[i] || dk_wpms[i] == 0)
-                       continue;
-               for (cp = defdrives; *cp; cp++)
-                       if (strcmp(dr_name[i], *cp) == 0) {
-                               dr_select[i] = 1;
-                               ++ndrives;
-                               break;
-                       }
-       }
-       for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
-               if (dr_select[i])
-                       continue;
-               dr_select[i] = 1;
-               ++ndrives;
-       }
+       tv.tv_sec = interval;
+       tv.tv_usec = 0;
 
-       (void)signal(SIGCONT, phdr);
+       /* print a new header on sigcont */
+       (void)signal(SIGCONT, header);
 
        for (hdrcnt = 1;;) {
                if (!--hdrcnt) {
-                       phdr(0);
+                       header(0);
                        hdrcnt = 20;
                }
-               (void)kvm_read(kd, namelist[X_DK_TIME].n_value,
-                   cur.dk_time, dk_ndrive * sizeof(long));
-               (void)kvm_read(kd, namelist[X_DK_XFER].n_value,
-                   cur.dk_xfer, dk_ndrive * sizeof(long));
-               (void)kvm_read(kd, namelist[X_DK_WDS].n_value,
-                   cur.dk_wds, dk_ndrive * sizeof(long));
-               (void)kvm_read(kd, namelist[X_DK_SEEK].n_value,
-                   cur.dk_seek, dk_ndrive * sizeof(long));
-               (void)kvm_read(kd, namelist[X_TK_NIN].n_value,
-                   &cur.tk_nin, sizeof(cur.tk_nin));
-               (void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
-                   &cur.tk_nout, sizeof(cur.tk_nout));
-               (void)kvm_read(kd, namelist[X_CP_TIME].n_value,
-                   cur.cp_time, sizeof(cur.cp_time));
-               for (i = 0; i < dk_ndrive; i++) {
-                       if (!dr_select[i])
-                               continue;
-#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
-                       X(dk_xfer);
-                       X(dk_seek);
-                       X(dk_wds);
-                       X(dk_time);
-               }
-               tmp = cur.tk_nin;
-               cur.tk_nin -= last.tk_nin;
-               last.tk_nin = tmp;
-               tmp = cur.tk_nout;
-               cur.tk_nout -= last.tk_nout;
-               last.tk_nout = tmp;
-               etime = 0;
-               for (i = 0; i < CPUSTATES; i++) {
-                       X(cp_time);
-                       etime += cur.cp_time[i];
-               }
-               if (etime == 0.0)
-                       etime = 1.0;
-               etime /= (float)hz;
-               (void)printf("%4.0f%5.0f",
-                   cur.tk_nin / etime, cur.tk_nout / etime);
-               dkstats();
-               cpustats();
-               (void)printf("\n");
-               (void)fflush(stdout);
+
+               if (!ISSET(todo, SHOW_TOTALS))
+                       dkswap();
+               display();
 
                if (reps >= 0 && --reps <= 0)
                        break;
-               (void)sleep(interval);
+               select(0, NULL, NULL, NULL, &tv);
+               dkreadstats();
        }
        exit(0);
 }
 
-/* ARGUSED */
-void
-phdr(signo)
+static void
+header(signo)
        int signo;
 {
        register int i;
 
-       (void)printf("      tty");
+       /* Main Headers. */
+       if (ISSET(todo, SHOW_TTY))
+               (void)printf("      tty");
+
+       if (ISSET(todo, SHOW_STATS_1))
+       for (i = 0; i < dk_ndrive; i++)
+               if (cur.dk_select[i])
+                       (void)printf("            %3.3s ", cur.dk_name[i]);
+
+       if (ISSET(todo, SHOW_STATS_2))
        for (i = 0; i < dk_ndrive; i++)
-               if (dr_select[i])
-                       (void)printf("          %3.3s ", dr_name[i]);
-       (void)printf("         cpu\n tin tout");
+               if (cur.dk_select[i])
+                       (void)printf("           %3.3s ", cur.dk_name[i]);
+
+       if (ISSET(todo, SHOW_CPU))
+               (void)printf("            cpu");
+       printf("\n");
+
+       /* Sub-Headers. */
+       if (ISSET(todo, SHOW_TTY))
+               printf(" tin tout");
+
+       if (ISSET(todo, SHOW_STATS_1))
+       for (i = 0; i < dk_ndrive; i++)
+               if (cur.dk_select[i])
+                       if (ISSET(todo, SHOW_TOTALS))
+                               (void)printf("   K/t xfr Mb   ");
+                       else
+                               (void)printf("   K/t t/s Mb/s ");
+
+       if (ISSET(todo, SHOW_STATS_2))
        for (i = 0; i < dk_ndrive; i++)
-               if (dr_select[i])
-                       (void)printf(" sps tps msps ");
-       (void)printf(" us ni sy in id\n");
+               if (cur.dk_select[i])
+                       (void)printf("   Kb xfr time ");
+
+       if (ISSET(todo, SHOW_CPU))
+               (void)printf(" us ni sy in id");
+       printf("\n");
+}
+
+static void
+disk_stats(etime)
+double etime;
+{
+       register int dn;
+       double atime, mbps;
+
+       for (dn = 0; dn < dk_ndrive; ++dn) {
+               if (!cur.dk_select[dn])
+                       continue;
+
+               /* average Kbytes per transfer. */
+               if (cur.dk_xfer[dn])
+                       mbps = (cur.dk_bytes[dn] / (1024.0)) / cur.dk_xfer[dn];
+               else
+                       mbps = 0.0;
+               (void)printf(" %5.2f", mbps); 
+
+               /* average transfers per second. */
+               (void)printf(" %3.0f", cur.dk_xfer[dn] / etime);
+
+               /* time busy in disk activity */
+               atime = (double)cur.dk_time[dn].tv_sec +
+                       ((double)cur.dk_time[dn].tv_usec / (double)1000000);
+
+               /* Megabytes per second. */
+               if (atime != 0.0)
+                       mbps = cur.dk_bytes[dn] / (double)(1024 * 1024);
+               else 
+                       mbps = 0;
+               (void)printf(" %4.2f ", mbps / etime);
+       }
 }
 
-void
-dkstats()
+static void
+disk_stats2(etime)
+double etime;
 {
        register int dn;
-       double atime, itime, msps, words, xtime;
+       double atime;
 
        for (dn = 0; dn < dk_ndrive; ++dn) {
-               if (!dr_select[dn])
+               if (!cur.dk_select[dn])
                        continue;
-               words = cur.dk_wds[dn] * 32;            /* words xfer'd */
-               (void)printf("%4.0f",                   /* sectors */
-                   words / (DEV_BSIZE / 2) / etime);
-
-               (void)printf("%4.0f", cur.dk_xfer[dn] / etime);
-
-               if (dk_wpms[dn] && cur.dk_xfer[dn]) {
-                       atime = cur.dk_time[dn];        /* ticks disk busy */
-                       atime /= (float)hz;             /* ticks to seconds */
-                       xtime = words / dk_wpms[dn];    /* transfer time */
-                       itime = atime - xtime;          /* time not xfer'ing */
-                       if (itime < 0)
-                               msps = 0;
-                       else 
-                               msps = itime * 1000 / cur.dk_xfer[dn];
-               } else
-                       msps = 0;
-               (void)printf("%5.1f ", msps);
+
+               /* average kbytes per second. */
+               (void)printf(" %4.0f", cur.dk_bytes[dn] / (1024.0) / etime);
+
+               /* average transfers per second. */
+               (void)printf(" %3.0f", cur.dk_xfer[dn] / etime);
+
+               /* average time busy in disk activity. */
+               atime = (double)cur.dk_time[dn].tv_sec +
+                       ((double)cur.dk_time[dn].tv_usec / (double)1000000);
+               (void)printf(" %4.2f ", atime / etime);
        }
 }
 
-void
+static void
 cpustats()
 {
        register int state;
@@ -378,15 +320,109 @@ cpustats()
        time = 0;
        for (state = 0; state < CPUSTATES; ++state)
                time += cur.cp_time[state];
+       if (!time)
+               time = 1.0;
+       /* States are generally never 100% and can use %3.0f. */
        for (state = 0; state < CPUSTATES; ++state)
-               (void)printf("%3.0f",
-                   100. * cur.cp_time[state] / (time ? time : 1));
+               printf("%3.0f", 100. * cur.cp_time[state] / time);
 }
 
-void
+static void
 usage()
 {
        (void)fprintf(stderr,
-"usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n");
+"usage: iostat [-CdDIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n");
        exit(1);
 }
+
+static void
+display()
+{
+       int     i;
+       double  etime;
+
+       /* Sum up the elapsed ticks. */
+       etime = 0.0;
+       for (i = 0; i < CPUSTATES; i++) {
+               etime += cur.cp_time[i];
+       }
+       if (etime == 0.0)
+               etime = 1.0;
+       /* Convert to seconds. */
+       etime /= (float)hz;
+
+       /* If we're showing totals only, then don't divide by the
+        * system time.
+        */
+       if (ISSET(todo, SHOW_TOTALS))
+               etime = 1.0;
+
+       if (ISSET(todo, SHOW_TTY))
+               printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime);
+       
+       if (ISSET(todo, SHOW_STATS_1))
+               disk_stats(etime);
+
+       if (ISSET(todo, SHOW_STATS_2))
+               disk_stats2(etime);
+
+       if (ISSET(todo, SHOW_CPU))
+               cpustats();
+
+       (void)printf("\n");
+       (void)fflush(stdout);
+}
+
+static void
+selectdrives(argc, argv)
+int    argc;
+char   *argv[];
+{
+       int     i, ndrives;
+
+       /*
+        * Choose drives to be displayed.  Priority goes to (in order) drives
+        * supplied as arguments and default drives.  If everything isn't
+        * filled in and there are drives not taken care of, display the first
+        * few that fit.
+        *
+        * The backward compatibility #ifdefs permit the syntax:
+        *      iostat [ drives ] [ interval [ count ] ]
+        */
+#define        BACKWARD_COMPATIBILITY
+       for (ndrives = 0; *argv; ++argv) {
+#ifdef BACKWARD_COMPATIBILITY
+               if (isdigit(**argv))
+                       break;
+#endif
+               for (i = 0; i < dk_ndrive; i++) {
+                       if (strcmp(cur.dk_name[i], *argv))
+                               continue;
+                       cur.dk_select[i] = 1;
+                       ++ndrives;
+               }
+       }
+#ifdef BACKWARD_COMPATIBILITY
+       if (*argv) {
+               interval = atoi(*argv);
+               if (*++argv)
+                       reps = atoi(*argv);
+       }
+#endif
+
+       if (interval) {
+               if (!reps)
+                       reps = -1;
+       } else
+               if (reps)
+                       interval = 1;
+
+       /* Pick up to 4 drives if none specified. */
+       if (ndrives == 0)
+               for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
+                       if (cur.dk_select[i])
+                               continue;
+                       cur.dk_select[i] = 1;
+                       ++ndrives;
+               }
+}