"Fossies" - the Fresh Open Source Software Archive

Member "sysstat-12.4.1/cifsiostat.c" (31 Oct 2020, 15800 Bytes) of package /linux/misc/sysstat-12.4.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cifsiostat.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 12.4.0_vs_12.4.1.

    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 io_cifs *cifs_list = NULL;
   55 
   56 int cpu_nr = 0;     /* Nb of processors on the machine */
   57 int flags = 0;      /* Flag for common options and system state */
   58 int dplaces_nr = -1;    /* Number of decimal places */
   59 
   60 long interval = 0;
   61 char timestamp[TIMESTAMP_LEN];
   62 
   63 struct sigaction alrm_act;
   64 
   65 /*
   66  ***************************************************************************
   67  * Print usage and exit.
   68  *
   69  * IN:
   70  * @progname    Name of sysstat command.
   71  ***************************************************************************
   72  */
   73 void usage(char *progname)
   74 {
   75     fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
   76         progname);
   77 
   78 #ifdef DEBUG
   79     fprintf(stderr, _("Options are:\n"
   80               "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ]\n"
   81               "[ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ]\n"));
   82 #else
   83     fprintf(stderr, _("Options are:\n"
   84               "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ]\n"
   85               "[ -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  * Set every cifs entry to nonexistent status.
  106  *
  107  * IN:
  108  * @clist   Pointer on the start of the linked list.
  109  ***************************************************************************
  110  */
  111 void set_cifs_nonexistent(struct io_cifs *clist)
  112 {
  113     while (clist != NULL) {
  114         clist->exist = FALSE;
  115         clist = clist->next;
  116     }
  117 }
  118 
  119 /*
  120  ***************************************************************************
  121  * Check if a cifs filesystem is present in the list, and add it if requested.
  122  *
  123  * IN:
  124  * @clist   Address of pointer on the start of the linked list.
  125  * @name    cifs name.
  126  *
  127  * RETURNS:
  128  * Pointer on the io_cifs structure in the list where the cifs is located
  129  * (whether it was already in the list or if it has been added).
  130  * NULL if the cifs name is too long or if the cifs doesn't exist and we
  131  * don't want to add it.
  132  ***************************************************************************
  133  */
  134 struct io_cifs *add_list_cifs(struct io_cifs **clist, char *name)
  135 {
  136     struct io_cifs *c, *cs;
  137     int i;
  138 
  139     if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN)
  140         /* cifs name is too long */
  141         return NULL;
  142 
  143     while (*clist != NULL) {
  144         c = *clist;
  145         if ((i = strcmp(c->name, name)) == 0) {
  146             /* cifs found in list */
  147             c->exist = TRUE;
  148             return c;
  149         }
  150         if (i > 0)
  151             /*
  152              * If no group defined and we don't use /proc/diskstats,
  153              * insert current device in alphabetical order.
  154              * NB: Using /proc/diskstats ("iostat -p ALL") is a bit better than
  155              * using alphabetical order because sda10 comes after sda9...
  156              */
  157             break;
  158 
  159         clist = &(c->next);
  160     }
  161 
  162     /* cifs not found */
  163     cs = *clist;
  164 
  165     /* Add cifs to the list */
  166     if ((*clist = (struct io_cifs *) malloc(IO_CIFS_SIZE)) == NULL) {
  167         perror("malloc");
  168         exit(4);
  169     }
  170     memset(*clist, 0, IO_CIFS_SIZE);
  171 
  172     c = *clist;
  173     for (i = 0; i < 2; i++) {
  174         if ((c->cifs_stats[i] = (struct cifs_st *) malloc(CIFS_ST_SIZE)) == NULL) {
  175             perror("malloc");
  176             exit(4);
  177         }
  178         memset(c->cifs_stats[i], 0, CIFS_ST_SIZE);
  179     }
  180     strncpy(c->name, name, sizeof(c->name));
  181     c->name[sizeof(c->name) - 1] = '\0';
  182     c->exist = TRUE;
  183     c->next = cs;
  184 
  185     return c;
  186 }
  187 
  188 /*
  189  ***************************************************************************
  190  * Read CIFS-mount directories stats from /proc/fs/cifs/Stats.
  191  *
  192  * IN:
  193  * @curr    Index in array for current sample statistics.
  194  ***************************************************************************
  195  */
  196 void read_cifs_stat(int curr)
  197 {
  198     FILE *fp;
  199     char line[256];
  200     char aux[32];
  201     int start = 0;
  202     long long unsigned aux_open;
  203     long long unsigned all_open = 0;
  204     char cifs_name[MAX_NAME_LEN];
  205     char name_tmp[MAX_NAME_LEN];
  206     struct cifs_st scifs;
  207     struct io_cifs *ci;
  208 
  209     if ((fp = fopen(CIFSSTATS, "r")) == NULL)
  210         return;
  211 
  212     sprintf(aux, "%%*d) %%%ds",
  213         MAX_NAME_LEN < 200 ? MAX_NAME_LEN - 1 : 200);
  214 
  215     memset(&scifs, 0, CIFS_ST_SIZE);
  216 
  217     while (fgets(line, sizeof(line), fp) != NULL) {
  218 
  219         /* Read CIFS directory name */
  220         if (isdigit((unsigned char) line[0]) && sscanf(line, aux , name_tmp) == 1) {
  221             if (start) {
  222                 scifs.fopens = all_open;
  223                 ci = add_list_cifs(&cifs_list, cifs_name);
  224                 if (ci != NULL) {
  225                     *ci->cifs_stats[curr] = scifs;
  226                 }
  227                 all_open = 0;
  228             }
  229             else {
  230                 start = 1;
  231             }
  232             strncpy(cifs_name, name_tmp, sizeof(cifs_name));
  233             cifs_name[sizeof(cifs_name) - 1] = '\0';
  234             memset(&scifs, 0, CIFS_ST_SIZE);
  235         }
  236         else {
  237             if (!strncmp(line, "Reads:", 6)) {
  238                 /*
  239                  * SMB1 format: Reads: %llu Bytes: %llu
  240                  * SMB2 format: Reads: %llu sent %llu failed
  241                  * If this is SMB2 format then only the first variable (rd_ops) will be set.
  242                  */
  243                 sscanf(line, "Reads: %llu Bytes: %llu", &scifs.rd_ops, &scifs.rd_bytes);
  244             }
  245             else if (!strncmp(line, "Bytes read:", 11)) {
  246                 sscanf(line, "Bytes read: %llu  Bytes written: %llu",
  247                        &scifs.rd_bytes, &scifs.wr_bytes);
  248             }
  249             else if (!strncmp(line, "Writes:", 7)) {
  250                 /*
  251                  * SMB1 format: Writes: %llu Bytes: %llu
  252                  * SMB2 format: Writes: %llu sent %llu failed
  253                  * If this is SMB2 format then only the first variable (wr_ops) will be set.
  254                  */
  255                 sscanf(line, "Writes: %llu Bytes: %llu", &scifs.wr_ops, &scifs.wr_bytes);
  256             }
  257             else if (!strncmp(line, "Opens:", 6)) {
  258                 sscanf(line, "Opens: %llu Closes:%llu Deletes: %llu",
  259                        &aux_open, &scifs.fcloses, &scifs.fdeletes);
  260                 all_open += aux_open;
  261             }
  262             else if (!strncmp(line, "Posix Opens:", 12)) {
  263                 sscanf(line, "Posix Opens: %llu", &aux_open);
  264                 all_open += aux_open;
  265             }
  266             else if (!strncmp(line, "Open files:", 11)) {
  267                 sscanf(line, "Open files: %llu total (local), %llu",
  268                        &all_open, &aux_open);
  269                 all_open += aux_open;
  270             }
  271             else if (!strncmp(line, "Closes:", 7)) {
  272                 sscanf(line, "Closes: %llu", &scifs.fcloses);
  273             }
  274         }
  275     }
  276 
  277     if (start) {
  278         scifs.fopens = all_open;
  279         ci = add_list_cifs(&cifs_list, cifs_name);
  280         if (ci != NULL) {
  281             *ci->cifs_stats[curr] = scifs;
  282         }
  283     }
  284 
  285     fclose(fp);
  286 }
  287 
  288 /*
  289  ***************************************************************************
  290  * Display CIFS stats header.
  291  *
  292  * OUT:
  293  * @fctr    Conversion factor.
  294  ***************************************************************************
  295  */
  296 void write_cifs_stat_header(int *fctr)
  297 {
  298     if (!DISPLAY_PRETTY(flags)) {
  299         printf("Filesystem            ");
  300     }
  301     if (DISPLAY_KILOBYTES(flags)) {
  302         printf("        rkB/s        wkB/s");
  303         *fctr = 1024;
  304     }
  305     else if (DISPLAY_MEGABYTES(flags)) {
  306         printf("        rMB/s        wMB/s");
  307         *fctr = 1024 * 1024;
  308     }
  309     else {
  310         printf("         rB/s         wB/s");
  311         *fctr = 1;
  312     }
  313     printf("    rops/s    wops/s         fo/s         fc/s         fd/s");
  314     if (DISPLAY_PRETTY(flags)) {
  315         printf(" Filesystem");
  316     }
  317     printf("\n");
  318 }
  319 
  320 /*
  321  ***************************************************************************
  322  * Write CIFS stats read from /proc/fs/cifs/Stats.
  323  *
  324  * IN:
  325  * @curr    Index in array for current sample statistics.
  326  * @itv     Interval of time (in 1/100th of a second).
  327  * @fctr    Conversion factor.
  328  * @clist   Pointer on the linked list where the cifs is saved.
  329  * @ioi     Current sample statistics.
  330  * @ioj     Previous sample statistics.
  331  ***************************************************************************
  332  */
  333 void write_cifs_stat(int curr, unsigned long long itv, int fctr,
  334              struct io_cifs *clist, struct cifs_st *ioni,
  335              struct cifs_st *ionj)
  336 {
  337     double rbytes, wbytes;
  338 
  339     if (!DISPLAY_PRETTY(flags)) {
  340         cprintf_in(IS_STR, "%-22s", clist->name, 0);
  341     }
  342 
  343     /*       rB/s   wB/s   fo/s   fc/s   fd/s*/
  344     rbytes = S_VALUE(ionj->rd_bytes, ioni->rd_bytes, itv);
  345     wbytes = S_VALUE(ionj->wr_bytes, ioni->wr_bytes, itv);
  346     if (!DISPLAY_UNIT(flags)) {
  347         rbytes /= fctr;
  348         wbytes /= fctr;
  349     }
  350     cprintf_f(DISPLAY_UNIT(flags) ? UNIT_BYTE : NO_UNIT, 2, 12, 2,
  351           rbytes, wbytes);
  352     cprintf_f(NO_UNIT, 2, 9, 2,
  353           S_VALUE(ionj->rd_ops, ioni->rd_ops, itv),
  354           S_VALUE(ionj->wr_ops, ioni->wr_ops, itv));
  355     cprintf_f(NO_UNIT, 3, 12, 2,
  356           S_VALUE(ionj->fopens, ioni->fopens, itv),
  357           S_VALUE(ionj->fcloses, ioni->fcloses, itv),
  358           S_VALUE(ionj->fdeletes, ioni->fdeletes, itv));
  359     if (DISPLAY_PRETTY(flags)) {
  360         cprintf_in(IS_STR, " %s", clist->name, 0);
  361     }
  362     printf("\n");
  363 }
  364 
  365 /*
  366  ***************************************************************************
  367  * Print everything now (stats and uptime).
  368  *
  369  * IN:
  370  * @curr    Index in array for current sample statistics.
  371  * @rectime Current date and time.
  372  ***************************************************************************
  373  */
  374 void write_stats(int curr, struct tm *rectime)
  375 {
  376     int fctr = 1;
  377     unsigned long long itv;
  378     struct io_cifs *clist;
  379     struct cifs_st *ioni, *ionj;
  380 
  381     /* Test stdout */
  382     TEST_STDOUT(STDOUT_FILENO);
  383 
  384     /* Print time stamp */
  385     if (DISPLAY_TIMESTAMP(flags)) {
  386         if (DISPLAY_ISO(flags)) {
  387             strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime);
  388         }
  389         else {
  390             strftime(timestamp, sizeof(timestamp), "%x %X", rectime);
  391         }
  392         printf("%s\n", timestamp);
  393 #ifdef DEBUG
  394         if (DISPLAY_DEBUG(flags)) {
  395             fprintf(stderr, "%s\n", timestamp);
  396         }
  397 #endif
  398     }
  399 
  400     /* Interval of time, reduced to one processor */
  401     itv = get_interval(uptime_cs[!curr], uptime_cs[curr]);
  402 
  403     /* Display CIFS stats header */
  404     write_cifs_stat_header(&fctr);
  405 
  406     for (clist = cifs_list; clist != NULL; clist = clist->next) {
  407 
  408         if (!clist->exist)
  409             /* Current cifs non existent */
  410             continue;
  411 
  412         ioni = clist->cifs_stats[curr];
  413         ionj = clist->cifs_stats[!curr];
  414 
  415 #ifdef DEBUG
  416         if (DISPLAY_DEBUG(flags)) {
  417             /* Debug output */
  418             fprintf(stderr, "name=%s itv=%llu fctr=%d ioni{ rd_bytes=%llu "
  419                     "wr_bytes=%llu rd_ops=%llu wr_ops=%llu fopens=%llu "
  420                     "fcloses=%llu fdeletes=%llu}\n",
  421                 clist->name, itv, fctr,
  422                 ioni->rd_bytes, ioni->wr_bytes,
  423                 ioni->rd_ops,   ioni->wr_ops,
  424                 ioni->fopens,   ioni->fcloses,
  425                 ioni->fdeletes);
  426         }
  427 #endif
  428         write_cifs_stat(curr, itv, fctr, clist, ioni, ionj);
  429     }
  430     printf("\n");
  431 }
  432 
  433 /*
  434  ***************************************************************************
  435  * Main loop: Read stats from the relevant sources and display them.
  436  *
  437  * IN:
  438  * @count   Number of lines of stats to print.
  439  * @rectime Current date and time.
  440  ***************************************************************************
  441  */
  442 void rw_io_stat_loop(long int count, struct tm *rectime)
  443 {
  444     int curr = 1;
  445 
  446     /* Set a handler for SIGALRM */
  447     memset(&alrm_act, 0, sizeof(alrm_act));
  448     alrm_act.sa_handler = alarm_handler;
  449     sigaction(SIGALRM, &alrm_act, NULL);
  450     alarm(interval);
  451 
  452     do {
  453         /* Every device is potentially nonexistent */
  454         set_cifs_nonexistent(cifs_list);
  455 
  456         /* Read system uptime in 1/100th of a second */
  457         read_uptime(&(uptime_cs[curr]));
  458 
  459         /* Read CIFS stats */
  460         read_cifs_stat(curr);
  461 
  462         /* Get time */
  463         get_localtime(rectime, 0);
  464 
  465         /* Print results */
  466         write_stats(curr, rectime);
  467 
  468         if (count > 0) {
  469             count--;
  470         }
  471 
  472         if (count) {
  473             curr ^= 1;
  474             __pause();
  475         }
  476     }
  477     while (count);
  478 }
  479 
  480 /*
  481  ***************************************************************************
  482  * Main entry to the cifsiostat program.
  483  ***************************************************************************
  484  */
  485 int main(int argc, char **argv)
  486 {
  487     int it = 0;
  488     int opt = 1;
  489     int i;
  490     long count = 1;
  491     struct utsname header;
  492     struct tm rectime;
  493 
  494 #ifdef USE_NLS
  495     /* Init National Language Support */
  496     init_nls();
  497 #endif
  498 
  499     /* Init color strings */
  500     init_colors();
  501 
  502     /* Process args... */
  503     while (opt < argc) {
  504 
  505 #ifdef DEBUG
  506         if (!strcmp(argv[opt], "--debuginfo")) {
  507             flags |= I_D_DEBUG;
  508             opt++;
  509         } else
  510 #endif
  511 
  512         if (!strcmp(argv[opt], "--human")) {
  513             flags |= I_D_UNIT;
  514             opt++;
  515         }
  516 
  517         else if (!strcmp(argv[opt], "--pretty")) {
  518             /* Display an easy-to-read CIFS report */
  519             flags |= I_D_PRETTY;
  520             opt++;
  521         }
  522 
  523         else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
  524             /* Get number of decimal places */
  525             dplaces_nr = atoi(argv[opt] + 6);
  526             if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
  527                 usage(argv[0]);
  528             }
  529             opt++;
  530         }
  531 
  532         else if (!strncmp(argv[opt], "-", 1)) {
  533             for (i = 1; *(argv[opt] + i); i++) {
  534 
  535                 switch (*(argv[opt] + i)) {
  536 
  537                 case 'h':
  538                     /* Option -h is equivalent to --pretty --human */
  539                     flags |= I_D_PRETTY + I_D_UNIT;
  540                     break;
  541 
  542                 case 'k':
  543                     if (DISPLAY_MEGABYTES(flags)) {
  544                         usage(argv[0]);
  545                     }
  546                     /* Display stats in kB/s */
  547                     flags |= I_D_KILOBYTES;
  548                     break;
  549 
  550                 case 'm':
  551                     if (DISPLAY_KILOBYTES(flags)) {
  552                         usage(argv[0]);
  553                     }
  554                     /* Display stats in MB/s */
  555                     flags |= I_D_MEGABYTES;
  556                     break;
  557 
  558                 case 't':
  559                     /* Display timestamp */
  560                     flags |= I_D_TIMESTAMP;
  561                     break;
  562 
  563                 case 'V':
  564                     /* Print version number and exit */
  565                     print_version();
  566                     break;
  567 
  568                 default:
  569                     usage(argv[0]);
  570                 }
  571             }
  572             opt++;
  573         }
  574 
  575         else if (!it) {
  576             interval = atol(argv[opt++]);
  577             if (interval < 0) {
  578                 usage(argv[0]);
  579             }
  580             count = -1;
  581             it = 1;
  582         }
  583 
  584         else if (it > 0) {
  585             count = atol(argv[opt++]);
  586             if ((count < 1) || !interval) {
  587                 usage(argv[0]);
  588             }
  589             it = -1;
  590         }
  591         else {
  592             usage(argv[0]);
  593         }
  594     }
  595 
  596     if (!interval) {
  597         count = 1;
  598     }
  599 
  600     /* How many processors on this machine? */
  601     cpu_nr = get_cpu_nr(~0, FALSE);
  602 
  603     get_localtime(&rectime, 0);
  604 
  605     /*
  606      * Don't buffer data if redirected to a pipe.
  607      * Note: With musl-c, the behavior of this function is undefined except
  608      * when it is the first operation on the stream.
  609      */
  610     setbuf(stdout, NULL);
  611 
  612     /* Get system name, release number and hostname */
  613     __uname(&header);
  614     if (print_gal_header(&rectime, header.sysname, header.release,
  615                  header.nodename, header.machine, cpu_nr,
  616                  PLAIN_OUTPUT)) {
  617         flags |= I_D_ISO;
  618     }
  619     printf("\n");
  620 
  621     /* Main loop */
  622     rw_io_stat_loop(count, &rectime);
  623 
  624     return 0;
  625 }