]> granicus.if.org Git - sysstat/blobdiff - cifsiostat.c
count.c: Move SOURCE_SADC macro definition
[sysstat] / cifsiostat.c
index e03e839563a78a187976a42c96cd9d21b8a7fa6c..52e9cabd8516944b3eb3c837f18379935ad56289 100644 (file)
@@ -30,7 +30,8 @@
 
 #include "version.h"
 #include "cifsiostat.h"
-#include "common.h"
+#include "rd_stats.h"
+#include "count.h"
 
 #ifdef USE_NLS
 #include <locale.h>
 #define _(string) (string)
 #endif
 
+#ifdef USE_SCCSID
 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
 char *sccsid(void) { return (SCCSID); }
+#endif
+
+#ifdef TEST
+void int_handler(int n) { return; }
+#endif
 
-unsigned long long uptime[2]  = {0, 0};
-unsigned long long uptime0[2] = {0, 0};
-struct cifs_stats *st_cifs[2];
-struct io_hdr_stats *st_hdr_cifs;
+unsigned long long uptime_cs[2] = {0, 0};
+struct io_cifs *cifs_list = NULL;
 
-int cifs_nr = 0;       /* Nb of CIFS mounted directories found */
 int cpu_nr = 0;                /* Nb of processors on the machine */
 int flags = 0;         /* Flag for common options and system state */
+int dplaces_nr = -1;   /* Number of decimal places */
 
 long interval = 0;
-char timestamp[64];
+char timestamp[TIMESTAMP_LEN];
 
+struct sigaction alrm_act;
 
 /*
  ***************************************************************************
@@ -71,9 +77,11 @@ void usage(char *progname)
 
 #ifdef DEBUG
        fprintf(stderr, _("Options are:\n"
-                         "[ --debuginfo ] [ -h ] [ -k | -m ] [ -t ] [ -V ]\n"));
+                         "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ]\n"
+                         "[ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ]\n"));
 #else
        fprintf(stderr, _("Options are:\n"
+                         "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ]\n"
                          "[ -h ] [ -k | -m ] [ -t ] [ -V ]\n"));
 #endif
        exit(1);
@@ -84,225 +92,97 @@ void usage(char *progname)
  * SIGALRM signal handler.
  *
  * IN:
- * @sig        Signal number. Set to 0 for the first time, then to SIGALRM.
+ * @sig        Signal number.
  ***************************************************************************
  */
 void alarm_handler(int sig)
 {
-       signal(SIGALRM, alarm_handler);
        alarm(interval);
 }
 
 /*
  ***************************************************************************
- * Find number of CIFS-mounted points that are registered in
- * /proc/fs/cifs/Stats.
+ * Set every cifs entry to nonexistent status.
  *
- * RETURNS:
- * Number of CIFS-mounted points.
+ * IN:
+ * @clist      Pointer on the start of the linked list.
  ***************************************************************************
  */
-int get_cifs_nr(void)
+void set_cifs_nonexistent(struct io_cifs *clist)
 {
-       FILE *fp;
-       char line[128];
-       int cifs = 0;
-
-       if ((fp = fopen(CIFSSTATS, "r")) == NULL)
-               /* File non-existent */
-               return 0;
-
-       while (fgets(line, 128, fp) != NULL) {
-               
-               if (!strncmp(line, "Share (unique mount targets): ", 30)) {
-                       sscanf(line + 30, "%d", &cifs);
-                       break;
-               }
+       while (clist != NULL) {
+               clist->exist = FALSE;
+               clist = clist->next;
        }
-
-       /* Close file */
-       fclose(fp);
-
-       return cifs;
 }
 
 /*
  ***************************************************************************
- * Set every cifs_io entry to inactive state (unregistered).
+ * Check if a cifs filesystem is present in the list, and add it if requested.
+ *
+ * IN:
+ * @clist      Address of pointer on the start of the linked list.
+ * @name       cifs name.
+ *
+ * RETURNS:
+ * Pointer on the io_cifs structure in the list where the cifs is located
+ * (whether it was already in the list or if it has been added).
+ * NULL if the cifs name is too long or if the cifs doesn't exist and we
+ * don't want to add it.
  ***************************************************************************
  */
-void set_entries_inactive(void)
+struct io_cifs *add_list_cifs(struct io_cifs **clist, char *name)
 {
+       struct io_cifs *c, *cs;
        int i;
-       struct io_hdr_stats *shi = st_hdr_cifs;
 
-       for (i = 0; i < cifs_nr; i++, shi++) {
-               shi->active = FALSE;
-       }
-}
-
-/*
- ***************************************************************************
- * Free inactive entries (mark them as unused).
- ***************************************************************************
- */
-void free_inactive_entries(void)
-{
-       int i;
-       struct io_hdr_stats *shi = st_hdr_cifs;
+       if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN)
+               /* cifs name is too long */
+               return NULL;
 
-       for (i = 0; i < cifs_nr; i++, shi++) {
-               if (!shi->active) {
-                       shi->used = FALSE;
+       while (*clist != NULL) {
+               c = *clist;
+               if ((i = strcmp(c->name, name)) == 0) {
+                       /* cifs found in list */
+                       c->exist = TRUE;
+                       return c;
                }
+               if (i > 0)
+                       /*
+                        * If no group defined and we don't use /proc/diskstats,
+                        * insert current device in alphabetical order.
+                        * NB: Using /proc/diskstats ("iostat -p ALL") is a bit better than
+                        * using alphabetical order because sda10 comes after sda9...
+                        */
+                       break;
+
+               clist = &(c->next);
        }
-}
 
-/*
- ***************************************************************************
- * Allocate and init structures, according to system state.
- ***************************************************************************
- */
-void io_sys_init(void)
-{
-       int i;
-       
-       /* How many processors on this machine? */
-       cpu_nr = get_cpu_nr(~0);
+       /* cifs not found */
+       cs = *clist;
 
-       /* Get number of CIFS directories in /proc/fs/cifs/Stats */
-       if ((cifs_nr = get_cifs_nr()) > 0) {
-               cifs_nr += NR_CIFS_PREALLOC;
-       }
-       if ((st_hdr_cifs = (struct io_hdr_stats *) calloc(cifs_nr, IO_HDR_STATS_SIZE)) == NULL) {
+       /* Add cifs to the list */
+       if ((*clist = (struct io_cifs *) malloc(IO_CIFS_SIZE)) == NULL) {
                perror("malloc");
                exit(4);
        }
-       
-       /* Allocate structures for number of CIFS directories found */
+       memset(*clist, 0, IO_CIFS_SIZE);
+
+       c = *clist;
        for (i = 0; i < 2; i++) {
-               if ((st_cifs[i] =
-                   (struct cifs_stats *) calloc(cifs_nr, CIFS_STATS_SIZE)) == NULL) {
+               if ((c->cifs_stats[i] = (struct cifs_st *) malloc(CIFS_ST_SIZE)) == NULL) {
                        perror("malloc");
                        exit(4);
                }
+               memset(c->cifs_stats[i], 0, CIFS_ST_SIZE);
        }
-}
-
-/*
- ***************************************************************************
- * Free various structures.
- ***************************************************************************
-*/
-void io_sys_free(void)
-{
-       int i;
-
-       /* Free CIFS directories structures */
-       for (i = 0; i < 2; i++) {
+       strncpy(c->name, name, sizeof(c->name));
+       c->name[sizeof(c->name) - 1] = '\0';
+       c->exist = TRUE;
+       c->next = cs;
 
-               if (st_cifs[i]) {
-                       free(st_cifs[i]);
-               }
-       }
-       
-       if (st_hdr_cifs) {
-               free(st_hdr_cifs);
-       }
-}
-
-/*
- ***************************************************************************
- * Save stats for current CIFS filesystem.
- *
- * IN:
- * @name               Name of CIFS filesystem.
- * @curr               Index in array for current sample statistics.
- * @st_io              Structure with CIFS statistics to save.
- ***************************************************************************
- */
-void save_stats(char *name, int curr, struct cifs_stats *st_io)
-{
-       int i, j;
-       struct io_hdr_stats *st_hdr_cifs_i;
-       struct cifs_stats *st_cifs_i;
-
-       /* Look for CIFS directory in data table */
-       for (i = 0; i < cifs_nr; i++) {
-               st_hdr_cifs_i = st_hdr_cifs + i;
-               if ((st_hdr_cifs_i->used == TRUE) &&
-                   (!strcmp(st_hdr_cifs_i->name, name))) {
-                       break;
-               }
-       }
-
-       if (i == cifs_nr) {
-               /*
-                * This is a new filesystem: Look for an unused entry to store it.
-                */
-               for (i = 0; i < cifs_nr; i++) {
-                       st_hdr_cifs_i = st_hdr_cifs + i;
-                       if (!st_hdr_cifs_i->used) {
-                               /* Unused entry found... */
-                               st_hdr_cifs_i->used = TRUE; /* Indicate it is now used */
-                               st_hdr_cifs_i->active = TRUE;
-                               strcpy(st_hdr_cifs_i->name, name);
-                               st_cifs_i = st_cifs[curr] + i;
-                               *st_cifs_i = *((struct cifs_stats *) st_io);
-                               break;
-                       }
-               }
-               if (i == cifs_nr) {
-                       /*
-                        * It is a new CIFS directory
-                        * but there is no free structure to store it.
-                        */
-
-                       /* All entries are used: The number has to be increased */
-                       cifs_nr = cifs_nr + 5;
-
-                       /* Increase the size of st_hdr_ionfs buffer */
-                       if ((st_hdr_cifs = (struct io_hdr_stats *)
-                               realloc(st_hdr_cifs, cifs_nr * IO_HDR_STATS_SIZE)) == NULL) {
-                               perror("malloc");
-                               exit(4);
-                       }
-
-                       /* Set the new entries inactive */
-                       for (j = 0; j < 5; j++) {
-                               st_hdr_cifs_i = st_hdr_cifs + i + j;
-                               st_hdr_cifs_i->used = FALSE;
-                               st_hdr_cifs_i->active = FALSE;
-                       }
-
-                       /* Increase the size of st_hdr_ionfs buffer */
-                       for (j = 0; j < 2; j++) {
-                               if ((st_cifs[j] = (struct cifs_stats *)
-                                       realloc(st_cifs[j], cifs_nr * CIFS_STATS_SIZE)) == NULL) {
-                                       perror("malloc");
-                                       exit(4);
-                               }
-                               memset(st_cifs[j] + i, 0, 5 * CIFS_STATS_SIZE);
-                       }
-                       /* Now i shows the first unused entry of the new block */
-                       st_hdr_cifs_i = st_hdr_cifs + i;
-                       st_hdr_cifs_i->used = TRUE; /* Indicate it is now used */
-                       st_hdr_cifs_i->active = TRUE;
-                       strcpy(st_hdr_cifs_i->name, name);
-                       st_cifs_i = st_cifs[curr] + i;
-                       *st_cifs_i = *st_io;
-               }
-       } else {
-               st_hdr_cifs_i = st_hdr_cifs + i;
-               st_hdr_cifs_i->active = TRUE;
-               st_hdr_cifs_i->used = TRUE;
-               st_cifs_i = st_cifs[curr] + i;
-               *st_cifs_i = *st_io;
-       }
-       /*
-        * else it was a new CIFS directory
-        * but there was no free structure to store it.
-        */
+       return c;
 }
 
 /*
@@ -319,12 +199,12 @@ void read_cifs_stat(int curr)
        char line[256];
        char aux[32];
        int start = 0;
+       long long unsigned aux_open;
+       long long unsigned all_open = 0;
        char cifs_name[MAX_NAME_LEN];
        char name_tmp[MAX_NAME_LEN];
-       struct cifs_stats scifs;
-
-       /* Every CIFS entry is potentially unregistered */
-       set_entries_inactive();
+       struct cifs_st scifs;
+       struct io_cifs *ci;
 
        if ((fp = fopen(CIFSSTATS, "r")) == NULL)
                return;
@@ -332,40 +212,77 @@ void read_cifs_stat(int curr)
        sprintf(aux, "%%*d) %%%ds",
                MAX_NAME_LEN < 200 ? MAX_NAME_LEN - 1 : 200);
 
-       while (fgets(line, 256, fp) != NULL) {
+       memset(&scifs, 0, CIFS_ST_SIZE);
+
+       while (fgets(line, sizeof(line), fp) != NULL) {
 
                /* Read CIFS directory name */
                if (isdigit((unsigned char) line[0]) && sscanf(line, aux , name_tmp) == 1) {
                        if (start) {
-                               save_stats(cifs_name, curr, &scifs);
+                               scifs.fopens = all_open;
+                               ci = add_list_cifs(&cifs_list, cifs_name);
+                               if (ci != NULL) {
+                                       *ci->cifs_stats[curr] = scifs;
+                               }
+                               all_open = 0;
                        }
                        else {
                                start = 1;
                        }
-                       strcpy(cifs_name, name_tmp);
+                       strncpy(cifs_name, name_tmp, sizeof(cifs_name));
+                       cifs_name[sizeof(cifs_name) - 1] = '\0';
+                       memset(&scifs, 0, CIFS_ST_SIZE);
                }
                else {
                        if (!strncmp(line, "Reads:", 6)) {
+                               /*
+                                * SMB1 format: Reads: %llu Bytes: %llu
+                                * SMB2 format: Reads: %llu sent %llu failed
+                                * If this is SMB2 format then only the first variable (rd_ops) will be set.
+                                */
                                sscanf(line, "Reads: %llu Bytes: %llu", &scifs.rd_ops, &scifs.rd_bytes);
                        }
-                       if (!strncmp(line, "Writes:", 7)) {
+                       else if (!strncmp(line, "Bytes read:", 11)) {
+                               sscanf(line, "Bytes read: %llu  Bytes written: %llu",
+                                      &scifs.rd_bytes, &scifs.wr_bytes);
+                       }
+                       else if (!strncmp(line, "Writes:", 7)) {
+                               /*
+                                * SMB1 format: Writes: %llu Bytes: %llu
+                                * SMB2 format: Writes: %llu sent %llu failed
+                                * If this is SMB2 format then only the first variable (wr_ops) will be set.
+                                */
                                sscanf(line, "Writes: %llu Bytes: %llu", &scifs.wr_ops, &scifs.wr_bytes);
                        }
-                       if (!strncmp(line, "Opens:", 6)) {
+                       else if (!strncmp(line, "Opens:", 6)) {
                                sscanf(line, "Opens: %llu Closes:%llu Deletes: %llu",
-                                      &scifs.fopens, &scifs.fcloses, &scifs.fdeletes);
+                                      &aux_open, &scifs.fcloses, &scifs.fdeletes);
+                               all_open += aux_open;
+                       }
+                       else if (!strncmp(line, "Posix Opens:", 12)) {
+                               sscanf(line, "Posix Opens: %llu", &aux_open);
+                               all_open += aux_open;
+                       }
+                       else if (!strncmp(line, "Open files:", 11)) {
+                               sscanf(line, "Open files: %llu total (local), %llu",
+                                      &all_open, &aux_open);
+                               all_open += aux_open;
+                       }
+                       else if (!strncmp(line, "Closes:", 7)) {
+                               sscanf(line, "Closes: %llu", &scifs.fcloses);
                        }
                }
        }
-       
+
        if (start) {
-               save_stats(cifs_name, curr, &scifs);
+               scifs.fopens = all_open;
+               ci = add_list_cifs(&cifs_list, cifs_name);
+               if (ci != NULL) {
+                       *ci->cifs_stats[curr] = scifs;
+               }
        }
 
        fclose(fp);
-
-       /* Free structures corresponding to unregistered filesystems */
-       free_inactive_entries();
 }
 
 /*
@@ -378,7 +295,9 @@ void read_cifs_stat(int curr)
  */
 void write_cifs_stat_header(int *fctr)
 {
-       printf("Filesystem:           ");
+       if (!DISPLAY_PRETTY(flags)) {
+               printf("Filesystem            ");
+       }
        if (DISPLAY_KILOBYTES(flags)) {
                printf("        rkB/s        wkB/s");
                *fctr = 1024;
@@ -391,7 +310,11 @@ void write_cifs_stat_header(int *fctr)
                printf("         rB/s         wB/s");
                *fctr = 1;
        }
-       printf("    rops/s    wops/s         fo/s         fc/s         fd/s\n");
+       printf("    rops/s    wops/s         fo/s         fc/s         fd/s");
+       if (DISPLAY_PRETTY(flags)) {
+               printf(" Filesystem");
+       }
+       printf("\n");
 }
 
 /*
@@ -400,33 +323,43 @@ void write_cifs_stat_header(int *fctr)
  *
  * IN:
  * @curr       Index in array for current sample statistics.
- * @itv                Interval of time.
+ * @itv                Interval of time (in 1/100th of a second).
  * @fctr       Conversion factor.
- * @shi                Structures describing the CIFS filesystems.
+ * @clist      Pointer on the linked list where the cifs is saved.
  * @ioi                Current sample statistics.
  * @ioj                Previous sample statistics.
  ***************************************************************************
  */
 void write_cifs_stat(int curr, unsigned long long itv, int fctr,
-                    struct io_hdr_stats *shi, struct cifs_stats *ioni,
-                    struct cifs_stats *ionj)
+                    struct io_cifs *clist, struct cifs_st *ioni,
+                    struct cifs_st *ionj)
 {
-       if (DISPLAY_HUMAN_READ(flags)) {
-               printf("%-22s\n%23s", shi->name, "");
-       }
-       else {
-               printf("%-22s ", shi->name);
+       double rbytes, wbytes;
+
+       if (!DISPLAY_PRETTY(flags)) {
+               cprintf_in(IS_STR, "%-22s", clist->name, 0);
        }
 
        /*       rB/s   wB/s   fo/s   fc/s   fd/s*/
-       printf("%12.2f %12.2f %9.2f %9.2f %12.2f %12.2f %12.2f \n",
-              S_VALUE(ionj->rd_bytes, ioni->rd_bytes, itv) / fctr,
-              S_VALUE(ionj->wr_bytes, ioni->wr_bytes, itv) / fctr,
-              S_VALUE(ionj->rd_ops, ioni->rd_ops, itv),
-              S_VALUE(ionj->wr_ops, ioni->wr_ops, itv),
-              S_VALUE(ionj->fopens, ioni->fopens, itv),
-              S_VALUE(ionj->fcloses, ioni->fcloses, itv),
-              S_VALUE(ionj->fdeletes, ioni->fdeletes, itv));
+       rbytes = S_VALUE(ionj->rd_bytes, ioni->rd_bytes, itv);
+       wbytes = S_VALUE(ionj->wr_bytes, ioni->wr_bytes, itv);
+       if (!DISPLAY_UNIT(flags)) {
+               rbytes /= fctr;
+               wbytes /= fctr;
+       }
+       cprintf_f(DISPLAY_UNIT(flags) ? UNIT_BYTE : NO_UNIT, 2, 12, 2,
+                 rbytes, wbytes);
+       cprintf_f(NO_UNIT, 2, 9, 2,
+                 S_VALUE(ionj->rd_ops, ioni->rd_ops, itv),
+                 S_VALUE(ionj->wr_ops, ioni->wr_ops, itv));
+       cprintf_f(NO_UNIT, 3, 12, 2,
+                 S_VALUE(ionj->fopens, ioni->fopens, itv),
+                 S_VALUE(ionj->fcloses, ioni->fcloses, itv),
+                 S_VALUE(ionj->fdeletes, ioni->fdeletes, itv));
+       if (DISPLAY_PRETTY(flags)) {
+               cprintf_in(IS_STR, " %s", clist->name, 0);
+       }
+       printf("\n");
 }
 
 /*
@@ -440,10 +373,10 @@ void write_cifs_stat(int curr, unsigned long long itv, int fctr,
  */
 void write_stats(int curr, struct tm *rectime)
 {
-       int i, fctr = 1;
+       int fctr = 1;
        unsigned long long itv;
-       struct io_hdr_stats *shi;
-       struct cifs_stats *ioni, *ionj;
+       struct io_cifs *clist;
+       struct cifs_st *ioni, *ionj;
 
        /* Test stdout */
        TEST_STDOUT(STDOUT_FILENO);
@@ -464,38 +397,35 @@ void write_stats(int curr, struct tm *rectime)
 #endif
        }
 
-       /* Interval is multiplied by the number of processors */
-       itv = get_interval(uptime[!curr], uptime[curr]);
-
-       if (cpu_nr > 1) {
-               /* On SMP machines, reduce itv to one processor (see note above) */
-               itv = get_interval(uptime0[!curr], uptime0[curr]);
-       }
-
-       shi = st_hdr_cifs;
+       /* Interval of time, reduced to one processor */
+       itv = get_interval(uptime_cs[!curr], uptime_cs[curr]);
 
        /* Display CIFS stats header */
        write_cifs_stat_header(&fctr);
 
-       for (i = 0; i < cifs_nr; i++, shi++) {
-               if (shi->used) {
-                       ioni = st_cifs[curr]  + i;
-                       ionj = st_cifs[!curr] + i;
+       for (clist = cifs_list; clist != NULL; clist = clist->next) {
+
+               if (!clist->exist)
+                       /* Current cifs non existent */
+                       continue;
+
+               ioni = clist->cifs_stats[curr];
+               ionj = clist->cifs_stats[!curr];
+
 #ifdef DEBUG
-                       if (DISPLAY_DEBUG(flags)) {
-                               /* Debug output */
-                               fprintf(stderr, "name=%s itv=%llu fctr=%d ioni{ rd_bytes=%llu "
-                                               "wr_bytes=%llu rd_ops=%llu wr_ops=%llu fopens=%llu "
-                                               "fcloses=%llu fdeletes=%llu}\n",
-                                       shi->name, itv, fctr,
-                                       ioni->rd_bytes, ioni->wr_bytes,
-                                       ioni->rd_ops,   ioni->wr_ops,
-                                       ioni->fopens,   ioni->fcloses,
-                                       ioni->fdeletes);
-                       }
-#endif
-                       write_cifs_stat(curr, itv, fctr, shi, ioni, ionj);
+               if (DISPLAY_DEBUG(flags)) {
+                       /* Debug output */
+                       fprintf(stderr, "name=%s itv=%llu fctr=%d ioni{ rd_bytes=%llu "
+                                       "wr_bytes=%llu rd_ops=%llu wr_ops=%llu fopens=%llu "
+                                       "fcloses=%llu fdeletes=%llu}\n",
+                               clist->name, itv, fctr,
+                               ioni->rd_bytes, ioni->wr_bytes,
+                               ioni->rd_ops,   ioni->wr_ops,
+                               ioni->fopens,   ioni->fcloses,
+                               ioni->fdeletes);
                }
+#endif
+               write_cifs_stat(curr, itv, fctr, clist, ioni, ionj);
        }
        printf("\n");
 }
@@ -513,25 +443,24 @@ void rw_io_stat_loop(long int count, struct tm *rectime)
 {
        int curr = 1;
 
-       /* Don't buffer data if redirected to a pipe */
-       setbuf(stdout, NULL);
-       
+       /* Set a handler for SIGALRM */
+       memset(&alrm_act, 0, sizeof(alrm_act));
+       alrm_act.sa_handler = alarm_handler;
+       sigaction(SIGALRM, &alrm_act, NULL);
+       alarm(interval);
+
        do {
-               if (cpu_nr > 1) {
-                       /*
-                        * Read system uptime (only for SMP machines).
-                        * Init uptime0. So if /proc/uptime cannot fill it,
-                        * this will be done by /proc/stat.
-                        */
-                       uptime0[curr] = 0;
-                       read_uptime(&(uptime0[curr]));
-               }
+               /* Every device is potentially nonexistent */
+               set_cifs_nonexistent(cifs_list);
+
+               /* Read system uptime in 1/100th of a second */
+               read_uptime(&(uptime_cs[curr]));
 
                /* Read CIFS stats */
                read_cifs_stat(curr);
 
                /* Get time */
-               get_localtime(rectime);
+               get_localtime(rectime, 0);
 
                /* Print results */
                write_stats(curr, rectime);
@@ -542,7 +471,7 @@ void rw_io_stat_loop(long int count, struct tm *rectime)
 
                if (count) {
                        curr ^= 1;
-                       pause();
+                       __pause();
                }
        }
        while (count);
@@ -567,8 +496,8 @@ int main(int argc, char **argv)
        init_nls();
 #endif
 
-       /* Get HZ */
-       get_HZ();
+       /* Init color strings */
+       init_colors();
 
        /* Process args... */
        while (opt < argc) {
@@ -579,16 +508,37 @@ int main(int argc, char **argv)
                        opt++;
                } else
 #endif
-               if (!strncmp(argv[opt], "-", 1)) {
+
+               if (!strcmp(argv[opt], "--human")) {
+                       flags |= I_D_UNIT;
+                       opt++;
+               }
+
+               else if (!strcmp(argv[opt], "--pretty")) {
+                       /* Display an easy-to-read CIFS report */
+                       flags |= I_D_PRETTY;
+                       opt++;
+               }
+
+               else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
+                       /* Get number of decimal places */
+                       dplaces_nr = atoi(argv[opt] + 6);
+                       if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
+                               usage(argv[0]);
+                       }
+                       opt++;
+               }
+
+               else if (!strncmp(argv[opt], "-", 1)) {
                        for (i = 1; *(argv[opt] + i); i++) {
 
                                switch (*(argv[opt] + i)) {
 
                                case 'h':
-                                       /* Display an easy-to-read CIFS report */
-                                       flags |= I_D_HUMAN_READ;
+                                       /* Option -h is equivalent to --pretty --human */
+                                       flags |= I_D_PRETTY + I_D_UNIT;
                                        break;
-       
+
                                case 'k':
                                        if (DISPLAY_MEGABYTES(flags)) {
                                                usage(argv[0]);
@@ -614,7 +564,7 @@ int main(int argc, char **argv)
                                        /* Print version number and exit */
                                        print_version();
                                        break;
-       
+
                                default:
                                        usage(argv[0]);
                                }
@@ -647,27 +597,29 @@ int main(int argc, char **argv)
                count = 1;
        }
 
-       /* Init structures according to machine architecture */
-       io_sys_init();
+       /* How many processors on this machine? */
+       cpu_nr = get_cpu_nr(~0, FALSE);
+
+       get_localtime(&rectime, 0);
 
-       get_localtime(&rectime);
+       /*
+        * Don't buffer data if redirected to a pipe.
+        * Note: With musl-c, the behavior of this function is undefined except
+        * when it is the first operation on the stream.
+        */
+       setbuf(stdout, NULL);
 
        /* Get system name, release number and hostname */
-       uname(&header);
+       __uname(&header);
        if (print_gal_header(&rectime, header.sysname, header.release,
-                            header.nodename, header.machine, cpu_nr)) {
+                            header.nodename, header.machine, cpu_nr,
+                            PLAIN_OUTPUT)) {
                flags |= I_D_ISO;
        }
        printf("\n");
 
-       /* Set a handler for SIGALRM */
-       alarm_handler(0);
-
        /* Main loop */
        rw_io_stat_loop(count, &rectime);
 
-       /* Free structures */
-       io_sys_free();
-
        return 0;
 }