X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=cifsiostat.c;h=52e9cabd8516944b3eb3c837f18379935ad56289;hb=5781102b0d3f6d118ef30389fa46933dc00dabd5;hp=a3c81d00fef3860725bfb722eaef8959ce8b06e5;hpb=83313c003f8569c3df3c736175b2f5e0ca4c31f5;p=sysstat diff --git a/cifsiostat.c b/cifsiostat.c index a3c81d0..52e9cab 100644 --- a/cifsiostat.c +++ b/cifsiostat.c @@ -30,8 +30,8 @@ #include "version.h" #include "cifsiostat.h" +#include "rd_stats.h" #include "count.h" -#include "common.h" #ifdef USE_NLS #include @@ -41,16 +41,21 @@ #define _(string) (string) #endif +#ifdef USE_SCCSID #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__ char *sccsid(void) { return (SCCSID); } +#endif + +#ifdef TEST +void int_handler(int n) { return; } +#endif -unsigned long long uptime0[2] = {0, 0}; -struct cifs_stats *st_cifs[2]; -struct io_hdr_stats *st_hdr_cifs; +unsigned long long uptime_cs[2] = {0, 0}; +struct io_cifs *cifs_list = NULL; -int cifs_nr = 0; /* Nb of CIFS mounted directories found */ int cpu_nr = 0; /* Nb of processors on the machine */ int flags = 0; /* Flag for common options and system state */ +int dplaces_nr = -1; /* Number of decimal places */ long interval = 0; char timestamp[TIMESTAMP_LEN]; @@ -72,10 +77,12 @@ void usage(char *progname) #ifdef DEBUG fprintf(stderr, _("Options are:\n" - "[ --human ] [ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ]\n")); + "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ]\n" + "[ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ]\n")); #else fprintf(stderr, _("Options are:\n" - "[ --human ] [ -h ] [ -k | -m ] [ -t ] [ -V ]\n")); + "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ]\n" + "[ -h ] [ -k | -m ] [ -t ] [ -V ]\n")); #endif exit(1); } @@ -95,221 +102,87 @@ void alarm_handler(int sig) /* *************************************************************************** - * Find number of CIFS-mounted points that are registered in - * /proc/fs/cifs/Stats. + * Set every cifs entry to nonexistent status. * - * RETURNS: - * Number of CIFS-mounted points. + * IN: + * @clist Pointer on the start of the linked list. *************************************************************************** */ -int get_cifs_nr(void) +void set_cifs_nonexistent(struct io_cifs *clist) { - FILE *fp; - char line[128]; - int cifs = 0; - - if ((fp = fopen(CIFSSTATS, "r")) == NULL) - /* File non-existent */ - return 0; - - while (fgets(line, sizeof(line), fp) != NULL) { - - if (!strncmp(line, "Share (unique mount targets): ", 30)) { - sscanf(line + 30, "%d", &cifs); - break; - } + while (clist != NULL) { + clist->exist = FALSE; + clist = clist->next; } - - /* Close file */ - fclose(fp); - - return cifs; } /* *************************************************************************** - * Set every cifs_io entry to inactive state (unregistered). + * Check if a cifs filesystem is present in the list, and add it if requested. + * + * IN: + * @clist Address of pointer on the start of the linked list. + * @name cifs name. + * + * RETURNS: + * Pointer on the io_cifs structure in the list where the cifs is located + * (whether it was already in the list or if it has been added). + * NULL if the cifs name is too long or if the cifs doesn't exist and we + * don't want to add it. *************************************************************************** */ -void set_entries_inactive(void) +struct io_cifs *add_list_cifs(struct io_cifs **clist, char *name) { + struct io_cifs *c, *cs; int i; - struct io_hdr_stats *shi = st_hdr_cifs; - for (i = 0; i < cifs_nr; i++, shi++) { - shi->active = FALSE; - } -} + if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) + /* cifs name is too long */ + return NULL; -/* - *************************************************************************** - * Free inactive entries (mark them as unused). - *************************************************************************** - */ -void free_inactive_entries(void) -{ - int i; - struct io_hdr_stats *shi = st_hdr_cifs; - - for (i = 0; i < cifs_nr; i++, shi++) { - if (!shi->active) { - shi->used = FALSE; + while (*clist != NULL) { + c = *clist; + if ((i = strcmp(c->name, name)) == 0) { + /* cifs found in list */ + c->exist = TRUE; + return c; } - } -} - -/* - *************************************************************************** - * Allocate and init structures, according to system state. - *************************************************************************** - */ -void io_sys_init(void) -{ - int i; - - /* How many processors on this machine? */ - cpu_nr = get_cpu_nr(~0, FALSE); + if (i > 0) + /* + * If no group defined and we don't use /proc/diskstats, + * insert current device in alphabetical order. + * NB: Using /proc/diskstats ("iostat -p ALL") is a bit better than + * using alphabetical order because sda10 comes after sda9... + */ + break; - /* Get number of CIFS directories in /proc/fs/cifs/Stats */ - if ((cifs_nr = get_cifs_nr()) > 0) { - cifs_nr += NR_CIFS_PREALLOC; + clist = &(c->next); } - if (cifs_nr > 0) { - if ((st_hdr_cifs = (struct io_hdr_stats *) calloc(cifs_nr, IO_HDR_STATS_SIZE)) == NULL) { - perror("malloc"); - exit(4); - } + /* cifs not found */ + cs = *clist; - /* Allocate structures for number of CIFS directories found */ - for (i = 0; i < 2; i++) { - if ((st_cifs[i] = - (struct cifs_stats *) calloc(cifs_nr, CIFS_STATS_SIZE)) == NULL) { - perror("malloc"); - exit(4); - } - } + /* Add cifs to the list */ + if ((*clist = (struct io_cifs *) malloc(IO_CIFS_SIZE)) == NULL) { + perror("malloc"); + exit(4); } - else { - /* - * cifs_nr value is probably zero, but it can also be negative - * (possible overflow when adding NR_CIFS_PREALLOC above). - */ - cifs_nr = 0; - } -} + memset(*clist, 0, IO_CIFS_SIZE); -/* - *************************************************************************** - * Free various structures. - *************************************************************************** -*/ -void io_sys_free(void) -{ - int i; - - /* Free CIFS directories structures */ + c = *clist; for (i = 0; i < 2; i++) { - free(st_cifs[i]); - } - - free(st_hdr_cifs); -} - -/* - *************************************************************************** - * Save stats for current CIFS filesystem. - * - * IN: - * @name Name of CIFS filesystem. - * @curr Index in array for current sample statistics. - * @st_io Structure with CIFS statistics to save. - *************************************************************************** - */ -void save_stats(char *name, int curr, struct cifs_stats *st_io) -{ - int i, j; - struct io_hdr_stats *st_hdr_cifs_i; - struct cifs_stats *st_cifs_i; - - /* Look for CIFS directory in data table */ - for (i = 0; i < cifs_nr; i++) { - st_hdr_cifs_i = st_hdr_cifs + i; - if ((st_hdr_cifs_i->used == TRUE) && - (!strcmp(st_hdr_cifs_i->name, name))) { - break; + if ((c->cifs_stats[i] = (struct cifs_st *) malloc(CIFS_ST_SIZE)) == NULL) { + perror("malloc"); + exit(4); } + memset(c->cifs_stats[i], 0, CIFS_ST_SIZE); } + strncpy(c->name, name, sizeof(c->name)); + c->name[sizeof(c->name) - 1] = '\0'; + c->exist = TRUE; + c->next = cs; - if (i == cifs_nr) { - /* - * This is a new filesystem: Look for an unused entry to store it. - */ - for (i = 0; i < cifs_nr; i++) { - st_hdr_cifs_i = st_hdr_cifs + i; - if (!st_hdr_cifs_i->used) { - /* Unused entry found... */ - st_hdr_cifs_i->used = TRUE; /* Indicate it is now used */ - st_hdr_cifs_i->active = TRUE; - strncpy(st_hdr_cifs_i->name, name, MAX_NAME_LEN - 1); - st_hdr_cifs_i->name[MAX_NAME_LEN - 1] = '\0'; - st_cifs_i = st_cifs[curr] + i; - *st_cifs_i = *((struct cifs_stats *) st_io); - break; - } - } - if (i == cifs_nr) { - /* - * It is a new CIFS directory - * but there is no free structure to store it. - */ - - /* All entries are used: The number has to be increased */ - cifs_nr = cifs_nr + 5; - - /* Increase the size of st_hdr_ionfs buffer */ - if ((st_hdr_cifs = (struct io_hdr_stats *) - realloc(st_hdr_cifs, cifs_nr * IO_HDR_STATS_SIZE)) == NULL) { - perror("malloc"); - exit(4); - } - - /* Set the new entries inactive */ - for (j = 0; j < 5; j++) { - st_hdr_cifs_i = st_hdr_cifs + i + j; - st_hdr_cifs_i->used = FALSE; - st_hdr_cifs_i->active = FALSE; - } - - /* Increase the size of st_hdr_ionfs buffer */ - for (j = 0; j < 2; j++) { - if ((st_cifs[j] = (struct cifs_stats *) - realloc(st_cifs[j], cifs_nr * CIFS_STATS_SIZE)) == NULL) { - perror("malloc"); - exit(4); - } - memset(st_cifs[j] + i, 0, 5 * CIFS_STATS_SIZE); - } - /* Now i shows the first unused entry of the new block */ - st_hdr_cifs_i = st_hdr_cifs + i; - st_hdr_cifs_i->used = TRUE; /* Indicate it is now used */ - st_hdr_cifs_i->active = TRUE; - strncpy(st_hdr_cifs_i->name, name, MAX_NAME_LEN - 1); - st_hdr_cifs_i->name[MAX_NAME_LEN - 1] = '\0'; - st_cifs_i = st_cifs[curr] + i; - *st_cifs_i = *st_io; - } - } else { - st_hdr_cifs_i = st_hdr_cifs + i; - st_hdr_cifs_i->active = TRUE; - st_hdr_cifs_i->used = TRUE; - st_cifs_i = st_cifs[curr] + i; - *st_cifs_i = *st_io; - } - /* - * else it was a new CIFS directory - * but there was no free structure to store it. - */ + return c; } /* @@ -330,10 +203,8 @@ void read_cifs_stat(int curr) long long unsigned all_open = 0; char cifs_name[MAX_NAME_LEN]; char name_tmp[MAX_NAME_LEN]; - struct cifs_stats scifs = {0, 0, 0, 0, 0, 0, 0}; - - /* Every CIFS entry is potentially unregistered */ - set_entries_inactive(); + struct cifs_st scifs; + struct io_cifs *ci; if ((fp = fopen(CIFSSTATS, "r")) == NULL) return; @@ -341,49 +212,77 @@ void read_cifs_stat(int curr) sprintf(aux, "%%*d) %%%ds", MAX_NAME_LEN < 200 ? MAX_NAME_LEN - 1 : 200); + memset(&scifs, 0, CIFS_ST_SIZE); + while (fgets(line, sizeof(line), fp) != NULL) { /* Read CIFS directory name */ if (isdigit((unsigned char) line[0]) && sscanf(line, aux , name_tmp) == 1) { if (start) { scifs.fopens = all_open; - save_stats(cifs_name, curr, &scifs); + ci = add_list_cifs(&cifs_list, cifs_name); + if (ci != NULL) { + *ci->cifs_stats[curr] = scifs; + } all_open = 0; } else { start = 1; } - strncpy(cifs_name, name_tmp, MAX_NAME_LEN); - cifs_name[MAX_NAME_LEN - 1] = '\0'; + strncpy(cifs_name, name_tmp, sizeof(cifs_name)); + cifs_name[sizeof(cifs_name) - 1] = '\0'; + memset(&scifs, 0, CIFS_ST_SIZE); } else { if (!strncmp(line, "Reads:", 6)) { + /* + * SMB1 format: Reads: %llu Bytes: %llu + * SMB2 format: Reads: %llu sent %llu failed + * If this is SMB2 format then only the first variable (rd_ops) will be set. + */ sscanf(line, "Reads: %llu Bytes: %llu", &scifs.rd_ops, &scifs.rd_bytes); } - if (!strncmp(line, "Writes:", 7)) { + else if (!strncmp(line, "Bytes read:", 11)) { + sscanf(line, "Bytes read: %llu Bytes written: %llu", + &scifs.rd_bytes, &scifs.wr_bytes); + } + else if (!strncmp(line, "Writes:", 7)) { + /* + * SMB1 format: Writes: %llu Bytes: %llu + * SMB2 format: Writes: %llu sent %llu failed + * If this is SMB2 format then only the first variable (wr_ops) will be set. + */ sscanf(line, "Writes: %llu Bytes: %llu", &scifs.wr_ops, &scifs.wr_bytes); } - if (!strncmp(line, "Opens:", 6)) { + else if (!strncmp(line, "Opens:", 6)) { sscanf(line, "Opens: %llu Closes:%llu Deletes: %llu", &aux_open, &scifs.fcloses, &scifs.fdeletes); all_open += aux_open; } - if (!strncmp(line, "Posix Opens:", 12)) { + else if (!strncmp(line, "Posix Opens:", 12)) { sscanf(line, "Posix Opens: %llu", &aux_open); all_open += aux_open; } + else if (!strncmp(line, "Open files:", 11)) { + sscanf(line, "Open files: %llu total (local), %llu", + &all_open, &aux_open); + all_open += aux_open; + } + else if (!strncmp(line, "Closes:", 7)) { + sscanf(line, "Closes: %llu", &scifs.fcloses); + } } } if (start) { scifs.fopens = all_open; - save_stats(cifs_name, curr, &scifs); + ci = add_list_cifs(&cifs_list, cifs_name); + if (ci != NULL) { + *ci->cifs_stats[curr] = scifs; + } } fclose(fp); - - /* Free structures corresponding to unregistered filesystems */ - free_inactive_entries(); } /* @@ -396,7 +295,9 @@ void read_cifs_stat(int curr) */ void write_cifs_stat_header(int *fctr) { - printf("Filesystem: "); + if (!DISPLAY_PRETTY(flags)) { + printf("Filesystem "); + } if (DISPLAY_KILOBYTES(flags)) { printf(" rkB/s wkB/s"); *fctr = 1024; @@ -409,7 +310,11 @@ void write_cifs_stat_header(int *fctr) printf(" rB/s wB/s"); *fctr = 1; } - printf(" rops/s wops/s fo/s fc/s fd/s\n"); + printf(" rops/s wops/s fo/s fc/s fd/s"); + if (DISPLAY_PRETTY(flags)) { + printf(" Filesystem"); + } + printf("\n"); } /* @@ -418,25 +323,21 @@ void write_cifs_stat_header(int *fctr) * * IN: * @curr Index in array for current sample statistics. - * @itv Interval of time. + * @itv Interval of time (in 1/100th of a second). * @fctr Conversion factor. - * @shi Structures describing the CIFS filesystems. + * @clist Pointer on the linked list where the cifs is saved. * @ioi Current sample statistics. * @ioj Previous sample statistics. *************************************************************************** */ void write_cifs_stat(int curr, unsigned long long itv, int fctr, - struct io_hdr_stats *shi, struct cifs_stats *ioni, - struct cifs_stats *ionj) + struct io_cifs *clist, struct cifs_st *ioni, + struct cifs_st *ionj) { double rbytes, wbytes; - if (DISPLAY_HUMAN_READ(flags)) { - cprintf_in(IS_STR, "%-22s\n", shi->name, 0); - printf("%22s", ""); - } - else { - cprintf_in(IS_STR, "%-22s", shi->name, 0); + if (!DISPLAY_PRETTY(flags)) { + cprintf_in(IS_STR, "%-22s", clist->name, 0); } /* rB/s wB/s fo/s fc/s fd/s*/ @@ -455,6 +356,9 @@ void write_cifs_stat(int curr, unsigned long long itv, int fctr, S_VALUE(ionj->fopens, ioni->fopens, itv), S_VALUE(ionj->fcloses, ioni->fcloses, itv), S_VALUE(ionj->fdeletes, ioni->fdeletes, itv)); + if (DISPLAY_PRETTY(flags)) { + cprintf_in(IS_STR, " %s", clist->name, 0); + } printf("\n"); } @@ -469,10 +373,10 @@ void write_cifs_stat(int curr, unsigned long long itv, int fctr, */ void write_stats(int curr, struct tm *rectime) { - int i, fctr = 1; + int fctr = 1; unsigned long long itv; - struct io_hdr_stats *shi; - struct cifs_stats *ioni, *ionj; + struct io_cifs *clist; + struct cifs_st *ioni, *ionj; /* Test stdout */ TEST_STDOUT(STDOUT_FILENO); @@ -494,32 +398,34 @@ void write_stats(int curr, struct tm *rectime) } /* Interval of time, reduced to one processor */ - itv = get_interval(uptime0[!curr], uptime0[curr]); - - shi = st_hdr_cifs; + itv = get_interval(uptime_cs[!curr], uptime_cs[curr]); /* Display CIFS stats header */ write_cifs_stat_header(&fctr); - for (i = 0; i < cifs_nr; i++, shi++) { - if (shi->used) { - ioni = st_cifs[curr] + i; - ionj = st_cifs[!curr] + i; + for (clist = cifs_list; clist != NULL; clist = clist->next) { + + if (!clist->exist) + /* Current cifs non existent */ + continue; + + ioni = clist->cifs_stats[curr]; + ionj = clist->cifs_stats[!curr]; + #ifdef DEBUG - if (DISPLAY_DEBUG(flags)) { - /* Debug output */ - fprintf(stderr, "name=%s itv=%llu fctr=%d ioni{ rd_bytes=%llu " - "wr_bytes=%llu rd_ops=%llu wr_ops=%llu fopens=%llu " - "fcloses=%llu fdeletes=%llu}\n", - shi->name, itv, fctr, - ioni->rd_bytes, ioni->wr_bytes, - ioni->rd_ops, ioni->wr_ops, - ioni->fopens, ioni->fcloses, - ioni->fdeletes); - } -#endif - write_cifs_stat(curr, itv, fctr, shi, ioni, ionj); + if (DISPLAY_DEBUG(flags)) { + /* Debug output */ + fprintf(stderr, "name=%s itv=%llu fctr=%d ioni{ rd_bytes=%llu " + "wr_bytes=%llu rd_ops=%llu wr_ops=%llu fopens=%llu " + "fcloses=%llu fdeletes=%llu}\n", + clist->name, itv, fctr, + ioni->rd_bytes, ioni->wr_bytes, + ioni->rd_ops, ioni->wr_ops, + ioni->fopens, ioni->fcloses, + ioni->fdeletes); } +#endif + write_cifs_stat(curr, itv, fctr, clist, ioni, ionj); } printf("\n"); } @@ -537,16 +443,18 @@ void rw_io_stat_loop(long int count, struct tm *rectime) { int curr = 1; - /* Don't buffer data if redirected to a pipe */ - setbuf(stdout, NULL); + /* Set a handler for SIGALRM */ + memset(&alrm_act, 0, sizeof(alrm_act)); + alrm_act.sa_handler = alarm_handler; + sigaction(SIGALRM, &alrm_act, NULL); + alarm(interval); do { - /* Read system uptime (reduced to one processor) */ - uptime0[curr] = 0; - read_uptime(&(uptime0[curr])); - if (!uptime0[curr]) - /* Cannot read system uptime (/proc/uptime doesn't exist) */ - exit(2); + /* Every device is potentially nonexistent */ + set_cifs_nonexistent(cifs_list); + + /* Read system uptime in 1/100th of a second */ + read_uptime(&(uptime_cs[curr])); /* Read CIFS stats */ read_cifs_stat(curr); @@ -563,7 +471,7 @@ void rw_io_stat_loop(long int count, struct tm *rectime) if (count) { curr ^= 1; - pause(); + __pause(); } } while (count); @@ -591,9 +499,6 @@ int main(int argc, char **argv) /* Init color strings */ init_colors(); - /* Get HZ */ - get_HZ(); - /* Process args... */ while (opt < argc) { @@ -609,14 +514,29 @@ int main(int argc, char **argv) opt++; } + else if (!strcmp(argv[opt], "--pretty")) { + /* Display an easy-to-read CIFS report */ + flags |= I_D_PRETTY; + opt++; + } + + else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) { + /* Get number of decimal places */ + dplaces_nr = atoi(argv[opt] + 6); + if ((dplaces_nr < 0) || (dplaces_nr > 2)) { + usage(argv[0]); + } + opt++; + } + else if (!strncmp(argv[opt], "-", 1)) { for (i = 1; *(argv[opt] + i); i++) { switch (*(argv[opt] + i)) { case 'h': - /* Display an easy-to-read CIFS report. Also imply --human */ - flags |= I_D_HUMAN_READ + I_D_UNIT; + /* Option -h is equivalent to --pretty --human */ + flags |= I_D_PRETTY + I_D_UNIT; break; case 'k': @@ -677,13 +597,20 @@ int main(int argc, char **argv) count = 1; } - /* Init structures according to machine architecture */ - io_sys_init(); + /* How many processors on this machine? */ + cpu_nr = get_cpu_nr(~0, FALSE); get_localtime(&rectime, 0); + /* + * Don't buffer data if redirected to a pipe. + * Note: With musl-c, the behavior of this function is undefined except + * when it is the first operation on the stream. + */ + setbuf(stdout, NULL); + /* Get system name, release number and hostname */ - uname(&header); + __uname(&header); if (print_gal_header(&rectime, header.sysname, header.release, header.nodename, header.machine, cpu_nr, PLAIN_OUTPUT)) { @@ -691,17 +618,8 @@ int main(int argc, char **argv) } printf("\n"); - /* Set a handler for SIGALRM */ - memset(&alrm_act, 0, sizeof(alrm_act)); - alrm_act.sa_handler = alarm_handler; - sigaction(SIGALRM, &alrm_act, NULL); - alarm(interval); - /* Main loop */ rw_io_stat_loop(count, &rectime); - /* Free structures */ - io_sys_free(); - return 0; }