]> granicus.if.org Git - sysstat/blob - count.c
sysstat 10.2.1
[sysstat] / count.c
1 /*
2  * count.c: Count items for which statistics will be collected.
3  * (C) 1999-2014 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
5  ***************************************************************************
6  * This program is free software; you can redistribute it and/or modify it *
7  * under the terms of the GNU General Public License as published  by  the *
8  * Free Software Foundation; either version 2 of the License, or (at  your *
9  * option) any later version.                                              *
10  *                                                                         *
11  * This program is distributed in the hope that it  will  be  useful,  but *
12  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
14  * for more details.                                                       *
15  *                                                                         *
16  * You should have received a copy of the GNU General Public License along *
17  * with this program; if not, write to the Free Software Foundation, Inc., *
18  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                   *
19  ***************************************************************************
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <dirent.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/vfs.h>
31 #include <unistd.h>
32
33 #include "common.h"
34 #include "rd_stats.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
45 /*
46  ***************************************************************************
47  * Count number of processors in /sys.
48  *
49  * IN:
50  * @highest     If set to TRUE, then look for the highest processor number.
51  *              This is used when eg. the machine has 4 CPU numbered 0, 1, 4
52  *              and 5. In this case, this procedure will return 6.
53  *
54  * RETURNS:
55  * Number of processors (online and offline).
56  * A value of 0 means that /sys was not mounted.
57  * A value of N (!=0) means N processor(s) (cpu0 .. cpu(N-1)).
58  ***************************************************************************
59  */
60 int get_sys_cpu_nr(int highest)
61 {
62         DIR *dir;
63         struct dirent *drd;
64         struct stat buf;
65         char line[MAX_PF_NAME];
66         int num_proc, proc_nr = -1;
67
68         /* Open relevant /sys directory */
69         if ((dir = opendir(SYSFS_DEVCPU)) == NULL)
70                 return 0;
71
72         /* Get current file entry */
73         while ((drd = readdir(dir)) != NULL) {
74
75                 if (!strncmp(drd->d_name, "cpu", 3) && isdigit(drd->d_name[3])) {
76                         snprintf(line, MAX_PF_NAME, "%s/%s", SYSFS_DEVCPU, drd->d_name);
77                         line[MAX_PF_NAME - 1] = '\0';
78                         if (stat(line, &buf) < 0)
79                                 continue;
80                         if (S_ISDIR(buf.st_mode)) {
81                                 if (highest) {
82                                         sscanf(drd->d_name + 3, "%d", &num_proc);
83                                         if (num_proc > proc_nr) {
84                                                 proc_nr = num_proc;
85                                         }
86                                 }
87                                 else {
88                                         proc_nr++;
89                                 }
90                         }
91                 }
92         }
93
94         /* Close directory */
95         closedir(dir);
96
97         return (proc_nr + 1);
98 }
99
100 /*
101  ***************************************************************************
102  * Count number of processors in /proc/stat.
103  *
104  * RETURNS:
105  * Number of processors. The returned value is greater than or equal to the
106  * number of online processors.
107  * A value of 0 means one processor and non SMP kernel.
108  * A value of N (!=0) means N processor(s) (0 .. N-1) with SMP kernel.
109  ***************************************************************************
110  */
111 int get_proc_cpu_nr(void)
112 {
113         FILE *fp;
114         char line[16];
115         int num_proc, proc_nr = -1;
116
117         if ((fp = fopen(STAT, "r")) == NULL) {
118                 fprintf(stderr, _("Cannot open %s: %s\n"), STAT, strerror(errno));
119                 exit(1);
120         }
121
122         while (fgets(line, sizeof(line), fp) != NULL) {
123
124                 if (strncmp(line, "cpu ", 4) && !strncmp(line, "cpu", 3)) {
125                         sscanf(line + 3, "%d", &num_proc);
126                         if (num_proc > proc_nr) {
127                                 proc_nr = num_proc;
128                         }
129                 }
130         }
131
132         fclose(fp);
133
134         return (proc_nr + 1);
135 }
136
137 /*
138  ***************************************************************************
139  * Count the number of processors on the machine, or look for the
140  * highest processor number.
141  * Try to use /sys for that, or /proc/stat if /sys doesn't exist.
142  *
143  * IN:
144  * @max_nr_cpus Maximum number of proc that sysstat can handle.
145  * @highest     If set to TRUE, then look for the highest processor number.
146  *              This is used when eg. the machine has 4 CPU numbered 0, 1, 4
147  *              and 5. In this case, this procedure will return 6.
148  *
149  * RETURNS:
150  * Number of processors.
151  * 0: one proc and non SMP kernel.
152  * 1: one proc and SMP kernel (NB: On SMP machines where all the CPUs but
153  *    one have been disabled, we get the total number of proc since we use
154  *    /sys to count them).
155  * 2: two proc...
156  ***************************************************************************
157  */
158 int get_cpu_nr(unsigned int max_nr_cpus, int highest)
159 {
160         int cpu_nr;
161
162         if ((cpu_nr = get_sys_cpu_nr(highest)) == 0) {
163                 /* /sys may be not mounted. Use /proc/stat instead */
164                 cpu_nr = get_proc_cpu_nr();
165         }
166
167         if (cpu_nr > max_nr_cpus) {
168                 fprintf(stderr, _("Cannot handle so many processors!\n"));
169                 exit(1);
170         }
171
172         return cpu_nr;
173 }
174
175 /*
176  ***************************************************************************
177  * Find number of interrupts available per processor (use
178  * /proc/interrupts file or /proc/softirqs).
179  *
180  * IN:
181  * @file                /proc file to read (interrupts or softirqs).
182  * @max_nr_irqcpu       Maximum number of interrupts per processor that
183  *                      sadc can handle.
184  * @cpu_nr              Number of processors.
185  *
186  * RETURNS:
187  * Number of interrupts per processor + a pre-allocation constant.
188  ***************************************************************************
189  */
190 int get_irqcpu_nr(char *file, int max_nr_irqcpu, int cpu_nr)
191 {
192         FILE *fp;
193         char *line = NULL;
194         unsigned int irq = 0;
195         int p;
196
197         if ((fp = fopen(file, "r")) == NULL)
198                 return 0;       /* No interrupts file */
199
200         SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
201
202         while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr , fp) != NULL) &&
203                (irq < max_nr_irqcpu)) {
204                 p = strcspn(line, ":");
205                 if ((p > 0) && (p < 16)) {
206                         irq++;
207                 }
208         }
209
210         fclose(fp);
211
212         free(line);
213
214         return irq;
215 }
216
217 /*
218  ***************************************************************************
219  * Find number of devices and partitions available in /proc/diskstats.
220  *
221  * IN:
222  * @count_part          Set to TRUE if devices _and_ partitions are to be
223  *                      counted.
224  * @only_used_dev       When counting devices, set to TRUE if only devices
225  *                      with non zero stats must be counted.
226  *
227  * RETURNS:
228  * Number of devices (and partitions).
229  ***************************************************************************
230  */
231 int get_diskstats_dev_nr(int count_part, int only_used_dev)
232 {
233         FILE *fp;
234         char line[256];
235         char dev_name[MAX_NAME_LEN];
236         int dev = 0, i;
237         unsigned long rd_ios, wr_ios;
238
239         if ((fp = fopen(DISKSTATS, "r")) == NULL)
240                 /* File non-existent */
241                 return 0;
242
243         /*
244          * Counting devices and partitions is simply a matter of counting
245          * the number of lines...
246          */
247         while (fgets(line, sizeof(line), fp) != NULL) {
248                 if (!count_part) {
249                         i = sscanf(line, "%*d %*d %s %lu %*u %*u %*u %lu",
250                                    dev_name, &rd_ios, &wr_ios);
251                         if ((i == 2) || !is_device(dev_name, ACCEPT_VIRTUAL_DEVICES))
252                                 /* It was a partition and not a device */
253                                 continue;
254                         if (only_used_dev && !rd_ios && !wr_ios)
255                                 /* Unused device */
256                                 continue;
257                 }
258                 dev++;
259         }
260
261         fclose(fp);
262
263         return dev;
264 }
265
266 #ifdef SOURCE_SADC
267 /*---------------- BEGIN: FUNCTIONS USED BY SADC ONLY ---------------------*/
268
269 /*
270  ***************************************************************************
271  * Count number of interrupts that are in /proc/stat file.
272  *
273  * RETURNS:
274  * Number of interrupts, including total number of interrupts.
275  ***************************************************************************
276  */
277 int get_irq_nr(void)
278 {
279         FILE *fp;
280         char line[8192];
281         int in = 0;
282         int pos = 4;
283
284         if ((fp = fopen(STAT, "r")) == NULL)
285                 return 0;
286
287         while (fgets(line, sizeof(line), fp) != NULL) {
288
289                 if (!strncmp(line, "intr ", 5)) {
290
291                         while (pos < strlen(line)) {
292                                 in++;
293                                 pos += strcspn(line + pos + 1, " ") + 1;
294                         }
295                 }
296         }
297
298         fclose(fp);
299
300         return in;
301 }
302
303 /*
304  ***************************************************************************
305  * Find number of serial lines that support tx/rx accounting
306  * in /proc/tty/driver/serial file.
307  *
308  * RETURNS:
309  * Number of serial lines supporting tx/rx accouting.
310  ***************************************************************************
311  */
312 int get_serial_nr(void)
313 {
314         FILE *fp;
315         char line[256];
316         int sl = 0;
317
318         if ((fp = fopen(SERIAL, "r")) == NULL)
319                 return 0;       /* No SERIAL file */
320
321         while (fgets(line, sizeof(line), fp) != NULL) {
322                 /*
323                  * tx/rx statistics are always present,
324                  * except when serial line is unknown.
325                  */
326                 if (strstr(line, "tx:") != NULL) {
327                         sl++;
328                 }
329         }
330
331         fclose(fp);
332
333         return sl;
334 }
335
336 /*
337  ***************************************************************************
338  * Find number of interfaces (network devices) that are in /proc/net/dev
339  * file.
340  *
341  * RETURNS:
342  * Number of network interfaces.
343  ***************************************************************************
344  */
345 int get_iface_nr(void)
346 {
347         FILE *fp;
348         char line[128];
349         int iface = 0;
350
351         if ((fp = fopen(NET_DEV, "r")) == NULL)
352                 return 0;       /* No network device file */
353
354         while (fgets(line, sizeof(line), fp) != NULL) {
355                 if (strchr(line, ':')) {
356                         iface++;
357                 }
358         }
359
360         fclose(fp);
361
362         return iface;
363 }
364
365 /*
366  ***************************************************************************
367  * Get number of devices in /proc/diskstats.
368  *
369  * IN:
370  * @f   Non zero (true) if disks *and* partitions should be counted, and
371  *      zero (false) if only disks must be counted.
372  *
373  * RETURNS:
374  * Number of devices.
375  ***************************************************************************
376  */
377 int get_disk_nr(unsigned int f)
378 {
379         int disk_nr;
380
381         /*
382          * Partitions are taken into account by sar -d only with
383          * kernels 2.6.25 and later.
384          */
385         disk_nr = get_diskstats_dev_nr(f, CNT_USED_DEV);
386
387         return disk_nr;
388 }
389
390 /*
391  ***************************************************************************
392  * Count number of possible frequencies for CPU#0.
393  *
394  * RETURNS:
395  * Number of frequencies.
396  ***************************************************************************
397  */
398 int get_freq_nr(void)
399 {
400         FILE *fp;
401         char filename[MAX_PF_NAME];
402         char line[128];
403         int freq = 0;
404
405         snprintf(filename, MAX_PF_NAME, "%s/cpu0/%s",
406                  SYSFS_DEVCPU, SYSFS_TIME_IN_STATE);
407         if ((fp = fopen(filename, "r")) == NULL)
408                 return 0;       /* No time_in_state file for CPU#0 */
409
410         while (fgets(line, sizeof(line), fp) != NULL) {
411                 freq++;
412         }
413
414         fclose(fp);
415
416         return freq;
417 }
418
419 /*
420  ***************************************************************************
421  * Count number of USB devices in /sys/bus/usb/devices.
422  *
423  * RETURNS:
424  * Number of USB devices plugged into the system.
425  * Don't count USB root hubs.
426  * Return -1 if directory doesn't exist in sysfs.
427  ***************************************************************************
428  */
429 int get_usb_nr(void)
430 {
431         DIR *dir;
432         struct dirent *drd;
433         int usb = 0;
434
435         /* Open relevant /sys directory */
436         if ((dir = opendir(SYSFS_USBDEV)) == NULL)
437                 return -1;
438
439         /* Get current file entry */
440         while ((drd = readdir(dir)) != NULL) {
441
442                 if (isdigit(drd->d_name[0]) && !strchr(drd->d_name, ':')) {
443                         usb++;
444                 }
445         }
446
447         /* Close directory */
448         closedir(dir);
449
450         return usb;
451 }
452
453 /*
454  ***************************************************************************
455  * Find number of filesystems in /etc/mtab. Pseudo-filesystems are ignored.
456  *
457  * RETURNS:
458  * Number of filesystems.
459  ***************************************************************************
460  */
461 int get_filesystem_nr(void)
462 {
463         FILE *fp;
464         char line[256], fs_name[MAX_FS_LEN], mountp[128];
465         int fs = 0;
466         struct statfs buf;
467
468         if ((fp = fopen(MTAB, "r")) == NULL)
469                 /* File non-existent */
470                 return 0;
471
472         /* Get current filesystem */
473         while (fgets(line, sizeof(line), fp) != NULL) {
474                 if (line[0] == '/') {
475                         
476                         /* Read filesystem name and mount point */
477                         sscanf(line, "%71s %127s", fs_name, mountp);
478                         
479                         /* Replace octal codes */
480                         oct2chr(mountp);
481                         
482                         /* Check that total size is not null */
483                         if (statfs(mountp, &buf) < 0)
484                                 continue;
485                         
486                         if (buf.f_blocks) {
487                                 fs++;
488                         }
489                 }
490         }
491
492         fclose(fp);
493
494         return fs;
495 }
496
497 /*------------------ END: FUNCTIONS USED BY SADC ONLY ---------------------*/
498 #endif /* SOURCE_SADC */