]> granicus.if.org Git - sysstat/blobdiff - count.c
A_IRQ: sar: Always display a header line for each sample
[sysstat] / count.c
diff --git a/count.c b/count.c
index 1c76013ffb22583a20fc3001bf9e7aa3e7b4a9d6..0c49be0eb0cff36e62f83de78f71663f1c7eb189 100644 (file)
--- a/count.c
+++ b/count.c
@@ -1,6 +1,6 @@
 /*
  * count.c: Count items for which statistics will be collected.
- * (C) 1999-2013 by Sebastien GODARD (sysstat <at> orange.fr)
+ * (C) 1999-2021 by Sebastien GODARD (sysstat <at> orange.fr)
  *
  ***************************************************************************
  * This program is free software; you can redistribute it and/or modify it *
@@ -15,7 +15,7 @@
  *                                                                         *
  * You should have received a copy of the GNU General Public License along *
  * with this program; if not, write to the Free Software Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                   *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
  ***************************************************************************
  */
 
@@ -27,7 +27,7 @@
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/vfs.h>
+#include <sys/statvfs.h>
 #include <unistd.h>
 
 #include "common.h"
 
 /*
  ***************************************************************************
- * Count number of interrupts that are in /proc/stat file.
+ * Count number of processors in /sys.
+ *
+ * IN:
+ * @highest    If set to TRUE, then look for the highest processor number.
+ *             This is used when eg. the machine has 4 CPU numbered 0, 1, 4
+ *             and 5. In this case, this procedure will return 6.
  *
  * RETURNS:
- * Number of interrupts, including total number of interrupts.
+ * Number of processors (online and offline).
+ * A value of 0 means that /sys was not mounted.
+ * A value of N (!=0) means N processor(s) (cpu0 .. cpu(N-1)).
  ***************************************************************************
  */
-int get_irq_nr(void)
+int get_sys_cpu_nr(int highest)
 {
-       FILE *fp;
-       char line[8192];
-       int in = 0;
-       int pos = 4;
+       DIR *dir;
+       struct dirent *drd;
+       struct stat buf;
+       char line[MAX_PF_NAME];
+       int num_proc, proc_nr = -1;
 
-       if ((fp = fopen(STAT, "r")) == NULL)
+       /* Open relevant /sys directory */
+       if ((dir = opendir(SYSFS_DEVCPU)) == NULL)
                return 0;
 
-       while (fgets(line, 8192, fp) != NULL) {
-
-               if (!strncmp(line, "intr ", 5)) {
+       /* Get current file entry */
+       while ((drd = readdir(dir)) != NULL) {
 
-                       while (pos < strlen(line)) {
-                               in++;
-                               pos += strcspn(line + pos + 1, " ") + 1;
+               if (!strncmp(drd->d_name, "cpu", 3) && isdigit(drd->d_name[3])) {
+                       snprintf(line, sizeof(line), "%s/%s", SYSFS_DEVCPU, drd->d_name);
+                       line[sizeof(line) - 1] = '\0';
+                       if (stat(line, &buf) < 0)
+                               continue;
+                       if (S_ISDIR(buf.st_mode)) {
+                               if (highest) {
+                                       sscanf(drd->d_name + 3, "%d", &num_proc);
+                                       if (num_proc > proc_nr) {
+                                               proc_nr = num_proc;
+                                       }
+                               }
+                               else {
+                                       proc_nr++;
+                               }
                        }
                }
        }
 
-       fclose(fp);
+       /* Close directory */
+       closedir(dir);
 
-       return in;
+       return (proc_nr + 1);
 }
 
 /*
  ***************************************************************************
- * Find number of serial lines that support tx/rx accounting
- * in /proc/tty/driver/serial file.
+ * Count number of processors in /proc/stat.
  *
  * RETURNS:
- * Number of serial lines supporting tx/rx accouting.
+ * Number of processors. The returned value is greater than or equal to the
+ * number of online processors.
+ * A value of 0 means one processor and non SMP kernel.
+ * A value of N (!=0) means N processor(s) (0 .. N-1) with SMP kernel.
  ***************************************************************************
  */
-int get_serial_nr(void)
+int get_proc_cpu_nr(void)
 {
        FILE *fp;
-       char line[256];
-       int sl = 0;
+       char line[16];
+       int num_proc, proc_nr = -1;
 
-       if ((fp = fopen(SERIAL, "r")) == NULL)
-               return 0;       /* No SERIAL file */
+       if ((fp = fopen(STAT, "r")) == NULL) {
+               fprintf(stderr, _("Cannot open %s: %s\n"), STAT, strerror(errno));
+               exit(1);
+       }
 
-       while (fgets(line, 256, fp) != NULL) {
-               /*
-                * tx/rx statistics are always present,
-                * except when serial line is unknown.
-                */
-               if (strstr(line, "tx:") != NULL) {
-                       sl++;
+       while (fgets(line, sizeof(line), fp) != NULL) {
+
+               if (strncmp(line, "cpu ", 4) && !strncmp(line, "cpu", 3)) {
+                       sscanf(line + 3, "%d", &num_proc);
+                       if (num_proc > proc_nr) {
+                               proc_nr = num_proc;
+                       }
                }
        }
 
        fclose(fp);
 
-       return sl;
+       proc_nr++;
+       return proc_nr;
 }
 
 /*
  ***************************************************************************
- * Find number of interfaces (network devices) that are in /proc/net/dev
- * file.
+ * Count the number of processors on the machine, or look for the
+ * highest processor number.
+ * Try to use /sys for that, or /proc/stat if /sys doesn't exist.
+ *
+ * IN:
+ * @max_nr_cpus        Maximum number of proc that sysstat can handle.
+ * @highest    If set to TRUE, then look for the highest processor number.
+ *             This is used when eg. the machine has 4 CPU numbered 0, 1, 4
+ *             and 5. In this case, this procedure will return 6.
  *
  * RETURNS:
- * Number of network interfaces.
+ * Number of processors.
+ * 0: one proc and non SMP kernel.
+ * 1: one proc and SMP kernel (NB: On SMP machines where all the CPUs but
+ *    one have been disabled, we get the total number of proc since we use
+ *    /sys to count them).
+ * 2: two proc...
+ *
+ * USED BY:
+ * sadc, cifsiostat, iostat, mpstat, pidstat, tapestat
+ ***************************************************************************
+ */
+__nr_t get_cpu_nr(unsigned int max_nr_cpus, int highest)
+{
+       __nr_t cpu_nr;
+
+       if ((cpu_nr = get_sys_cpu_nr(highest)) == 0) {
+               /* /sys may be not mounted. Use /proc/stat instead */
+               cpu_nr = get_proc_cpu_nr();
+       }
+
+       if (cpu_nr > max_nr_cpus) {
+               fprintf(stderr, _("Cannot handle so many processors!\n"));
+               exit(1);
+       }
+
+       return cpu_nr;
+}
+
+/*
+ ***************************************************************************
+ * Find number of interrupts available per processor (use
+ * /proc/interrupts file or /proc/softirqs).
+ *
+ * IN:
+ * @file               /proc file to read (interrupts or softirqs).
+ * @max_nr_irqcpu       Maximum number of interrupts per processor that
+ *                      sadc can handle.
+ * @cpu_nr             Number of processors.
+ *
+ * RETURNS:
+ * Number of interrupts per processor.
+ *
+ * USED BY:
+ * sadc, mpstat
  ***************************************************************************
  */
-int get_iface_nr(void)
+__nr_t get_irqcpu_nr(char *file, int max_nr_irqcpu, int cpu_nr)
 {
        FILE *fp;
-       char line[128];
-       int iface = 0;
+       char *line = NULL;
+       __nr_t irq = 0;
+       int p;
 
-       if ((fp = fopen(NET_DEV, "r")) == NULL)
-               return 0;       /* No network device file */
+       if ((fp = fopen(file, "r")) == NULL)
+               return 0;       /* No interrupts file */
 
-       while (fgets(line, 128, fp) != NULL) {
-               if (strchr(line, ':')) {
-                       iface++;
+       SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
+
+       while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr , fp) != NULL) &&
+              (irq < max_nr_irqcpu)) {
+               p = strcspn(line, ":");
+               if ((p > 0) && (p < 16)) {
+                       irq++;
                }
        }
 
        fclose(fp);
 
-       return iface;
+       free(line);
+
+       return irq;
 }
 
+#ifdef SOURCE_SADC
+/*---------------- BEGIN: FUNCTIONS USED BY SADC ONLY ---------------------*/
+
 /*
  ***************************************************************************
  * Find number of devices and partitions available in /proc/diskstats.
@@ -152,12 +238,13 @@ int get_iface_nr(void)
  * Number of devices (and partitions).
  ***************************************************************************
  */
-int get_diskstats_dev_nr(int count_part, int only_used_dev)
+__nr_t get_diskstats_dev_nr(int count_part, int only_used_dev)
 {
        FILE *fp;
        char line[256];
        char dev_name[MAX_NAME_LEN];
-       int dev = 0, i;
+       __nr_t dev = 0;
+       int i;
        unsigned long rd_ios, wr_ios;
 
        if ((fp = fopen(DISKSTATS, "r")) == NULL)
@@ -168,11 +255,11 @@ int get_diskstats_dev_nr(int count_part, int only_used_dev)
         * Counting devices and partitions is simply a matter of counting
         * the number of lines...
         */
-       while (fgets(line, 256, fp) != NULL) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
                if (!count_part) {
                        i = sscanf(line, "%*d %*d %s %lu %*u %*u %*u %lu",
                                   dev_name, &rd_ios, &wr_ios);
-                       if ((i == 2) || !is_device(dev_name, ACCEPT_VIRTUAL_DEVICES))
+                       if ((i == 2) || !is_device(SLASH_SYS, dev_name, ACCEPT_VIRTUAL_DEVICES))
                                /* It was a partition and not a device */
                                continue;
                        if (only_used_dev && !rd_ios && !wr_ios)
@@ -189,182 +276,89 @@ int get_diskstats_dev_nr(int count_part, int only_used_dev)
 
 /*
  ***************************************************************************
- * Get number of devices in /proc/diskstats.
- *
- * IN:
- * @f  Non zero (true) if disks *and* partitions should be counted, and
- *     zero (false) if only disks must be counted.
- *
- * RETURNS:
- * Number of devices.
- ***************************************************************************
- */
-int get_disk_nr(unsigned int f)
-{
-       int disk_nr;
-
-       /*
-        * Partitions are taken into account by sar -d only with
-        * kernels 2.6.25 and later.
-        */
-       disk_nr = get_diskstats_dev_nr(f, CNT_USED_DEV);
-
-       return disk_nr;
-}
-
-/*
- ***************************************************************************
- * Count number of processors in /sys.
+ * Find number of serial lines that support tx/rx accounting
+ * in /proc/tty/driver/serial file.
  *
  * RETURNS:
- * Number of processors (online and offline).
- * A value of 0 means that /sys was not mounted.
- * A value of N (!=0) means N processor(s) (cpu0 .. cpu(N-1)).
+ * Number of serial lines supporting tx/rx accouting.
  ***************************************************************************
  */
-int get_sys_cpu_nr(void)
+__nr_t get_serial_nr(void)
 {
-       DIR *dir;
-       struct dirent *drd;
-       struct stat buf;
-       char line[MAX_PF_NAME];
-       int proc_nr = 0;
-
-       /* Open relevant /sys directory */
-       if ((dir = opendir(SYSFS_DEVCPU)) == NULL)
-               return 0;
+       FILE *fp;
+       char line[256];
+       __nr_t sl = 0;
 
-       /* Get current file entry */
-       while ((drd = readdir(dir)) != NULL) {
+       if ((fp = fopen(SERIAL, "r")) == NULL)
+               return 0;       /* No SERIAL file */
 
-               if (!strncmp(drd->d_name, "cpu", 3) && isdigit(drd->d_name[3])) {
-                       snprintf(line, MAX_PF_NAME, "%s/%s", SYSFS_DEVCPU, drd->d_name);
-                       line[MAX_PF_NAME - 1] = '\0';
-                       if (stat(line, &buf) < 0)
-                               continue;
-                       if (S_ISDIR(buf.st_mode)) {
-                               proc_nr++;
-                       }
+       while (fgets(line, sizeof(line), fp) != NULL) {
+               /*
+                * tx/rx statistics are always present,
+                * except when serial line is unknown.
+                */
+               if (strstr(line, "tx:") != NULL) {
+                       sl++;
                }
        }
 
-       /* Close directory */
-       closedir(dir);
+       fclose(fp);
 
-       return proc_nr;
+       return sl;
 }
 
 /*
  ***************************************************************************
- * Count number of processors in /proc/stat.
+ * Find number of interfaces (network devices) that are in /proc/net/dev
+ * file.
  *
  * RETURNS:
- * Number of processors. The returned value is greater than or equal to the
- * number of online processors.
- * A value of 0 means one processor and non SMP kernel.
- * A value of N (!=0) means N processor(s) (0 .. N-1) with SMP kernel.
+ * Number of network interfaces.
  ***************************************************************************
  */
-int get_proc_cpu_nr(void)
+__nr_t get_iface_nr(void)
 {
        FILE *fp;
-       char line[16];
-       int num_proc, proc_nr = -1;
-
-       if ((fp = fopen(STAT, "r")) == NULL) {
-               fprintf(stderr, _("Cannot open %s: %s\n"), STAT, strerror(errno));
-               exit(1);
-       }
+       char line[128];
+       __nr_t iface = 0;
 
-       while (fgets(line, 16, fp) != NULL) {
+       if ((fp = fopen(NET_DEV, "r")) == NULL)
+               return 0;       /* No network device file */
 
-               if (strncmp(line, "cpu ", 4) && !strncmp(line, "cpu", 3)) {
-                       sscanf(line + 3, "%d", &num_proc);
-                       if (num_proc > proc_nr) {
-                               proc_nr = num_proc;
-                       }
+       while (fgets(line, sizeof(line), fp) != NULL) {
+               if (strchr(line, ':')) {
+                       iface++;
                }
        }
 
        fclose(fp);
 
-       return (proc_nr + 1);
-}
-
-/*
- ***************************************************************************
- * Count the number of processors on the machine.
- * Try to use /sys for that, or /proc/stat if /sys doesn't exist.
- *
- * IN:
- * @max_nr_cpus        Maximum number of proc that sysstat can handle.
- *
- * RETURNS:
- * Number of processors.
- * 0: one proc and non SMP kernel.
- * 1: one proc and SMP kernel (NB: On SMP machines where all the CPUs but
- *    one have been disabled, we get the total number of proc since we use
- *    /sys to count them).
- * 2: two proc...
- ***************************************************************************
- */
-int get_cpu_nr(unsigned int max_nr_cpus)
-{
-       int cpu_nr;
-
-       if ((cpu_nr = get_sys_cpu_nr()) == 0) {
-               /* /sys may be not mounted. Use /proc/stat instead */
-               cpu_nr = get_proc_cpu_nr();
-       }
-
-       if (cpu_nr > max_nr_cpus) {
-               fprintf(stderr, _("Cannot handle so many processors!\n"));
-               exit(1);
-       }
-
-       return cpu_nr;
+       return iface;
 }
 
 /*
  ***************************************************************************
- * Find number of interrupts available per processor (use
- * /proc/interrupts file or /proc/softirqs).
+ * Get number of devices in /proc/diskstats.
  *
  * IN:
- * @file               /proc file to read (interrupts or softirqs).
- * @max_nr_irqcpu       Maximum number of interrupts per processor that
- *                      sadc can handle.
- * @cpu_nr             Number of processors.
+ * @f  Non zero (true) if disks *and* partitions should be counted, and
+ *     zero (false) if only disks must be counted.
  *
  * RETURNS:
- * Number of interrupts per processor + a pre-allocation constant.
+ * Number of devices.
  ***************************************************************************
  */
-int get_irqcpu_nr(char *file, int max_nr_irqcpu, int cpu_nr)
+__nr_t get_disk_nr(unsigned int f)
 {
-       FILE *fp;
-       char *line = NULL;
-       unsigned int irq = 0;
-       int p;
+       __nr_t disk_nr;
 
-       if ((fp = fopen(file, "r")) == NULL)
-               return 0;       /* No interrupts file */
-
-       SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
-
-       while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr , fp) != NULL) &&
-              (irq < max_nr_irqcpu)) {
-               p = strcspn(line, ":");
-               if ((p > 0) && (p < 16)) {
-                       irq++;
-               }
-       }
-
-       fclose(fp);
-
-       free(line);
+       /*
+        * Partitions are taken into account by sar -d only with
+        * kernels 2.6.25 and later.
+        */
+       disk_nr = get_diskstats_dev_nr(f, CNT_USED_DEV);
 
-       return irq;
+       return disk_nr;
 }
 
 /*
@@ -375,19 +369,19 @@ int get_irqcpu_nr(char *file, int max_nr_irqcpu, int cpu_nr)
  * Number of frequencies.
  ***************************************************************************
  */
-int get_freq_nr(void)
+__nr_t get_freq_nr(void)
 {
        FILE *fp;
        char filename[MAX_PF_NAME];
        char line[128];
-       int freq = 0;
+       __nr_t freq = 0;
 
        snprintf(filename, MAX_PF_NAME, "%s/cpu0/%s",
                 SYSFS_DEVCPU, SYSFS_TIME_IN_STATE);
        if ((fp = fopen(filename, "r")) == NULL)
                return 0;       /* No time_in_state file for CPU#0 */
 
-       while (fgets(line, 128, fp) != NULL) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
                freq++;
        }
 
@@ -406,11 +400,11 @@ int get_freq_nr(void)
  * Return -1 if directory doesn't exist in sysfs.
  ***************************************************************************
  */
-int get_usb_nr(void)
+__nr_t get_usb_nr(void)
 {
        DIR *dir;
        struct dirent *drd;
-       int usb = 0;
+       __nr_t usb = 0;
 
        /* Open relevant /sys directory */
        if ((dir = opendir(SYSFS_USBDEV)) == NULL)
@@ -438,31 +432,61 @@ int get_usb_nr(void)
  * Number of filesystems.
  ***************************************************************************
  */
-int get_filesystem_nr(void)
+__nr_t get_filesystem_nr(void)
 {
        FILE *fp;
-       char line[256], fs_name[MAX_FS_LEN], mountp[128];
-       int fs = 0;
-       struct statfs buf;
+       char line[512], fs_name[MAX_FS_LEN], mountp[256], type[128];
+       char *pos = 0, *pos2 = 0;
+       __nr_t fs = 0;
+       int skip = 0, skip_next = 0;
+       struct statvfs buf;
 
        if ((fp = fopen(MTAB, "r")) == NULL)
                /* File non-existent */
                return 0;
 
        /* Get current filesystem */
-       while (fgets(line, 256, fp) != NULL) {
+       while (fgets(line, sizeof(line), fp) != NULL) {
+               /*
+                * Ignore line if the preceding line did not contain '\n'.
+                * (Some very long lines may be found for instance when
+                * overlay2 filesystem with docker is used).
+                */
+               skip = skip_next;
+               skip_next = (strchr(line, '\n') == NULL);
+               if (skip)
+                       continue;
+
                if (line[0] == '/') {
-                       
+                       /* Find field separator position */
+                       pos = strchr(line, ' ');
+                       if (pos == NULL)
+                               continue;
+
+                       /*
+                        * Find second field separator position,
+                        * read filesystem type,
+                        * if filesystem type is autofs, skip it
+                       */
+                       pos2 = strchr(pos + 1, ' ');
+                       if (pos2 == NULL)
+                               continue;
+
+                       sscanf(pos2 + 1, "%127s", type);
+                       if(strcmp(type, "autofs") == 0)
+                               continue;
+
                        /* Read filesystem name and mount point */
-                       sscanf(line, "%71s %127s", fs_name, mountp);
-                       
+                       sscanf(line, "%127s", fs_name);
+                       sscanf(pos + 1, "%255s", mountp);
+
                        /* Replace octal codes */
                        oct2chr(mountp);
-                       
-                       /* Check that total size is not null */
-                       if (statfs(mountp, &buf) < 0)
+
+                       /* Check that total size is not zero */
+                       if (__statvfs(mountp, &buf) < 0)
                                continue;
-                       
+
                        if (buf.f_blocks) {
                                fs++;
                        }
@@ -473,3 +497,39 @@ int get_filesystem_nr(void)
 
        return fs;
 }
+
+/*
+ ***************************************************************************
+ * Find number of fibre channel hosts in /sys/class/fc_host/.
+ *
+ * RETURNS:
+ * Number of FC hosts.
+ * Return -1 if directory doesn't exist in sysfs.
+ ***************************************************************************
+ */
+__nr_t get_fchost_nr(void)
+{
+       DIR *dir;
+       struct dirent *drd;
+       __nr_t fc = 0;
+
+       if ((dir = opendir(SYSFS_FCHOST)) == NULL) {
+               /* Directory non-existent */
+               return -1;
+       }
+
+       while ((drd = readdir(dir)) != NULL) {
+
+               if (!strncmp(drd->d_name, "host", 4)) {
+                       fc++;
+               }
+       }
+
+       /* Close directory */
+       closedir(dir);
+
+       return fc;
+}
+
+/*------------------ END: FUNCTIONS USED BY SADC ONLY ---------------------*/
+#endif /* SOURCE_SADC */