#include "version.h"
#include "cifsiostat.h"
+#include "rd_stats.h"
#include "count.h"
-#include "common.h"
#ifdef USE_NLS
#include <locale.h>
#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[64];
+char timestamp[TIMESTAMP_LEN];
struct sigaction alrm_act;
#ifdef DEBUG
fprintf(stderr, _("Options are:\n"
+ "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ]\n"
"[ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ]\n"));
#else
fprintf(stderr, _("Options are:\n"
+ "[ --dec={ 0 | 1 | 2 } ] [ --human ] [ --pretty ]\n"
"[ -h ] [ -k | -m ] [ -t ] [ -V ]\n"));
#endif
exit(1);
/*
***************************************************************************
- * 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;
- }
-}
-
-/*
- ***************************************************************************
- * Free inactive entries (mark them as unused).
- ***************************************************************************
- */
-void free_inactive_entries(void)
-{
- int i;
- struct io_hdr_stats *shi = st_hdr_cifs;
+ if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN)
+ /* cifs name is too long */
+ return NULL;
- 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);
- }
- }
- }
- else {
- /*
- * cifs_nr value is probably zero, but it can also be negative
- * (possible overflow when adding NR_CIFS_PREALLOC above).
- */
- cifs_nr = 0;
+ /* Add cifs to the list */
+ if ((*clist = (struct io_cifs *) malloc(IO_CIFS_SIZE)) == NULL) {
+ perror("malloc");
+ exit(4);
}
-}
-
-/*
- ***************************************************************************
- * Free various structures.
- ***************************************************************************
-*/
-void io_sys_free(void)
-{
- int i;
+ memset(*clist, 0, IO_CIFS_SIZE);
- /* 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;
}
/*
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;
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;
}
- strcpy(cifs_name, name_tmp);
+ 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();
}
/*
*/
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;
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");
}
/*
*
* 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)
{
- if (DISPLAY_HUMAN_READ(flags)) {
- printf("%-22s\n%23s", shi->name, "");
- }
- else {
- printf("%-22s ", shi->name);
+ double rbytes, wbytes;
+
+ if (!DISPLAY_PRETTY(flags)) {
+ cprintf_in(IS_STR, "%-22s", clist->name, 0);
}
/* rB/s wB/s fo/s fc/s fd/s*/
- printf("%12.2f %12.2f %9.2f %9.2f %12.2f %12.2f %12.2f \n",
- S_VALUE(ionj->rd_bytes, ioni->rd_bytes, itv) / fctr,
- S_VALUE(ionj->wr_bytes, ioni->wr_bytes, itv) / fctr,
- S_VALUE(ionj->rd_ops, ioni->rd_ops, itv),
- S_VALUE(ionj->wr_ops, ioni->wr_ops, itv),
- S_VALUE(ionj->fopens, ioni->fopens, itv),
- S_VALUE(ionj->fcloses, ioni->fcloses, itv),
- S_VALUE(ionj->fdeletes, ioni->fdeletes, itv));
+ rbytes = S_VALUE(ionj->rd_bytes, ioni->rd_bytes, itv);
+ wbytes = S_VALUE(ionj->wr_bytes, ioni->wr_bytes, itv);
+ if (!DISPLAY_UNIT(flags)) {
+ rbytes /= fctr;
+ wbytes /= fctr;
+ }
+ cprintf_f(DISPLAY_UNIT(flags) ? UNIT_BYTE : NO_UNIT, 2, 12, 2,
+ rbytes, wbytes);
+ cprintf_f(NO_UNIT, 2, 9, 2,
+ S_VALUE(ionj->rd_ops, ioni->rd_ops, itv),
+ S_VALUE(ionj->wr_ops, ioni->wr_ops, itv));
+ cprintf_f(NO_UNIT, 3, 12, 2,
+ 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");
}
/*
*/
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);
}
/* 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");
}
{
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);
if (count) {
curr ^= 1;
- pause();
+ __pause();
}
}
while (count);
init_nls();
#endif
- /* Get HZ */
- get_HZ();
+ /* Init color strings */
+ init_colors();
/* Process args... */
while (opt < argc) {
opt++;
} else
#endif
- if (!strncmp(argv[opt], "-", 1)) {
+
+ if (!strcmp(argv[opt], "--human")) {
+ flags |= I_D_UNIT;
+ 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 */
- flags |= I_D_HUMAN_READ;
+ /* Option -h is equivalent to --pretty --human */
+ flags |= I_D_PRETTY + I_D_UNIT;
break;
case 'k':
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)) {
+ header.nodename, header.machine, cpu_nr,
+ PLAIN_OUTPUT)) {
flags |= I_D_ISO;
}
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;
}