]> granicus.if.org Git - sysstat/blob - iostat.c
Cosmetic fixes
[sysstat] / iostat.c
1 /*
2  * iostat: report CPU and I/O statistics
3  * (C) 1998-2016 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 "common.h"
39 #include "ioconf.h"
40 #include "rd_stats.h"
41 #include "count.h"
42
43 #ifdef USE_NLS
44 #include <locale.h>
45 #include <libintl.h>
46 #define _(string) gettext(string)
47 #else
48 #define _(string) (string)
49 #endif
50
51 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
52 char *sccsid(void) { return (SCCSID); }
53
54 struct stats_cpu *st_cpu[2];
55 unsigned long long uptime[2]  = {0, 0};
56 unsigned long long uptime0[2] = {0, 0};
57 struct io_stats *st_iodev[2];
58 struct io_hdr_stats *st_hdr_iodev;
59 struct io_dlist *st_dev_list;
60
61 /* Last group name entered on the command line */
62 char group_name[MAX_NAME_LEN];
63
64 int iodev_nr = 0;       /* Nb of devices and partitions found. Includes nb of device groups */
65 int group_nr = 0;       /* Nb of device groups */
66 int cpu_nr = 0;         /* Nb of processors on the machine */
67 int dlist_idx = 0;      /* Nb of devices entered on the command line */
68 int flags = 0;          /* Flag for common options and system state */
69 unsigned int dm_major;  /* Device-mapper major number */
70
71 long interval = 0;
72 char timestamp[64];
73
74 struct sigaction alrm_act;
75
76 /*
77  ***************************************************************************
78  * Print usage and exit.
79  *
80  * IN:
81  * @progname    Name of sysstat command.
82  ***************************************************************************
83  */
84 void usage(char *progname)
85 {
86         fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
87                 progname);
88 #ifdef DEBUG
89         fprintf(stderr, _("Options are:\n"
90                           "[ -c ] [ -d ] [ -h ] [ -k | -m ] [ -N ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ]\n"
91                           "[ -j { ID | LABEL | PATH | UUID | ... } ] [ -o JSON ]\n"
92                           "[ [ -H ] -g <group_name> ] [ -p [ <device> [,...] | ALL ] ]\n"
93                           "[ <device> [...] | ALL ] [ --debuginfo ]\n"));
94 #else
95         fprintf(stderr, _("Options are:\n"
96                           "[ -c ] [ -d ] [ -h ] [ -k | -m ] [ -N ] [ -t ] [ -V ] [ -x ] [ -y ] [ -z ]\n"
97                           "[ -j { ID | LABEL | PATH | UUID | ... } ] [ -o JSON ]\n"
98                           "[ [ -H ] -g <group_name> ] [ -p [ <device> [,...] | ALL ] ]\n"
99                           "[ <device> [...] | ALL ]\n"));
100 #endif
101         exit(1);
102 }
103
104 /*
105  ***************************************************************************
106  * Set disk output unit. Unit will be kB/s unless POSIXLY_CORRECT
107  * environment variable has been set, in which case the output will be
108  * expressed in blocks/s.
109  ***************************************************************************
110  */
111 void set_disk_output_unit(void)
112 {
113         if (DISPLAY_KILOBYTES(flags) || DISPLAY_MEGABYTES(flags))
114                 return;
115
116         /* Check POSIXLY_CORRECT environment variable */
117         if (getenv(ENV_POSIXLY_CORRECT) == NULL) {
118                 /* Variable not set: Unit is kB/s and not blocks/s */
119                 flags |= I_D_KILOBYTES;
120         }
121 }
122
123 /*
124  ***************************************************************************
125  * SIGALRM signal handler. No need to reset the handler here.
126  *
127  * IN:
128  * @sig Signal number.
129  ***************************************************************************
130  */
131 void alarm_handler(int sig)
132 {
133         alarm(interval);
134 }
135
136 /*
137  ***************************************************************************
138  * Initialize stats common structures.
139  ***************************************************************************
140  */
141 void init_stats(void)
142 {
143         int i;
144
145         /* Allocate structures for CPUs "all" and 0 */
146         for (i = 0; i < 2; i++) {
147                 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * 2)) == NULL) {
148                         perror("malloc");
149                         exit(4);
150                 }
151                 memset(st_cpu[i], 0, STATS_CPU_SIZE * 2);
152         }
153 }
154
155 /*
156  ***************************************************************************
157  * Set every device entry to unregistered status. But don't change status
158  * for group entries (whose status is DISK_GROUP).
159  *
160  * IN:
161  * @iodev_nr            Number of devices and partitions.
162  * @st_hdr_iodev        Pointer on first structure describing a device/partition.
163  ***************************************************************************
164  */
165 void set_entries_unregistered(int iodev_nr, struct io_hdr_stats *st_hdr_iodev)
166 {
167         int i;
168         struct io_hdr_stats *shi = st_hdr_iodev;
169
170         for (i = 0; i < iodev_nr; i++, shi++) {
171                 if (shi->status == DISK_REGISTERED) {
172                         shi->status = DISK_UNREGISTERED;
173                 }
174         }
175 }
176
177 /*
178  ***************************************************************************
179  * Free unregistered entries (mark them as unused).
180  *
181  * IN:
182  * @iodev_nr            Number of devices and partitions.
183  * @st_hdr_iodev        Pointer on first structure describing a device/partition.
184  ***************************************************************************
185  */
186 void free_unregistered_entries(int iodev_nr, struct io_hdr_stats *st_hdr_iodev)
187 {
188         int i;
189         struct io_hdr_stats *shi = st_hdr_iodev;
190
191         for (i = 0; i < iodev_nr; i++, shi++) {
192                 if (shi->status == DISK_UNREGISTERED) {
193                         shi->used = FALSE;
194                 }
195         }
196 }
197
198 /*
199  ***************************************************************************
200  * Allocate and init I/O device structures.
201  *
202  * IN:
203  * @dev_nr      Number of devices and partitions (also including groups
204  *              if option -g has been used).
205  ***************************************************************************
206  */
207 void salloc_device(int dev_nr)
208 {
209         int i;
210
211         for (i = 0; i < 2; i++) {
212                 if ((st_iodev[i] =
213                      (struct io_stats *) malloc(IO_STATS_SIZE * dev_nr)) == NULL) {
214                         perror("malloc");
215                         exit(4);
216                 }
217                 memset(st_iodev[i], 0, IO_STATS_SIZE * dev_nr);
218         }
219
220         if ((st_hdr_iodev =
221              (struct io_hdr_stats *) malloc(IO_HDR_STATS_SIZE * dev_nr)) == NULL) {
222                 perror("malloc");
223                 exit(4);
224         }
225         memset(st_hdr_iodev, 0, IO_HDR_STATS_SIZE * dev_nr);
226 }
227
228 /*
229  ***************************************************************************
230  * Allocate structures for devices entered on the command line.
231  *
232  * IN:
233  * @list_len    Number of arguments on the command line.
234  ***************************************************************************
235  */
236 void salloc_dev_list(int list_len)
237 {
238         if ((st_dev_list = (struct io_dlist *) malloc(IO_DLIST_SIZE * list_len)) == NULL) {
239                 perror("malloc");
240                 exit(4);
241         }
242         memset(st_dev_list, 0, IO_DLIST_SIZE * list_len);
243 }
244
245 /*
246  ***************************************************************************
247  * Free structures used for devices entered on the command line.
248  ***************************************************************************
249  */
250 void sfree_dev_list(void)
251 {
252         free(st_dev_list);
253 }
254
255 /*
256  ***************************************************************************
257  * Look for the device in the device list and store it if not found.
258  *
259  * IN:
260  * @dlist_idx   Length of the device list.
261  * @device_name Name of the device.
262  *
263  * OUT:
264  * @dlist_idx   Length of the device list.
265  *
266  * RETURNS:
267  * Position of the device in the list.
268  ***************************************************************************
269  */
270 int update_dev_list(int *dlist_idx, char *device_name)
271 {
272         int i;
273         struct io_dlist *sdli = st_dev_list;
274
275         for (i = 0; i < *dlist_idx; i++, sdli++) {
276                 if (!strcmp(sdli->dev_name, device_name))
277                         break;
278         }
279
280         if (i == *dlist_idx) {
281                 /*
282                  * Device not found: Store it.
283                  * Group names will be distinguished from real device names
284                  * thanks to their names which begin with a space.
285                  */
286                 (*dlist_idx)++;
287                 strncpy(sdli->dev_name, device_name, MAX_NAME_LEN - 1);
288         }
289
290         return i;
291 }
292
293 /*
294  ***************************************************************************
295  * Allocate and init structures, according to system state.
296  ***************************************************************************
297  */
298 void io_sys_init(void)
299 {
300         /* Allocate and init stat common counters */
301         init_stats();
302
303         /* How many processors on this machine? */
304         cpu_nr = get_cpu_nr(~0, FALSE);
305
306         /* Get number of block devices and partitions in /proc/diskstats */
307         if ((iodev_nr = get_diskstats_dev_nr(CNT_PART, CNT_ALL_DEV)) > 0) {
308                 flags |= I_F_HAS_DISKSTATS;
309                 iodev_nr += NR_DEV_PREALLOC;
310         }
311
312         if (!HAS_DISKSTATS(flags) ||
313             (DISPLAY_PARTITIONS(flags) && !DISPLAY_PART_ALL(flags))) {
314                 /*
315                  * If /proc/diskstats exists but we also want stats for the partitions
316                  * of a particular device, stats will have to be found in /sys. So we
317                  * need to know if /sys is mounted or not, and set flags accordingly.
318                  */
319
320                 /* Get number of block devices (and partitions) in sysfs */
321                 if ((iodev_nr = get_sysfs_dev_nr(DISPLAY_PARTITIONS(flags))) > 0) {
322                         flags |= I_F_HAS_SYSFS;
323                         iodev_nr += NR_DEV_PREALLOC;
324                 }
325                 else {
326                         fprintf(stderr, _("Cannot find disk data\n"));
327                         exit(2);
328                 }
329         }
330
331         /* Also allocate stat structures for "group" devices */
332         iodev_nr += group_nr;
333
334         /*
335          * Allocate structures for number of disks found, but also
336          * for groups of devices if option -g has been entered on the command line.
337          * iodev_nr must be <> 0.
338          */
339         salloc_device(iodev_nr);
340 }
341
342 /*
343  ***************************************************************************
344  * When group stats are to be displayed (option -g entered on the command
345  * line), save devices and group names in the io_hdr_stats structures. This
346  * is normally done later when stats are actually read from /proc or /sys
347  * files (via a call to save_stats() function), but here we want to make
348  * sure that the structures are ordered and that each device belongs to its
349  * proper group.
350  * Note that we can still have an unexpected device that gets attached to a
351  * group as devices can be registered or unregistered dynamically.
352  ***************************************************************************
353  */
354 void presave_device_list(void)
355 {
356         int i;
357         struct io_hdr_stats *shi = st_hdr_iodev;
358         struct io_dlist *sdli = st_dev_list;
359
360         if (dlist_idx>0) {
361                 /* First, save the last group name entered on the command line in the list */
362                 update_dev_list(&dlist_idx, group_name);
363
364                 /* Now save devices and group names in the io_hdr_stats structures */
365                 for (i = 0; (i < dlist_idx) && (i < iodev_nr); i++, shi++, sdli++) {
366                         strncpy(shi->name, sdli->dev_name, MAX_NAME_LEN);
367                         shi->name[MAX_NAME_LEN - 1] = '\0';
368                         shi->used = TRUE;
369                         if (shi->name[0] == ' ') {
370                                 /* Current device name is in fact the name of a group */
371                                 shi->status = DISK_GROUP;
372                         }
373                         else {
374                                 shi->status = DISK_REGISTERED;
375                         }
376                 }
377         }
378         else {
379                 /*
380                  * No device names have been entered on the command line but
381                  * the name of a group. Save that name at the end of the
382                  * data table so that all devices that will be read will be
383                  * included in that group.
384                  */
385                 shi += iodev_nr - 1;
386                 strncpy(shi->name, group_name, MAX_NAME_LEN);
387                 shi->name[MAX_NAME_LEN - 1] = '\0';
388                 shi->used = TRUE;
389                 shi->status = DISK_GROUP;
390         }
391 }
392
393 /*
394  ***************************************************************************
395  * Free various structures.
396  ***************************************************************************
397 */
398 void io_sys_free(void)
399 {
400         int i;
401
402         for (i = 0; i < 2; i++) {
403                 /* Free CPU structures */
404                 free(st_cpu[i]);
405
406                 /* Free I/O device structures */
407                 free(st_iodev[i]);
408         }
409
410         free(st_hdr_iodev);
411 }
412
413 /*
414  ***************************************************************************
415  * Save stats for current device or partition.
416  *
417  * IN:
418  * @name                Name of the device/partition.
419  * @curr                Index in array for current sample statistics.
420  * @st_io               Structure with device or partition to save.
421  * @iodev_nr            Number of devices and partitions.
422  * @st_hdr_iodev        Pointer on structures describing a device/partition.
423  *
424  * OUT:
425  * @st_hdr_iodev        Pointer on structures describing a device/partition.
426  ***************************************************************************
427  */
428 void save_stats(char *name, int curr, void *st_io, int iodev_nr,
429                 struct io_hdr_stats *st_hdr_iodev)
430 {
431         int i;
432         struct io_hdr_stats *st_hdr_iodev_i;
433         struct io_stats *st_iodev_i;
434
435         /* Look for device in data table */
436         for (i = 0; i < iodev_nr; i++) {
437                 st_hdr_iodev_i = st_hdr_iodev + i;
438                 if (!strcmp(st_hdr_iodev_i->name, name)) {
439                         break;
440                 }
441         }
442
443         if (i == iodev_nr) {
444                 /*
445                  * This is a new device: Look for an unused entry to store it.
446                  * Thus we are able to handle dynamically registered devices.
447                  */
448                 for (i = 0; i < iodev_nr; i++) {
449                         st_hdr_iodev_i = st_hdr_iodev + i;
450                         if (!st_hdr_iodev_i->used) {
451                                 /* Unused entry found... */
452                                 st_hdr_iodev_i->used = TRUE; /* Indicate it is now used */
453                                 strncpy(st_hdr_iodev_i->name, name, MAX_NAME_LEN - 1);
454                                 st_hdr_iodev_i->name[MAX_NAME_LEN - 1] = '\0';
455                                 st_iodev_i = st_iodev[!curr] + i;
456                                 memset(st_iodev_i, 0, IO_STATS_SIZE);
457                                 break;
458                         }
459                 }
460         }
461         if (i < iodev_nr) {
462                 st_hdr_iodev_i = st_hdr_iodev + i;
463                 if (st_hdr_iodev_i->status == DISK_UNREGISTERED) {
464                         st_hdr_iodev_i->status = DISK_REGISTERED;
465                 }
466                 st_iodev_i = st_iodev[curr] + i;
467                 *st_iodev_i = *((struct io_stats *) st_io);
468         }
469         /*
470          * else it was a new device
471          * but there was no free structure to store it.
472          */
473 }
474
475 /*
476  ***************************************************************************
477  * Read sysfs stat for current block device or partition.
478  *
479  * IN:
480  * @curr        Index in array for current sample statistics.
481  * @filename    File name where stats will be read.
482  * @dev_name    Device or partition name.
483  *
484  * RETURNS:
485  * 0 if file couldn't be opened, 1 otherwise.
486  ***************************************************************************
487  */
488 int read_sysfs_file_stat(int curr, char *filename, char *dev_name)
489 {
490         FILE *fp;
491         struct io_stats sdev;
492         int i;
493         unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks;
494         unsigned long rd_ios, rd_merges_or_rd_sec, wr_ios, wr_merges;
495         unsigned long rd_sec_or_wr_ios, wr_sec, rd_ticks_or_wr_sec;
496
497         /* Try to read given stat file */
498         if ((fp = fopen(filename, "r")) == NULL)
499                 return 0;
500
501         i = fscanf(fp, "%lu %lu %lu %lu %lu %lu %lu %u %u %u %u",
502                    &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
503                    &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);
504
505         if (i == 11) {
506                 /* Device or partition */
507                 sdev.rd_ios     = rd_ios;
508                 sdev.rd_merges  = rd_merges_or_rd_sec;
509                 sdev.rd_sectors = rd_sec_or_wr_ios;
510                 sdev.rd_ticks   = (unsigned int) rd_ticks_or_wr_sec;
511                 sdev.wr_ios     = wr_ios;
512                 sdev.wr_merges  = wr_merges;
513                 sdev.wr_sectors = wr_sec;
514                 sdev.wr_ticks   = wr_ticks;
515                 sdev.ios_pgr    = ios_pgr;
516                 sdev.tot_ticks  = tot_ticks;
517                 sdev.rq_ticks   = rq_ticks;
518         }
519         else if (i == 4) {
520                 /* Partition without extended statistics */
521                 sdev.rd_ios     = rd_ios;
522                 sdev.rd_sectors = rd_merges_or_rd_sec;
523                 sdev.wr_ios     = rd_sec_or_wr_ios;
524                 sdev.wr_sectors = rd_ticks_or_wr_sec;
525         }
526
527         if ((i == 11) || !DISPLAY_EXTENDED(flags)) {
528                 /*
529                  * In fact, we _don't_ save stats if it's a partition without
530                  * extended stats and yet we want to display ext stats.
531                  */
532                 save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev);
533         }
534
535         fclose(fp);
536
537         return 1;
538 }
539
540 /*
541  ***************************************************************************
542  * Read sysfs stats for all the partitions of a device.
543  *
544  * IN:
545  * @curr        Index in array for current sample statistics.
546  * @dev_name    Device name.
547  ***************************************************************************
548  */
549 void read_sysfs_dlist_part_stat(int curr, char *dev_name)
550 {
551         DIR *dir;
552         struct dirent *drd;
553         char dfile[MAX_PF_NAME], filename[MAX_PF_NAME];
554
555         snprintf(dfile, MAX_PF_NAME, "%s/%s", SYSFS_BLOCK, dev_name);
556         dfile[MAX_PF_NAME - 1] = '\0';
557
558         /* Open current device directory in /sys/block */
559         if ((dir = opendir(dfile)) == NULL)
560                 return;
561
562         /* Get current entry */
563         while ((drd = readdir(dir)) != NULL) {
564                 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
565                         continue;
566                 snprintf(filename, MAX_PF_NAME, "%s/%s/%s", dfile, drd->d_name, S_STAT);
567                 filename[MAX_PF_NAME - 1] = '\0';
568
569                 /* Read current partition stats */
570                 read_sysfs_file_stat(curr, filename, drd->d_name);
571         }
572
573         /* Close device directory */
574         closedir(dir);
575 }
576
577 /*
578  ***************************************************************************
579  * Read stats from the sysfs filesystem for the devices entered on the
580  * command line.
581  *
582  * IN:
583  * @curr        Index in array for current sample statistics.
584  ***************************************************************************
585  */
586 void read_sysfs_dlist_stat(int curr)
587 {
588         int dev, ok;
589         char filename[MAX_PF_NAME];
590         char *slash;
591         struct io_dlist *st_dev_list_i;
592
593         /* Every I/O device (or partition) is potentially unregistered */
594         set_entries_unregistered(iodev_nr, st_hdr_iodev);
595
596         for (dev = 0; dev < dlist_idx; dev++) {
597                 st_dev_list_i = st_dev_list + dev;
598
599                 /* Some devices may have a slash in their name (eg. cciss/c0d0...) */
600                 while ((slash = strchr(st_dev_list_i->dev_name, '/'))) {
601                         *slash = '!';
602                 }
603
604                 snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
605                          SYSFS_BLOCK, st_dev_list_i->dev_name, S_STAT);
606                 filename[MAX_PF_NAME - 1] = '\0';
607
608                 /* Read device stats */
609                 ok = read_sysfs_file_stat(curr, filename, st_dev_list_i->dev_name);
610
611                 if (ok && st_dev_list_i->disp_part) {
612                         /* Also read stats for its partitions */
613                         read_sysfs_dlist_part_stat(curr, st_dev_list_i->dev_name);
614                 }
615         }
616
617         /* Free structures corresponding to unregistered devices */
618         free_unregistered_entries(iodev_nr, st_hdr_iodev);
619 }
620
621 /*
622  ***************************************************************************
623  * Read stats from the sysfs filesystem for every block devices found.
624  *
625  * IN:
626  * @curr        Index in array for current sample statistics.
627  ***************************************************************************
628  */
629 void read_sysfs_stat(int curr)
630 {
631         DIR *dir;
632         struct dirent *drd;
633         char filename[MAX_PF_NAME];
634         int ok;
635
636         /* Every I/O device entry is potentially unregistered */
637         set_entries_unregistered(iodev_nr, st_hdr_iodev);
638
639         /* Open /sys/block directory */
640         if ((dir = opendir(SYSFS_BLOCK)) != NULL) {
641
642                 /* Get current entry */
643                 while ((drd = readdir(dir)) != NULL) {
644                         if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
645                                 continue;
646                         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
647                                  SYSFS_BLOCK, drd->d_name, S_STAT);
648                         filename[MAX_PF_NAME - 1] = '\0';
649
650                         /* If current entry is a directory, try to read its stat file */
651                         ok = read_sysfs_file_stat(curr, filename, drd->d_name);
652
653                         /*
654                          * If '-p ALL' was entered on the command line,
655                          * also try to read stats for its partitions
656                          */
657                         if (ok && DISPLAY_PART_ALL(flags)) {
658                                 read_sysfs_dlist_part_stat(curr, drd->d_name);
659                         }
660                 }
661
662                 /* Close /sys/block directory */
663                 closedir(dir);
664         }
665
666         /* Free structures corresponding to unregistered devices */
667         free_unregistered_entries(iodev_nr, st_hdr_iodev);
668 }
669
670 /*
671  ***************************************************************************
672  * Read stats from /proc/diskstats.
673  *
674  * IN:
675  * @curr        Index in array for current sample statistics.
676  ***************************************************************************
677  */
678 void read_diskstats_stat(int curr)
679 {
680         FILE *fp;
681         char line[256], dev_name[MAX_NAME_LEN];
682         char *dm_name;
683         struct io_stats sdev;
684         int i;
685         unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks;
686         unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
687         unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
688         char *ioc_dname;
689         unsigned int major, minor;
690
691         /* Every I/O device entry is potentially unregistered */
692         set_entries_unregistered(iodev_nr, st_hdr_iodev);
693
694         if ((fp = fopen(DISKSTATS, "r")) == NULL)
695                 return;
696
697         while (fgets(line, sizeof(line), fp) != NULL) {
698
699                 /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */
700                 i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u",
701                            &major, &minor, dev_name,
702                            &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
703                            &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);
704
705                 if (i == 14) {
706                         /* Device or partition */
707                         if (!dlist_idx && !DISPLAY_PARTITIONS(flags) &&
708                             !is_device(dev_name, ACCEPT_VIRTUAL_DEVICES))
709                                 continue;
710                         sdev.rd_ios     = rd_ios;
711                         sdev.rd_merges  = rd_merges_or_rd_sec;
712                         sdev.rd_sectors = rd_sec_or_wr_ios;
713                         sdev.rd_ticks   = (unsigned int) rd_ticks_or_wr_sec;
714                         sdev.wr_ios     = wr_ios;
715                         sdev.wr_merges  = wr_merges;
716                         sdev.wr_sectors = wr_sec;
717                         sdev.wr_ticks   = wr_ticks;
718                         sdev.ios_pgr    = ios_pgr;
719                         sdev.tot_ticks  = tot_ticks;
720                         sdev.rq_ticks   = rq_ticks;
721                 }
722                 else if (i == 7) {
723                         /* Partition without extended statistics */
724                         if (DISPLAY_EXTENDED(flags) ||
725                             (!dlist_idx && !DISPLAY_PARTITIONS(flags)))
726                                 continue;
727
728                         sdev.rd_ios     = rd_ios;
729                         sdev.rd_sectors = rd_merges_or_rd_sec;
730                         sdev.wr_ios     = rd_sec_or_wr_ios;
731                         sdev.wr_sectors = rd_ticks_or_wr_sec;
732                 }
733                 else
734                         /* Unknown entry: Ignore it */
735                         continue;
736
737                 if ((ioc_dname = ioc_name(major, minor)) != NULL) {
738                         if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname, K_NODEV)) {
739                                 /*
740                                  * No match: Use name generated from sysstat.ioconf data
741                                  * (if different from "nodev") works around known issues
742                                  * with EMC PowerPath.
743                                  */
744                                 strncpy(dev_name, ioc_dname, MAX_NAME_LEN - 1);
745                                 dev_name[MAX_NAME_LEN - 1] = '\0';
746                         }
747                 }
748
749                 if ((DISPLAY_DEVMAP_NAME(flags)) && (major == dm_major)) {
750                         /*
751                          * If the device is a device mapper device, try to get its
752                          * assigned name of its logical device.
753                          */
754                         dm_name = transform_devmapname(major, minor);
755                         if (dm_name) {
756                                 strncpy(dev_name, dm_name, MAX_NAME_LEN - 1);
757                                 dev_name[MAX_NAME_LEN - 1] = '\0';
758                         }
759                 }
760
761                 save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev);
762         }
763         fclose(fp);
764
765         /* Free structures corresponding to unregistered devices */
766         free_unregistered_entries(iodev_nr, st_hdr_iodev);
767 }
768
769 /*
770  ***************************************************************************
771  * Compute stats for device groups using stats of every device belonging
772  * to each of these groups.
773  *
774  * IN:
775  * @curr        Index in array for current sample statistics.
776  ***************************************************************************
777  */
778 void compute_device_groups_stats(int curr)
779 {
780         struct io_stats gdev, *ioi;
781         struct io_hdr_stats *shi = st_hdr_iodev;
782         int i, nr_disks;
783
784         memset(&gdev, 0, IO_STATS_SIZE);
785         nr_disks = 0;
786
787         for (i = 0; i < iodev_nr; i++, shi++) {
788                 if (shi->used && (shi->status == DISK_REGISTERED)) {
789                         ioi = st_iodev[curr] + i;
790
791                         if (!DISPLAY_UNFILTERED(flags)) {
792                                 if (!ioi->rd_ios && !ioi->wr_ios)
793                                         continue;
794                         }
795
796                         gdev.rd_ios     += ioi->rd_ios;
797                         gdev.rd_merges  += ioi->rd_merges;
798                         gdev.rd_sectors += ioi->rd_sectors;
799                         gdev.rd_ticks   += ioi->rd_ticks;
800                         gdev.wr_ios     += ioi->wr_ios;
801                         gdev.wr_merges  += ioi->wr_merges;
802                         gdev.wr_sectors += ioi->wr_sectors;
803                         gdev.wr_ticks   += ioi->wr_ticks;
804                         gdev.ios_pgr    += ioi->ios_pgr;
805                         gdev.tot_ticks  += ioi->tot_ticks;
806                         gdev.rq_ticks   += ioi->rq_ticks;
807                         nr_disks++;
808                 }
809                 else if (shi->status == DISK_GROUP) {
810                         save_stats(shi->name, curr, &gdev, iodev_nr, st_hdr_iodev);
811                         shi->used = nr_disks;
812                         nr_disks = 0;
813                         memset(&gdev, 0, IO_STATS_SIZE);
814                 }
815         }
816 }
817
818 /*
819  ***************************************************************************
820  * Write current sample's timestamp, either in plain or JSON format.
821  *
822  * IN:
823  * @tab         Number of tabs to print.
824  * @rectime     Current date and time.
825  ***************************************************************************
826  */
827 void write_sample_timestamp(int tab, struct tm *rectime)
828 {
829         if (DISPLAY_ISO(flags)) {
830                 strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime);
831         }
832         else {
833                 strftime(timestamp, sizeof(timestamp), "%x %X", rectime);
834         }
835         if (DISPLAY_JSON_OUTPUT(flags)) {
836                 xprintf(tab, "\"timestamp\": \"%s\",", timestamp);
837         }
838         else {
839                 printf("%s\n", timestamp);
840         }
841 }
842
843 /*
844  ***************************************************************************
845  * Display CPU utilization in plain format.
846  *
847  * IN:
848  * @curr        Index in array for current sample statistics.
849  * @itv         Interval of time.
850  ***************************************************************************
851  */
852 void write_plain_cpu_stat(int curr, unsigned long long itv)
853 {
854         printf("avg-cpu:  %%user   %%nice %%system %%iowait  %%steal   %%idle\n");
855
856         printf("       ");
857         cprintf_pc(6, 7, 2,
858                    ll_sp_value(st_cpu[!curr]->cpu_user,   st_cpu[curr]->cpu_user,   itv),
859                    ll_sp_value(st_cpu[!curr]->cpu_nice,   st_cpu[curr]->cpu_nice,   itv),
860                    /*
861                     * Time spent in system mode also includes time spent servicing
862                     * hard and soft interrupts.
863                     */
864                    ll_sp_value(st_cpu[!curr]->cpu_sys + st_cpu[!curr]->cpu_softirq +
865                                st_cpu[!curr]->cpu_hardirq,
866                                st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq +
867                                st_cpu[curr]->cpu_hardirq, itv),
868                    ll_sp_value(st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, itv),
869                    ll_sp_value(st_cpu[!curr]->cpu_steal,  st_cpu[curr]->cpu_steal,  itv),
870                    (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
871                    0.0 :
872                    ll_sp_value(st_cpu[!curr]->cpu_idle,   st_cpu[curr]->cpu_idle,   itv));
873
874         printf("\n\n");
875 }
876
877 /*
878  ***************************************************************************
879  * Display CPU utilization in JSON format.
880  *
881  * IN:
882  * @tab         Number of tabs to print.
883  * @curr        Index in array for current sample statistics.
884  * @itv         Interval of time.
885  ***************************************************************************
886  */
887 void write_json_cpu_stat(int tab, int curr, unsigned long long itv)
888 {
889         xprintf0(tab, "\"avg-cpu\":  {\"user\": %.2f, \"nice\": %.2f, \"system\": %.2f,"
890                       " \"iowait\": %.2f, \"steal\": %.2f, \"idle\": %.2f}",
891                  ll_sp_value(st_cpu[!curr]->cpu_user,   st_cpu[curr]->cpu_user,   itv),
892                  ll_sp_value(st_cpu[!curr]->cpu_nice,   st_cpu[curr]->cpu_nice,   itv),
893                  /*
894                   * Time spent in system mode also includes time spent servicing
895                   * hard and soft interrupts.
896                   */
897                  ll_sp_value(st_cpu[!curr]->cpu_sys + st_cpu[!curr]->cpu_softirq +
898                              st_cpu[!curr]->cpu_hardirq,
899                              st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_softirq +
900                              st_cpu[curr]->cpu_hardirq, itv),
901                  ll_sp_value(st_cpu[!curr]->cpu_iowait, st_cpu[curr]->cpu_iowait, itv),
902                  ll_sp_value(st_cpu[!curr]->cpu_steal,  st_cpu[curr]->cpu_steal,  itv),
903                  (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
904                  0.0 :
905                  ll_sp_value(st_cpu[!curr]->cpu_idle,   st_cpu[curr]->cpu_idle,   itv));
906 }
907
908 /*
909  ***************************************************************************
910  * Display CPU utilization in plain or JSON format.
911  *
912  * IN:
913  * @curr        Index in array for current sample statistics.
914  * @itv         Interval of time.
915  * @tab         Number of tabs to print (JSON format only).
916  ***************************************************************************
917  */
918 void write_cpu_stat(int curr, unsigned long long itv, int tab)
919 {
920         if (DISPLAY_JSON_OUTPUT(flags)) {
921                 write_json_cpu_stat(tab, curr, itv);
922         }
923         else {
924                 write_plain_cpu_stat(curr, itv);
925         }
926 }
927
928 /*
929  ***************************************************************************
930  * Display disk stats header in plain or JSON format.
931  *
932  * OUT:
933  * @fctr        Conversion factor.
934  * @tab         Number of tabs to print (JSON format only).
935  ***************************************************************************
936  */
937 void write_disk_stat_header(int *fctr, int *tab)
938 {
939         if (DISPLAY_KILOBYTES(flags)) {
940                 *fctr = 2;
941         }
942         else if (DISPLAY_MEGABYTES(flags)) {
943                 *fctr = 2048;
944         }
945
946         if (DISPLAY_JSON_OUTPUT(flags)) {
947                 xprintf((*tab)++, "\"disk\": [");
948                 return;
949         }
950
951         if (DISPLAY_EXTENDED(flags)) {
952                 /* Extended stats */
953                 printf("Device:         rrqm/s   wrqm/s     r/s     w/s");
954                 if (DISPLAY_MEGABYTES(flags)) {
955                         printf("    rMB/s    wMB/s");
956                 }
957                 else if (DISPLAY_KILOBYTES(flags)) {
958                         printf("    rkB/s    wkB/s");
959                 }
960                 else {
961                         printf("   rsec/s   wsec/s");
962                 }
963                 printf(" avgrq-sz avgqu-sz   await r_await w_await  svctm  %%util\n");
964         }
965         else {
966                 /* Basic stats */
967                 printf("Device:            tps");
968                 if (DISPLAY_KILOBYTES(flags)) {
969                         printf("    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn\n");
970                 }
971                 else if (DISPLAY_MEGABYTES(flags)) {
972                         printf("    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn\n");
973                 }
974                 else {
975                         printf("   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn\n");
976                 }
977         }
978 }
979
980 /*
981  ***************************************************************************
982  * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
983  * in plain format.
984  *
985  * IN:
986  * @itv         Interval of time.
987  * @fctr        Conversion factor.
988  * @shi         Structures describing the devices and partitions.
989  * @ioi         Current sample statistics.
990  * @ioj         Previous sample statistics.
991  * @devname     Current device name.
992  * @xds         Extended stats for current device.
993  * @r_await     r_await metric value.
994  * @w_await     w_await metric value.
995  ***************************************************************************
996  */
997 void write_plain_ext_stat(unsigned long long itv, int fctr,
998                           struct io_hdr_stats *shi, struct io_stats *ioi,
999                           struct io_stats *ioj, char *devname, struct ext_disk_stats *xds,
1000                           double r_await, double w_await)
1001 {
1002         if (DISPLAY_HUMAN_READ(flags)) {
1003                 cprintf_in(IS_STR, "%s\n", devname, 0);
1004                 printf("%13s", "");
1005         }
1006         else {
1007                 cprintf_in(IS_STR, "%-13s", devname, 0);
1008         }
1009
1010         /*       rrq/s wrq/s   r/s   w/s  rsec  wsec  rqsz  qusz await r_await w_await svctm %util */
1011         cprintf_f(2, 8, 2,
1012                   S_VALUE(ioj->rd_merges, ioi->rd_merges, itv),
1013                   S_VALUE(ioj->wr_merges, ioi->wr_merges, itv));
1014         cprintf_f(2, 7, 2,
1015                   S_VALUE(ioj->rd_ios, ioi->rd_ios, itv),
1016                   S_VALUE(ioj->wr_ios, ioi->wr_ios, itv));
1017         cprintf_f(4, 8, 2,
1018                   S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1019                   S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,
1020                   xds->arqsz,
1021                   S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
1022         cprintf_f(3, 7, 2, xds->await, r_await, w_await);
1023         /* The ticks output is biased to output 1000 ticks per second */
1024         cprintf_f(1, 6, 2, xds->svctm);
1025         /*
1026          * Again: Ticks in milliseconds.
1027          * In the case of a device group (option -g), shi->used is the number of
1028          * devices in the group. Else shi->used equals 1.
1029          */
1030         cprintf_pc(1, 6, 2,
1031                    shi->used ? xds->util / 10.0 / (double) shi->used
1032                              : xds->util / 10.0);       /* shi->used should never be zero here */
1033         printf("\n");
1034 }
1035
1036 /*
1037  ***************************************************************************
1038  * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1039  * in JSON format.
1040  *
1041  * IN:
1042  * @tab         Number of tabs to print.
1043  * @itv         Interval of time.
1044  * @fctr        Conversion factor.
1045  * @shi         Structures describing the devices and partitions.
1046  * @ioi         Current sample statistics.
1047  * @ioj         Previous sample statistics.
1048  * @devname     Current device name.
1049  * @xds         Extended stats for current device.
1050  * @r_await     r_await metric value.
1051  * @w_await     w_await metric value.
1052  ***************************************************************************
1053  */
1054 void write_json_ext_stat(int tab, unsigned long long itv, int fctr,
1055                     struct io_hdr_stats *shi, struct io_stats *ioi,
1056                     struct io_stats *ioj, char *devname, struct ext_disk_stats *xds,
1057                     double r_await, double w_await)
1058 {
1059         xprintf0(tab,
1060                  "{\"disk_device\": \"%s\", \"rrqm\": %.2f, \"wrqm\": %.2f, "
1061                  "\"r\": %.2f, \"w\": %.2f, \"rkB\": %.2f, \"wkB\": %.2f, "
1062                  "\"avgrq-sz\": %.2f, \"avgqu-sz\": %.2f, "
1063                  "\"await\": %.2f, \"r_await\": %.2f, \"w_await\": %.2f, "
1064                  "\"svctm\": %.2f, \"util\": %.2f}",
1065                  devname,
1066                  S_VALUE(ioj->rd_merges, ioi->rd_merges, itv),
1067                  S_VALUE(ioj->wr_merges, ioi->wr_merges, itv),
1068                  S_VALUE(ioj->rd_ios, ioi->rd_ios, itv),
1069                  S_VALUE(ioj->wr_ios, ioi->wr_ios, itv),
1070                  S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1071                  S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,
1072                  xds->arqsz,
1073                  S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0,
1074                  xds->await,
1075                  r_await,
1076                  w_await,
1077                  xds->svctm,
1078                  shi->used ? xds->util / 10.0 / (double) shi->used
1079                            : xds->util / 10.0); /* shi->used should never be zero here */
1080 }
1081
1082 /*
1083  ***************************************************************************
1084  * Display extended stats, read from /proc/{diskstats,partitions} or /sys,
1085  * in plain or JSON format.
1086  *
1087  * IN:
1088  * @itv         Interval of time.
1089  * @fctr        Conversion factor.
1090  * @shi         Structures describing the devices and partitions.
1091  * @ioi         Current sample statistics.
1092  * @ioj         Previous sample statistics.
1093  * @tab         Number of tabs to print (JSON output only).
1094  ***************************************************************************
1095  */
1096 void write_ext_stat(unsigned long long itv, int fctr,
1097                     struct io_hdr_stats *shi, struct io_stats *ioi,
1098                     struct io_stats *ioj, int tab)
1099 {
1100         char *devname = NULL;
1101         struct stats_disk sdc, sdp;
1102         struct ext_disk_stats xds;
1103         double r_await, w_await;
1104
1105         /*
1106          * Counters overflows are possible, but don't need to be handled in
1107          * a special way: The difference is still properly calculated if the
1108          * result is of the same type as the two values.
1109          * Exception is field rq_ticks which is incremented by the number of
1110          * I/O in progress times the number of milliseconds spent doing I/O.
1111          * But the number of I/O in progress (field ios_pgr) happens to be
1112          * sometimes negative...
1113          */
1114         sdc.nr_ios    = ioi->rd_ios + ioi->wr_ios;
1115         sdp.nr_ios    = ioj->rd_ios + ioj->wr_ios;
1116
1117         sdc.tot_ticks = ioi->tot_ticks;
1118         sdp.tot_ticks = ioj->tot_ticks;
1119
1120         sdc.rd_ticks  = ioi->rd_ticks;
1121         sdp.rd_ticks  = ioj->rd_ticks;
1122         sdc.wr_ticks  = ioi->wr_ticks;
1123         sdp.wr_ticks  = ioj->wr_ticks;
1124
1125         sdc.rd_sect   = ioi->rd_sectors;
1126         sdp.rd_sect   = ioj->rd_sectors;
1127         sdc.wr_sect   = ioi->wr_sectors;
1128         sdp.wr_sect   = ioj->wr_sectors;
1129
1130         compute_ext_disk_stats(&sdc, &sdp, itv, &xds);
1131
1132         r_await = (ioi->rd_ios - ioj->rd_ios) ?
1133                   (ioi->rd_ticks - ioj->rd_ticks) /
1134                   ((double) (ioi->rd_ios - ioj->rd_ios)) : 0.0;
1135         w_await = (ioi->wr_ios - ioj->wr_ios) ?
1136                   (ioi->wr_ticks - ioj->wr_ticks) /
1137                   ((double) (ioi->wr_ios - ioj->wr_ios)) : 0.0;
1138
1139         /* Get device name */
1140         if (DISPLAY_PERSIST_NAME_I(flags)) {
1141                 devname = get_persistent_name_from_pretty(shi->name);
1142         }
1143         if (!devname) {
1144                 devname = shi->name;
1145         }
1146
1147         if (DISPLAY_JSON_OUTPUT(flags)) {
1148                 write_json_ext_stat(tab, itv, fctr, shi, ioi, ioj, devname, &xds,
1149                                     r_await, w_await);
1150         }
1151         else {
1152                 write_plain_ext_stat(itv, fctr, shi, ioi, ioj, devname, &xds,
1153                                      r_await, w_await);
1154         }
1155 }
1156
1157 /*
1158  ***************************************************************************
1159  * Write basic stats, read from /proc/diskstats or from sysfs, in plain
1160  * format.
1161  *
1162  * IN:
1163  * @itv         Interval of time.
1164  * @fctr        Conversion factor.
1165  * @ioi         Current sample statistics.
1166  * @ioj         Previous sample statistics.
1167  * @devname     Current device name.
1168  * @rd_sec      Number of sectors read.
1169  * @wr_sec      Number of sectors written.
1170  ***************************************************************************
1171  */
1172 void write_plain_basic_stat(unsigned long long itv, int fctr,
1173                             struct io_stats *ioi, struct io_stats *ioj,
1174                             char *devname, unsigned long long rd_sec,
1175                             unsigned long long wr_sec)
1176 {
1177         if (DISPLAY_HUMAN_READ(flags)) {
1178                 cprintf_in(IS_STR, "%s\n", devname, 0);
1179                 printf("%13s", "");
1180         }
1181         else {
1182                 cprintf_in(IS_STR, "%-13s", devname, 0);
1183         }
1184         cprintf_f(1, 8, 2,
1185                   S_VALUE(ioj->rd_ios + ioj->wr_ios, ioi->rd_ios + ioi->wr_ios, itv));
1186         cprintf_f(2, 12, 2,
1187                   S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1188                   S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr);
1189         cprintf_u64(2, 10,
1190                     (unsigned long long) rd_sec / fctr,
1191                     (unsigned long long) wr_sec / fctr);
1192         printf("\n");
1193 }
1194
1195 /*
1196  ***************************************************************************
1197  * Write basic stats, read from /proc/diskstats or from sysfs, in JSON
1198  * format.
1199  *
1200  * IN:
1201  * @tab         Number of tabs to print.
1202  * @itv         Interval of time.
1203  * @fctr        Conversion factor.
1204  * @ioi         Current sample statistics.
1205  * @ioj         Previous sample statistics.
1206  * @devname     Current device name.
1207  * @rd_sec      Number of sectors read.
1208  * @wr_sec      Number of sectors written.
1209  ***************************************************************************
1210  */
1211 void write_json_basic_stat(int tab, unsigned long long itv, int fctr,
1212                            struct io_stats *ioi, struct io_stats *ioj,
1213                            char *devname, unsigned long long rd_sec,
1214                            unsigned long long wr_sec)
1215 {
1216         xprintf0(tab,
1217                  "{\"disk_device\": \"%s\", \"tps\": %.2f, "
1218                  "\"kB_read_per_sec\": %.2f, \"kB_wrtn_per_sec\": %.2f, "
1219                  "\"kB_read\": %llu, \"kB_wrtn\": %llu}",
1220                  devname,
1221                  S_VALUE(ioj->rd_ios + ioj->wr_ios, ioi->rd_ios + ioi->wr_ios, itv),
1222                  S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
1223                  S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,
1224                  (unsigned long long) rd_sec / fctr,
1225                  (unsigned long long) wr_sec / fctr);
1226 }
1227
1228 /*
1229  ***************************************************************************
1230  * Write basic stats, read from /proc/diskstats or from sysfs, in plain or
1231  * JSON format.
1232  *
1233  * IN:
1234  * @itv         Interval of time.
1235  * @fctr        Conversion factor.
1236  * @shi         Structures describing the devices and partitions.
1237  * @ioi         Current sample statistics.
1238  * @ioj         Previous sample statistics.
1239  * @tab         Number of tabs to print (JSON format only).
1240  ***************************************************************************
1241  */
1242 void write_basic_stat(unsigned long long itv, int fctr,
1243                       struct io_hdr_stats *shi, struct io_stats *ioi,
1244                       struct io_stats *ioj, int tab)
1245 {
1246         char *devname = NULL;
1247         unsigned long long rd_sec, wr_sec;
1248
1249         /* Print device name */
1250         if (DISPLAY_PERSIST_NAME_I(flags)) {
1251                 devname = get_persistent_name_from_pretty(shi->name);
1252         }
1253         if (!devname) {
1254                 devname = shi->name;
1255         }
1256
1257         /* Print stats coming from /sys or /proc/diskstats */
1258         rd_sec = ioi->rd_sectors - ioj->rd_sectors;
1259         if ((ioi->rd_sectors < ioj->rd_sectors) && (ioj->rd_sectors <= 0xffffffff)) {
1260                 rd_sec &= 0xffffffff;
1261         }
1262         wr_sec = ioi->wr_sectors - ioj->wr_sectors;
1263         if ((ioi->wr_sectors < ioj->wr_sectors) && (ioj->wr_sectors <= 0xffffffff)) {
1264                 wr_sec &= 0xffffffff;
1265         }
1266
1267         if (DISPLAY_JSON_OUTPUT(flags)) {
1268                 write_json_basic_stat(tab, itv, fctr, ioi, ioj, devname,
1269                                       rd_sec, wr_sec);
1270         }
1271         else {
1272                 write_plain_basic_stat(itv, fctr, ioi, ioj, devname,
1273                                        rd_sec, wr_sec);
1274         }
1275 }
1276
1277 /*
1278  ***************************************************************************
1279  * Print everything now (stats and uptime).
1280  *
1281  * IN:
1282  * @curr        Index in array for current sample statistics.
1283  * @rectime     Current date and time.
1284  ***************************************************************************
1285  */
1286 void write_stats(int curr, struct tm *rectime)
1287 {
1288         int dev, i, fctr = 1, tab = 4, next = FALSE;
1289         unsigned long long itv;
1290         struct io_hdr_stats *shi;
1291         struct io_dlist *st_dev_list_i;
1292
1293         /* Test stdout */
1294         TEST_STDOUT(STDOUT_FILENO);
1295
1296         if (DISPLAY_JSON_OUTPUT(flags)) {
1297                 xprintf(tab++, "{");
1298         }
1299
1300         /* Print time stamp */
1301         if (DISPLAY_TIMESTAMP(flags)) {
1302                 write_sample_timestamp(tab, rectime);
1303 #ifdef DEBUG
1304                 if (DISPLAY_DEBUG(flags)) {
1305                         fprintf(stderr, "%s\n", timestamp);
1306                 }
1307 #endif
1308         }
1309
1310         /* Interval is multiplied by the number of processors */
1311         itv = get_interval(uptime[!curr], uptime[curr]);
1312
1313         if (DISPLAY_CPU(flags)) {
1314 #ifdef DEBUG
1315                 if (DISPLAY_DEBUG(flags)) {
1316                         /* Debug output */
1317                         fprintf(stderr, "itv=%llu st_cpu[curr]{ cpu_user=%llu cpu_nice=%llu "
1318                                         "cpu_sys=%llu cpu_idle=%llu cpu_iowait=%llu cpu_steal=%llu "
1319                                         "cpu_hardirq=%llu cpu_softirq=%llu cpu_guest=%llu "
1320                                         "cpu_guest_nice=%llu }\n",
1321                                 itv,
1322                                 st_cpu[curr]->cpu_user,
1323                                 st_cpu[curr]->cpu_nice,
1324                                 st_cpu[curr]->cpu_sys,
1325                                 st_cpu[curr]->cpu_idle,
1326                                 st_cpu[curr]->cpu_iowait,
1327                                 st_cpu[curr]->cpu_steal,
1328                                 st_cpu[curr]->cpu_hardirq,
1329                                 st_cpu[curr]->cpu_softirq,
1330                                 st_cpu[curr]->cpu_guest,
1331                                 st_cpu[curr]->cpu_guest_nice);
1332                 }
1333 #endif
1334
1335                 /* Display CPU utilization */
1336                 write_cpu_stat(curr, itv, tab);
1337
1338                 if (DISPLAY_JSON_OUTPUT(flags)) {
1339                         if (DISPLAY_DISK(flags)) {
1340                                 printf(",");
1341                         }
1342                         printf("\n");
1343                 }
1344         }
1345
1346         if (cpu_nr > 1) {
1347                 /* On SMP machines, reduce itv to one processor (see note above) */
1348                 itv = get_interval(uptime0[!curr], uptime0[curr]);
1349         }
1350
1351         if (DISPLAY_DISK(flags)) {
1352                 struct io_stats *ioi, *ioj;
1353
1354                 shi = st_hdr_iodev;
1355
1356                 /* Display disk stats header */
1357                 write_disk_stat_header(&fctr, &tab);
1358
1359                 for (i = 0; i < iodev_nr; i++, shi++) {
1360                         if (shi->used) {
1361
1362                                 if (dlist_idx && !HAS_SYSFS(flags)) {
1363                                         /*
1364                                          * With /proc/diskstats, stats for every device
1365                                          * are read even if we have entered a list on devices
1366                                          * on the command line. Thus we need to check
1367                                          * if stats for current device are to be displayed.
1368                                          */
1369                                         for (dev = 0; dev < dlist_idx; dev++) {
1370                                                 st_dev_list_i = st_dev_list + dev;
1371                                                 if (!strcmp(shi->name, st_dev_list_i->dev_name))
1372                                                         break;
1373                                         }
1374                                         if (dev == dlist_idx)
1375                                                 /* Device not found in list: Don't display it */
1376                                                 continue;
1377                                 }
1378
1379                                 ioi = st_iodev[curr] + i;
1380                                 ioj = st_iodev[!curr] + i;
1381
1382                                 if (!DISPLAY_UNFILTERED(flags)) {
1383                                         if (!ioi->rd_ios && !ioi->wr_ios)
1384                                                 continue;
1385                                 }
1386
1387                                 if (DISPLAY_ZERO_OMIT(flags)) {
1388                                         if ((ioi->rd_ios == ioj->rd_ios) &&
1389                                                 (ioi->wr_ios == ioj->wr_ios))
1390                                                 /* No activity: Ignore it */
1391                                                 continue;
1392                                 }
1393
1394                                 if (DISPLAY_GROUP_TOTAL_ONLY(flags)) {
1395                                         if (shi->status != DISK_GROUP)
1396                                                 continue;
1397                                 }
1398 #ifdef DEBUG
1399                                 if (DISPLAY_DEBUG(flags)) {
1400                                         /* Debug output */
1401                                         fprintf(stderr, "name=%s itv=%llu fctr=%d ioi{ rd_sectors=%lu "
1402                                                         "wr_sectors=%lu rd_ios=%lu rd_merges=%lu rd_ticks=%u "
1403                                                         "wr_ios=%lu wr_merges=%lu wr_ticks=%u ios_pgr=%u tot_ticks=%u "
1404                                                         "rq_ticks=%u }\n",
1405                                                 shi->name,
1406                                                 itv,
1407                                                 fctr,
1408                                                 ioi->rd_sectors,
1409                                                 ioi->wr_sectors,
1410                                                 ioi->rd_ios,
1411                                                 ioi->rd_merges,
1412                                                 ioi->rd_ticks,
1413                                                 ioi->wr_ios,
1414                                                 ioi->wr_merges,
1415                                                 ioi->wr_ticks,
1416                                                 ioi->ios_pgr,
1417                                                 ioi->tot_ticks,
1418                                                 ioi->rq_ticks
1419                                                 );
1420                                 }
1421 #endif
1422
1423                                 if (DISPLAY_JSON_OUTPUT(flags) && next) {
1424                                         printf(",\n");
1425                                 }
1426                                 next = TRUE;
1427
1428                                 if (DISPLAY_EXTENDED(flags)) {
1429                                         write_ext_stat(itv, fctr, shi, ioi, ioj, tab);
1430                                 }
1431                                 else {
1432                                         write_basic_stat(itv, fctr, shi, ioi, ioj, tab);
1433                                 }
1434                         }
1435                 }
1436                 if (DISPLAY_JSON_OUTPUT(flags)) {
1437                         printf("\n");
1438                         xprintf(--tab, "]");
1439                 }
1440         }
1441
1442         if (DISPLAY_JSON_OUTPUT(flags)) {
1443                 xprintf0(--tab, "}");
1444         }
1445         else {
1446                 printf("\n");
1447         }
1448 }
1449
1450 /*
1451  ***************************************************************************
1452  * Main loop: Read I/O stats from the relevant sources and display them.
1453  *
1454  * IN:
1455  * @count       Number of reports to print.
1456  * @rectime     Current date and time.
1457  ***************************************************************************
1458  */
1459 void rw_io_stat_loop(long int count, struct tm *rectime)
1460 {
1461         int curr = 1;
1462         int skip = 0;
1463
1464         /* Should we skip first report? */
1465         if (DISPLAY_OMIT_SINCE_BOOT(flags) && interval > 0) {
1466                 skip = 1;
1467         }
1468
1469         /* Don't buffer data if redirected to a pipe */
1470         setbuf(stdout, NULL);
1471
1472         do {
1473                 if (cpu_nr > 1) {
1474                         /*
1475                          * Read system uptime (only for SMP machines).
1476                          * Init uptime0. So if /proc/uptime cannot fill it,
1477                          * this will be done by /proc/stat.
1478                          */
1479                         uptime0[curr] = 0;
1480                         read_uptime(&(uptime0[curr]));
1481                 }
1482
1483                 /*
1484                  * Read stats for CPU "all" and 0.
1485                  * Note that stats for CPU 0 are not used per se. It only makes
1486                  * read_stat_cpu() fill uptime0.
1487                  */
1488                 read_stat_cpu(st_cpu[curr], 2, &(uptime[curr]), &(uptime0[curr]));
1489
1490                 if (dlist_idx) {
1491                         /*
1492                          * A device or partition name was explicitly entered
1493                          * on the command line, with or without -p option
1494                          * (but not -p ALL).
1495                          */
1496                         if (HAS_DISKSTATS(flags) && !DISPLAY_PARTITIONS(flags)) {
1497                                 read_diskstats_stat(curr);
1498                         }
1499                         else if (HAS_SYSFS(flags)) {
1500                                 read_sysfs_dlist_stat(curr);
1501                         }
1502                 }
1503                 else {
1504                         /*
1505                          * No devices nor partitions entered on the command line
1506                          * (for example if -p ALL was used).
1507                          */
1508                         if (HAS_DISKSTATS(flags)) {
1509                                 read_diskstats_stat(curr);
1510                         }
1511                         else if (HAS_SYSFS(flags)) {
1512                                 read_sysfs_stat(curr);
1513                         }
1514                 }
1515
1516                 /* Compute device groups stats */
1517                 if (group_nr > 0) {
1518                         compute_device_groups_stats(curr);
1519                 }
1520
1521                 /* Get time */
1522                 get_localtime(rectime, 0);
1523
1524                 /* Check whether we should skip first report */
1525                 if (!skip) {
1526                         /* Print results */
1527                         write_stats(curr, rectime);
1528
1529                         if (count > 0) {
1530                                 count--;
1531                         }
1532                 }
1533                 else {
1534                         skip = 0;
1535                 }
1536
1537                 if (DISPLAY_JSON_OUTPUT(flags)) {
1538                         if (count) {
1539                         printf(",");
1540                         }
1541                         printf("\n");
1542                 }
1543                 if (count) {
1544                         curr ^= 1;
1545                         pause();
1546                 }
1547         }
1548         while (count);
1549
1550         if (DISPLAY_JSON_OUTPUT(flags)) {
1551                 printf("\t\t\t]\n\t\t}\n\t]\n}}\n");
1552         }
1553 }
1554
1555 /*
1556  ***************************************************************************
1557  * Main entry to the iostat program.
1558  ***************************************************************************
1559  */
1560 int main(int argc, char **argv)
1561 {
1562         int it = 0;
1563         int opt = 1;
1564         int i, report_set = FALSE;
1565         long count = 1;
1566         struct utsname header;
1567         struct io_dlist *st_dev_list_i;
1568         struct tm rectime;
1569         char *t, *persist_devname, *devname;
1570
1571 #ifdef USE_NLS
1572         /* Init National Language Support */
1573         init_nls();
1574 #endif
1575
1576         /* Init color strings */
1577         init_colors();
1578
1579         /* Get HZ */
1580         get_HZ();
1581
1582         /* Allocate structures for device list */
1583         if (argc > 1) {
1584                 salloc_dev_list(argc - 1 + count_csvalues(argc, argv));
1585         }
1586
1587         /* Process args... */
1588         while (opt < argc) {
1589
1590                 /* -p option used individually. See below for grouped use */
1591                 if (!strcmp(argv[opt], "-p")) {
1592                         flags |= I_D_PARTITIONS;
1593                         if (argv[++opt] &&
1594                             (strspn(argv[opt], DIGITS) != strlen(argv[opt])) &&
1595                             (strncmp(argv[opt], "-", 1))) {
1596                                 flags |= I_D_UNFILTERED;
1597
1598                                 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
1599                                         if (!strcmp(t, K_ALL)) {
1600                                                 flags |= I_D_PART_ALL;
1601                                         }
1602                                         else {
1603                                                 devname = device_name(t);
1604                                                 if (DISPLAY_PERSIST_NAME_I(flags)) {
1605                                                         /* Get device persistent name */
1606                                                         persist_devname = get_pretty_name_from_persistent(devname);
1607                                                         if (persist_devname != NULL) {
1608                                                                 devname = persist_devname;
1609                                                         }
1610                                                 }
1611                                                 /* Store device name */
1612                                                 i = update_dev_list(&dlist_idx, devname);
1613                                                 st_dev_list_i = st_dev_list + i;
1614                                                 st_dev_list_i->disp_part = TRUE;
1615                                         }
1616                                 }
1617                                 opt++;
1618                         }
1619                         else {
1620                                 flags |= I_D_PART_ALL;
1621                         }
1622                 }
1623
1624                 else if (!strcmp(argv[opt], "-g")) {
1625                         /*
1626                          * Option -g: Stats for a group of devices.
1627                          * group_name contains the last group name entered on
1628                          * the command line. If we define an additional one, save
1629                          * the previous one in the list. We do that this way because we
1630                          * want the group name to appear in the list _after_ all
1631                          * the devices included in that group. The last group name
1632                          * will be saved in the list later, in presave_device_list() function.
1633                          */
1634                         if (group_nr > 0) {
1635                                 update_dev_list(&dlist_idx, group_name);
1636                         }
1637                         if (argv[++opt]) {
1638                                 /*
1639                                  * MAX_NAME_LEN - 2: one char for the heading space,
1640                                  * and one for the trailing '\0'.
1641                                  */
1642                                 snprintf(group_name, MAX_NAME_LEN, " %-.*s", MAX_NAME_LEN - 2, argv[opt++]);
1643                         }
1644                         else {
1645                                 usage(argv[0]);
1646                         }
1647                         group_nr++;
1648                 }
1649
1650                 else if (!strcmp(argv[opt], "-j")) {
1651                         if (argv[++opt]) {
1652                                 if (strnlen(argv[opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1) {
1653                                         usage(argv[0]);
1654                                 }
1655                                 strncpy(persistent_name_type, argv[opt], MAX_FILE_LEN - 1);
1656                                 persistent_name_type[MAX_FILE_LEN - 1] = '\0';
1657                                 strtolower(persistent_name_type);
1658                                 /* Check that this is a valid type of persistent device name */
1659                                 if (!get_persistent_type_dir(persistent_name_type)) {
1660                                         fprintf(stderr, _("Invalid type of persistent device name\n"));
1661                                         exit(1);
1662                                 }
1663                                 /*
1664                                  * Persistent names are usually long: Display
1665                                  * them as human readable by default.
1666                                  */
1667                                 flags |= I_D_PERSIST_NAME + I_D_HUMAN_READ;
1668                                 opt++;
1669                         }
1670                         else {
1671                                 usage(argv[0]);
1672                         }
1673                 }
1674
1675                 else if (!strcmp(argv[opt], "-o")) {
1676                         /* Select output format */
1677                         if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
1678                                 flags |= I_D_JSON_OUTPUT;
1679                                 opt++;
1680                         }
1681                         else {
1682                                 usage(argv[0]);
1683                         }
1684                 }
1685
1686 #ifdef DEBUG
1687                 else if (!strcmp(argv[opt], "--debuginfo")) {
1688                         flags |= I_D_DEBUG;
1689                         opt++;
1690                 }
1691 #endif
1692
1693                 else if (!strncmp(argv[opt], "-", 1)) {
1694                         for (i = 1; *(argv[opt] + i); i++) {
1695
1696                                 switch (*(argv[opt] + i)) {
1697
1698                                 case 'c':
1699                                         /* Display cpu usage */
1700                                         flags |= I_D_CPU;
1701                                         report_set = TRUE;
1702                                         break;
1703
1704                                 case 'd':
1705                                         /* Display disk utilization */
1706                                         flags |= I_D_DISK;
1707                                         report_set = TRUE;
1708                                         break;
1709
1710                                 case 'H':
1711                                         /* Display stats only for the groups */
1712                                         flags |= I_D_GROUP_TOTAL_ONLY;
1713                                         break;
1714
1715                                 case 'h':
1716                                         /*
1717                                          * Display device utilization report
1718                                          * in a human readable format.
1719                                          */
1720                                         flags |= I_D_HUMAN_READ;
1721                                         break;
1722
1723                                 case 'k':
1724                                         if (DISPLAY_MEGABYTES(flags)) {
1725                                                 usage(argv[0]);
1726                                         }
1727                                         /* Display stats in kB/s */
1728                                         flags |= I_D_KILOBYTES;
1729                                         break;
1730
1731                                 case 'm':
1732                                         if (DISPLAY_KILOBYTES(flags)) {
1733                                                 usage(argv[0]);
1734                                         }
1735                                         /* Display stats in MB/s */
1736                                         flags |= I_D_MEGABYTES;
1737                                         break;
1738
1739                                 case 'N':
1740                                         /* Display device mapper logical name */
1741                                         flags |= I_D_DEVMAP_NAME;
1742                                         break;
1743
1744                                 case 'p':
1745                                         /* If option -p is grouped then it cannot take an arg */
1746                                         flags |= I_D_PARTITIONS + I_D_PART_ALL;
1747                                         break;
1748
1749                                 case 't':
1750                                         /* Display timestamp */
1751                                         flags |= I_D_TIMESTAMP;
1752                                         break;
1753
1754                                 case 'x':
1755                                         /* Display extended stats */
1756                                         flags |= I_D_EXTENDED;
1757                                         break;
1758
1759                                 case 'y':
1760                                         /* Don't display stats since system restart */
1761                                         flags |= I_D_OMIT_SINCE_BOOT;
1762                                         break;
1763
1764                                 case 'z':
1765                                         /* Omit output for devices with no activity */
1766                                         flags |= I_D_ZERO_OMIT;
1767                                         break;
1768
1769                                 case 'V':
1770                                         /* Print version number and exit */
1771                                         print_version();
1772                                         break;
1773
1774                                 default:
1775                                         usage(argv[0]);
1776                                 }
1777                         }
1778                         opt++;
1779                 }
1780
1781                 else if (!isdigit(argv[opt][0])) {
1782                         /*
1783                          * By default iostat doesn't display unused devices.
1784                          * If some devices are explicitly entered on the command line
1785                          * then don't apply this rule any more.
1786                          */
1787                         flags |= I_D_UNFILTERED;
1788
1789                         if (strcmp(argv[opt], K_ALL)) {
1790                                 /* Store device name entered on the command line */
1791                                 devname = device_name(argv[opt++]);
1792                                 if (DISPLAY_PERSIST_NAME_I(flags)) {
1793                                         persist_devname = get_pretty_name_from_persistent(devname);
1794                                         if (persist_devname != NULL) {
1795                                                 devname = persist_devname;
1796                                         }
1797                                 }
1798                                 update_dev_list(&dlist_idx, devname);
1799                         }
1800                         else {
1801                                 opt++;
1802                         }
1803                 }
1804
1805                 else if (!it) {
1806                         interval = atol(argv[opt++]);
1807                         if (interval < 0) {
1808                                 usage(argv[0]);
1809                         }
1810                         count = -1;
1811                         it = 1;
1812                 }
1813
1814                 else if (it > 0) {
1815                         count = atol(argv[opt++]);
1816                         if ((count < 1) || !interval) {
1817                                 usage(argv[0]);
1818                         }
1819                         it = -1;
1820                 }
1821                 else {
1822                         usage(argv[0]);
1823                 }
1824         }
1825
1826         if (!interval) {
1827                 count = 1;
1828         }
1829
1830         /* Default: Display CPU and DISK reports */
1831         if (!report_set) {
1832                 flags |= I_D_CPU + I_D_DISK;
1833         }
1834         /*
1835          * Also display DISK reports if options -p, -x or a device has been entered
1836          * on the command line.
1837          */
1838         if (DISPLAY_PARTITIONS(flags) || DISPLAY_EXTENDED(flags) ||
1839             DISPLAY_UNFILTERED(flags)) {
1840                 flags |= I_D_DISK;
1841         }
1842
1843         /* Option -T can only be used with option -g */
1844         if (DISPLAY_GROUP_TOTAL_ONLY(flags) && !group_nr) {
1845                 usage(argv[0]);
1846         }
1847
1848         /* Select disk output unit (kB/s or blocks/s) */
1849         set_disk_output_unit();
1850
1851         /* Ignore device list if '-p ALL' entered on the command line */
1852         if (DISPLAY_PART_ALL(flags)) {
1853                 dlist_idx = 0;
1854         }
1855
1856         if (DISPLAY_DEVMAP_NAME(flags)) {
1857                 dm_major = get_devmap_major();
1858         }
1859
1860         /* Init structures according to machine architecture */
1861         io_sys_init();
1862         if (group_nr > 0) {
1863                 /*
1864                  * If groups of devices have been defined
1865                  * then save devices and groups in the list.
1866                  */
1867                 presave_device_list();
1868         }
1869
1870         get_localtime(&rectime, 0);
1871
1872         /* Get system name, release number and hostname */
1873         uname(&header);
1874         if (print_gal_header(&rectime, header.sysname, header.release,
1875                              header.nodename, header.machine, cpu_nr,
1876                              DISPLAY_JSON_OUTPUT(flags))) {
1877                 flags |= I_D_ISO;
1878         }
1879         if (!DISPLAY_JSON_OUTPUT(flags)) {
1880                 printf("\n");
1881         }
1882
1883         /* Set a handler for SIGALRM */
1884         memset(&alrm_act, 0, sizeof(alrm_act));
1885         alrm_act.sa_handler = alarm_handler;
1886         sigaction(SIGALRM, &alrm_act, NULL);
1887         alarm(interval);
1888
1889         /* Main loop */
1890         rw_io_stat_loop(count, &rectime);
1891
1892         /* Free structures */
1893         io_sys_free();
1894         sfree_dev_list();
1895
1896         return 0;
1897 }