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