]> granicus.if.org Git - sysstat/blob - iostat.c
sa_common.c: Remove some dead code
[sysstat] / iostat.c
1 /*
2  * iostat: report CPU and I/O statistics
3  * (C) 1998-2020 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
5  ***************************************************************************
6  * This program is free software; you can redistribute it and/or modify it *
7  * under the terms of the GNU General Public License as published  by  the *
8  * Free Software Foundation; either version 2 of the License, or (at  your *
9  * option) any later version.                                              *
10  *                                                                         *
11  * This program is distributed in the hope that it  will  be  useful,  but *
12  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
14  * for more details.                                                       *
15  *                                                                         *
16  * You should have received a copy of the GNU General Public License along *
17  * with this program; if not, write to the Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
19  ***************************************************************************
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <ctype.h>
31 #include <dirent.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/utsname.h>
35
36 #include "version.h"
37 #include "iostat.h"
38 #include "ioconf.h"
39 #include "rd_stats.h"
40 #include "count.h"
41
42 #include <locale.h>     /* For setlocale() */
43 #ifdef USE_NLS
44 #include <libintl.h>
45 #define _(string) gettext(string)
46 #else
47 #define _(string) (string)
48 #endif
49
50 #ifdef USE_SCCSID
51 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
52 char *sccsid(void) { return (SCCSID); }
53 #endif
54
55 #ifdef TEST
56 extern int __env;
57 #endif
58
59 struct stats_cpu *st_cpu[2];
60 unsigned long long uptime_cs[2] = {0, 0};
61 unsigned long long tot_jiffies[2] = {0, 0};
62 struct io_device *dev_list = NULL;
63
64 /* Number of decimal places */
65 int dplaces_nr = -1;
66
67 int group_nr = 0;       /* Nb of device groups */
68 int cpu_nr = 0;         /* Nb of processors on the machine */
69 int flags = 0;          /* Flag for common options and system state */
70
71 long interval = 0;
72 char timestamp[TIMESTAMP_LEN];
73 char alt_dir[MAX_FILE_LEN];
74
75 struct sigaction alrm_act, int_act;
76 int sigint_caught = 0;
77
78 /*
79  ***************************************************************************
80  * Print usage and exit.
81  *
82  * IN:
83  * @progname    Name of sysstat command.
84  ***************************************************************************
85  */
86 void usage(char *progname)
87 {
88         fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
89                 progname);
90 #ifdef DEBUG
91         fprintf(stderr, _("Options are:\n"
92                           "[ -c ] [ -d ] [ -h ] [ -k | -m ] [ -N ] [ -s ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ]\n"
93                           "[ { -f | +f } <directory> ] [ -j { ID | LABEL | PATH | UUID | ... } ]\n"
94                           "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ] [ -o JSON ]\n"
95                           "[ [ -H ] -g <group_name> ] [ -p [ <device> [,...] | ALL ] ]\n"
96                           "[ <device> [...] | ALL ] [ --debuginfo ]\n"));
97 #else
98         fprintf(stderr, _("Options are:\n"
99                           "[ -c ] [ -d ] [ -h ] [ -k | -m ] [ -N ] [ -s ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ]\n"
100                           "[ { -f | +f } <directory> ] [ -j { ID | LABEL | PATH | UUID | ... } ]\n"
101                           "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ] [ -o JSON ]\n"
102                           "[ [ -H ] -g <group_name> ] [ -p [ <device> [,...] | ALL ] ]\n"
103                           "[ <device> [...] | ALL ]\n"));
104 #endif
105         exit(1);
106 }
107
108 /*
109  ***************************************************************************
110  * Set disk output unit. Unit will be kB/s unless POSIXLY_CORRECT
111  * environment variable has been set, in which case the output will be
112  * expressed in blocks/s.
113  ***************************************************************************
114  */
115 void set_disk_output_unit(void)
116 {
117         if (DISPLAY_KILOBYTES(flags) || DISPLAY_MEGABYTES(flags))
118                 return;
119
120         /* Check POSIXLY_CORRECT environment variable */
121         if (__getenv(ENV_POSIXLY_CORRECT) == NULL) {
122                 /* Variable not set: Unit is kB/s and not blocks/s */
123                 flags |= I_D_KILOBYTES;
124         }
125 }
126
127 /*
128  ***************************************************************************
129  * SIGALRM signal handler. No need to reset the handler here.
130  *
131  * IN:
132  * @sig Signal number.
133  ***************************************************************************
134  */
135 void alarm_handler(int sig)
136 {
137         alarm(interval);
138 }
139
140 /*
141  ***************************************************************************
142  * SIGINT signal handler.
143  *
144  * IN:
145  * @sig Signal number.
146  **************************************************************************
147  */
148 void int_handler(int sig)
149 {
150         sigint_caught = 1;
151 }
152
153 /*
154  ***************************************************************************
155  * Initialize stats common structures.
156  ***************************************************************************
157  */
158 void init_stats(void)
159 {
160         int i;
161
162         /* Allocate structures for CPUs "all" and 0 */
163         for (i = 0; i < 2; i++) {
164                 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * 2)) == NULL) {
165                         perror("malloc");
166                         exit(4);
167                 }
168                 memset(st_cpu[i], 0, STATS_CPU_SIZE * 2);
169         }
170 }
171
172 /*
173  ***************************************************************************
174  * Set every device entry to nonexistent status.
175  *
176  * IN:
177  * @dlist       Pointer on the start of the linked list.
178  ***************************************************************************
179  */
180 void set_devices_nonexistent(struct io_device *dlist)
181 {
182         while (dlist != NULL) {
183                 dlist->exist = FALSE;
184                 dlist = dlist->next;
185         }
186 }
187
188 /*
189  ***************************************************************************
190  * Check if a device is present in the list, and add it if requested.
191  * Also look for its type (device or partition) and save it.
192  *
193  * IN:
194  * @dlist       Address of pointer on the start of the linked list.
195  * @name        Device name.
196  * @dtype       T_PART_DEV (=2) if the device and all its partitions should
197  *              also be read (option -p used), T_GROUP (=3) if it's a group
198  *              name, and 0 otherwise.
199  *
200  * RETURNS:
201  * Pointer on the io_device structure in the list where the device is located
202  * (whether it was already in the list or if it has been added).
203  * NULL if the device name is too long or if the device doesn't exist and we
204  * don't want to add it.
205  ***************************************************************************
206  */
207 struct io_device *add_list_device(struct io_device **dlist, char *name, int dtype)
208 {
209         struct io_device *d, *ds;
210         int i, rc = 0;
211
212         if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN)
213                 /* Device name is too long */
214                 return NULL;
215
216         while (*dlist != NULL) {
217                 d = *dlist;
218                 if ((i = strcmp(d->name, name)) == 0) {
219                         /* Device found in list */
220                         if ((dtype == T_PART_DEV) && (d->dev_tp == T_DEV)) {
221                                 d->dev_tp = dtype;
222                         }
223                         d->exist = TRUE;
224                         return d;
225                 }
226                 if (!GROUP_DEFINED(flags) && !DISPLAY_EVERYTHING(flags) && (i > 0))
227                         /*
228                          * If no group defined and we don't use /proc/diskstats,
229                          * insert current device in alphabetical order.
230                          * NB: Using /proc/diskstats ("iostat -p ALL") is a bit better than
231                          * using alphabetical order because sda10 comes after sda9...
232                          */
233                         break;
234
235                 dlist = &(d->next);
236         }
237
238         /* Device not found */
239         ds = *dlist;
240
241         /* Add device to the list */
242         if ((*dlist = (struct io_device *) malloc(sizeof(struct io_device))) == NULL) {
243                 perror("malloc");
244                 exit(4);
245         }
246         memset(*dlist, 0, sizeof(struct io_device));
247
248         d = *dlist;
249         for (i = 0; i < 2; i++) {
250                 if ((d->dev_stats[i] = (struct io_stats *) malloc(sizeof(struct io_stats))) == NULL) {
251                         perror("malloc");
252                         exit(4);
253                 }
254                 memset(d->dev_stats[i], 0, sizeof(struct io_stats));
255         }
256         strncpy(d->name, name, MAX_NAME_LEN);
257         d->name[MAX_NAME_LEN - 1] = '\0';
258         d->exist = TRUE;
259         d->next = ds;
260
261         if (dtype == T_GROUP) {
262                 d->dev_tp = dtype;
263         }
264         else  {
265                 if (!alt_dir[0] || USE_ALL_DIR(flags)) {
266                         rc = is_device(SLASH_SYS, name, ACCEPT_VIRTUAL_DEVICES);
267                 }
268
269                 if (alt_dir[0] && (!USE_ALL_DIR(flags) || (USE_ALL_DIR(flags) && !rc))) {
270                         rc = is_device(alt_dir, name, ACCEPT_VIRTUAL_DEVICES);
271                 }
272
273                 if (rc) {
274                         d->dev_tp = (dtype == T_PART_DEV ? T_PART_DEV : T_DEV);
275                 }
276                 else {
277                         /* This is a partition (T_PART) */
278                         d->dev_tp = T_PART;
279                 }
280         }
281
282         return d;
283 }
284
285 /*
286  ***************************************************************************
287  * Get device major and minor numbers.
288  *
289  * IN:
290  * @filename    Name of the device ("sda", "/dev/sdb1"...)
291  *
292  * OUT:
293  * @major       Major number of the device.
294  * @minor       Minor number of the device.
295  *
296  * RETURNS:
297  * 0 on success, and -1 otherwise.
298  ***************************************************************************
299  */
300 int get_major_minor_nr(char filename[], int *major, int *minor)
301 {
302         struct stat statbuf;
303         char *bang;
304         char dfile[MAX_PF_NAME];
305
306         snprintf(dfile, sizeof(dfile), "%s%s", filename[0] == '/' ? "" : SLASH_DEV, filename);
307         dfile[sizeof(dfile) - 1] = '\0';
308
309         while ((bang = strchr(dfile, '!'))) {
310                 /*
311                  * Some devices may have had a slash replaced with a bang character (eg. cciss!c0d0...)
312                  * Restore their original names so that they can be found in /dev directory.
313                  */
314                 *bang = '/';
315         }
316
317         if (__stat(dfile, &statbuf) < 0)
318                 return -1;
319
320         *major = __major(statbuf.st_rdev);
321         *minor = __minor(statbuf.st_rdev);
322
323         return 0;
324 }
325
326 /*
327  ***************************************************************************
328  * Read sysfs stat for current block device or partition.
329  *
330  * IN:
331  * @filename    File name where stats will be read.
332  * @ios         Structure where stats will be saved.
333  *
334  * OUT:
335  * @ios         Structure where stats have been saved.
336  *
337  * RETURNS:
338  * 0 on success, -1 otherwise.
339  ***************************************************************************
340  */
341 int read_sysfs_file_stat_work(char *filename, struct io_stats *ios)
342 {
343         FILE *fp;
344         struct io_stats sdev;
345         int i;
346         unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
347         unsigned long rd_ios, rd_merges_or_rd_sec, wr_ios, wr_merges;
348         unsigned long rd_sec_or_wr_ios, wr_sec, rd_ticks_or_wr_sec;
349         unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
350
351         /* Try to read given stat file */
352         if ((fp = fopen(filename, "r")) == NULL)
353                 return -1;
354
355         i = fscanf(fp, "%lu %lu %lu %lu %lu %lu %lu %u %u %u %u %lu %lu %lu %u %lu %u",
356                    &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
357                    &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
358                    &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
359                    &fl_ios, &fl_ticks);
360
361         memset(&sdev, 0, sizeof(struct io_stats));
362
363         if (i >= 11) {
364                 /* Device or partition */
365                 sdev.rd_ios     = rd_ios;
366                 sdev.rd_merges  = rd_merges_or_rd_sec;
367                 sdev.rd_sectors = rd_sec_or_wr_ios;
368                 sdev.rd_ticks   = (unsigned int) rd_ticks_or_wr_sec;
369                 sdev.wr_ios     = wr_ios;
370                 sdev.wr_merges  = wr_merges;
371                 sdev.wr_sectors = wr_sec;
372                 sdev.wr_ticks   = wr_ticks;
373                 sdev.ios_pgr    = ios_pgr;
374                 sdev.tot_ticks  = tot_ticks;
375                 sdev.rq_ticks   = rq_ticks;
376
377                 if (i >= 15) {
378                         /* Discard I/O */
379                         sdev.dc_ios     = dc_ios;
380                         sdev.dc_merges  = dc_merges;
381                         sdev.dc_sectors = dc_sec;
382                         sdev.dc_ticks   = dc_ticks;
383                 }
384
385                 if (i >= 17) {
386                         /* Flush I/O */
387                         sdev.fl_ios     = fl_ios;
388                         sdev.fl_ticks   = fl_ticks;
389                 }
390         }
391         else if (i == 4) {
392                 /* Partition without extended statistics */
393                 sdev.rd_ios     = rd_ios;
394                 sdev.rd_sectors = rd_merges_or_rd_sec;
395                 sdev.wr_ios     = rd_sec_or_wr_ios;
396                 sdev.wr_sectors = rd_ticks_or_wr_sec;
397         }
398
399         *ios = sdev;
400
401         fclose(fp);
402
403         return 0;
404 }
405
406 /*
407  ***************************************************************************
408  * Read sysfs stat for current whole device using /sys or an alternate
409  * location.
410  *
411  * IN:
412  * @devname     Device name for which stats have to be read.
413  * @ios         Structure where stats will be saved.
414  *
415  * OUT:
416  * @ios         Structure where stats have been saved.
417  *
418  * RETURNS:
419  * 0 on success, -1 otherwise.
420  ***************************************************************************
421  */
422 int read_sysfs_file_stat(char *devname, struct io_stats *ios)
423 {
424         int rc = 0;
425         char dfile[MAX_PF_NAME];
426
427         if (!alt_dir[0] || USE_ALL_DIR(flags)) {
428                 /* Read stats for current whole device using /sys/block/ directory */
429                 snprintf(dfile, sizeof(dfile), "%s/%s/%s/%s",
430                          SLASH_SYS, __BLOCK, devname, S_STAT);
431                 dfile[sizeof(dfile) - 1] = '\0';
432
433                 rc = read_sysfs_file_stat_work(dfile, ios);
434         }
435
436         if (alt_dir[0] && (!USE_ALL_DIR(flags) || (USE_ALL_DIR(flags) && (rc < 0)))) {
437                 /* Read stats for current whole device using an alternate /sys directory */
438                 snprintf(dfile, sizeof(dfile), "%s/%s/%s/%s",
439                          alt_dir, __BLOCK, devname, S_STAT);
440                 dfile[sizeof(dfile) - 1] = '\0';
441
442                 rc = read_sysfs_file_stat_work(dfile, ios);
443         }
444
445         return rc;
446 }
447
448 /*
449  ***************************************************************************
450  * Read sysfs stats for all the partitions of a whole device. Devices are
451  * saved in the linked list.
452  *
453  * IN:
454  * @curr        Index in array for current sample statistics.
455  * @dname       Whole device name.
456  * @sysdev      sysfs location.
457  *
458  * RETURNS:
459  * 0 on success, -1 otherwise.
460  ***************************************************************************
461  */
462 int read_sysfs_device_part_stat_work(int curr, char *dname, char *sysdev)
463 {
464         DIR *dir;
465         struct dirent *drd;
466         struct io_stats sdev;
467         struct io_device *d;
468         char dfile[MAX_PF_NAME], filename[MAX_PF_NAME + 512];
469         int major, minor;
470
471         snprintf(dfile, sizeof(dfile), "%s/%s/%s", sysdev, __BLOCK, dname);
472         dfile[sizeof(dfile) - 1] = '\0';
473
474         /* Open current device directory in /sys/block */
475         if ((dir = __opendir(dfile)) == NULL)
476                 return -1;
477
478         /* Get current entry */
479         while ((drd = __readdir(dir)) != NULL) {
480
481                 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
482                         continue;
483                 snprintf(filename, sizeof(filename), "%s/%s/%s", dfile, drd->d_name, S_STAT);
484                 filename[sizeof(filename) - 1] = '\0';
485
486                 /* Read current partition stats */
487                 if (read_sysfs_file_stat_work(filename, &sdev) < 0)
488                         continue;
489
490                 d = add_list_device(&dev_list, drd->d_name, 0);
491                 if (d != NULL) {
492                         *(d->dev_stats[curr]) = sdev;
493
494                         if (!d->major) {
495                                 /* Get major and minor numbers for given device */
496                                 if (get_major_minor_nr(d->name, &major, &minor) == 0) {
497                                         d->major = major;
498                                         d->minor = minor;
499                                 }
500                         }
501                 }
502         }
503
504         /* Close device directory */
505         __closedir(dir);
506
507         return 0;
508 }
509
510 /*
511  ***************************************************************************
512  * Read sysfs stats for all the partitions of a whole device.
513  * Stats are from /sys or an alternate directory.
514  *
515  * IN:
516  * @curr        Index in array for current sample statistics.
517  * @dname       Whole device name.
518  *
519  * RETURNS:
520  * 0 on success, -1 otherwise.
521  ***************************************************************************
522  */
523 int read_sysfs_device_part_stat(int curr, char *dname)
524 {
525         int rc = 0;
526
527         if (!alt_dir[0] || USE_ALL_DIR(flags)) {
528                 /* Read partition stats from /sys */
529                 rc = read_sysfs_device_part_stat_work(curr, dname, SLASH_SYS);
530         }
531
532         if (alt_dir[0] && (!USE_ALL_DIR(flags) || (USE_ALL_DIR(flags) && (rc < 0)))) {
533                 /* Read partition stats from an alternate /sys directory */
534                 rc = read_sysfs_device_part_stat_work(curr, dname, alt_dir);
535         }
536
537         return rc;
538 }
539
540 /*
541  ***************************************************************************
542  * Read sysfs stats for every whole device. Devices are saved in the linked
543  * list.
544  *
545  * IN:
546  * @curr        Index in array for current sample statistics.
547  * @sysblock    __sys/block directory location.
548  *
549  * RETURNS:
550  * 0 on success, -1 otherwise.
551  ***************************************************************************
552  */
553 int read_sysfs_all_devices_stat_work(int curr, char *sysblock)
554 {
555         DIR *dir;
556         struct dirent *drd;
557         struct io_stats sdev;
558         struct io_device *d;
559         char dfile[MAX_PF_NAME];
560         int major, minor;
561
562         /* Open __sys/block directory */
563         if ((dir = __opendir(sysblock)) == NULL)
564                 return -1;
565
566         /* Get current entry */
567         while ((drd = __readdir(dir)) != NULL) {
568
569                 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
570                         continue;
571                 snprintf(dfile, sizeof(dfile), "%s/%s/%s", sysblock, drd->d_name, S_STAT);
572                 dfile[sizeof(dfile) - 1] = '\0';
573
574                 /* Read current whole device stats */
575                 if (read_sysfs_file_stat_work(dfile, &sdev) < 0)
576                         continue;
577
578                 d = add_list_device(&dev_list, drd->d_name, 0);
579                 if (d != NULL) {
580                         *(d->dev_stats[curr]) = sdev;
581
582                         if (!d->major) {
583                                 /* Get major and minor numbers for given device */
584                                 if (get_major_minor_nr(d->name, &major, &minor) == 0) {
585                                         d->major = major;
586                                         d->minor = minor;
587                                 }
588                         }
589                 }
590         }
591
592         /* Close device directory */
593         __closedir(dir);
594
595         return 0;
596 }
597
598 /*
599  ***************************************************************************
600  * Read sysfs stats for every whole device from /sys or an alternate
601  * location.
602  *
603  * IN:
604  * @curr        Index in array for current sample statistics.
605  *
606  * RETURNS:
607  * 0 on success, -1 otherwise.
608  ***************************************************************************
609  */
610 int read_sysfs_all_devices_stat(int curr)
611 {
612         int rc = 0;
613         char sysblock[MAX_PF_NAME];
614
615         if (!alt_dir[0] || USE_ALL_DIR(flags)) {
616                 /* Read all whole devices from /sys */
617                 rc = read_sysfs_all_devices_stat_work(curr, SYSFS_BLOCK);
618         }
619
620         if (alt_dir[0]) {
621                 snprintf(sysblock, sizeof(sysblock), "%s/%s", alt_dir, __BLOCK);
622                 sysblock[sizeof(sysblock) - 1] = '\0';
623                 /* Read stats from an alternate sys location */
624                 rc = read_sysfs_all_devices_stat_work(curr, sysblock);
625         }
626
627         return rc;
628 }
629
630 /*
631  ***************************************************************************
632  * Read sysfs stats for a partition using __sys/dev/block/M:m/ directory.
633  *
634  * IN:
635  * @curr        Index in array for current sample statistics.
636  * @d           Device structure.
637  * @sysdev      sysfs directory.
638  *
639  * RETURNS:
640  * 0 on success, and -1 otherwise.
641  ***************************************************************************
642  */
643 int read_sysfs_part_stat_work(int curr, struct io_device *d, char *sysdev)
644 {
645         char dfile[MAX_PF_NAME];
646         int major, minor;
647
648         if (!d->major) {
649                 /* Get major and minor numbers for given device */
650                 if (get_major_minor_nr(d->name, &major, &minor) < 0)
651                         return -1;
652                 d->major = major;
653                 d->minor = minor;
654         }
655
656         /* Read stats for device */
657         snprintf(dfile, sizeof(dfile), "%s/%s/%d:%d/%s",
658                  sysdev, __DEV_BLOCK, d->major, d->minor, S_STAT);
659         dfile[sizeof(dfile) - 1] = '\0';
660
661         return read_sysfs_file_stat_work(dfile, d->dev_stats[curr]);
662 }
663
664 /*
665  ***************************************************************************
666  * Read sysfs stats for a partition using /sys/dev/block/M:m/ directory or
667  * an alternate directory.
668  *
669  * IN:
670  * @curr        Index in array for current sample statistics.
671  * @d           Device structure.
672  *
673  * RETURNS:
674  * 0 on success, and -1 otherwise.
675  ***************************************************************************
676  */
677 int read_sysfs_part_stat(int curr, struct io_device *d)
678 {
679         int rc = 0;
680
681         if (!alt_dir[0] || USE_ALL_DIR(flags)) {
682                 /* Read partition stats from /sys */
683                 rc = read_sysfs_part_stat_work(curr, d, SLASH_SYS);
684         }
685
686         if (alt_dir[0] && (!USE_ALL_DIR(flags) || (USE_ALL_DIR(flags) && (rc < 0)))) {
687                 /* Read partition stats from an alternate /sys directory */
688                 rc = read_sysfs_part_stat_work(curr, d, alt_dir);
689         }
690
691         return rc;
692 }
693
694 /*
695  ***************************************************************************
696  * Read stats from the sysfs filesystem for the devices entered on the
697  * command line.
698  *
699  * IN:
700  * @curr        Index in array for current sample statistics.
701  ***************************************************************************
702  */
703 void read_sysfs_dlist_stat(int curr)
704 {
705         struct io_device *dlist;
706
707         for (dlist = dev_list; dlist != NULL; dlist = dlist->next) {
708                 if (dlist->exist)
709                         /* Device stats already read */
710                         continue;
711
712                 else if (dlist->dev_tp == T_PART) {
713                         /*
714                          * This is a partition.
715                          * Read its stats using /sys/dev/block/M:n/ directory.
716                          */
717                         if (read_sysfs_part_stat(curr, dlist) == 0) {
718                                 dlist->exist = TRUE;
719                         }
720                 }
721
722                 else if ((dlist->dev_tp == T_PART_DEV) || (dlist->dev_tp == T_DEV)) {
723                         /* Read stats for current whole device using /sys/block/ directory */
724                         if (read_sysfs_file_stat(dlist->name, dlist->dev_stats[curr]) == 0) {
725                                 dlist->exist = TRUE;
726                         }
727
728                         if (dlist->dev_tp == T_PART_DEV) {
729                                 /* Also read all its partitions now */
730                                 read_sysfs_device_part_stat(curr, dlist->name);
731                         }
732                 }
733         }
734
735         /* Read all whole devices stats if requested ("iostat ALL ...") */
736         if (DISPLAY_ALL_DEVICES(flags)) {
737                 read_sysfs_all_devices_stat(curr);
738         }
739 }
740
741 /*
742  ***************************************************************************
743  * Read stats from the diskstats file. Only used when "-p ALL" has been
744  * entered on the command line.
745  *
746  * IN:
747  * @curr        Index in array for current sample statistics.
748  * @diskstats   Path to diskstats file (e.g. "/proc/diskstats").
749  ***************************************************************************
750  */
751 void read_diskstats_stat_work(int curr, char *diskstats)
752 {
753         FILE *fp;
754         char line[256], dev_name[MAX_NAME_LEN];
755         struct io_device *d;
756         struct io_stats sdev;
757         int i;
758         unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
759         unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
760         unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
761         unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
762         unsigned int major, minor;
763
764         if ((fp = fopen(diskstats, "r")) == NULL)
765                 return;
766
767         while (fgets(line, sizeof(line), fp) != NULL) {
768
769                 memset(&sdev, 0, sizeof(struct io_stats));
770
771                 /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq dcio dcmerge dcsect dcuse flio fltm */
772                 i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u %lu %lu %lu %u %lu %u",
773                            &major, &minor, dev_name,
774                            &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
775                            &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
776                            &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
777                            &fl_ios, &fl_ticks);
778
779                 if (i >= 14) {
780                         sdev.rd_ios     = rd_ios;
781                         sdev.rd_merges  = rd_merges_or_rd_sec;
782                         sdev.rd_sectors = rd_sec_or_wr_ios;
783                         sdev.rd_ticks   = (unsigned int) rd_ticks_or_wr_sec;
784                         sdev.wr_ios     = wr_ios;
785                         sdev.wr_merges  = wr_merges;
786                         sdev.wr_sectors = wr_sec;
787                         sdev.wr_ticks   = wr_ticks;
788                         sdev.ios_pgr    = ios_pgr;
789                         sdev.tot_ticks  = tot_ticks;
790                         sdev.rq_ticks   = rq_ticks;
791
792                         if (i >= 18) {
793                                 /* Discard I/O */
794                                 sdev.dc_ios     = dc_ios;
795                                 sdev.dc_merges  = dc_merges;
796                                 sdev.dc_sectors = dc_sec;
797                                 sdev.dc_ticks   = dc_ticks;
798                         }
799
800                         if (i >= 20) {
801                                 /* Flush I/O */
802                                 sdev.fl_ios     = fl_ios;
803                                 sdev.fl_ticks   = fl_ticks;
804                         }
805                 }
806                 else if (i == 7) {
807                         /* Partition without extended statistics */
808                         if (DISPLAY_EXTENDED(flags))
809                                 continue;
810
811                         sdev.rd_ios     = rd_ios;
812                         sdev.rd_sectors = rd_merges_or_rd_sec;
813                         sdev.wr_ios     = rd_sec_or_wr_ios;
814                         sdev.wr_sectors = rd_ticks_or_wr_sec;
815                 }
816                 else
817                         /* Unknown entry: Ignore it */
818                         continue;
819
820                 d = add_list_device(&dev_list, dev_name, 0);
821                 if (d != NULL) {
822                         *d->dev_stats[curr] = sdev;
823                         d->major = major;
824                         d->minor = minor;
825                 }
826         }
827         fclose(fp);
828 }
829
830 /*
831  ***************************************************************************
832  * Read stats from /proc/diskstats or an alternate diskstats file.
833  * Only used when "-p ALL" has been entered on the command line.
834  *
835  * IN:
836  * @curr        Index in array for current sample statistics.
837  ***************************************************************************
838  */
839 void read_diskstats_stat(int curr)
840 {
841         char diskstats[MAX_PF_NAME];
842
843         if (!alt_dir[0] || USE_ALL_DIR(flags)) {
844                 /* Read stats from /proc/diskstats */
845                 read_diskstats_stat_work(curr, DISKSTATS);
846         }
847
848         if (alt_dir[0]) {
849                 snprintf(diskstats, sizeof(diskstats), "%s/%s", alt_dir, __DISKSTATS);
850                 diskstats[sizeof(diskstats) - 1] = '\0';
851                 /* Read stats from an alternate diskstats file */
852                 read_diskstats_stat_work(curr, diskstats);
853         }
854 }
855
856 /*
857  ***************************************************************************
858  * Add current device statistics to corresponding group.
859  *
860  * IN:
861  * @curr        Index in array for current sample statistics.
862  * @iodev_nr            Number of devices and partitions.
863  ***************************************************************************
864  */
865 void compute_device_groups_stats(int curr, struct io_device *d, struct io_device *g)
866 {
867         if (!DISPLAY_UNFILTERED(flags)) {
868                 if (!d->dev_stats[curr]->rd_ios &&
869                     !d->dev_stats[curr]->wr_ios &&
870                     !d->dev_stats[curr]->dc_ios &&
871                     !d->dev_stats[curr]->fl_ios)
872                         return;
873         }
874
875         g->dev_stats[curr]->rd_ios     += d->dev_stats[curr]->rd_ios;
876         g->dev_stats[curr]->rd_merges  += d->dev_stats[curr]->rd_merges;
877         g->dev_stats[curr]->rd_sectors += d->dev_stats[curr]->rd_sectors;
878         g->dev_stats[curr]->rd_ticks   += d->dev_stats[curr]->rd_ticks;
879         g->dev_stats[curr]->wr_ios     += d->dev_stats[curr]->wr_ios;
880         g->dev_stats[curr]->wr_merges  += d->dev_stats[curr]->wr_merges;
881         g->dev_stats[curr]->wr_sectors += d->dev_stats[curr]->wr_sectors;
882         g->dev_stats[curr]->wr_ticks   += d->dev_stats[curr]->wr_ticks;
883         g->dev_stats[curr]->dc_ios     += d->dev_stats[curr]->dc_ios;
884         g->dev_stats[curr]->dc_merges  += d->dev_stats[curr]->dc_merges;
885         g->dev_stats[curr]->dc_sectors += d->dev_stats[curr]->dc_sectors;
886         g->dev_stats[curr]->dc_ticks   += d->dev_stats[curr]->dc_ticks;
887         g->dev_stats[curr]->fl_ios     += d->dev_stats[curr]->fl_ios;
888         g->dev_stats[curr]->fl_ticks   += d->dev_stats[curr]->fl_ticks;
889         g->dev_stats[curr]->ios_pgr    += d->dev_stats[curr]->ios_pgr;
890         g->dev_stats[curr]->tot_ticks  += d->dev_stats[curr]->tot_ticks;
891         g->dev_stats[curr]->rq_ticks   += d->dev_stats[curr]->rq_ticks;
892 }
893
894 /*
895  ***************************************************************************
896  * Write current sample's timestamp, either in plain or JSON format.
897  *
898  * IN:
899  * @tab         Number of tabs to print.
900  * @rectime     Current date and time.
901  ***************************************************************************
902  */
903 void write_sample_timestamp(int tab, struct tm *rectime)
904 {
905         if (DISPLAY_ISO(flags)) {
906                 strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime);
907         }
908         else {
909                 strftime(timestamp, sizeof(timestamp), "%x %X", rectime);
910         }
911         if (DISPLAY_JSON_OUTPUT(flags)) {
912                 xprintf(tab, "\"timestamp\": \"%s\",", timestamp);
913         }
914         else {
915                 printf("%s\n", timestamp);
916         }
917 }
918
919 /*
920  ***************************************************************************
921  * Display CPU utilization in plain format.
922  *
923  * IN:
924  * @curr        Index in array for current sample statistics.
925  * @deltot_jiffies
926  *              Number of jiffies spent on the interval by all processors.
927  ***************************************************************************
928  */
929 void write_plain_cpu_stat(int curr, unsigned long long deltot_jiffies)
930 {
931         printf("avg-cpu:  %%user   %%nice %%system %%iowait  %%steal   %%idle\n");
932
933         printf("       ");
934         cprintf_pc(DISPLAY_UNIT(flags), 6, 7, 2,
935                    ll_sp_value(st_cpu[!curr]->cpu_user, st_cpu[curr]->cpu_user, deltot_jiffies),
936                    ll_sp_value(st_cpu[!curr]->cpu_nice, st_cpu[curr]->cpu_nice, deltot_jiffies),
937                    /*
938                     * Time spent in system mode also includes time spent servicing
939                     * hard and soft interrupts.
940                     */
941                    ll_sp_value(st_cpu[!curr]->cpu_sys + st_cpu[!curr]->cpu_softirq +
942                                st_cpu[!curr]->cpu_hardirq,
943                                st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq +
944                                st_cpu[curr]->cpu_hardirq, deltot_jiffies),
945                    ll_sp_value(st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, deltot_jiffies),
946                    ll_sp_value(st_cpu[!curr]->cpu_steal, st_cpu[curr]->cpu_steal, deltot_jiffies),
947                    (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
948                    0.0 :
949                    ll_sp_value(st_cpu[!curr]->cpu_idle, st_cpu[curr]->cpu_idle, deltot_jiffies));
950
951         printf("\n\n");
952 }
953
954 /*
955  ***************************************************************************
956  * Display CPU utilization in JSON format.
957  *
958  * IN:
959  * @tab         Number of tabs to print.
960  * @curr        Index in array for current sample statistics.
961  * @deltot_jiffies
962  *              Number of jiffies spent on the interval by all processors.
963  ***************************************************************************
964  */
965 void write_json_cpu_stat(int tab, int curr, unsigned long long deltot_jiffies)
966 {
967         xprintf0(tab, "\"avg-cpu\":  {\"user\": %.2f, \"nice\": %.2f, \"system\": %.2f,"
968                       " \"iowait\": %.2f, \"steal\": %.2f, \"idle\": %.2f}",
969                  ll_sp_value(st_cpu[!curr]->cpu_user, st_cpu[curr]->cpu_user, deltot_jiffies),
970                  ll_sp_value(st_cpu[!curr]->cpu_nice, st_cpu[curr]->cpu_nice, deltot_jiffies),
971                  /*
972                   * Time spent in system mode also includes time spent servicing
973                   * hard and soft interrupts.
974                   */
975                  ll_sp_value(st_cpu[!curr]->cpu_sys + st_cpu[!curr]->cpu_softirq +
976                              st_cpu[!curr]->cpu_hardirq,
977                              st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq +
978                              st_cpu[curr]->cpu_hardirq, deltot_jiffies),
979                  ll_sp_value(st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, deltot_jiffies),
980                  ll_sp_value(st_cpu[!curr]->cpu_steal, st_cpu[curr]->cpu_steal, deltot_jiffies),
981                  (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
982                  0.0 :
983                  ll_sp_value(st_cpu[!curr]->cpu_idle, st_cpu[curr]->cpu_idle, deltot_jiffies));
984 }
985
986 /*
987  ***************************************************************************
988  * Display CPU utilization in plain or JSON format.
989  *
990  * IN:
991  * @curr        Index in array for current sample statistics.
992  * @tab         Number of tabs to print (JSON format only).
993  ***************************************************************************
994  */
995 void write_cpu_stat(int curr, int tab)
996 {
997         unsigned long long deltot_jiffies;
998
999         /* Total number of jiffies spent on the interval */
1000         deltot_jiffies = get_interval(tot_jiffies[!curr], tot_jiffies[curr]);
1001
1002 #ifdef DEBUG
1003                 if (DISPLAY_DEBUG(flags)) {
1004                         /* Debug output */
1005                         fprintf(stderr, "deltot_jiffies=%llu st_cpu[curr]{ cpu_user=%llu cpu_nice=%llu "
1006                                         "cpu_sys=%llu cpu_idle=%llu cpu_iowait=%llu cpu_steal=%llu "
1007                                         "cpu_hardirq=%llu cpu_softirq=%llu cpu_guest=%llu "
1008                                         "cpu_guest_nice=%llu }\n",
1009                                 deltot_jiffies,
1010                                 st_cpu[curr]->cpu_user,
1011                                 st_cpu[curr]->cpu_nice,
1012                                 st_cpu[curr]->cpu_sys,
1013                                 st_cpu[curr]->cpu_idle,
1014                                 st_cpu[curr]->cpu_iowait,
1015                                 st_cpu[curr]->cpu_steal,
1016                                 st_cpu[curr]->cpu_hardirq,
1017                                 st_cpu[curr]->cpu_softirq,
1018                                 st_cpu[curr]->cpu_guest,
1019                                 st_cpu[curr]->cpu_guest_nice);
1020                 }
1021 #endif
1022
1023         if (DISPLAY_JSON_OUTPUT(flags)) {
1024                 write_json_cpu_stat(tab, curr, deltot_jiffies);
1025         }
1026         else {
1027                 write_plain_cpu_stat(curr, deltot_jiffies);
1028         }
1029 }
1030
1031 /*
1032  ***************************************************************************
1033  * Display disk stats header in plain or JSON format.
1034  *
1035  * OUT:
1036  * @fctr        Conversion factor.
1037  * @tab         Number of tabs to print (JSON format only).
1038  * @hpart       Indicate which part of the report should be displayed in
1039  *              human mode. A value of 0 indicates that output should not be
1040  *              broken in several parts.
1041  ***************************************************************************
1042  */
1043 void write_disk_stat_header(int *fctr, int *tab, int hpart)
1044 {
1045         char *units, *spc;
1046
1047         if (DISPLAY_KILOBYTES(flags)) {
1048                 *fctr = 2;
1049                 units = "kB";
1050                 spc = " ";
1051         }
1052         else if (DISPLAY_MEGABYTES(flags)) {
1053                 *fctr = 2048;
1054                 units = "MB";
1055                 spc = " ";
1056         }
1057         else if (DISPLAY_EXTENDED(flags)) {
1058                 units = "sec";
1059                 spc = "";
1060         }
1061         else {
1062                 units = "Blk";
1063                 spc = "";
1064         }
1065
1066         if (DISPLAY_JSON_OUTPUT(flags)) {
1067                 xprintf((*tab)++, "\"disk\": [");
1068                 return;
1069         }
1070
1071         if (!DISPLAY_PRETTY(flags)) {
1072                 printf("Device       ");
1073         }
1074         if (DISPLAY_EXTENDED(flags)) {
1075                 /* Extended stats */
1076                 if (DISPLAY_SHORT_OUTPUT(flags)) {
1077                         printf("      tps     %s%s/s    rqm/s   await  areq-sz  aqu-sz  %%util",
1078                                spc, units);
1079                 }
1080                 else {
1081                         if ((hpart == 1) || !hpart) {
1082                                 printf("     r/s    %sr%s/s   rrqm/s  %%rrqm r_await rareq-sz",
1083                                        spc, units);
1084                         }
1085                         if ((hpart == 2) || !hpart) {
1086                                 printf("     w/s    %sw%s/s   wrqm/s  %%wrqm w_await wareq-sz",
1087                                        spc, units);
1088                         }
1089                         if ((hpart == 3) || !hpart) {
1090                                printf("     d/s    %sd%s/s   drqm/s  %%drqm d_await dareq-sz",
1091                                       spc, units);
1092                         }
1093                         if ((hpart == 4) || !hpart) {
1094                                printf("     f/s f_await  aqu-sz  %%util");
1095                         }
1096                 }
1097         }
1098         else {
1099                 /* Basic stats */
1100                 if (DISPLAY_SHORT_OUTPUT(flags)) {
1101                         printf("      tps   %s%s_read/s    %s%s_w+d/s   %s%s_read    %s%s_w+d",
1102                                spc, units, spc, units, spc, units, spc, units);
1103                 }
1104                 else {
1105                         printf("      tps   %s%s_read/s   %s%s_wrtn/s   %s%s_dscd/s   %s%s_read   %s%s_wrtn   %s%s_dscd",
1106                                spc, units, spc, units, spc, units, spc, units, spc, units, spc, units);
1107                 }
1108         }
1109         if (DISPLAY_PRETTY(flags)) {
1110                 printf(" Device");
1111         }
1112         printf("\n");
1113 }
1114
1115 /*
1116  ***************************************************************************
1117  * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1118  * in plain format.
1119  *
1120  * IN:
1121  * @itv         Interval of time.
1122  * @fctr        Conversion factor.
1123  * @hpart       Indicate which part of the report should be displayed in
1124  *              human mode. A value of 0 indicates that output should not be
1125  *              broken in several parts.
1126  * @d           Structure containing device description.
1127  * @ioi         Current sample statistics.
1128  * @ioj         Previous sample statistics.
1129  * @devname     Current device name.
1130  * @xds         Extended stats for current device.
1131  * @xios        Additional extended statistics for current device.
1132  ***************************************************************************
1133  */
1134 void write_plain_ext_stat(unsigned long long itv, int fctr, int hpart,
1135                           struct io_device *d, struct io_stats *ioi,
1136                           struct io_stats *ioj, char *devname, struct ext_disk_stats *xds,
1137                           struct ext_io_stats *xios)
1138 {
1139         int n;
1140
1141         /* If this is a group with no devices, skip it */
1142         if (d->dev_tp == T_GROUP)
1143                 return;
1144
1145         if (!DISPLAY_PRETTY(flags)) {
1146                 cprintf_in(IS_STR, "%-13s", devname, 0);
1147         }
1148
1149         /* Compute number of devices in group */
1150         if (d->dev_tp > T_GROUP) {
1151                 n = d->dev_tp - T_GROUP;
1152         }
1153         else {
1154                 n = 1;
1155         }
1156
1157         if (DISPLAY_SHORT_OUTPUT(flags)) {
1158                 /* tps */
1159                 /* Origin (unmerged) flush operations are counted as writes */
1160                 cprintf_f(NO_UNIT, 1, 8, 2,
1161                           S_VALUE(ioj->rd_ios + ioj->wr_ios + ioj->dc_ios,
1162                                   ioi->rd_ios + ioi->wr_ios + ioi->dc_ios, itv));
1163                 /* kB/s */
1164                 if (!DISPLAY_UNIT(flags)) {
1165                         xios->sectors /= fctr;
1166                 }
1167                 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 1, 9, 2,
1168                           xios->sectors);
1169                 /* rqm/s */
1170                 cprintf_f(NO_UNIT, 1, 8, 2,
1171                           S_VALUE(ioj->rd_merges + ioj->wr_merges + ioj->dc_merges,
1172                                   ioi->rd_merges + ioi->wr_merges + ioi->dc_merges, itv));
1173                 /* await */
1174                 cprintf_f(NO_UNIT, 1, 7, 2,
1175                           xds->await);
1176                 /* areq-sz (in kB, not sectors) */
1177                 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_KILOBYTE : NO_UNIT, 1, 8, 2,
1178                           xds->arqsz / 2);
1179                 /* aqu-sz */
1180                 cprintf_f(NO_UNIT, 1, 7, 2,
1181                           S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1182                 /*
1183                  * %util
1184                  * Again: Ticks in milliseconds.
1185                  */
1186                 cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2, xds->util / 10.0 / (double) n);
1187         }
1188         else {
1189                 if ((hpart == 1) || !hpart) {
1190                         /* r/s */
1191                         cprintf_f(NO_UNIT, 1, 7, 2,
1192                                   S_VALUE(ioj->rd_ios, ioi->rd_ios, itv));
1193                         /* rkB/s */
1194                         if (!DISPLAY_UNIT(flags)) {
1195                                 xios->rsectors /= fctr;
1196                         }
1197                         cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 1, 9, 2,
1198                                   xios->rsectors);
1199                         /* rrqm/s */
1200                         cprintf_f(NO_UNIT, 1, 8, 2,
1201                                   S_VALUE(ioj->rd_merges, ioi->rd_merges, itv));
1202                         /* %rrqm */
1203                         cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2,
1204                                    xios->rrqm_pc);
1205                         /* r_await */
1206                         cprintf_f(NO_UNIT, 1, 7, 2,
1207                                   xios->r_await);
1208                         /* rareq-sz  (in kB, not sectors) */
1209                         cprintf_f(DISPLAY_UNIT(flags) ? UNIT_KILOBYTE : NO_UNIT, 1, 8, 2,
1210                                   xios->rarqsz / 2);
1211                 }
1212                 if ((hpart == 2) || !hpart) {
1213                         /* w/s */
1214                         cprintf_f(NO_UNIT, 1, 7, 2,
1215                                   S_VALUE(ioj->wr_ios, ioi->wr_ios, itv));
1216                         /* wkB/s */
1217                         if (!DISPLAY_UNIT(flags)) {
1218                                 xios->wsectors /= fctr;
1219                         }
1220                         cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 1, 9, 2,
1221                                   xios->wsectors);
1222                         /* wrqm/s */
1223                         cprintf_f(NO_UNIT, 1, 8, 2,
1224                                   S_VALUE(ioj->wr_merges, ioi->wr_merges, itv));
1225                         /* %wrqm */
1226                         cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2,
1227                                    xios->wrqm_pc);
1228                         /* w_await */
1229                         cprintf_f(NO_UNIT, 1, 7, 2,
1230                                   xios->w_await);
1231                         /* wareq-sz (in kB, not sectors) */
1232                         cprintf_f(DISPLAY_UNIT(flags) ? UNIT_KILOBYTE : NO_UNIT, 1, 8, 2,
1233                                   xios->warqsz / 2);
1234                 }
1235                 if ((hpart == 3) || !hpart) {
1236                         /* d/s */
1237                         cprintf_f(NO_UNIT, 1, 7, 2,
1238                                   S_VALUE(ioj->dc_ios, ioi->dc_ios, itv));
1239                         /* dkB/s */
1240                         if (!DISPLAY_UNIT(flags)) {
1241                                 xios->dsectors /= fctr;
1242                         }
1243                         cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 1, 9, 2,
1244                                   xios->dsectors);
1245                         /* drqm/s */
1246                         cprintf_f(NO_UNIT, 1, 8, 2,
1247                                   S_VALUE(ioj->dc_merges, ioi->dc_merges, itv));
1248                         /* %drqm */
1249                         cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2,
1250                                    xios->drqm_pc);
1251                         /* d_await */
1252                         cprintf_f(NO_UNIT, 1, 7, 2,
1253                                   xios->d_await);
1254                         /* dareq-sz (in kB, not sectors) */
1255                         cprintf_f(DISPLAY_UNIT(flags) ? UNIT_KILOBYTE : NO_UNIT, 1, 8, 2,
1256                                   xios->darqsz / 2);
1257                 }
1258                 if ((hpart == 4) || !hpart) {
1259                         /* f/s */
1260                         cprintf_f(NO_UNIT, 1, 7, 2,
1261                                   S_VALUE(ioj->fl_ios, ioi->fl_ios, itv));
1262                         /* f_await */
1263                         cprintf_f(NO_UNIT, 1, 7, 2,
1264                                   xios->f_await);
1265                         /* aqu-sz */
1266                         cprintf_f(NO_UNIT, 1, 7, 2,
1267                                   S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1268                         /*
1269                          * %util
1270                          * Again: Ticks in milliseconds.
1271                          */
1272                         if (d->dev_tp > T_GROUP) {
1273                                 n = d->dev_tp - T_GROUP;
1274                         }
1275                         else {
1276                                 n = 1;
1277                         }
1278                         cprintf_pc(DISPLAY_UNIT(flags), 1, 6, 2, xds->util / 10.0 / (double) n);
1279                 }
1280         }
1281
1282         if (DISPLAY_PRETTY(flags)) {
1283                 cprintf_in(IS_STR, " %s", devname, 0);
1284         }
1285         printf("\n");
1286 }
1287
1288 /*
1289  ***************************************************************************
1290  * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1291  * in JSON format.
1292  *
1293  * IN:
1294  * @tab         Number of tabs to print.
1295  * @itv         Interval of time.
1296  * @fctr        Conversion factor.
1297  * @d           Structure containing the device description.
1298  * @ioi         Current sample statistics.
1299  * @ioj         Previous sample statistics.
1300  * @devname     Current device name.
1301  * @xds         Extended stats for current device.
1302  * @xios        Additional extended statistics for current device.
1303  ***************************************************************************
1304  */
1305 void write_json_ext_stat(int tab, unsigned long long itv, int fctr,
1306                          struct io_device *d, struct io_stats *ioi,
1307                          struct io_stats *ioj, char *devname, struct ext_disk_stats *xds,
1308                          struct ext_io_stats *xios)
1309 {
1310         int n;
1311         char line[256];
1312
1313         /* If this is a group with no devices, skip it */
1314         if (d->dev_tp == T_GROUP)
1315                 return;
1316
1317         xprintf0(tab,
1318                  "{\"disk_device\": \"%s\", ",
1319                  devname);
1320
1321         if (DISPLAY_SHORT_OUTPUT(flags)) {
1322                 printf("\"tps\": %.2f, \"",
1323                        /* Origin (unmerged) flush operations are counted as writes */
1324                        S_VALUE(ioj->rd_ios + ioj->wr_ios + ioj->dc_ios,
1325                                ioi->rd_ios + ioi->wr_ios + ioi->dc_ios, itv));
1326                 if (DISPLAY_MEGABYTES(flags)) {
1327                         printf("MB/s");
1328                 }
1329                 else if (DISPLAY_KILOBYTES(flags)) {
1330                         printf("kB/s");
1331                 }
1332                 else {
1333                         printf("sec/s");
1334                 }
1335                 printf("\": %.2f, \"rqm/s\": %.2f, \"await\": %.2f, "
1336                        "\"areq-sz\": %.2f, \"aqu-sz\": %.2f, ",
1337                        xios->sectors /= fctr,
1338                        S_VALUE(ioj->rd_merges + ioj->wr_merges + ioj->dc_merges,
1339                                ioi->rd_merges + ioi->wr_merges + ioi->dc_merges, itv),
1340                        xds->await,
1341                        xds->arqsz / 2,
1342                        S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1343         }
1344         else {
1345                 printf("\"r/s\": %.2f, \"w/s\": %.2f, \"d/s\": %.2f, \"f/s\": %.2f, ",
1346                        S_VALUE(ioj->rd_ios, ioi->rd_ios, itv),
1347                        S_VALUE(ioj->wr_ios, ioi->wr_ios, itv),
1348                        S_VALUE(ioj->dc_ios, ioi->dc_ios, itv),
1349                        S_VALUE(ioj->fl_ios, ioi->fl_ios, itv));
1350                 if (DISPLAY_MEGABYTES(flags)) {
1351                         sprintf(line, "\"rMB/s\": %%.2f, \"wMB/s\": %%.2f, \"dMB/s\": %%.2f, ");
1352                 }
1353                 else if (DISPLAY_KILOBYTES(flags)) {
1354                         sprintf(line, "\"rkB/s\": %%.2f, \"wkB/s\": %%.2f, \"dkB/s\": %%.2f, ");
1355                 }
1356                 else {
1357                         sprintf(line, "\"rsec/s\": %%.2f, \"wsec/s\": %%.2f, \"dsec/s\": %%.2f, ");
1358                 }
1359                 printf(line,
1360                        xios->rsectors /= fctr,
1361                        xios->wsectors /= fctr,
1362                        xios->dsectors /= fctr);
1363                 printf("\"rrqm/s\": %.2f, \"wrqm/s\": %.2f, \"drqm/s\": %.2f, "
1364                        "\"rrqm\": %.2f, \"wrqm\": %.2f, \"drqm\": %.2f, "
1365                        "\"r_await\": %.2f, \"w_await\": %.2f, \"d_await\": %.2f, \"f_await\": %.2f, "
1366                        "\"rareq-sz\": %.2f, \"wareq-sz\": %.2f, \"dareq-sz\": %.2f, "
1367                        "\"aqu-sz\": %.2f, ",
1368                        S_VALUE(ioj->rd_merges, ioi->rd_merges, itv),
1369                        S_VALUE(ioj->wr_merges, ioi->wr_merges, itv),
1370                        S_VALUE(ioj->dc_merges, ioi->dc_merges, itv),
1371                        xios->rrqm_pc,
1372                        xios->wrqm_pc,
1373                        xios->drqm_pc,
1374                        xios->r_await,
1375                        xios->w_await,
1376                        xios->d_await,
1377                        xios->f_await,
1378                        xios->rarqsz / 2,
1379                        xios->warqsz / 2,
1380                        xios->darqsz / 2,
1381                        S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1382         }
1383
1384         if (d->dev_tp > T_GROUP) {
1385                 n = d->dev_tp - T_GROUP;
1386         }
1387         else {
1388                 n = 1;
1389         }
1390         printf("\"util\": %.2f}", xds->util / 10.0 / (double) n);
1391 }
1392
1393 /*
1394  ***************************************************************************
1395  * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1396  * in plain or JSON format.
1397  *
1398  * IN:
1399  * @itv         Interval of time.
1400  * @fctr        Conversion factor.
1401  * @hpart       Indicate which part of the report should be displayed in
1402  *              human mode. A value of 0 indicates that output should not be
1403  *              broken in several parts.
1404  * @d           Structure containing device description.
1405  * @ioi         Current sample statistics.
1406  * @ioj         Previous sample statistics.
1407  * @tab         Number of tabs to print (JSON output only).
1408  * @dname       Name to be used for display for current device.
1409  ***************************************************************************
1410  */
1411 void write_ext_stat(unsigned long long itv, int fctr, int hpart,
1412                     struct io_device *d, struct io_stats *ioi,
1413                     struct io_stats *ioj, int tab, char *dname)
1414 {
1415         struct stats_disk sdc, sdp;
1416         struct ext_disk_stats xds;
1417         struct ext_io_stats xios;
1418
1419         memset(&xds, 0, sizeof(struct ext_disk_stats));
1420         memset(&xios, 0, sizeof(struct ext_io_stats));
1421
1422         /*
1423          * Counters overflows are possible, but don't need to be handled in
1424          * a special way: The difference is still properly calculated if the
1425          * result is of the same type as the two values.
1426          * Exception is field rq_ticks which is incremented by the number of
1427          * I/O in progress times the number of milliseconds spent doing I/O.
1428          * But the number of I/O in progress (field ios_pgr) happens to be
1429          * sometimes negative...
1430          */
1431
1432         if ((hpart == 4) || !hpart || DISPLAY_SHORT_OUTPUT(flags)) {
1433                 /* Origin (unmerged) flush operations are counted as writes */
1434                 sdc.nr_ios    = ioi->rd_ios + ioi->wr_ios + ioi->dc_ios;
1435                 sdp.nr_ios    = ioj->rd_ios + ioj->wr_ios + ioj->dc_ios;
1436
1437                 sdc.tot_ticks = ioi->tot_ticks;
1438                 sdp.tot_ticks = ioj->tot_ticks;
1439
1440                 sdc.rd_ticks  = ioi->rd_ticks;
1441                 sdp.rd_ticks  = ioj->rd_ticks;
1442                 sdc.wr_ticks  = ioi->wr_ticks;
1443                 sdp.wr_ticks  = ioj->wr_ticks;
1444                 sdc.dc_ticks  = ioi->dc_ticks;
1445                 sdp.dc_ticks  = ioj->dc_ticks;
1446
1447                 sdc.rd_sect   = ioi->rd_sectors;
1448                 sdp.rd_sect   = ioj->rd_sectors;
1449                 sdc.wr_sect   = ioi->wr_sectors;
1450                 sdp.wr_sect   = ioj->wr_sectors;
1451                 sdc.dc_sect   = ioi->dc_sectors;
1452                 sdp.dc_sect   = ioj->dc_sectors;
1453
1454                 compute_ext_disk_stats(&sdc, &sdp, itv, &xds);
1455         }
1456
1457         /* rkB/s  wkB/s dkB/s */
1458         xios.rsectors = S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv);
1459         xios.wsectors = S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv);
1460         xios.dsectors = S_VALUE(ioj->dc_sectors, ioi->dc_sectors, itv);
1461
1462         if (DISPLAY_SHORT_OUTPUT(flags)) {
1463                 xios.sectors  = xios.rsectors + xios.wsectors + xios.dsectors;
1464         }
1465         else {
1466                 if ((hpart == 1) || !hpart) {
1467                         /* %rrqm */
1468                         xios.rrqm_pc = (ioi->rd_merges - ioj->rd_merges) + (ioi->rd_ios - ioj->rd_ios) ?
1469                                        (double) ((ioi->rd_merges - ioj->rd_merges)) /
1470                                        ((ioi->rd_merges - ioj->rd_merges) + (ioi->rd_ios - ioj->rd_ios)) * 100 :
1471                                        0.0;
1472                         /* r_await */
1473                         xios.r_await = (ioi->rd_ios - ioj->rd_ios) ?
1474                                        (ioi->rd_ticks - ioj->rd_ticks) /
1475                                        ((double) (ioi->rd_ios - ioj->rd_ios)) : 0.0;
1476                         /* rareq-sz (still in sectors, not kB) */
1477                         xios.rarqsz = (ioi->rd_ios - ioj->rd_ios) ?
1478                                       (ioi->rd_sectors - ioj->rd_sectors) / ((double) (ioi->rd_ios - ioj->rd_ios)) :
1479                                       0.0;
1480                 }
1481                 if ((hpart == 2) || !hpart) {
1482                         /* %wrqm */
1483                         xios.wrqm_pc = (ioi->wr_merges - ioj->wr_merges) + (ioi->wr_ios - ioj->wr_ios) ?
1484                                        (double) ((ioi->wr_merges - ioj->wr_merges)) /
1485                                        ((ioi->wr_merges - ioj->wr_merges) + (ioi->wr_ios - ioj->wr_ios)) * 100 :
1486                                        0.0;
1487                         /* w_await */
1488                         xios.w_await = (ioi->wr_ios - ioj->wr_ios) ?
1489                                        (ioi->wr_ticks - ioj->wr_ticks) /
1490                                        ((double) (ioi->wr_ios - ioj->wr_ios)) : 0.0;
1491                         /* wareq-sz (still in sectors, not kB) */
1492                         xios.warqsz = (ioi->wr_ios - ioj->wr_ios) ?
1493                                       (ioi->wr_sectors - ioj->wr_sectors) / ((double) (ioi->wr_ios - ioj->wr_ios)) :
1494                                       0.0;
1495                 }
1496                 if ((hpart == 3) || !hpart) {
1497                         /* %drqm */
1498                         xios.drqm_pc = (ioi->dc_merges - ioj->dc_merges) + (ioi->dc_ios - ioj->dc_ios) ?
1499                                        (double) ((ioi->dc_merges - ioj->dc_merges)) /
1500                                        ((ioi->dc_merges - ioj->dc_merges) + (ioi->dc_ios - ioj->dc_ios)) * 100 :
1501                                        0.0;
1502                         /* d_await */
1503                         xios.d_await = (ioi->dc_ios - ioj->dc_ios) ?
1504                                        (ioi->dc_ticks - ioj->dc_ticks) /
1505                                        ((double) (ioi->dc_ios - ioj->dc_ios)) : 0.0;
1506                         /* dareq-sz (still in sectors, not kB) */
1507                         xios.darqsz = (ioi->dc_ios - ioj->dc_ios) ?
1508                                       (ioi->dc_sectors - ioj->dc_sectors) / ((double) (ioi->dc_ios - ioj->dc_ios)) :
1509                                       0.0;
1510                 }
1511                 if ((hpart == 4) || !hpart) {
1512                         /* f_await */
1513                         xios.f_await = (ioi->fl_ios - ioj->fl_ios) ?
1514                                        (ioi->fl_ticks - ioj->fl_ticks) /
1515                                        ((double) (ioi->fl_ios - ioj->fl_ios)) : 0.0;
1516                 }
1517         }
1518
1519         if (DISPLAY_JSON_OUTPUT(flags)) {
1520                 write_json_ext_stat(tab, itv, fctr, d, ioi, ioj, dname, &xds, &xios);
1521         }
1522         else {
1523                 write_plain_ext_stat(itv, fctr, hpart, d, ioi, ioj, dname, &xds, &xios);
1524         }
1525 }
1526
1527 /*
1528  ***************************************************************************
1529  * Write basic stats, read from /proc/diskstats or from sysfs, in plain
1530  * format.
1531  *
1532  * IN:
1533  * @itv         Interval of time.
1534  * @fctr        Conversion factor.
1535  * @ioi         Current sample statistics.
1536  * @ioj         Previous sample statistics.
1537  * @devname     Current device name.
1538  * @rd_sec      Number of sectors read.
1539  * @wr_sec      Number of sectors written.
1540  * @dc_sec      Number of sectors discarded.
1541  ***************************************************************************
1542  */
1543 void write_plain_basic_stat(unsigned long long itv, int fctr,
1544                             struct io_stats *ioi, struct io_stats *ioj,
1545                             char *devname, unsigned long long rd_sec,
1546                             unsigned long long wr_sec, unsigned long long dc_sec)
1547 {
1548         double rsectors, wsectors, dsectors;
1549
1550         if (!DISPLAY_PRETTY(flags)) {
1551                 cprintf_in(IS_STR, "%-13s", devname, 0);
1552         }
1553
1554         rsectors = S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv);
1555         wsectors = S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv);
1556         dsectors = S_VALUE(ioj->dc_sectors, ioi->dc_sectors, itv);
1557         if (!DISPLAY_UNIT(flags)) {
1558                 rsectors /= fctr;
1559                 wsectors /= fctr;
1560                 dsectors /= fctr;
1561         }
1562
1563         /* tps */
1564         cprintf_f(NO_UNIT, 1, 8, 2,
1565                   /* Origin (unmerged) flush operations are counted as writes */
1566                   S_VALUE(ioj->rd_ios + ioj->wr_ios + ioj->dc_ios,
1567                           ioi->rd_ios + ioi->wr_ios + ioi->dc_ios, itv));
1568
1569         if (DISPLAY_SHORT_OUTPUT(flags)) {
1570                 /* kB_read/s kB_w+d/s */
1571                 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 2, 12, 2,
1572                           rsectors, wsectors + dsectors);
1573                 /* kB_read kB_w+d */
1574                 cprintf_u64(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 2, 10,
1575                             DISPLAY_UNIT(flags) ? (unsigned long long) rd_sec
1576                                                 : (unsigned long long) rd_sec / fctr,
1577                             DISPLAY_UNIT(flags) ? (unsigned long long) wr_sec + dc_sec
1578                                                 : (unsigned long long) (wr_sec + dc_sec) / fctr);
1579         }
1580         else {
1581                 /* kB_read/s kB_wrtn/s kB_dscd/s */
1582                 cprintf_f(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 3, 12, 2,
1583                           rsectors, wsectors, dsectors);
1584                 /* kB_read kB_wrtn kB_dscd */
1585                 cprintf_u64(DISPLAY_UNIT(flags) ? UNIT_SECTOR : NO_UNIT, 3, 10,
1586                             DISPLAY_UNIT(flags) ? (unsigned long long) rd_sec
1587                                                 : (unsigned long long) rd_sec / fctr,
1588                             DISPLAY_UNIT(flags) ? (unsigned long long) wr_sec
1589                                                 : (unsigned long long) wr_sec / fctr,
1590                             DISPLAY_UNIT(flags) ? (unsigned long long) dc_sec
1591                                                 : (unsigned long long) dc_sec / fctr);
1592         }
1593
1594         if (DISPLAY_PRETTY(flags)) {
1595                 cprintf_in(IS_STR, " %s", devname, 0);
1596         }
1597         printf("\n");
1598 }
1599
1600 /*
1601  ***************************************************************************
1602  * Write basic stats, read from /proc/diskstats or from sysfs, in JSON
1603  * format.
1604  *
1605  * IN:
1606  * @tab         Number of tabs to print.
1607  * @itv         Interval of time.
1608  * @fctr        Conversion factor.
1609  * @ioi         Current sample statistics.
1610  * @ioj         Previous sample statistics.
1611  * @devname     Current device name.
1612  * @rd_sec      Number of sectors read.
1613  * @wr_sec      Number of sectors written.
1614  ***************************************************************************
1615  */
1616 void write_json_basic_stat(int tab, unsigned long long itv, int fctr,
1617                            struct io_stats *ioi, struct io_stats *ioj,
1618                            char *devname, unsigned long long rd_sec,
1619                            unsigned long long wr_sec, unsigned long long dc_sec)
1620 {
1621         char line[256];
1622
1623         xprintf0(tab,
1624                  "{\"disk_device\": \"%s\", \"tps\": %.2f, ",
1625                  devname,
1626                  /* Origin (unmerged) flush operations are counted as writes */
1627                  S_VALUE(ioj->rd_ios + ioj->wr_ios + ioj->dc_ios,
1628                          ioi->rd_ios + ioi->wr_ios + ioi->dc_ios, itv));
1629         if (DISPLAY_KILOBYTES(flags)) {
1630                 sprintf(line, "\"kB_read/s\": %%.2f, \"kB_wrtn/s\": %%.2f, \"kB_dscd/s\": %%.2f, "
1631                         "\"kB_read\": %%llu, \"kB_wrtn\": %%llu, \"kB_dscd\": %%llu}");
1632         }
1633         else if (DISPLAY_MEGABYTES(flags)) {
1634                 sprintf(line, "\"MB_read/s\": %%.2f, \"MB_wrtn/s\": %%.2f, \"MB_dscd/s\": %%.2f, "
1635                         "\"MB_read\": %%llu, \"MB_wrtn\": %%llu, \"MB_dscd\": %%llu}");
1636         }
1637         else {
1638                 sprintf(line, "\"Blk_read/s\": %%.2f, \"Blk_wrtn/s\": %%.2f, \"Blk_dscd/s\": %%.2f, "
1639                         "\"Blk_read\": %%llu, \"Blk_wrtn\": %%llu, \"Blk_dscd\": %%llu}");
1640         }
1641         printf(line,
1642                S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1643                S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,
1644                S_VALUE(ioj->dc_sectors, ioi->dc_sectors, itv) / fctr,
1645                (unsigned long long) rd_sec / fctr,
1646                (unsigned long long) wr_sec / fctr,
1647                (unsigned long long) dc_sec / fctr);
1648 }
1649
1650 /*
1651  ***************************************************************************
1652  * Write basic stats, read from /proc/diskstats or from sysfs, in plain or
1653  * JSON format.
1654  *
1655  * IN:
1656  * @itv         Interval of time.
1657  * @fctr        Conversion factor.
1658  * @d           Structure containing device description.
1659  * @ioi         Current sample statistics.
1660  * @ioj         Previous sample statistics.
1661  * @tab         Number of tabs to print (JSON format only).
1662  * @dname       Name to be used for display for current device.
1663  ***************************************************************************
1664  */
1665 void write_basic_stat(unsigned long long itv, int fctr,
1666                       struct io_device *d, struct io_stats *ioi,
1667                       struct io_stats *ioj, int tab, char *dname)
1668 {
1669         unsigned long long rd_sec, wr_sec, dc_sec;
1670
1671         /* Print stats coming from /sys or /proc/diskstats */
1672         rd_sec = ioi->rd_sectors - ioj->rd_sectors;
1673         if ((ioi->rd_sectors < ioj->rd_sectors) && (ioj->rd_sectors <= 0xffffffff)) {
1674                 rd_sec &= 0xffffffff;
1675         }
1676         wr_sec = ioi->wr_sectors - ioj->wr_sectors;
1677         if ((ioi->wr_sectors < ioj->wr_sectors) && (ioj->wr_sectors <= 0xffffffff)) {
1678                 wr_sec &= 0xffffffff;
1679         }
1680         dc_sec = ioi->dc_sectors - ioj->dc_sectors;
1681         if ((ioi->dc_sectors < ioj->dc_sectors) && (ioj->dc_sectors <= 0xffffffff)) {
1682                 dc_sec &= 0xffffffff;
1683         }
1684
1685         if (DISPLAY_JSON_OUTPUT(flags)) {
1686                 write_json_basic_stat(tab, itv, fctr, ioi, ioj, dname,
1687                                       rd_sec, wr_sec, dc_sec);
1688         }
1689         else {
1690                 write_plain_basic_stat(itv, fctr, ioi, ioj, dname,
1691                                        rd_sec, wr_sec, dc_sec);
1692         }
1693 }
1694
1695 /*
1696  ***************************************************************************
1697  * Print everything now (stats and uptime).
1698  *
1699  * IN:
1700  * @curr        Index in array for current sample statistics.
1701  * @rectime     Current date and time.
1702  * @skip        TRUE if nothing should be displayed (option -y). We must
1703  *              go through write_stats() anyway to compute groups statistics.
1704  ***************************************************************************
1705  */
1706 void write_stats(int curr, struct tm *rectime, int skip)
1707 {
1708         int h, hl = 0, hh = 0, fctr = 1, tab = 4, next = FALSE;
1709         unsigned long long itv;
1710         struct io_device *d, *dtmp, *g = NULL, *dnext = NULL;
1711         char *dev_name;
1712
1713         /* Test stdout */
1714         TEST_STDOUT(STDOUT_FILENO);
1715
1716         if (DISPLAY_JSON_OUTPUT(flags) && !skip) {
1717                 xprintf(tab++, "{");
1718         }
1719
1720         /* Print time stamp */
1721         if (DISPLAY_TIMESTAMP(flags) && !skip) {
1722                 write_sample_timestamp(tab, rectime);
1723 #ifdef DEBUG
1724                 if (DISPLAY_DEBUG(flags)) {
1725                         fprintf(stderr, "%s\n", timestamp);
1726                 }
1727 #endif
1728         }
1729
1730         if (DISPLAY_CPU(flags) && !skip) {
1731                 /* Display CPU utilization */
1732                 write_cpu_stat(curr, tab);
1733
1734                 if (DISPLAY_JSON_OUTPUT(flags)) {
1735                         if (DISPLAY_DISK(flags)) {
1736                                 printf(",");
1737                         }
1738                         printf("\n");
1739                 }
1740         }
1741
1742         /* Calculate time interval in 1/100th of a second */
1743         itv = get_interval(uptime_cs[!curr], uptime_cs[curr]);
1744
1745         if (DISPLAY_DISK(flags)) {
1746                 struct io_stats *ioi, *ioj, iozero;
1747
1748                 memset(&iozero, 0, sizeof(struct io_stats));
1749
1750                 if (DISPLAY_PRETTY(flags) &&
1751                     DISPLAY_EXTENDED(flags) &&
1752                     !DISPLAY_SHORT_OUTPUT(flags) &&
1753                     !DISPLAY_JSON_OUTPUT(flags)) {
1754                         hl = 1; hh = 4;
1755                 }
1756
1757                 for (h = hl; h <= hh; h++) {
1758
1759                         if (!skip) {
1760                                 /* Display disk stats header */
1761                                 write_disk_stat_header(&fctr, &tab, h);
1762                         }
1763
1764                         for (d = dev_list; ; d = dnext) {
1765
1766                                 if (d == NULL) {
1767                                         if (g == NULL)
1768                                                 /* No group processing in progress */
1769                                                 break;
1770                                         /* Display last group before exit */
1771                                         dnext = NULL;
1772                                         d = g;
1773                                         g = NULL;
1774                                 }
1775                                 else {
1776                                         dnext = d->next;
1777
1778                                         if (d->dev_tp >= T_GROUP) {
1779                                                 /*
1780                                                  * This is a new group: Save group position
1781                                                  * and display previous one.
1782                                                  */
1783                                                 if (g != NULL) {
1784                                                         dtmp = g;
1785                                                         g = d;
1786                                                         d = dtmp;
1787                                                         memset(g->dev_stats[curr], 0, sizeof(struct io_stats));
1788                                                 }
1789                                                 else {
1790                                                         g = d;
1791                                                         memset(g->dev_stats[curr], 0, sizeof(struct io_stats));
1792                                                         continue;       /* No previous group to display */
1793                                                 }
1794                                         }
1795                                 }
1796
1797                                 if (!d->exist && (d->dev_tp < T_GROUP))
1798                                         /* Current device is non existent (e.g. it has been unregistered from the system */
1799                                         continue;
1800
1801                                 if ((g != NULL) && (h == hl) && (d->dev_tp < T_GROUP)) {
1802                                         /* We are within a group: Increment number of disks in the group */
1803                                         (g->dev_tp)++;
1804                                         /* Add current device stats to group */
1805                                         compute_device_groups_stats(curr, d, g);
1806                                 }
1807
1808                                 if (DISPLAY_GROUP_TOTAL_ONLY(flags) && (g != NULL) && (d->dev_tp < T_GROUP))
1809                                         continue;
1810
1811                                 ioi = d->dev_stats[curr];
1812                                 ioj = d->dev_stats[!curr];
1813                                 /* Origin (unmerged) flush operations are counted as writes */
1814                                 if (!DISPLAY_UNFILTERED(flags)) {
1815                                         if (!ioi->rd_ios && !ioi->wr_ios && !ioi->dc_ios && !ioi->fl_ios)
1816                                                 continue;
1817                                 }
1818
1819                                 if (DISPLAY_ZERO_OMIT(flags)) {
1820                                         if ((ioi->rd_ios == ioj->rd_ios) &&
1821                                             (ioi->wr_ios == ioj->wr_ios) &&
1822                                             (ioi->dc_ios == ioj->dc_ios) &&
1823                                             (ioi->fl_ios == ioj->fl_ios))
1824                                                 /* No activity: Ignore it */
1825                                                 continue;
1826                                 }
1827
1828                                 /* Try to detect if device has been removed then inserted again */
1829                                 if (((ioi->rd_ios + ioi->wr_ios + ioi->dc_ios + ioi->fl_ios) <
1830                                         (ioj->rd_ios + ioj->wr_ios + ioj->dc_ios + ioj->fl_ios)) &&
1831                                     (!ioj->rd_sectors || (ioi->rd_sectors < ioj->rd_sectors)) &&
1832                                     (!ioj->wr_sectors || (ioi->wr_sectors < ioj->wr_sectors)) &&
1833                                     (!ioj->dc_sectors || (ioi->dc_sectors < ioj->dc_sectors))) {
1834                                             ioj = &iozero;
1835                                 }
1836
1837                                 dev_name = get_device_name(d->major, d->minor, NULL, 0,
1838                                                            DISPLAY_DEVMAP_NAME(flags),
1839                                                            DISPLAY_PERSIST_NAME_I(flags),
1840                                                            FALSE, d->name);
1841 #ifdef DEBUG
1842                                 if (DISPLAY_DEBUG(flags)) {
1843                                         /* Debug output */
1844                                         fprintf(stderr,
1845                                                 "name=%s itv=%llu fctr=%d ioi{ rd_sectors=%lu "
1846                                                 "wr_sectors=%lu dc_sectors=%lu "
1847                                                 "rd_ios=%lu rd_merges=%lu rd_ticks=%u "
1848                                                 "wr_ios=%lu wr_merges=%lu wr_ticks=%u "
1849                                                 "dc_ios=%lu dc_merges=%lu dc_ticks=%u "
1850                                                 "fl_ios=%lu fl_ticks=%u "
1851                                                 "ios_pgr=%u tot_ticks=%u "
1852                                                 "rq_ticks=%u }\n",
1853                                                 dev_name,
1854                                                 itv,
1855                                                 fctr,
1856                                                 ioi->rd_sectors,
1857                                                 ioi->wr_sectors,
1858                                                 ioi->dc_sectors,
1859                                                 ioi->rd_ios,
1860                                                 ioi->rd_merges,
1861                                                 ioi->rd_ticks,
1862                                                 ioi->wr_ios,
1863                                                 ioi->wr_merges,
1864                                                 ioi->wr_ticks,
1865                                                 ioi->dc_ios,
1866                                                 ioi->dc_merges,
1867                                                 ioi->dc_ticks,
1868                                                 ioi->fl_ios,
1869                                                 ioi->fl_ticks,
1870                                                 ioi->ios_pgr,
1871                                                 ioi->tot_ticks,
1872                                                 ioi->rq_ticks);
1873                                 }
1874 #endif
1875
1876                                 if (!skip) {
1877                                         if (DISPLAY_JSON_OUTPUT(flags) && next) {
1878                                                 printf(",\n");
1879                                         }
1880                                         next = TRUE;
1881
1882                                         if (DISPLAY_EXTENDED(flags)) {
1883                                                 write_ext_stat(itv, fctr, h, d, ioi, ioj, tab, dev_name);
1884                                         }
1885                                         else {
1886                                                 write_basic_stat(itv, fctr, d, ioi, ioj, tab, dev_name);
1887                                         }
1888                                 }
1889                         }
1890
1891                         if ((h > 0) && (h < hh) && !skip) {
1892                                 printf("\n");
1893                         }
1894                 }
1895                 if (DISPLAY_JSON_OUTPUT(flags) && !skip) {
1896                         printf("\n");
1897                         xprintf(--tab, "]");
1898                 }
1899         }
1900
1901         if (!skip) {
1902                 if (DISPLAY_JSON_OUTPUT(flags)) {
1903                         xprintf0(--tab, "}");
1904                 }
1905                 else {
1906                         printf("\n");
1907                 }
1908         }
1909 }
1910
1911 /*
1912  ***************************************************************************
1913  * Main loop: Read I/O stats from the relevant sources and display them.
1914  *
1915  * IN:
1916  * @count       Number of reports to print.
1917  * @rectime     Current date and time.
1918  ***************************************************************************
1919  */
1920 void rw_io_stat_loop(long int count, struct tm *rectime)
1921 {
1922         int curr = 1;
1923         int skip = 0;
1924
1925         /* Should we skip first report? */
1926         if (DISPLAY_OMIT_SINCE_BOOT(flags) && interval > 0) {
1927                 skip = 1;
1928         }
1929
1930         /* Set a handler for SIGALRM */
1931         memset(&alrm_act, 0, sizeof(alrm_act));
1932         alrm_act.sa_handler = alarm_handler;
1933         sigaction(SIGALRM, &alrm_act, NULL);
1934         alarm(interval);
1935
1936         /* Set a handler for SIGINT */
1937         memset(&int_act, 0, sizeof(int_act));
1938         int_act.sa_handler = int_handler;
1939         sigaction(SIGINT, &int_act, NULL);
1940
1941         do {
1942                 /* Every device is potentially nonexistent */
1943                 set_devices_nonexistent(dev_list);
1944
1945                 /* Read system uptime */
1946                 read_uptime(&(uptime_cs[curr]));
1947
1948                 /* Read stats for CPU "all" */
1949                 read_stat_cpu(st_cpu[curr], 1);
1950
1951                 /*
1952                  * Compute the total number of jiffies spent by all processors.
1953                  * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
1954                  * already include them.
1955                  */
1956                 tot_jiffies[curr] = st_cpu[curr]->cpu_user + st_cpu[curr]->cpu_nice +
1957                                     st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_idle +
1958                                     st_cpu[curr]->cpu_iowait + st_cpu[curr]->cpu_hardirq +
1959                                     st_cpu[curr]->cpu_steal + st_cpu[curr]->cpu_softirq;
1960
1961                 if (DISPLAY_EVERYTHING(flags)) {
1962                         read_diskstats_stat(curr);
1963                 }
1964                 else {
1965                         read_sysfs_dlist_stat(curr);
1966                 }
1967
1968                 /* Get time */
1969                 get_localtime(rectime, 0);
1970
1971                 /* Print results */
1972                 write_stats(curr, rectime, skip);
1973
1974                 if (!skip) {
1975                         if (count > 0) {
1976                                 count--;
1977                         }
1978                 }
1979
1980                 if (count) {
1981                         curr ^= 1;
1982                         __pause();
1983
1984                         if (sigint_caught) {
1985                                 /* SIGINT signal caught => Terminate JSON output properly */
1986                                 count = 0;
1987                         }
1988                         else if (DISPLAY_JSON_OUTPUT(flags) && count && !skip) {
1989                                 printf(",");
1990                         }
1991                         skip = 0;
1992                 }
1993                 printf("\n");
1994         }
1995         while (count);
1996
1997         if (DISPLAY_JSON_OUTPUT(flags)) {
1998                 printf("\t\t\t]\n\t\t}\n\t]\n}}\n");
1999         }
2000 }
2001
2002 /*
2003  ***************************************************************************
2004  * Main entry to the iostat program.
2005  ***************************************************************************
2006  */
2007 int main(int argc, char **argv)
2008 {
2009         int it = 0;
2010         int opt = 1;
2011         int i, report_set = FALSE;
2012         long count = 1;
2013         struct utsname header;
2014         struct tm rectime;
2015         char *t, *persist_devname, *devname;
2016         char group_name[MAX_NAME_LEN];
2017
2018 #ifdef USE_NLS
2019         /* Init National Language Support */
2020         init_nls();
2021 #endif
2022
2023         alt_dir[0] = '\0';
2024
2025         /* Process args... */
2026         while (opt < argc) {
2027
2028                 /* -p option used individually. See below for grouped use */
2029                 if (!strcmp(argv[opt], "-p")) {
2030                         if (argv[++opt] &&
2031                             (strspn(argv[opt], DIGITS) != strlen(argv[opt])) &&
2032                             (strncmp(argv[opt], "-", 1))) {
2033                                 flags |= I_D_UNFILTERED;
2034
2035                                 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2036                                         if (!strcmp(t, K_ALL)) {
2037                                                 flags |= I_D_EVERYTHING;
2038                                         }
2039                                         else {
2040                                                 devname = device_name(t);
2041                                                 if (DISPLAY_PERSIST_NAME_I(flags)) {
2042                                                         /* Get device persistent name */
2043                                                         persist_devname = get_pretty_name_from_persistent(devname);
2044                                                         if (persist_devname != NULL) {
2045                                                                 devname = persist_devname;
2046                                                         }
2047                                                 }
2048                                                 /* Store device name */
2049                                                 add_list_device(&dev_list, devname, T_PART_DEV);
2050                                         }
2051                                 }
2052                                 opt++;
2053                         }
2054                         else {
2055                                 flags |= I_D_EVERYTHING;
2056                         }
2057                 }
2058
2059                 else if (!strcmp(argv[opt], "-g")) {
2060                         if (!argv[++opt]) {
2061                                 usage(argv[0]);
2062                         }
2063                         flags |= I_F_GROUP_DEFINED;
2064
2065                         /*
2066                          * MAX_NAME_LEN - 2: one char for the heading space,
2067                          * and one for the trailing '\0'.
2068                          */
2069                         snprintf(group_name, MAX_NAME_LEN, " %-.*s", MAX_NAME_LEN - 2, argv[opt++]);
2070                         add_list_device(&dev_list, group_name, T_GROUP);
2071                 }
2072
2073                 else if (!strcmp(argv[opt], "--human")) {
2074                         flags |= I_D_UNIT;
2075                         opt++;
2076                 }
2077
2078                 else if (!strcmp(argv[opt], "--pretty")) {
2079                         /* Display an easy-to-read CIFS report */
2080                         flags |= I_D_PRETTY;
2081                         opt++;
2082                 }
2083
2084 #ifdef TEST
2085                 else if (!strncmp(argv[opt], "--getenv", 8)) {
2086                         __env = TRUE;
2087                         opt++;
2088                 }
2089 #endif
2090
2091                 else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2092                         /* Get number of decimal places */
2093                         dplaces_nr = atoi(argv[opt] + 6);
2094                         if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2095                                 usage(argv[0]);
2096                         }
2097                         opt++;
2098                 }
2099
2100                 else if (!strcmp(argv[opt], "-f") || !strcmp(argv[opt], "+f")) {
2101                         if (alt_dir[0] || !argv[opt + 1]) {
2102                                 usage(argv[0]);
2103                         }
2104                         if (argv[opt++][0] == '+') {
2105                                 flags |= I_D_ALL_DIR;
2106                         }
2107                         strncpy(alt_dir, argv[opt++], sizeof(alt_dir));
2108                         alt_dir[sizeof(alt_dir) - 1] = '\0';
2109                         if (!check_dir(alt_dir)) {
2110                                 usage(argv[0]);
2111                         }
2112                 }
2113
2114                 else if (!strcmp(argv[opt], "-j")) {
2115                         if (!argv[++opt]) {
2116                                 usage(argv[0]);
2117                         }
2118                         if (strnlen(argv[opt], sizeof(persistent_name_type)) >= sizeof(persistent_name_type) - 1) {
2119                                 usage(argv[0]);
2120                         }
2121                         strncpy(persistent_name_type, argv[opt], sizeof(persistent_name_type) - 1);
2122                         persistent_name_type[sizeof(persistent_name_type) - 1] = '\0';
2123                         strtolower(persistent_name_type);
2124                         /* Check that this is a valid type of persistent device name */
2125                         if (!get_persistent_type_dir(persistent_name_type)) {
2126                                 fprintf(stderr, _("Invalid type of persistent device name\n"));
2127                                 exit(1);
2128                         }
2129                         /* Persistent names are usually long: Pretty display them */
2130                         flags |= I_D_PERSIST_NAME + I_D_PRETTY;
2131                         opt++;
2132                 }
2133
2134                 else if (!strcmp(argv[opt], "-o")) {
2135                         /* Select output format */
2136                         if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2137                                 flags |= I_D_JSON_OUTPUT;
2138                                 opt++;
2139                         }
2140                         else {
2141                                 usage(argv[0]);
2142                         }
2143                 }
2144
2145 #ifdef DEBUG
2146                 else if (!strcmp(argv[opt], "--debuginfo")) {
2147                         flags |= I_D_DEBUG;
2148                         opt++;
2149                 }
2150 #endif
2151
2152                 else if (!strncmp(argv[opt], "-", 1)) {
2153                         for (i = 1; *(argv[opt] + i); i++) {
2154
2155                                 switch (*(argv[opt] + i)) {
2156
2157                                 case 'c':
2158                                         /* Display cpu usage */
2159                                         flags |= I_D_CPU;
2160                                         report_set = TRUE;
2161                                         break;
2162
2163                                 case 'd':
2164                                         /* Display disk utilization */
2165                                         flags |= I_D_DISK;
2166                                         report_set = TRUE;
2167                                         break;
2168
2169                                 case 'H':
2170                                         /* Display stats only for the groups */
2171                                         flags |= I_D_GROUP_TOTAL_ONLY;
2172                                         break;
2173
2174                                 case 'h':
2175                                         /* Option -h is equivalent to --pretty --human */
2176                                         flags |= I_D_PRETTY + I_D_UNIT;
2177                                         break;
2178
2179                                 case 'k':
2180                                         if (DISPLAY_MEGABYTES(flags)) {
2181                                                 usage(argv[0]);
2182                                         }
2183                                         /* Display stats in kB/s */
2184                                         flags |= I_D_KILOBYTES;
2185                                         break;
2186
2187                                 case 'm':
2188                                         if (DISPLAY_KILOBYTES(flags)) {
2189                                                 usage(argv[0]);
2190                                         }
2191                                         /* Display stats in MB/s */
2192                                         flags |= I_D_MEGABYTES;
2193                                         break;
2194
2195                                 case 'N':
2196                                         /* Display device mapper logical name */
2197                                         flags |= I_D_DEVMAP_NAME;
2198                                         break;
2199
2200                                 case 'p':
2201                                         /* If option -p is grouped then it cannot take an arg */
2202                                         flags |= I_D_EVERYTHING;
2203                                         break;
2204
2205                                 case 's':
2206                                         /* Display short output */
2207                                         flags |= I_D_SHORT_OUTPUT;
2208                                         break;
2209
2210                                 case 't':
2211                                         /* Display timestamp */
2212                                         flags |= I_D_TIMESTAMP;
2213                                         break;
2214
2215                                 case 'x':
2216                                         /* Display extended stats */
2217                                         flags |= I_D_EXTENDED;
2218                                         break;
2219
2220                                 case 'y':
2221                                         /* Don't display stats since system restart */
2222                                         flags |= I_D_OMIT_SINCE_BOOT;
2223                                         break;
2224
2225                                 case 'z':
2226                                         /* Omit output for devices with no activity */
2227                                         flags |= I_D_ZERO_OMIT;
2228                                         break;
2229
2230                                 case 'V':
2231                                         /* Print version number and exit */
2232                                         print_version();
2233                                         break;
2234
2235                                 default:
2236                                         usage(argv[0]);
2237                                 }
2238                         }
2239                         opt++;
2240                 }
2241
2242                 else if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2243                         /*
2244                          * By default iostat doesn't display unused devices.
2245                          * If some devices are explicitly entered on the command line
2246                          * then don't apply this rule any more.
2247                          */
2248                         flags |= I_D_UNFILTERED;
2249
2250                         if (strcmp(argv[opt], K_ALL)) {
2251                                 /* Store device name entered on the command line */
2252                                 devname = device_name(argv[opt++]);
2253                                 if (DISPLAY_PERSIST_NAME_I(flags)) {
2254                                         persist_devname = get_pretty_name_from_persistent(devname);
2255                                         if (persist_devname != NULL) {
2256                                                 devname = persist_devname;
2257                                         }
2258                                 }
2259                                 add_list_device(&dev_list, devname, 0);
2260                         }
2261                         else {
2262                                 flags |= I_D_ALL_DEVICES;
2263                                 opt++;
2264                         }
2265                 }
2266
2267                 else if (!it) {
2268                         interval = atol(argv[opt++]);
2269                         if (interval < 0) {
2270                                 usage(argv[0]);
2271                         }
2272                         count = -1;
2273                         it = 1;
2274                 }
2275
2276                 else if (it > 0) {
2277                         count = atol(argv[opt++]);
2278                         if ((count < 1) || !interval) {
2279                                 usage(argv[0]);
2280                         }
2281                         it = -1;
2282                 }
2283                 else {
2284                         usage(argv[0]);
2285                 }
2286         }
2287
2288         if (!interval) {
2289                 count = 1;
2290         }
2291
2292         /* Init color strings */
2293         init_colors();
2294
2295         /* Default: Display CPU and DISK reports */
2296         if (!report_set) {
2297                 flags |= I_D_CPU + I_D_DISK;
2298         }
2299         /*
2300          * Also display DISK reports if options -p, -x or a device has been entered
2301          * on the command line.
2302          */
2303         if (DISPLAY_EVERYTHING(flags) || DISPLAY_EXTENDED(flags) ||
2304             DISPLAY_UNFILTERED(flags)) {
2305                 flags |= I_D_DISK;
2306         }
2307
2308         if (!DISPLAY_UNFILTERED(flags)) {
2309                 flags |= I_D_ALL_DEVICES;
2310         }
2311         /* Option -H can only be used with option -g */
2312         if (DISPLAY_GROUP_TOTAL_ONLY(flags) && !GROUP_DEFINED(flags)) {
2313                 usage(argv[0]);
2314         }
2315
2316         /* Select disk output unit (kB/s or blocks/s) */
2317         set_disk_output_unit();
2318
2319         if (DISPLAY_JSON_OUTPUT(flags)) {
2320                 /* Use a decimal point to make JSON code compliant with RFC7159 */
2321                 setlocale(LC_NUMERIC, "C");
2322         }
2323
2324         /* Allocate and init stat common counters */
2325         init_stats();
2326
2327         /* How many processors on this machine? */
2328         cpu_nr = get_cpu_nr(~0, FALSE);
2329
2330         get_localtime(&rectime, 0);
2331
2332         /*
2333          * Don't buffer data if redirected to a pipe.
2334          * Note: With musl-c, the behavior of this function is undefined except
2335          * when it is the first operation on the stream.
2336          */
2337         setbuf(stdout, NULL);
2338
2339         /* Get system name, release number and hostname */
2340         __uname(&header);
2341         if (print_gal_header(&rectime, header.sysname, header.release,
2342                              header.nodename, header.machine, cpu_nr,
2343                              DISPLAY_JSON_OUTPUT(flags))) {
2344                 flags |= I_D_ISO;
2345         }
2346         if (!DISPLAY_JSON_OUTPUT(flags)) {
2347                 printf("\n");
2348         }
2349
2350         /* Main loop */
2351         rw_io_stat_loop(count, &rectime);
2352
2353         return 0;
2354 }