]> granicus.if.org Git - sysstat/blob - cifsiostat.c
cifsiostat: Fix compilation warning
[sysstat] / cifsiostat.c
1 /*
2  * cifsiostat: Report I/O statistics for CIFS filesystems.
3  * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved
4  * Written by Ivana Varekova <varekova@redhat.com>
5  *
6  ***************************************************************************
7  * This program is free software; you can redistribute it and/or modify it *
8  * under the terms of the GNU General Public License as published  by  the *
9  * Free Software Foundation; either version 2 of the License, or (at  your *
10  * option) any later version.                                              *
11  *                                                                         *
12  * This program is distributed in the hope that it  will  be  useful,  but *
13  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
14  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
15  * for more details.                                                       *
16  *                                                                         *
17  * You should have received a copy of the GNU General Public License along *
18  * with this program; if not, write to the Free Software Foundation, Inc., *
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                   *
20  ***************************************************************************
21  */
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <sys/utsname.h>
29 #include <ctype.h>
30
31 #include "version.h"
32 #include "cifsiostat.h"
33 #include "rd_stats.h"
34 #include "count.h"
35
36 #ifdef USE_NLS
37 #include <locale.h>
38 #include <libintl.h>
39 #define _(string) gettext(string)
40 #else
41 #define _(string) (string)
42 #endif
43
44 #ifdef USE_SCCSID
45 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
46 char *sccsid(void) { return (SCCSID); }
47 #endif
48
49 #ifdef TEST
50 void int_handler(int n) { return; }
51 #endif
52
53 unsigned long long uptime_cs[2] = {0, 0};
54 struct cifs_stats *st_cifs[2];
55 struct io_hdr_stats *st_hdr_cifs;
56
57 int cifs_nr = 0;        /* Nb of CIFS mounted directories found */
58 int cpu_nr = 0;         /* Nb of processors on the machine */
59 int flags = 0;          /* Flag for common options and system state */
60 int dplaces_nr = -1;    /* Number of decimal places */
61
62 long interval = 0;
63 char timestamp[TIMESTAMP_LEN];
64
65 struct sigaction alrm_act;
66
67 /*
68  ***************************************************************************
69  * Print usage and exit.
70  *
71  * IN:
72  * @progname    Name of sysstat command.
73  ***************************************************************************
74  */
75 void usage(char *progname)
76 {
77         fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
78                 progname);
79
80 #ifdef DEBUG
81         fprintf(stderr, _("Options are:\n"
82                           "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ]\n"));
83 #else
84         fprintf(stderr, _("Options are:\n"
85                           "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ -h ] [ -k | -m ] [ -t ] [ -V ]\n"));
86 #endif
87         exit(1);
88 }
89
90 /*
91  ***************************************************************************
92  * SIGALRM signal handler.
93  *
94  * IN:
95  * @sig Signal number.
96  ***************************************************************************
97  */
98 void alarm_handler(int sig)
99 {
100         alarm(interval);
101 }
102
103 /*
104  ***************************************************************************
105  * Find number of CIFS-mounted points that are registered in
106  * /proc/fs/cifs/Stats.
107  *
108  * RETURNS:
109  * Number of CIFS-mounted points.
110  ***************************************************************************
111  */
112 int get_cifs_nr(void)
113 {
114         FILE *fp;
115         char line[128];
116         int cifs = 0;
117
118         if ((fp = fopen(CIFSSTATS, "r")) == NULL)
119                 /* File non-existent */
120                 return 0;
121
122         while (fgets(line, sizeof(line), fp) != NULL) {
123
124                 if (!strncmp(line, "Share (unique mount targets): ", 30)) {
125                         sscanf(line + 30, "%d", &cifs);
126                         break;
127                 }
128         }
129
130         /* Close file */
131         fclose(fp);
132
133         return cifs;
134 }
135
136 /*
137  ***************************************************************************
138  * Set every cifs_io entry to inactive state (unregistered).
139  ***************************************************************************
140  */
141 void set_entries_inactive(void)
142 {
143         int i;
144         struct io_hdr_stats *shi = st_hdr_cifs;
145
146         for (i = 0; i < cifs_nr; i++, shi++) {
147                 shi->active = FALSE;
148         }
149 }
150
151 /*
152  ***************************************************************************
153  * Free inactive entries (mark them as unused).
154  ***************************************************************************
155  */
156 void free_inactive_entries(void)
157 {
158         int i;
159         struct io_hdr_stats *shi = st_hdr_cifs;
160
161         for (i = 0; i < cifs_nr; i++, shi++) {
162                 if (!shi->active) {
163                         shi->used = FALSE;
164                 }
165         }
166 }
167
168 /*
169  ***************************************************************************
170  * Allocate and init structures, according to system state.
171  ***************************************************************************
172  */
173 void io_sys_init(void)
174 {
175         int i;
176
177         /* How many processors on this machine? */
178         cpu_nr = get_cpu_nr(~0, FALSE);
179
180         /* Get number of CIFS directories in /proc/fs/cifs/Stats */
181         if ((cifs_nr = get_cifs_nr()) > 0) {
182                 cifs_nr += NR_CIFS_PREALLOC;
183         }
184
185         if (cifs_nr > 0) {
186                 if ((st_hdr_cifs = (struct io_hdr_stats *) calloc(cifs_nr, IO_HDR_STATS_SIZE)) == NULL) {
187                         perror("malloc");
188                         exit(4);
189                 }
190
191                 /* Allocate structures for number of CIFS directories found */
192                 for (i = 0; i < 2; i++) {
193                         if ((st_cifs[i] =
194                         (struct cifs_stats *) calloc(cifs_nr, CIFS_STATS_SIZE)) == NULL) {
195                                 perror("malloc");
196                                 exit(4);
197                         }
198                 }
199         }
200         else {
201                 /*
202                  * cifs_nr value is probably zero, but it can also be negative
203                  * (possible overflow when adding NR_CIFS_PREALLOC above).
204                  */
205                 cifs_nr = 0;
206         }
207 }
208
209 /*
210  ***************************************************************************
211  * Free various structures.
212  ***************************************************************************
213 */
214 void io_sys_free(void)
215 {
216         int i;
217
218         /* Free CIFS directories structures */
219         for (i = 0; i < 2; i++) {
220                 free(st_cifs[i]);
221         }
222
223         free(st_hdr_cifs);
224 }
225
226 /*
227  ***************************************************************************
228  * Save stats for current CIFS filesystem.
229  *
230  * IN:
231  * @name                Name of CIFS filesystem.
232  * @curr                Index in array for current sample statistics.
233  * @st_io               Structure with CIFS statistics to save.
234  ***************************************************************************
235  */
236 void save_stats(char *name, int curr, struct cifs_stats *st_io)
237 {
238         int i, j;
239         struct io_hdr_stats *st_hdr_cifs_i;
240         struct cifs_stats *st_cifs_i;
241
242         /* Look for CIFS directory in data table */
243         for (i = 0; i < cifs_nr; i++) {
244                 st_hdr_cifs_i = st_hdr_cifs + i;
245                 if ((st_hdr_cifs_i->used == TRUE) &&
246                     (!strcmp(st_hdr_cifs_i->name, name))) {
247                         break;
248                 }
249         }
250
251         if (i == cifs_nr) {
252                 /*
253                  * This is a new filesystem: Look for an unused entry to store it.
254                  */
255                 for (i = 0; i < cifs_nr; i++) {
256                         st_hdr_cifs_i = st_hdr_cifs + i;
257                         if (!st_hdr_cifs_i->used) {
258                                 /* Unused entry found... */
259                                 st_hdr_cifs_i->used = TRUE; /* Indicate it is now used */
260                                 st_hdr_cifs_i->active = TRUE;
261                                 strncpy(st_hdr_cifs_i->name, name, MAX_NAME_LEN - 1);
262                                 st_hdr_cifs_i->name[MAX_NAME_LEN - 1] = '\0';
263                                 st_cifs_i = st_cifs[curr] + i;
264                                 *st_cifs_i = *((struct cifs_stats *) st_io);
265                                 break;
266                         }
267                 }
268                 if (i == cifs_nr) {
269                         /*
270                          * It is a new CIFS directory
271                          * but there is no free structure to store it.
272                          */
273
274                         /* All entries are used: The number has to be increased */
275                         cifs_nr = cifs_nr + 5;
276
277                         /* Increase the size of st_hdr_ionfs buffer */
278                         if ((st_hdr_cifs = (struct io_hdr_stats *)
279                                 realloc(st_hdr_cifs, cifs_nr * IO_HDR_STATS_SIZE)) == NULL) {
280                                 perror("malloc");
281                                 exit(4);
282                         }
283
284                         /* Set the new entries inactive */
285                         for (j = 0; j < 5; j++) {
286                                 st_hdr_cifs_i = st_hdr_cifs + i + j;
287                                 st_hdr_cifs_i->used = FALSE;
288                                 st_hdr_cifs_i->active = FALSE;
289                         }
290
291                         /* Increase the size of st_hdr_ionfs buffer */
292                         for (j = 0; j < 2; j++) {
293                                 if ((st_cifs[j] = (struct cifs_stats *)
294                                         realloc(st_cifs[j], cifs_nr * CIFS_STATS_SIZE)) == NULL) {
295                                         perror("malloc");
296                                         exit(4);
297                                 }
298                                 memset(st_cifs[j] + i, 0, 5 * CIFS_STATS_SIZE);
299                         }
300                         /* Now i shows the first unused entry of the new block */
301                         st_hdr_cifs_i = st_hdr_cifs + i;
302                         st_hdr_cifs_i->used = TRUE; /* Indicate it is now used */
303                         st_hdr_cifs_i->active = TRUE;
304                         strncpy(st_hdr_cifs_i->name, name, MAX_NAME_LEN - 1);
305                         st_hdr_cifs_i->name[MAX_NAME_LEN - 1] = '\0';
306                         st_cifs_i = st_cifs[curr] + i;
307                         *st_cifs_i = *st_io;
308                 }
309         } else {
310                 st_hdr_cifs_i = st_hdr_cifs + i;
311                 st_hdr_cifs_i->active = TRUE;
312                 st_hdr_cifs_i->used = TRUE;
313                 st_cifs_i = st_cifs[curr] + i;
314                 *st_cifs_i = *st_io;
315         }
316         /*
317          * else it was a new CIFS directory
318          * but there was no free structure to store it.
319          */
320 }
321
322 /*
323  ***************************************************************************
324  * Read CIFS-mount directories stats from /proc/fs/cifs/Stats.
325  *
326  * IN:
327  * @curr        Index in array for current sample statistics.
328  ***************************************************************************
329  */
330 void read_cifs_stat(int curr)
331 {
332         FILE *fp;
333         char line[256];
334         char aux[32];
335         int start = 0;
336         long long unsigned aux_open;
337         long long unsigned all_open = 0;
338         char cifs_name[MAX_NAME_LEN];
339         char name_tmp[MAX_NAME_LEN];
340         struct cifs_stats scifs = {0, 0, 0, 0, 0, 0, 0};
341
342         /* Every CIFS entry is potentially unregistered */
343         set_entries_inactive();
344
345         if ((fp = fopen(CIFSSTATS, "r")) == NULL)
346                 return;
347
348         sprintf(aux, "%%*d) %%%ds",
349                 MAX_NAME_LEN < 200 ? MAX_NAME_LEN - 1 : 200);
350
351         while (fgets(line, sizeof(line), fp) != NULL) {
352
353                 /* Read CIFS directory name */
354                 if (isdigit((unsigned char) line[0]) && sscanf(line, aux , name_tmp) == 1) {
355                         if (start) {
356                                 scifs.fopens = all_open;
357                                 save_stats(cifs_name, curr, &scifs);
358                                 all_open = 0;
359                         }
360                         else {
361                                 start = 1;
362                         }
363                         strncpy(cifs_name, name_tmp, MAX_NAME_LEN);
364                         cifs_name[MAX_NAME_LEN - 1] = '\0';
365                         memset(&scifs, 0, sizeof(struct cifs_stats));
366                 }
367                 else {
368                         if (!strncmp(line, "Reads:", 6)) {
369                                 /*
370                                  * SMB1 format: Reads: %llu Bytes: %llu
371                                  * SMB2 format: Reads: %llu sent %llu failed
372                                  * If this is SMB2 format then only the first variable (rd_ops) will be set.
373                                  */
374                                 sscanf(line, "Reads: %llu Bytes: %llu", &scifs.rd_ops, &scifs.rd_bytes);
375                         }
376                         else if (!strncmp(line, "Bytes read:", 11)) {
377                                 sscanf(line, "Bytes read: %llu  Bytes written: %llu",
378                                        &scifs.rd_bytes, &scifs.wr_bytes);
379                         }
380                         else if (!strncmp(line, "Writes:", 7)) {
381                                 /*
382                                  * SMB1 format: Writes: %llu Bytes: %llu
383                                  * SMB2 format: Writes: %llu sent %llu failed
384                                  * If this is SMB2 format then only the first variable (wr_ops) will be set.
385                                  */
386                                 sscanf(line, "Writes: %llu Bytes: %llu", &scifs.wr_ops, &scifs.wr_bytes);
387                         }
388                         else if (!strncmp(line, "Opens:", 6)) {
389                                 sscanf(line, "Opens: %llu Closes:%llu Deletes: %llu",
390                                        &aux_open, &scifs.fcloses, &scifs.fdeletes);
391                                 all_open += aux_open;
392                         }
393                         else if (!strncmp(line, "Posix Opens:", 12)) {
394                                 sscanf(line, "Posix Opens: %llu", &aux_open);
395                                 all_open += aux_open;
396                         }
397                         else if (!strncmp(line, "Open files:", 11)) {
398                                 sscanf(line, "Open files: %llu total (local), %llu",
399                                        &all_open, &aux_open);
400                                 all_open += aux_open;
401                         }
402                         else if (!strncmp(line, "Closes:", 7)) {
403                                 sscanf(line, "Closes: %llu", &scifs.fcloses);
404                         }
405                 }
406         }
407
408         if (start) {
409                 scifs.fopens = all_open;
410                 save_stats(cifs_name, curr, &scifs);
411         }
412
413         fclose(fp);
414
415         /* Free structures corresponding to unregistered filesystems */
416         free_inactive_entries();
417 }
418
419 /*
420  ***************************************************************************
421  * Display CIFS stats header.
422  *
423  * OUT:
424  * @fctr        Conversion factor.
425  ***************************************************************************
426  */
427 void write_cifs_stat_header(int *fctr)
428 {
429         if (!DISPLAY_HUMAN_READ(flags)) {
430                 printf("Filesystem            ");
431         }
432         if (DISPLAY_KILOBYTES(flags)) {
433                 printf("        rkB/s        wkB/s");
434                 *fctr = 1024;
435         }
436         else if (DISPLAY_MEGABYTES(flags)) {
437                 printf("        rMB/s        wMB/s");
438                 *fctr = 1024 * 1024;
439         }
440         else {
441                 printf("         rB/s         wB/s");
442                 *fctr = 1;
443         }
444         printf("    rops/s    wops/s         fo/s         fc/s         fd/s");
445         if (DISPLAY_HUMAN_READ(flags)) {
446                 printf(" Filesystem");
447         }
448         printf("\n");
449 }
450
451 /*
452  ***************************************************************************
453  * Write CIFS stats read from /proc/fs/cifs/Stats.
454  *
455  * IN:
456  * @curr        Index in array for current sample statistics.
457  * @itv         Interval of time (in 1/100th of a second).
458  * @fctr        Conversion factor.
459  * @shi         Structures describing the CIFS filesystems.
460  * @ioi         Current sample statistics.
461  * @ioj         Previous sample statistics.
462  ***************************************************************************
463  */
464 void write_cifs_stat(int curr, unsigned long long itv, int fctr,
465                      struct io_hdr_stats *shi, struct cifs_stats *ioni,
466                      struct cifs_stats *ionj)
467 {
468         double rbytes, wbytes;
469
470         if (!DISPLAY_HUMAN_READ(flags)) {
471                 cprintf_in(IS_STR, "%-22s", shi->name, 0);
472         }
473
474         /*       rB/s   wB/s   fo/s   fc/s   fd/s*/
475         rbytes = S_VALUE(ionj->rd_bytes, ioni->rd_bytes, itv);
476         wbytes = S_VALUE(ionj->wr_bytes, ioni->wr_bytes, itv);
477         if (!DISPLAY_UNIT(flags)) {
478                 rbytes /= fctr;
479                 wbytes /= fctr;
480         }
481         cprintf_f(DISPLAY_UNIT(flags) ? UNIT_BYTE : NO_UNIT, 2, 12, 2,
482                   rbytes, wbytes);
483         cprintf_f(NO_UNIT, 2, 9, 2,
484                   S_VALUE(ionj->rd_ops, ioni->rd_ops, itv),
485                   S_VALUE(ionj->wr_ops, ioni->wr_ops, itv));
486         cprintf_f(NO_UNIT, 3, 12, 2,
487                   S_VALUE(ionj->fopens, ioni->fopens, itv),
488                   S_VALUE(ionj->fcloses, ioni->fcloses, itv),
489                   S_VALUE(ionj->fdeletes, ioni->fdeletes, itv));
490         if (DISPLAY_HUMAN_READ(flags)) {
491                 cprintf_in(IS_STR, " %s", shi->name, 0);
492         }
493         printf("\n");
494 }
495
496 /*
497  ***************************************************************************
498  * Print everything now (stats and uptime).
499  *
500  * IN:
501  * @curr        Index in array for current sample statistics.
502  * @rectime     Current date and time.
503  ***************************************************************************
504  */
505 void write_stats(int curr, struct tm *rectime)
506 {
507         int i, fctr = 1;
508         unsigned long long itv;
509         struct io_hdr_stats *shi;
510         struct cifs_stats *ioni, *ionj;
511
512         /* Test stdout */
513         TEST_STDOUT(STDOUT_FILENO);
514
515         /* Print time stamp */
516         if (DISPLAY_TIMESTAMP(flags)) {
517                 if (DISPLAY_ISO(flags)) {
518                         strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime);
519                 }
520                 else {
521                         strftime(timestamp, sizeof(timestamp), "%x %X", rectime);
522                 }
523                 printf("%s\n", timestamp);
524 #ifdef DEBUG
525                 if (DISPLAY_DEBUG(flags)) {
526                         fprintf(stderr, "%s\n", timestamp);
527                 }
528 #endif
529         }
530
531         /* Interval of time, reduced to one processor */
532         itv = get_interval(uptime_cs[!curr], uptime_cs[curr]);
533
534         shi = st_hdr_cifs;
535
536         /* Display CIFS stats header */
537         write_cifs_stat_header(&fctr);
538
539         for (i = 0; i < cifs_nr; i++, shi++) {
540                 if (shi->used) {
541                         ioni = st_cifs[curr]  + i;
542                         ionj = st_cifs[!curr] + i;
543 #ifdef DEBUG
544                         if (DISPLAY_DEBUG(flags)) {
545                                 /* Debug output */
546                                 fprintf(stderr, "name=%s itv=%llu fctr=%d ioni{ rd_bytes=%llu "
547                                                 "wr_bytes=%llu rd_ops=%llu wr_ops=%llu fopens=%llu "
548                                                 "fcloses=%llu fdeletes=%llu}\n",
549                                         shi->name, itv, fctr,
550                                         ioni->rd_bytes, ioni->wr_bytes,
551                                         ioni->rd_ops,   ioni->wr_ops,
552                                         ioni->fopens,   ioni->fcloses,
553                                         ioni->fdeletes);
554                         }
555 #endif
556                         write_cifs_stat(curr, itv, fctr, shi, ioni, ionj);
557                 }
558         }
559         printf("\n");
560 }
561
562 /*
563  ***************************************************************************
564  * Main loop: Read stats from the relevant sources and display them.
565  *
566  * IN:
567  * @count       Number of lines of stats to print.
568  * @rectime     Current date and time.
569  ***************************************************************************
570  */
571 void rw_io_stat_loop(long int count, struct tm *rectime)
572 {
573         int curr = 1;
574
575         /* Don't buffer data if redirected to a pipe */
576         setbuf(stdout, NULL);
577
578         do {
579                 /* Read system uptime in 1/100th of a second */
580                 read_uptime(&(uptime_cs[curr]));
581
582                 /* Read CIFS stats */
583                 read_cifs_stat(curr);
584
585                 /* Get time */
586                 get_localtime(rectime, 0);
587
588                 /* Print results */
589                 write_stats(curr, rectime);
590
591                 if (count > 0) {
592                         count--;
593                 }
594
595                 if (count) {
596                         curr ^= 1;
597                         __pause();
598                 }
599         }
600         while (count);
601 }
602
603 /*
604  ***************************************************************************
605  * Main entry to the cifsiostat program.
606  ***************************************************************************
607  */
608 int main(int argc, char **argv)
609 {
610         int it = 0;
611         int opt = 1;
612         int i;
613         long count = 1;
614         struct utsname header;
615         struct tm rectime;
616
617 #ifdef USE_NLS
618         /* Init National Language Support */
619         init_nls();
620 #endif
621
622         /* Init color strings */
623         init_colors();
624
625         /* Process args... */
626         while (opt < argc) {
627
628 #ifdef DEBUG
629                 if (!strcmp(argv[opt], "--debuginfo")) {
630                         flags |= I_D_DEBUG;
631                         opt++;
632                 } else
633 #endif
634
635                 if (!strcmp(argv[opt], "--human")) {
636                         flags |= I_D_UNIT;
637                         opt++;
638                 }
639
640                 else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
641                         /* Get number of decimal places */
642                         dplaces_nr = atoi(argv[opt] + 6);
643                         if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
644                                 usage(argv[0]);
645                         }
646                         opt++;
647                 }
648
649                 else if (!strncmp(argv[opt], "-", 1)) {
650                         for (i = 1; *(argv[opt] + i); i++) {
651
652                                 switch (*(argv[opt] + i)) {
653
654                                 case 'h':
655                                         /* Display an easy-to-read CIFS report. Also imply --human */
656                                         flags |= I_D_HUMAN_READ + I_D_UNIT;
657                                         break;
658
659                                 case 'k':
660                                         if (DISPLAY_MEGABYTES(flags)) {
661                                                 usage(argv[0]);
662                                         }
663                                         /* Display stats in kB/s */
664                                         flags |= I_D_KILOBYTES;
665                                         break;
666
667                                 case 'm':
668                                         if (DISPLAY_KILOBYTES(flags)) {
669                                                 usage(argv[0]);
670                                         }
671                                         /* Display stats in MB/s */
672                                         flags |= I_D_MEGABYTES;
673                                         break;
674
675                                 case 't':
676                                         /* Display timestamp */
677                                         flags |= I_D_TIMESTAMP;
678                                         break;
679
680                                 case 'V':
681                                         /* Print version number and exit */
682                                         print_version();
683                                         break;
684
685                                 default:
686                                         usage(argv[0]);
687                                 }
688                         }
689                         opt++;
690                 }
691
692                 else if (!it) {
693                         interval = atol(argv[opt++]);
694                         if (interval < 0) {
695                                 usage(argv[0]);
696                         }
697                         count = -1;
698                         it = 1;
699                 }
700
701                 else if (it > 0) {
702                         count = atol(argv[opt++]);
703                         if ((count < 1) || !interval) {
704                                 usage(argv[0]);
705                         }
706                         it = -1;
707                 }
708                 else {
709                         usage(argv[0]);
710                 }
711         }
712
713         if (!interval) {
714                 count = 1;
715         }
716
717         /* Init structures according to machine architecture */
718         io_sys_init();
719
720         get_localtime(&rectime, 0);
721
722         /* Get system name, release number and hostname */
723         __uname(&header);
724         if (print_gal_header(&rectime, header.sysname, header.release,
725                              header.nodename, header.machine, cpu_nr,
726                              PLAIN_OUTPUT)) {
727                 flags |= I_D_ISO;
728         }
729         printf("\n");
730
731         /* Set a handler for SIGALRM */
732         memset(&alrm_act, 0, sizeof(alrm_act));
733         alrm_act.sa_handler = alarm_handler;
734         sigaction(SIGALRM, &alrm_act, NULL);
735         alarm(interval);
736
737         /* Main loop */
738         rw_io_stat_loop(count, &rectime);
739
740         /* Free structures */
741         io_sys_free();
742
743         return 0;
744 }