]> granicus.if.org Git - sysstat/blob - rd_stats.c
Added support for nice guest mode to sar.
[sysstat] / rd_stats.c
1 /*
2  * rd_stats.c: Read system statistics
3  * (C) 1999-2012 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 <unistd.h>
31
32 #include "common.h"
33 #include "rd_stats.h"
34 #include "ioconf.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  * Read CPU statistics and machine uptime.
47  *
48  * IN:
49  * @st_cpu      Structure where stats will be saved.
50  * @nbr         Total number of CPU (including cpu "all").
51  *
52  * OUT:
53  * @st_cpu      Structure with statistics.
54  * @uptime      Machine uptime multiplied by the number of processors.
55  * @uptime0     Machine uptime. Filled only if previously set to zero.
56  ***************************************************************************
57  */
58 void read_stat_cpu(struct stats_cpu *st_cpu, int nbr,
59                    unsigned long long *uptime, unsigned long long *uptime0)
60 {
61         FILE *fp;
62         struct stats_cpu *st_cpu_i;
63         struct stats_cpu sc;
64         char line[8192];
65         int proc_nb;
66
67         if ((fp = fopen(STAT, "r")) == NULL) {
68                 fprintf(stderr, _("Cannot open %s: %s\n"), STAT, strerror(errno));
69                 exit(2);
70         }
71
72         while (fgets(line, 8192, fp) != NULL) {
73
74                 if (!strncmp(line, "cpu ", 4)) {
75
76                         /*
77                          * All the fields don't necessarily exist,
78                          * depending on the kernel version used.
79                          */
80                         memset(st_cpu, 0, STATS_CPU_SIZE);
81
82                         /*
83                          * Read the number of jiffies spent in the different modes
84                          * (user, nice, etc.) among all proc. CPU usage is not reduced
85                          * to one processor to avoid rounding problems.
86                          */
87                         sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
88                                &st_cpu->cpu_user,
89                                &st_cpu->cpu_nice,
90                                &st_cpu->cpu_sys,
91                                &st_cpu->cpu_idle,
92                                &st_cpu->cpu_iowait,
93                                &st_cpu->cpu_hardirq,
94                                &st_cpu->cpu_softirq,
95                                &st_cpu->cpu_steal,
96                                &st_cpu->cpu_guest,
97                                &st_cpu->cpu_guest_nice);
98
99                         /*
100                          * Compute the uptime of the system in jiffies (1/100ths of a second
101                          * if HZ=100).
102                          * Machine uptime is multiplied by the number of processors here.
103                          *
104                          * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
105                          * already include them.
106                          */
107                         *uptime = st_cpu->cpu_user + st_cpu->cpu_nice    +
108                                 st_cpu->cpu_sys    + st_cpu->cpu_idle    +
109                                 st_cpu->cpu_iowait + st_cpu->cpu_hardirq +
110                                 st_cpu->cpu_steal  + st_cpu->cpu_softirq;
111                 }
112
113                 else if (!strncmp(line, "cpu", 3)) {
114                         if (nbr > 1) {
115                                 /* All the fields don't necessarily exist */
116                                 memset(&sc, 0, STATS_CPU_SIZE);
117                                 /*
118                                  * Read the number of jiffies spent in the different modes
119                                  * (user, nice, etc) for current proc.
120                                  * This is done only on SMP machines.
121                                  */
122                                 sscanf(line + 3, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
123                                        &proc_nb,
124                                        &sc.cpu_user,
125                                        &sc.cpu_nice,
126                                        &sc.cpu_sys,
127                                        &sc.cpu_idle,
128                                        &sc.cpu_iowait,
129                                        &sc.cpu_hardirq,
130                                        &sc.cpu_softirq,
131                                        &sc.cpu_steal,
132                                        &sc.cpu_guest,
133                                        &sc.cpu_guest_nice);
134
135                                 if (proc_nb < (nbr - 1)) {
136                                         st_cpu_i = st_cpu + proc_nb + 1;
137                                         *st_cpu_i = sc;
138                                 }
139                                 /*
140                                  * else additional CPUs have been dynamically registered
141                                  * in /proc/stat.
142                                  */
143
144                                 if (!proc_nb && !*uptime0) {
145                                         /*
146                                          * Compute uptime reduced to one proc using proc#0.
147                                          * Done if /proc/uptime was unavailable.
148                                          *
149                                          * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
150                                          * already include them.
151                                          */
152                                         *uptime0 = sc.cpu_user + sc.cpu_nice  +
153                                                 sc.cpu_sys     + sc.cpu_idle  +
154                                                 sc.cpu_iowait  + sc.cpu_steal +
155                                                 sc.cpu_hardirq + sc.cpu_softirq;
156                                 }
157                         }
158                 }
159         }
160
161         fclose(fp);
162 }
163
164 /*
165  ***************************************************************************
166  * Read processes (tasks) creation and context switches statistics
167  * from /proc/stat.
168  *
169  * IN:
170  * @st_pcsw     Structure where stats will be saved.
171  *
172  * OUT:
173  * @st_pcsw     Structure with statistics.
174  ***************************************************************************
175  */
176 void read_stat_pcsw(struct stats_pcsw *st_pcsw)
177 {
178         FILE *fp;
179         char line[8192];
180
181         if ((fp = fopen(STAT, "r")) == NULL)
182                 return;
183
184         while (fgets(line, 8192, fp) != NULL) {
185
186                 if (!strncmp(line, "ctxt ", 5)) {
187                         /* Read number of context switches */
188                         sscanf(line + 5, "%llu", &st_pcsw->context_switch);
189                 }
190
191                 else if (!strncmp(line, "processes ", 10)) {
192                         /* Read number of processes created since system boot */
193                         sscanf(line + 10, "%lu", &st_pcsw->processes);
194                 }
195         }
196
197         fclose(fp);
198 }
199
200 /*
201  ***************************************************************************
202  * Read interrupts statistics from /proc/stat.
203  *
204  * IN:
205  * @st_irq      Structure where stats will be saved.
206  * @nbr         Number of interrupts to read, including the total number
207  *              of interrupts.
208  *
209  * OUT:
210  * @st_irq      Structure with statistics.
211  ***************************************************************************
212  */
213 void read_stat_irq(struct stats_irq *st_irq, int nbr)
214 {
215         FILE *fp;
216         struct stats_irq *st_irq_i;
217         char line[8192];
218         int i, pos;
219
220         if ((fp = fopen(STAT, "r")) == NULL)
221                 return;
222         
223         while (fgets(line, 8192, fp) != NULL) {
224
225                 if (!strncmp(line, "intr ", 5)) {
226                         /* Read total number of interrupts received since system boot */
227                         sscanf(line + 5, "%llu", &st_irq->irq_nr);
228                         pos = strcspn(line + 5, " ") + 5;
229
230                         for (i = 1; i < nbr; i++) {
231                                 st_irq_i = st_irq + i;
232                                 sscanf(line + pos, " %llu", &st_irq_i->irq_nr);
233                                 pos += strcspn(line + pos + 1, " ") + 1;
234                         }
235                 }
236         }
237
238         fclose(fp);
239 }
240
241 /*
242  ***************************************************************************
243  * Read queue and load statistics from /proc/loadavg and /proc/stat.
244  *
245  * IN:
246  * @st_queue    Structure where stats will be saved.
247  *
248  * OUT:
249  * @st_queue    Structure with statistics.
250  ***************************************************************************
251  */
252 void read_loadavg(struct stats_queue *st_queue)
253 {
254         FILE *fp;
255         char line[8192];
256         int load_tmp[3];
257
258         if ((fp = fopen(LOADAVG, "r")) == NULL)
259                 return;
260         
261         /* Read load averages and queue length */
262         fscanf(fp, "%d.%d %d.%d %d.%d %ld/%d %*d\n",
263                &load_tmp[0], &st_queue->load_avg_1,
264                &load_tmp[1], &st_queue->load_avg_5,
265                &load_tmp[2], &st_queue->load_avg_15,
266                &st_queue->nr_running,
267                &st_queue->nr_threads);
268
269         fclose(fp);
270
271         st_queue->load_avg_1  += load_tmp[0] * 100;
272         st_queue->load_avg_5  += load_tmp[1] * 100;
273         st_queue->load_avg_15 += load_tmp[2] * 100;
274
275         if (st_queue->nr_running) {
276                 /* Do not take current process into account */
277                 st_queue->nr_running--;
278         }
279
280         /* Read nr of tasks blocked from /proc/stat */
281         if ((fp = fopen(STAT, "r")) == NULL)
282                 return;
283
284         while (fgets(line, 8192, fp) != NULL) {
285
286                 if (!strncmp(line, "procs_blocked ", 14)) {
287                         /* Read number of processes blocked */
288                         sscanf(line + 14, "%lu", &st_queue->procs_blocked);
289                         break;
290                 }
291         }
292
293         fclose(fp);
294 }
295
296 /*
297  ***************************************************************************
298  * Read memory statistics from /proc/meminfo.
299  *
300  * IN:
301  * @st_memory   Structure where stats will be saved.
302  *
303  * OUT:
304  * @st_memory   Structure with statistics.
305  ***************************************************************************
306  */
307 void read_meminfo(struct stats_memory *st_memory)
308 {
309         FILE *fp;
310         char line[128];
311         
312         if ((fp = fopen(MEMINFO, "r")) == NULL)
313                 return;
314
315         while (fgets(line, 128, fp) != NULL) {
316
317                 if (!strncmp(line, "MemTotal:", 9)) {
318                         /* Read the total amount of memory in kB */
319                         sscanf(line + 9, "%lu", &st_memory->tlmkb);
320                 }
321                 else if (!strncmp(line, "MemFree:", 8)) {
322                         /* Read the amount of free memory in kB */
323                         sscanf(line + 8, "%lu", &st_memory->frmkb);
324                 }
325                 else if (!strncmp(line, "Buffers:", 8)) {
326                         /* Read the amount of buffered memory in kB */
327                         sscanf(line + 8, "%lu", &st_memory->bufkb);
328                 }
329                 else if (!strncmp(line, "Cached:", 7)) {
330                         /* Read the amount of cached memory in kB */
331                         sscanf(line + 7, "%lu", &st_memory->camkb);
332                 }
333                 else if (!strncmp(line, "SwapCached:", 11)) {
334                         /* Read the amount of cached swap in kB */
335                         sscanf(line + 11, "%lu", &st_memory->caskb);
336                 }
337                 else if (!strncmp(line, "Active:", 7)) {
338                         /* Read the amount of active memory in kB */
339                         sscanf(line + 7, "%lu", &st_memory->activekb);
340                 }
341                 else if (!strncmp(line, "Inactive:", 9)) {
342                         /* Read the amount of inactive memory in kB */
343                         sscanf(line + 9, "%lu", &st_memory->inactkb);
344                 }
345                 else if (!strncmp(line, "SwapTotal:", 10)) {
346                         /* Read the total amount of swap memory in kB */
347                         sscanf(line + 10, "%lu", &st_memory->tlskb);
348                 }
349                 else if (!strncmp(line, "SwapFree:", 9)) {
350                         /* Read the amount of free swap memory in kB */
351                         sscanf(line + 9, "%lu", &st_memory->frskb);
352                 }
353                 else if (!strncmp(line, "Committed_AS:", 13)) {
354                         /* Read the amount of commited memory in kB */
355                         sscanf(line + 13, "%lu", &st_memory->comkb);
356                 }
357         }
358
359         fclose(fp);
360 }
361
362 /*
363  ***************************************************************************
364  * Read swapping statistics from /proc/vmstat.
365  *
366  * IN:
367  * @st_swap     Structure where stats will be saved.
368  *
369  * OUT:
370  * @st_swap     Structure with statistics.
371  ***************************************************************************
372  */
373 void read_vmstat_swap(struct stats_swap *st_swap)
374 {
375         FILE *fp;
376         char line[128];
377
378         if ((fp = fopen(VMSTAT, "r")) == NULL)
379                 return;
380
381         while (fgets(line, 128, fp) != NULL) {
382
383                 if (!strncmp(line, "pswpin ", 7)) {
384                         /* Read number of swap pages brought in */
385                         sscanf(line + 7, "%lu", &st_swap->pswpin);
386                 }
387                 else if (!strncmp(line, "pswpout ", 8)) {
388                         /* Read number of swap pages brought out */
389                         sscanf(line + 8, "%lu", &st_swap->pswpout);
390                 }
391         }
392         
393         fclose(fp);
394 }
395
396 /*
397  ***************************************************************************
398  * Read paging statistics from /proc/vmstat.
399  *
400  * IN:
401  * @st_paging   Structure where stats will be saved.
402  *
403  * OUT:
404  * @st_paging   Structure with statistics.
405  ***************************************************************************
406  */
407 void read_vmstat_paging(struct stats_paging *st_paging)
408 {
409         FILE *fp;
410         char line[128];
411         unsigned long pgtmp;
412
413         if ((fp = fopen(VMSTAT, "r")) == NULL)
414                 return;
415
416         st_paging->pgsteal = 0;
417         st_paging->pgscan_kswapd = st_paging->pgscan_direct = 0;
418
419         while (fgets(line, 128, fp) != NULL) {
420
421                 if (!strncmp(line, "pgpgin ", 7)) {
422                         /* Read number of pages the system paged in */
423                         sscanf(line + 7, "%lu", &st_paging->pgpgin);
424                 }
425                 else if (!strncmp(line, "pgpgout ", 8)) {
426                         /* Read number of pages the system paged out */
427                         sscanf(line + 8, "%lu", &st_paging->pgpgout);
428                 }
429                 else if (!strncmp(line, "pgfault ", 8)) {
430                         /* Read number of faults (major+minor) made by the system */
431                         sscanf(line + 8, "%lu", &st_paging->pgfault);
432                 }
433                 else if (!strncmp(line, "pgmajfault ", 11)) {
434                         /* Read number of faults (major only) made by the system */
435                         sscanf(line + 11, "%lu", &st_paging->pgmajfault);
436                 }
437                 else if (!strncmp(line, "pgfree ", 7)) {
438                         /* Read number of pages freed by the system */
439                         sscanf(line + 7, "%lu", &st_paging->pgfree);
440                 }
441                 else if (!strncmp(line, "pgsteal_", 8)) {
442                         /* Read number of pages stolen by the system */
443                         sscanf(strchr(line, ' '), "%lu", &pgtmp);
444                         st_paging->pgsteal += pgtmp;
445                 }
446                 else if (!strncmp(line, "pgscan_kswapd_", 14)) {
447                         /* Read number of pages scanned by the kswapd daemon */
448                         sscanf(strchr(line, ' '), "%lu", &pgtmp);
449                         st_paging->pgscan_kswapd += pgtmp;
450                 }
451                 else if (!strncmp(line, "pgscan_direct_", 14)) {
452                         /* Read number of pages scanned directly */
453                         sscanf(strchr(line, ' '), "%lu", &pgtmp);
454                         st_paging->pgscan_direct += pgtmp;
455                 }
456         }
457         
458         fclose(fp);
459 }
460
461 /*
462  ***************************************************************************
463  * Read I/O and transfer rates statistics from /proc/diskstats.
464  *
465  * IN:
466  * @st_io       Structure where stats will be saved.
467  *
468  * OUT:
469  * @st_io       Structure with statistics.
470  ***************************************************************************
471  */
472 void read_diskstats_io(struct stats_io *st_io)
473 {
474         FILE *fp;
475         char line[256];
476         char dev_name[MAX_NAME_LEN];
477         unsigned int major, minor;
478         unsigned long rd_ios, wr_ios, rd_sec, wr_sec;
479
480         if ((fp = fopen(DISKSTATS, "r")) == NULL)
481                 return;
482
483         while (fgets(line, 256, fp) != NULL) {
484
485                 if (sscanf(line, "%u %u %s %lu %*u %lu %*u %lu %*u %lu",
486                            &major, &minor, dev_name,
487                            &rd_ios, &rd_sec, &wr_ios, &wr_sec) == 7) {
488                         
489                         if (is_device(dev_name, IGNORE_VIRTUAL_DEVICES)) {
490                                 /*
491                                  * OK: It's a (real) device and not a partition.
492                                  * Note: Structure should have been initialized first!
493                                  */
494                                 st_io->dk_drive      += rd_ios + wr_ios;
495                                 st_io->dk_drive_rio  += rd_ios;
496                                 st_io->dk_drive_rblk += rd_sec;
497                                 st_io->dk_drive_wio  += wr_ios;
498                                 st_io->dk_drive_wblk += wr_sec;
499                         }
500                 }
501         }
502         
503         fclose(fp);
504 }
505
506 /*
507  ***************************************************************************
508  * Read block devices statistics from /proc/diskstats.
509  *
510  * IN:
511  * @st_disk     Structure where stats will be saved.
512  * @nbr         Maximum number of block devices.
513  * @read_part   True if disks *and* partitions should be read; False if only
514  *              disks are read.
515  *
516  * OUT:
517  * @st_disk     Structure with statistics.
518  ***************************************************************************
519  */
520 void read_diskstats_disk(struct stats_disk *st_disk, int nbr, int read_part)
521 {
522         FILE *fp;
523         char line[256];
524         char dev_name[MAX_NAME_LEN];
525         int dsk = 0;
526         struct stats_disk *st_disk_i;
527         unsigned int major, minor, rd_ticks, wr_ticks, tot_ticks, rq_ticks;
528         unsigned long rd_ios, wr_ios, rd_sec, wr_sec;
529
530         if ((fp = fopen(DISKSTATS, "r")) == NULL)
531                 return;
532
533         while ((fgets(line, 256, fp) != NULL) && (dsk < nbr)) {
534
535                 if (sscanf(line, "%u %u %s %lu %*u %lu %u %lu %*u %lu"
536                            " %u %*u %u %u",
537                            &major, &minor, dev_name,
538                            &rd_ios, &rd_sec, &rd_ticks, &wr_ios, &wr_sec, &wr_ticks,
539                            &tot_ticks, &rq_ticks) == 11) {
540                         
541                         if (!rd_ios && !wr_ios)
542                                 /* Unused device: Ignore it */
543                                 continue;
544                         if (read_part || is_device(dev_name, ACCEPT_VIRTUAL_DEVICES)) {
545                                 st_disk_i = st_disk + dsk++;
546                                 st_disk_i->major     = major;
547                                 st_disk_i->minor     = minor;
548                                 st_disk_i->nr_ios    = rd_ios + wr_ios;
549                                 st_disk_i->rd_sect   = rd_sec;
550                                 st_disk_i->wr_sect   = wr_sec;
551                                 st_disk_i->rd_ticks  = rd_ticks;
552                                 st_disk_i->wr_ticks  = wr_ticks;
553                                 st_disk_i->tot_ticks = tot_ticks;
554                                 st_disk_i->rq_ticks  = rq_ticks;
555                         }
556                 }
557         }
558
559         fclose(fp);
560 }
561
562 /*
563  ***************************************************************************
564  * Read serial lines statistics from /proc/tty/driver/serial.
565  *
566  * IN:
567  * @st_serial   Structure where stats will be saved.
568  * @nbr         Maximum number of serial lines.
569  *
570  * OUT:
571  * @st_serial   Structure with statistics.
572  ***************************************************************************
573  */
574 void read_tty_driver_serial(struct stats_serial *st_serial, int nbr)
575 {
576         FILE *fp;
577         struct stats_serial *st_serial_i;
578         int sl = 0;
579         char line[256];
580         char *p;
581
582         if ((fp = fopen(SERIAL, "r")) == NULL)
583                 return;
584
585         while ((fgets(line, 256, fp) != NULL) && (sl < nbr)) {
586
587                 if ((p = strstr(line, "tx:")) != NULL) {
588                         st_serial_i = st_serial + sl;
589                         sscanf(line, "%u", &st_serial_i->line);
590                         /*
591                          * A value of 0 means an unused structure.
592                          * So increment it to make sure it is not null.
593                          */
594                         (st_serial_i->line)++;
595                         /*
596                          * Read the number of chars transmitted and received by
597                          * current serial line.
598                          */
599                         sscanf(p + 3, "%u", &st_serial_i->tx);
600                         if ((p = strstr(line, "rx:")) != NULL) {
601                                 sscanf(p + 3, "%u", &st_serial_i->rx);
602                         }
603                         if ((p = strstr(line, "fe:")) != NULL) {
604                                 sscanf(p + 3, "%u", &st_serial_i->frame);
605                         }
606                         if ((p = strstr(line, "pe:")) != NULL) {
607                                 sscanf(p + 3, "%u", &st_serial_i->parity);
608                         }
609                         if ((p = strstr(line, "brk:")) != NULL) {
610                                 sscanf(p + 4, "%u", &st_serial_i->brk);
611                         }
612                         if ((p = strstr(line, "oe:")) != NULL) {
613                                 sscanf(p + 3, "%u", &st_serial_i->overrun);
614                         }
615                         
616                         sl++;
617                 }
618         }
619
620         fclose(fp);
621 }
622
623 /*
624  ***************************************************************************
625  * Read kernel tables statistics from various system files.
626  *
627  * IN:
628  * @st_ktables  Structure where stats will be saved.
629  *
630  * OUT:
631  * @st_ktables  Structure with statistics.
632  ***************************************************************************
633  */
634 void read_kernel_tables(struct stats_ktables *st_ktables)
635 {
636         FILE *fp;
637         unsigned int parm;
638         
639         /* Open /proc/sys/fs/dentry-state file */
640         if ((fp = fopen(FDENTRY_STATE, "r")) != NULL) {
641                 fscanf(fp, "%*d %u",
642                        &st_ktables->dentry_stat);
643                 fclose(fp);
644         }
645
646         /* Open /proc/sys/fs/file-nr file */
647         if ((fp = fopen(FFILE_NR, "r")) != NULL) {
648                 fscanf(fp, "%u %u",
649                        &st_ktables->file_used, &parm);
650                 fclose(fp);
651                 /*
652                  * The number of used handles is the number of allocated ones
653                  * minus the number of free ones.
654                  */
655                 st_ktables->file_used -= parm;
656         }
657
658         /* Open /proc/sys/fs/inode-state file */
659         if ((fp = fopen(FINODE_STATE, "r")) != NULL) {
660                 fscanf(fp, "%u %u",
661                        &st_ktables->inode_used, &parm);
662                 fclose(fp);
663                 /*
664                  * The number of inuse inodes is the number of allocated ones
665                  * minus the number of free ones.
666                  */
667                 st_ktables->inode_used -= parm;
668         }
669
670         /* Open /proc/sys/kernel/pty/nr file */
671         if ((fp = fopen(PTY_NR, "r")) != NULL) {
672                 fscanf(fp, "%u",
673                        &st_ktables->pty_nr);
674                 fclose(fp);
675         }
676 }
677
678 /*
679  ***************************************************************************
680  * Read network interfaces statistics from /proc/net/dev.
681  *
682  * IN:
683  * @st_net_dev  Structure where stats will be saved.
684  * @nbr         Maximum number of network interfaces.
685  *
686  * OUT:
687  * @st_net_dev  Structure with statistics.
688  ***************************************************************************
689  */
690 void read_net_dev(struct stats_net_dev *st_net_dev, int nbr)
691 {
692         FILE *fp;
693         struct stats_net_dev *st_net_dev_i;
694         char line[256];
695         char iface[MAX_IFACE_LEN];
696         int dev = 0;
697         int pos;
698
699         if ((fp = fopen(NET_DEV, "r")) == NULL)
700                 return;
701         
702         while ((fgets(line, 256, fp) != NULL) && (dev < nbr)) {
703
704                 pos = strcspn(line, ":");
705                 if (pos < strlen(line)) {
706                         st_net_dev_i = st_net_dev + dev;
707                         strncpy(iface, line, MINIMUM(pos, MAX_IFACE_LEN - 1));
708                         iface[MINIMUM(pos, MAX_IFACE_LEN - 1)] = '\0';
709                         sscanf(iface, "%s", st_net_dev_i->interface); /* Skip heading spaces */
710                         sscanf(line + pos + 1, "%lu %lu %*u %*u %*u %*u %lu %lu %lu %lu "
711                                "%*u %*u %*u %*u %*u %lu",
712                                &st_net_dev_i->rx_bytes,
713                                &st_net_dev_i->rx_packets,
714                                &st_net_dev_i->rx_compressed,
715                                &st_net_dev_i->multicast,
716                                &st_net_dev_i->tx_bytes,
717                                &st_net_dev_i->tx_packets,
718                                &st_net_dev_i->tx_compressed);
719                         dev++;
720                 }
721         }
722
723         fclose(fp);
724 }
725
726 /*
727  ***************************************************************************
728  * Read network interfaces errors statistics from /proc/net/dev.
729  *
730  * IN:
731  * @st_net_edev Structure where stats will be saved.
732  * @nbr         Maximum number of network interfaces.
733  *
734  * OUT:
735  * @st_net_edev Structure with statistics.
736  ***************************************************************************
737  */
738 void read_net_edev(struct stats_net_edev *st_net_edev, int nbr)
739 {
740         FILE *fp;
741         struct stats_net_edev *st_net_edev_i;
742         static char line[256];
743         char iface[MAX_IFACE_LEN];
744         int dev = 0;
745         int pos;
746
747         if ((fp = fopen(NET_DEV, "r")) == NULL)
748                 return;
749
750         while ((fgets(line, 256, fp) != NULL) && (dev < nbr)) {
751
752                 pos = strcspn(line, ":");
753                 if (pos < strlen(line)) {
754                         st_net_edev_i = st_net_edev + dev;
755                         strncpy(iface, line, MINIMUM(pos, MAX_IFACE_LEN - 1));
756                         iface[MINIMUM(pos, MAX_IFACE_LEN - 1)] = '\0';
757                         sscanf(iface, "%s", st_net_edev_i->interface); /* Skip heading spaces */
758                         sscanf(line + pos + 1, "%*u %*u %lu %lu %lu %lu %*u %*u %*u %*u "
759                                "%lu %lu %lu %lu %lu",
760                                &st_net_edev_i->rx_errors,
761                                &st_net_edev_i->rx_dropped,
762                                &st_net_edev_i->rx_fifo_errors,
763                                &st_net_edev_i->rx_frame_errors,
764                                &st_net_edev_i->tx_errors,
765                                &st_net_edev_i->tx_dropped,
766                                &st_net_edev_i->tx_fifo_errors,
767                                &st_net_edev_i->collisions,
768                                &st_net_edev_i->tx_carrier_errors);
769                         dev++;
770                 }
771         }
772
773         fclose(fp);
774 }
775
776 /*
777  ***************************************************************************
778  * Read NFS client statistics from /proc/net/rpc/nfs.
779  *
780  * IN:
781  * @st_net_nfs  Structure where stats will be saved.
782  *
783  * OUT:
784  * @st_net_nfs  Structure with statistics.
785  ***************************************************************************
786  */
787 void read_net_nfs(struct stats_net_nfs *st_net_nfs)
788 {
789         FILE *fp;
790         char line[256];
791         unsigned int getattcnt = 0, accesscnt = 0, readcnt = 0, writecnt = 0;
792
793         if ((fp = fopen(NET_RPC_NFS, "r")) == NULL)
794                 return;
795
796         memset(st_net_nfs, 0, STATS_NET_NFS_SIZE);
797         
798         while (fgets(line, 256, fp) != NULL) {
799
800                 if (!strncmp(line, "rpc ", 4)) {
801                         sscanf(line + 4, "%u %u",
802                                &st_net_nfs->nfs_rpccnt, &st_net_nfs->nfs_rpcretrans);
803                 }
804                 else if (!strncmp(line, "proc3 ", 6)) {
805                         sscanf(line + 6, "%*u %*u %u %*u %*u %u %*u %u %u",
806                                &getattcnt, &accesscnt, &readcnt, &writecnt);
807                         
808                         st_net_nfs->nfs_getattcnt += getattcnt;
809                         st_net_nfs->nfs_accesscnt += accesscnt;
810                         st_net_nfs->nfs_readcnt   += readcnt;
811                         st_net_nfs->nfs_writecnt  += writecnt;
812                 }
813                 else if (!strncmp(line, "proc4 ", 6)) {
814                         sscanf(line + 6, "%*u %*u %u %u "
815                                "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u %u",
816                                &readcnt, &writecnt, &accesscnt, &getattcnt);
817                         
818                         st_net_nfs->nfs_getattcnt += getattcnt;
819                         st_net_nfs->nfs_accesscnt += accesscnt;
820                         st_net_nfs->nfs_readcnt   += readcnt;
821                         st_net_nfs->nfs_writecnt  += writecnt;
822                 }
823         }
824
825         fclose(fp);
826 }
827
828 /*
829  ***************************************************************************
830  * Read NFS server statistics from /proc/net/rpc/nfsd.
831  *
832  * IN:
833  * @st_net_nfsd Structure where stats will be saved.
834  *
835  * OUT:
836  * @st_net_nfsd Structure with statistics.
837  ***************************************************************************
838  */
839 void read_net_nfsd(struct stats_net_nfsd *st_net_nfsd)
840 {
841         FILE *fp;
842         char line[256];
843         unsigned int getattcnt = 0, accesscnt = 0, readcnt = 0, writecnt = 0;
844
845         if ((fp = fopen(NET_RPC_NFSD, "r")) == NULL)
846                 return;
847         
848         memset(st_net_nfsd, 0, STATS_NET_NFSD_SIZE);
849
850         while (fgets(line, 256, fp) != NULL) {
851
852                 if (!strncmp(line, "rc ", 3)) {
853                         sscanf(line + 3, "%u %u",
854                                &st_net_nfsd->nfsd_rchits, &st_net_nfsd->nfsd_rcmisses);
855                 }
856                 else if (!strncmp(line, "net ", 4)) {
857                         sscanf(line + 4, "%u %u %u",
858                                &st_net_nfsd->nfsd_netcnt, &st_net_nfsd->nfsd_netudpcnt,
859                                &st_net_nfsd->nfsd_nettcpcnt);
860                 }
861                 else if (!strncmp(line, "rpc ", 4)) {
862                         sscanf(line + 4, "%u %u",
863                                &st_net_nfsd->nfsd_rpccnt, &st_net_nfsd->nfsd_rpcbad);
864                 }
865                 else if (!strncmp(line, "proc3 ", 6)) {
866                         sscanf(line + 6, "%*u %*u %u %*u %*u %u %*u %u %u",
867                                &getattcnt, &accesscnt, &readcnt, &writecnt);
868
869                         st_net_nfsd->nfsd_getattcnt += getattcnt;
870                         st_net_nfsd->nfsd_accesscnt += accesscnt;
871                         st_net_nfsd->nfsd_readcnt   += readcnt;
872                         st_net_nfsd->nfsd_writecnt  += writecnt;
873                         
874                 }
875                 else if (!strncmp(line, "proc4ops ", 9)) {
876                         sscanf(line + 9, "%*u %*u %*u %*u %u "
877                                "%*u %*u %*u %*u %*u %u "
878                                "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u "
879                                "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u",
880                                &accesscnt, &getattcnt, &readcnt, &writecnt);
881                         
882                         st_net_nfsd->nfsd_getattcnt += getattcnt;
883                         st_net_nfsd->nfsd_accesscnt += accesscnt;
884                         st_net_nfsd->nfsd_readcnt   += readcnt;
885                         st_net_nfsd->nfsd_writecnt  += writecnt;
886                 }
887         }
888
889         fclose(fp);
890 }
891
892 /*
893  ***************************************************************************
894  * Read network sockets statistics from /proc/net/sockstat.
895  *
896  * IN:
897  * @st_net_sock Structure where stats will be saved.
898  *
899  * OUT:
900  * @st_net_sock Structure with statistics.
901  ***************************************************************************
902  */
903 void read_net_sock(struct stats_net_sock *st_net_sock)
904 {
905         FILE *fp;
906         char line[96];
907         char *p;
908
909         if ((fp = fopen(NET_SOCKSTAT, "r")) == NULL)
910                 return;
911         
912         while (fgets(line, 96, fp) != NULL) {
913
914                 if (!strncmp(line, "sockets:", 8)) {
915                         /* Sockets */
916                         sscanf(line + 14, "%u", &st_net_sock->sock_inuse);
917                 }
918                 else if (!strncmp(line, "TCP:", 4)) {
919                         /* TCP sockets */
920                         sscanf(line + 11, "%u", &st_net_sock->tcp_inuse);
921                         if ((p = strstr(line, "tw")) != NULL) {
922                                 sscanf(p + 2, "%u", &st_net_sock->tcp_tw);
923                         }
924                 }
925                 else if (!strncmp(line, "UDP:", 4)) {
926                         /* UDP sockets */
927                         sscanf(line + 11, "%u", &st_net_sock->udp_inuse);
928                 }
929                 else if (!strncmp(line, "RAW:", 4)) {
930                         /* RAW sockets */
931                         sscanf(line + 11, "%u", &st_net_sock->raw_inuse);
932                 }
933                 else if (!strncmp(line, "FRAG:", 5)) {
934                         /* FRAGments */
935                         sscanf(line + 12, "%u", &st_net_sock->frag_inuse);
936                 }
937         }
938
939         fclose(fp);
940 }
941
942 /*
943  ***************************************************************************
944  * Read IP network traffic statistics from /proc/net/snmp.
945  *
946  * IN:
947  * @st_net_ip   Structure where stats will be saved.
948  *
949  * OUT:
950  * @st_net_ip   Structure with statistics.
951  ***************************************************************************
952  */
953 void read_net_ip(struct stats_net_ip *st_net_ip)
954 {
955         FILE *fp;
956         char line[1024];
957         int sw = FALSE;
958
959         if ((fp = fopen(NET_SNMP, "r")) == NULL)
960                 return;
961         
962         while (fgets(line, 1024, fp) != NULL) {
963
964                 if (!strncmp(line, "Ip:", 3)) {
965                         if (sw) {
966                                 sscanf(line + 3, "%*u %*u %lu %*u %*u %lu %*u %*u "
967                                        "%lu %lu %*u %*u %*u %lu %lu %*u %lu %*u %lu",
968                                        &st_net_ip->InReceives,
969                                        &st_net_ip->ForwDatagrams,
970                                        &st_net_ip->InDelivers,
971                                        &st_net_ip->OutRequests,
972                                        &st_net_ip->ReasmReqds,
973                                        &st_net_ip->ReasmOKs,
974                                        &st_net_ip->FragOKs,
975                                        &st_net_ip->FragCreates);
976                                 
977                                 break;
978                         }
979                         else {
980                                 sw = TRUE;
981                         }
982                 }
983         }
984
985         fclose(fp);
986 }
987
988 /*
989  ***************************************************************************
990  * Read IP network error statistics from /proc/net/snmp.
991  *
992  * IN:
993  * @st_net_eip  Structure where stats will be saved.
994  *
995  * OUT:
996  * @st_net_eip  Structure with statistics.
997  ***************************************************************************
998  */
999 void read_net_eip(struct stats_net_eip *st_net_eip)
1000 {
1001         FILE *fp;
1002         char line[1024];
1003         int sw = FALSE;
1004
1005         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1006                 return;
1007         
1008         while (fgets(line, 1024, fp) != NULL) {
1009
1010                 if (!strncmp(line, "Ip:", 3)) {
1011                         if (sw) {
1012                                 sscanf(line + 3, "%*u %*u %*u %lu %lu %*u %lu %lu "
1013                                        "%*u %*u %lu %lu %*u %*u %*u %lu %*u %lu",
1014                                        &st_net_eip->InHdrErrors,
1015                                        &st_net_eip->InAddrErrors,
1016                                        &st_net_eip->InUnknownProtos,
1017                                        &st_net_eip->InDiscards,
1018                                        &st_net_eip->OutDiscards,
1019                                        &st_net_eip->OutNoRoutes,
1020                                        &st_net_eip->ReasmFails,
1021                                        &st_net_eip->FragFails);
1022                                 
1023                                 break;
1024                         }
1025                         else {
1026                                 sw = TRUE;
1027                         }
1028                 }
1029         }
1030
1031         fclose(fp);
1032 }
1033
1034 /*
1035  ***************************************************************************
1036  * Read ICMP network traffic statistics from /proc/net/snmp.
1037  *
1038  * IN:
1039  * @st_net_icmp Structure where stats will be saved.
1040  *
1041  * OUT:
1042  * @st_net_icmp Structure with statistics.
1043  ***************************************************************************
1044  */
1045 void read_net_icmp(struct stats_net_icmp *st_net_icmp)
1046 {
1047         FILE *fp;
1048         char line[1024];
1049         int sw = FALSE;
1050
1051         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1052                 return;
1053         
1054         while (fgets(line, 1024, fp) != NULL) {
1055
1056                 if (!strncmp(line, "Icmp:", 5)) {
1057                         if (sw) {
1058                                 sscanf(line + 5, "%lu %*u %*u %*u %*u %*u %*u "
1059                                        "%lu %lu %lu %lu %lu %lu %lu %*u %*u %*u %*u "
1060                                        "%*u %*u %lu %lu %lu %lu %lu %lu",
1061                                        &st_net_icmp->InMsgs,
1062                                        &st_net_icmp->InEchos,
1063                                        &st_net_icmp->InEchoReps,
1064                                        &st_net_icmp->InTimestamps,
1065                                        &st_net_icmp->InTimestampReps,
1066                                        &st_net_icmp->InAddrMasks,
1067                                        &st_net_icmp->InAddrMaskReps,
1068                                        &st_net_icmp->OutMsgs,
1069                                        &st_net_icmp->OutEchos,
1070                                        &st_net_icmp->OutEchoReps,
1071                                        &st_net_icmp->OutTimestamps,
1072                                        &st_net_icmp->OutTimestampReps,
1073                                        &st_net_icmp->OutAddrMasks,
1074                                        &st_net_icmp->OutAddrMaskReps);
1075
1076                                 break;
1077                         }
1078                         else {
1079                                 sw = TRUE;
1080                         }
1081                 }
1082         }
1083
1084         fclose(fp);
1085 }
1086
1087 /*
1088  ***************************************************************************
1089  * Read ICMP network error statistics from /proc/net/snmp.
1090  *
1091  * IN:
1092  * @st_net_eicmp        Structure where stats will be saved.
1093  *
1094  * OUT:
1095  * @st_net_eicmp        Structure with statistics.
1096  ***************************************************************************
1097  */
1098 void read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
1099 {
1100         FILE *fp;
1101         char line[1024];
1102         int sw = FALSE;
1103
1104         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1105                 return;
1106         
1107         while (fgets(line, 1024, fp) != NULL) {
1108
1109                 if (!strncmp(line, "Icmp:", 5)) {
1110                         if (sw) {
1111                                 sscanf(line + 5, "%*u %lu %lu %lu %lu %lu %lu %*u %*u "
1112                                        "%*u %*u %*u %*u %*u %lu %lu %lu %lu %lu %lu",
1113                                        &st_net_eicmp->InErrors,
1114                                        &st_net_eicmp->InDestUnreachs,
1115                                        &st_net_eicmp->InTimeExcds,
1116                                        &st_net_eicmp->InParmProbs,
1117                                        &st_net_eicmp->InSrcQuenchs,
1118                                        &st_net_eicmp->InRedirects,
1119                                        &st_net_eicmp->OutErrors,
1120                                        &st_net_eicmp->OutDestUnreachs,
1121                                        &st_net_eicmp->OutTimeExcds,
1122                                        &st_net_eicmp->OutParmProbs,
1123                                        &st_net_eicmp->OutSrcQuenchs,
1124                                        &st_net_eicmp->OutRedirects);
1125
1126                                 break;
1127                         }
1128                         else {
1129                                 sw = TRUE;
1130                         }
1131                 }
1132         }
1133
1134         fclose(fp);
1135 }
1136
1137 /*
1138  ***************************************************************************
1139  * Read TCP network traffic statistics from /proc/net/snmp.
1140  *
1141  * IN:
1142  * @st_net_tcp  Structure where stats will be saved.
1143  *
1144  * OUT:
1145  * @st_net_tcp  Structure with statistics.
1146  ***************************************************************************
1147  */
1148 void read_net_tcp(struct stats_net_tcp *st_net_tcp)
1149 {
1150         FILE *fp;
1151         char line[1024];
1152         int sw = FALSE;
1153
1154         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1155                 return;
1156         
1157         while (fgets(line, 1024, fp) != NULL) {
1158
1159                 if (!strncmp(line, "Tcp:", 4)) {
1160                         if (sw) {
1161                                 sscanf(line + 4, "%*u %*u %*u %*d %lu %lu "
1162                                        "%*u %*u %*u %lu %lu",
1163                                        &st_net_tcp->ActiveOpens,
1164                                        &st_net_tcp->PassiveOpens,
1165                                        &st_net_tcp->InSegs,
1166                                        &st_net_tcp->OutSegs);
1167
1168                                 break;
1169                         }
1170                         else {
1171                                 sw = TRUE;
1172                         }
1173                 }
1174         }
1175
1176         fclose(fp);
1177 }
1178
1179 /*
1180  ***************************************************************************
1181  * Read TCP network error statistics from /proc/net/snmp.
1182  *
1183  * IN:
1184  * @st_net_etcp Structure where stats will be saved.
1185  *
1186  * OUT:
1187  * @st_net_etcp Structure with statistics.
1188  ***************************************************************************
1189  */
1190 void read_net_etcp(struct stats_net_etcp *st_net_etcp)
1191 {
1192         FILE *fp;
1193         char line[1024];
1194         int sw = FALSE;
1195
1196         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1197                 return;
1198         
1199         while (fgets(line, 1024, fp) != NULL) {
1200
1201                 if (!strncmp(line, "Tcp:", 4)) {
1202                         if (sw) {
1203                                 sscanf(line + 4, "%*u %*u %*u %*d %*u %*u "
1204                                        "%lu %lu %*u %*u %*u %lu %lu %lu",
1205                                        &st_net_etcp->AttemptFails,
1206                                        &st_net_etcp->EstabResets,
1207                                        &st_net_etcp->RetransSegs,
1208                                        &st_net_etcp->InErrs,
1209                                        &st_net_etcp->OutRsts);
1210
1211                                 break;
1212                         }
1213                         else {
1214                                 sw = TRUE;
1215                         }
1216                 }
1217         }
1218
1219         fclose(fp);
1220 }
1221
1222 /*
1223  ***************************************************************************
1224  * Read UDP network traffic statistics from /proc/net/snmp.
1225  *
1226  * IN:
1227  * @st_net_udp  Structure where stats will be saved.
1228  *
1229  * OUT:
1230  * @st_net_udp  Structure with statistics.
1231  ***************************************************************************
1232  */
1233 void read_net_udp(struct stats_net_udp *st_net_udp)
1234 {
1235         FILE *fp;
1236         char line[1024];
1237         int sw = FALSE;
1238
1239         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1240                 return;
1241         
1242         while (fgets(line, 1024, fp) != NULL) {
1243
1244                 if (!strncmp(line, "Udp:", 4)) {
1245                         if (sw) {
1246                                 sscanf(line + 4, "%lu %lu %lu %lu",
1247                                        &st_net_udp->InDatagrams,
1248                                        &st_net_udp->NoPorts,
1249                                        &st_net_udp->InErrors,
1250                                        &st_net_udp->OutDatagrams);
1251
1252                                 break;
1253                         }
1254                         else {
1255                                 sw = TRUE;
1256                         }
1257                 }
1258         }
1259
1260         fclose(fp);
1261 }
1262
1263 /*
1264  ***************************************************************************
1265  * Read IPv6 network sockets statistics from /proc/net/sockstat6.
1266  *
1267  * IN:
1268  * @st_net_sock6        Structure where stats will be saved.
1269  *
1270  * OUT:
1271  * @st_net_sock6        Structure with statistics.
1272  ***************************************************************************
1273  */
1274 void read_net_sock6(struct stats_net_sock6 *st_net_sock6)
1275 {
1276         FILE *fp;
1277         char line[96];
1278
1279         if ((fp = fopen(NET_SOCKSTAT6, "r")) == NULL)
1280                 return;
1281         
1282         while (fgets(line, 96, fp) != NULL) {
1283
1284                 if (!strncmp(line, "TCP6:", 5)) {
1285                         /* TCPv6 sockets */
1286                         sscanf(line + 12, "%u", &st_net_sock6->tcp6_inuse);
1287                 }
1288                 else if (!strncmp(line, "UDP6:", 5)) {
1289                         /* UDPv6 sockets */
1290                         sscanf(line + 12, "%u", &st_net_sock6->udp6_inuse);
1291                 }
1292                 else if (!strncmp(line, "RAW6:", 5)) {
1293                         /* IPv6 RAW sockets */
1294                         sscanf(line + 12, "%u", &st_net_sock6->raw6_inuse);
1295                 }
1296                 else if (!strncmp(line, "FRAG6:", 6)) {
1297                         /* IPv6 FRAGments */
1298                         sscanf(line + 13, "%u", &st_net_sock6->frag6_inuse);
1299                 }
1300         }
1301
1302         fclose(fp);
1303 }
1304
1305 /*
1306  ***************************************************************************
1307  * Read IPv6 network traffic statistics from /proc/net/snmp6.
1308  *
1309  * IN:
1310  * @st_net_ip6  Structure where stats will be saved.
1311  *
1312  * OUT:
1313  * @st_net_ip6  Structure with statistics.
1314  ***************************************************************************
1315  */
1316 void read_net_ip6(struct stats_net_ip6 *st_net_ip6)
1317 {
1318         FILE *fp;
1319         char line[128];
1320
1321         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1322                 return;
1323
1324         while (fgets(line, 128, fp) != NULL) {
1325
1326                 if (!strncmp(line, "Ip6InReceives ", 14)) {
1327                         sscanf(line + 14, "%lu", &st_net_ip6->InReceives6);
1328                 }
1329                 else if (!strncmp(line, "Ip6OutForwDatagrams ", 20)) {
1330                         sscanf(line + 20, "%lu", &st_net_ip6->OutForwDatagrams6);
1331                 }
1332                 else if (!strncmp(line, "Ip6InDelivers ", 14)) {
1333                         sscanf(line + 14, "%lu", &st_net_ip6->InDelivers6);
1334                 }
1335                 else if (!strncmp(line, "Ip6OutRequests ", 15)) {
1336                         sscanf(line + 15, "%lu", &st_net_ip6->OutRequests6);
1337                 }
1338                 else if (!strncmp(line, "Ip6ReasmReqds ", 14)) {
1339                         sscanf(line + 14, "%lu", &st_net_ip6->ReasmReqds6);
1340                 }
1341                 else if (!strncmp(line, "Ip6ReasmOKs ", 12)) {
1342                         sscanf(line + 12, "%lu", &st_net_ip6->ReasmOKs6);
1343                 }
1344                 else if (!strncmp(line, "Ip6InMcastPkts ", 15)) {
1345                         sscanf(line + 15, "%lu", &st_net_ip6->InMcastPkts6);
1346                 }
1347                 else if (!strncmp(line, "Ip6OutMcastPkts ", 16)) {
1348                         sscanf(line + 16, "%lu", &st_net_ip6->OutMcastPkts6);
1349                 }
1350                 else if (!strncmp(line, "Ip6FragOKs ", 11)) {
1351                         sscanf(line + 11, "%lu", &st_net_ip6->FragOKs6);
1352                 }
1353                 else if (!strncmp(line, "Ip6FragCreates ", 15)) {
1354                         sscanf(line + 15, "%lu", &st_net_ip6->FragCreates6);
1355                 }
1356         }
1357         
1358         fclose(fp);
1359 }
1360
1361 /*
1362  ***************************************************************************
1363  * Read IPv6 network error statistics from /proc/net/snmp6.
1364  *
1365  * IN:
1366  * @st_net_eip6 Structure where stats will be saved.
1367  *
1368  * OUT:
1369  * @st_net_eip6 Structure with statistics.
1370  ***************************************************************************
1371  */
1372 void read_net_eip6(struct stats_net_eip6 *st_net_eip6)
1373 {
1374         FILE *fp;
1375         char line[128];
1376
1377         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1378                 return;
1379
1380         while (fgets(line, 128, fp) != NULL) {
1381
1382                 if (!strncmp(line, "Ip6InHdrErrors ", 15)) {
1383                         sscanf(line + 15, "%lu", &st_net_eip6->InHdrErrors6);
1384                 }
1385                 else if (!strncmp(line, "Ip6InAddrErrors ", 16)) {
1386                         sscanf(line + 16, "%lu", &st_net_eip6->InAddrErrors6);
1387                 }
1388                 else if (!strncmp(line, "Ip6InUnknownProtos ", 19)) {
1389                         sscanf(line + 19, "%lu", &st_net_eip6->InUnknownProtos6);
1390                 }
1391                 else if (!strncmp(line, "Ip6InTooBigErrors ", 18)) {
1392                         sscanf(line + 18, "%lu", &st_net_eip6->InTooBigErrors6);
1393                 }
1394                 else if (!strncmp(line, "Ip6InDiscards ", 14)) {
1395                         sscanf(line + 14, "%lu", &st_net_eip6->InDiscards6);
1396                 }
1397                 else if (!strncmp(line, "Ip6OutDiscards ", 15)) {
1398                         sscanf(line + 15, "%lu", &st_net_eip6->OutDiscards6);
1399                 }
1400                 else if (!strncmp(line, "Ip6InNoRoutes ", 14)) {
1401                         sscanf(line + 14, "%lu", &st_net_eip6->InNoRoutes6);
1402                 }
1403                 else if (!strncmp(line, "Ip6OutNoRoutes ", 15)) {
1404                         sscanf(line + 15, "%lu", &st_net_eip6->OutNoRoutes6);
1405                 }
1406                 else if (!strncmp(line, "Ip6ReasmFails ", 14)) {
1407                         sscanf(line + 14, "%lu", &st_net_eip6->ReasmFails6);
1408                 }
1409                 else if (!strncmp(line, "Ip6FragFails ", 13)) {
1410                         sscanf(line + 13, "%lu", &st_net_eip6->FragFails6);
1411                 }
1412                 else if (!strncmp(line, "Ip6InTruncatedPkts ", 19)) {
1413                         sscanf(line + 19, "%lu", &st_net_eip6->InTruncatedPkts6);
1414                 }
1415         }
1416         
1417         fclose(fp);
1418 }
1419
1420 /*
1421  ***************************************************************************
1422  * Read ICMPv6 network traffic statistics from /proc/net/snmp6.
1423  *
1424  * IN:
1425  * @st_net_icmp6        Structure where stats will be saved.
1426  *
1427  * OUT:
1428  * @st_net_icmp6        Structure with statistics.
1429  ***************************************************************************
1430  */
1431 void read_net_icmp6(struct stats_net_icmp6 *st_net_icmp6)
1432 {
1433         FILE *fp;
1434         char line[128];
1435
1436         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1437                 return;
1438
1439         while (fgets(line, 128, fp) != NULL) {
1440
1441                 if (!strncmp(line, "Icmp6InMsgs ", 12)) {
1442                         sscanf(line + 12, "%lu", &st_net_icmp6->InMsgs6);
1443                 }
1444                 else if (!strncmp(line, "Icmp6OutMsgs ", 13)) {
1445                         sscanf(line + 13, "%lu", &st_net_icmp6->OutMsgs6);
1446                 }
1447                 else if (!strncmp(line, "Icmp6InEchos ", 13)) {
1448                         sscanf(line + 13, "%lu", &st_net_icmp6->InEchos6);
1449                 }
1450                 else if (!strncmp(line, "Icmp6InEchoReplies ", 19)) {
1451                         sscanf(line + 19, "%lu", &st_net_icmp6->InEchoReplies6);
1452                 }
1453                 else if (!strncmp(line, "Icmp6OutEchoReplies ", 20)) {
1454                         sscanf(line + 20, "%lu", &st_net_icmp6->OutEchoReplies6);
1455                 }
1456                 else if (!strncmp(line, "Icmp6InGroupMembQueries ", 24)) {
1457                         sscanf(line + 24, "%lu", &st_net_icmp6->InGroupMembQueries6);
1458                 }
1459                 else if (!strncmp(line, "Icmp6InGroupMembResponses ", 26)) {
1460                         sscanf(line + 26, "%lu", &st_net_icmp6->InGroupMembResponses6);
1461                 }
1462                 else if (!strncmp(line, "Icmp6OutGroupMembResponses ", 27)) {
1463                         sscanf(line + 27, "%lu", &st_net_icmp6->OutGroupMembResponses6);
1464                 }
1465                 else if (!strncmp(line, "Icmp6InGroupMembReductions ", 27)) {
1466                         sscanf(line + 27, "%lu", &st_net_icmp6->InGroupMembReductions6);
1467                 }
1468                 else if (!strncmp(line, "Icmp6OutGroupMembReductions ", 28)) {
1469                         sscanf(line + 28, "%lu", &st_net_icmp6->OutGroupMembReductions6);
1470                 }
1471                 else if (!strncmp(line, "Icmp6InRouterSolicits ", 22)) {
1472                         sscanf(line + 22, "%lu", &st_net_icmp6->InRouterSolicits6);
1473                 }
1474                 else if (!strncmp(line, "Icmp6OutRouterSolicits ", 23)) {
1475                         sscanf(line + 23, "%lu", &st_net_icmp6->OutRouterSolicits6);
1476                 }
1477                 else if (!strncmp(line, "Icmp6InRouterAdvertisements ", 28)) {
1478                         sscanf(line + 28, "%lu", &st_net_icmp6->InRouterAdvertisements6);
1479                 }
1480                 else if (!strncmp(line, "Icmp6InNeighborSolicits ", 24)) {
1481                         sscanf(line + 24, "%lu", &st_net_icmp6->InNeighborSolicits6);
1482                 }
1483                 else if (!strncmp(line, "Icmp6OutNeighborSolicits ", 25)) {
1484                         sscanf(line + 25, "%lu", &st_net_icmp6->OutNeighborSolicits6);
1485                 }
1486                 else if (!strncmp(line, "Icmp6InNeighborAdvertisements ", 30)) {
1487                         sscanf(line + 30, "%lu", &st_net_icmp6->InNeighborAdvertisements6);
1488                 }
1489                 else if (!strncmp(line, "Icmp6OutNeighborAdvertisements ", 31)) {
1490                         sscanf(line + 31, "%lu", &st_net_icmp6->OutNeighborAdvertisements6);
1491                 }
1492         }
1493         
1494         fclose(fp);
1495 }
1496
1497 /*
1498  ***************************************************************************
1499  * Read ICMPv6 network error statistics from /proc/net/snmp6.
1500  *
1501  * IN:
1502  * @st_net_eicmp6       Structure where stats will be saved.
1503  *
1504  * OUT:
1505  * @st_net_eicmp6       Structure with statistics.
1506  ***************************************************************************
1507  */
1508 void read_net_eicmp6(struct stats_net_eicmp6 *st_net_eicmp6)
1509 {
1510         FILE *fp;
1511         char line[128];
1512
1513         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1514                 return;
1515
1516         while (fgets(line, 128, fp) != NULL) {
1517
1518                 if (!strncmp(line, "Icmp6InErrors ", 14)) {
1519                         sscanf(line + 14, "%lu", &st_net_eicmp6->InErrors6);
1520                 }
1521                 else if (!strncmp(line, "Icmp6InDestUnreachs ", 20)) {
1522                         sscanf(line + 20, "%lu", &st_net_eicmp6->InDestUnreachs6);
1523                 }
1524                 else if (!strncmp(line, "Icmp6OutDestUnreachs ", 21)) {
1525                         sscanf(line + 21, "%lu", &st_net_eicmp6->OutDestUnreachs6);
1526                 }
1527                 else if (!strncmp(line, "Icmp6InTimeExcds ", 17)) {
1528                         sscanf(line + 17, "%lu", &st_net_eicmp6->InTimeExcds6);
1529                 }
1530                 else if (!strncmp(line, "Icmp6OutTimeExcds ", 18)) {
1531                         sscanf(line + 18, "%lu", &st_net_eicmp6->OutTimeExcds6);
1532                 }
1533                 else if (!strncmp(line, "Icmp6InParmProblems ", 20)) {
1534                         sscanf(line + 20, "%lu", &st_net_eicmp6->InParmProblems6);
1535                 }
1536                 else if (!strncmp(line, "Icmp6OutParmProblems ", 21)) {
1537                         sscanf(line + 21, "%lu", &st_net_eicmp6->OutParmProblems6);
1538                 }
1539                 else if (!strncmp(line, "Icmp6InRedirects ", 17)) {
1540                         sscanf(line + 17, "%lu", &st_net_eicmp6->InRedirects6);
1541                 }
1542                 else if (!strncmp(line, "Icmp6OutRedirects ", 18)) {
1543                         sscanf(line + 18, "%lu", &st_net_eicmp6->OutRedirects6);
1544                 }
1545                 else if (!strncmp(line, "Icmp6InPktTooBigs ", 18)) {
1546                         sscanf(line + 18, "%lu", &st_net_eicmp6->InPktTooBigs6);
1547                 }
1548                 else if (!strncmp(line, "Icmp6OutPktTooBigs ", 19)) {
1549                         sscanf(line + 19, "%lu", &st_net_eicmp6->OutPktTooBigs6);
1550                 }
1551         }
1552         
1553         fclose(fp);
1554 }
1555
1556 /*
1557  ***************************************************************************
1558  * Read UDPv6 network traffic statistics from /proc/net/snmp6.
1559  *
1560  * IN:
1561  * @st_net_udp6 Structure where stats will be saved.
1562  *
1563  * OUT:
1564  * @st_net_udp6 Structure with statistics.
1565  ***************************************************************************
1566  */
1567 void read_net_udp6(struct stats_net_udp6 *st_net_udp6)
1568 {
1569         FILE *fp;
1570         char line[128];
1571
1572         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1573                 return;
1574
1575         while (fgets(line, 128, fp) != NULL) {
1576
1577                 if (!strncmp(line, "Udp6InDatagrams ", 16)) {
1578                         sscanf(line + 16, "%lu", &st_net_udp6->InDatagrams6);
1579                 }
1580                 else if (!strncmp(line, "Udp6OutDatagrams ", 17)) {
1581                         sscanf(line + 17, "%lu", &st_net_udp6->OutDatagrams6);
1582                 }
1583                 else if (!strncmp(line, "Udp6NoPorts ", 12)) {
1584                         sscanf(line + 12, "%lu", &st_net_udp6->NoPorts6);
1585                 }
1586                 else if (!strncmp(line, "Udp6InErrors ", 13)) {
1587                         sscanf(line + 13, "%lu", &st_net_udp6->InErrors6);
1588                 }
1589         }
1590         
1591         fclose(fp);
1592 }
1593
1594 /*
1595  ***************************************************************************
1596  * Read CPU frequency statistics.
1597  *
1598  * IN:
1599  * @st_pwr_cpufreq      Structure where stats will be saved.
1600  * @nbr                 Total number of CPU (including cpu "all").
1601  *
1602  * OUT:
1603  * @st_pwr_cpufreq      Structure with statistics.
1604  ***************************************************************************
1605  */
1606 void read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, int nbr)
1607 {
1608         FILE *fp;
1609         struct stats_pwr_cpufreq *st_pwr_cpufreq_i;
1610         char line[1024];
1611         int proc_nb = 0, nr = 0;
1612         unsigned int ifreq, dfreq;
1613         
1614         if ((fp = fopen(CPUINFO, "r")) == NULL)
1615                 return;
1616         
1617         st_pwr_cpufreq->cpufreq = 0;
1618         
1619         while (fgets(line, 1024, fp) != NULL) {
1620                 
1621                 if (!strncmp(line, "processor\t", 10)) {
1622                         sscanf(strchr(line, ':') + 1, "%d", &proc_nb);
1623                 }
1624                 
1625                 else if (!strncmp(line, "cpu MHz\t", 8)) {
1626                         sscanf(strchr(line, ':') + 1, "%u.%u", &ifreq, &dfreq);
1627                         
1628                         if (proc_nb < (nbr - 1)) {
1629                                 /* Save current CPU frequency */
1630                                 st_pwr_cpufreq_i = st_pwr_cpufreq + proc_nb + 1;
1631                                 st_pwr_cpufreq_i->cpufreq = ifreq * 100 + dfreq / 10;
1632                                 
1633                                 /* Also save it to compute an average CPU frequency */
1634                                 st_pwr_cpufreq->cpufreq += st_pwr_cpufreq_i->cpufreq;
1635                                 nr++;
1636                         }
1637                         else if (!proc_nb && (nbr == 1)) {
1638                                 /*
1639                                  * We are reading freq for "Processor 0" and we have a machine
1640                                  * with only one processor and not an SMP kernel, with /sys not mounted
1641                                  * (the nr of proc has been counted using /proc/stat and there was
1642                                  * only one line with global CPU stats here).
1643                                  * This is a very specific case, I must admit...
1644                                  */
1645                                 st_pwr_cpufreq->cpufreq = ifreq * 100 + dfreq / 10;
1646                         }
1647                 }
1648         }
1649         
1650         fclose(fp);
1651         
1652         if (nr) {
1653                 /* Compute average CPU frequency for this machine */
1654                 st_pwr_cpufreq->cpufreq /= nr;
1655         }
1656 }
1657
1658 /*
1659  ***************************************************************************
1660  * Read hugepages statistics from /proc/meminfo.
1661  *
1662  * IN:
1663  * @st_huge     Structure where stats will be saved.
1664  *
1665  * OUT:
1666  * @st_huge     Structure with statistics.
1667  ***************************************************************************
1668  */
1669 void read_meminfo_huge(struct stats_huge *st_huge)
1670 {
1671         FILE *fp;
1672         char line[128];
1673         unsigned long szhkb = 0;
1674
1675         if ((fp = fopen(MEMINFO, "r")) == NULL)
1676                 return;
1677
1678         while (fgets(line, 128, fp) != NULL) {
1679
1680                 if (!strncmp(line, "HugePages_Total:", 16)) {
1681                         /* Read the total number of huge pages */
1682                         sscanf(line + 16, "%lu", &st_huge->tlhkb);
1683                 }
1684                 else if (!strncmp(line, "HugePages_Free:", 15)) {
1685                         /* Read the number of free huge pages */
1686                         sscanf(line + 15, "%lu", &st_huge->frhkb);
1687                 }
1688                 else if (!strncmp(line, "Hugepagesize:", 13)) {
1689                         /* Read the default size of a huge page in kB */
1690                         sscanf(line + 13, "%lu", &szhkb);
1691                 }
1692         }
1693
1694         fclose(fp);
1695
1696         /* We want huge pages stats in kB and not expressed in a number of pages */
1697         st_huge->tlhkb *= szhkb;
1698         st_huge->frhkb *= szhkb;
1699 }
1700
1701 /*
1702  ***************************************************************************
1703  * Read CPU average frequencies statistics.
1704  *
1705  * IN:
1706  * @st_pwr_wghfreq      Structure where stats will be saved.
1707  * @cpu_nr              CPU number for which time_in_state date will be read.
1708  * @nbr                 Total number of states (frequencies).
1709  *
1710  * OUT:
1711  * @st_pwr_wghfreq      Structure with statistics.
1712  ***************************************************************************
1713  */
1714 void read_time_in_state(struct stats_pwr_wghfreq *st_pwr_wghfreq, int cpu_nr, int nbr)
1715 {
1716         FILE *fp;
1717         struct stats_pwr_wghfreq *st_pwr_wghfreq_j;
1718         char filename[MAX_PF_NAME];
1719         char line[128];
1720         int j = 0;
1721         unsigned long freq;
1722         unsigned long long time_in_state;
1723
1724         snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s",
1725                  SYSFS_DEVCPU, cpu_nr, SYSFS_TIME_IN_STATE);
1726         if ((fp = fopen(filename, "r")) == NULL)
1727                 return;
1728
1729         while (fgets(line, 128, fp) != NULL) {
1730
1731                 sscanf(line, "%lu %llu", &freq, &time_in_state);
1732
1733                 if (j < nbr) {
1734                         /* Save current frequency and time */
1735                         st_pwr_wghfreq_j = st_pwr_wghfreq + j;
1736                         st_pwr_wghfreq_j->freq = freq;
1737                         st_pwr_wghfreq_j->time_in_state = time_in_state;
1738                         j++;
1739                 }
1740         }
1741
1742         fclose(fp);
1743 }
1744
1745 /*
1746  ***************************************************************************
1747  * Read current USB device data.
1748  *
1749  * IN:
1750  * @st_pwr_usb          Structure where stats will be saved.
1751  * @usb_device          File name for current USB device.
1752  *
1753  * OUT:
1754  * @st_pwr_usb          Structure with statistics.
1755  ***************************************************************************
1756  */
1757 void read_usb_stats(struct stats_pwr_usb *st_pwr_usb, char *usb_device)
1758 {
1759         int l;
1760         FILE *fp;
1761         char filename[MAX_PF_NAME];
1762
1763         /* Get USB device bus number */
1764         sscanf(usb_device, "%u", &st_pwr_usb->bus_nr);
1765
1766         /* Read USB device vendor ID */
1767         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
1768                  SYSFS_USBDEV, usb_device, SYSFS_IDVENDOR);
1769         if ((fp = fopen(filename, "r")) != NULL) {
1770                 fscanf(fp, "%x",
1771                        &st_pwr_usb->vendor_id);
1772                 fclose(fp);
1773         }
1774
1775         /* Read USB device product ID */
1776         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
1777                  SYSFS_USBDEV, usb_device, SYSFS_IDPRODUCT);
1778         if ((fp = fopen(filename, "r")) != NULL) {
1779                 fscanf(fp, "%x",
1780                        &st_pwr_usb->product_id);
1781                 fclose(fp);
1782         }
1783         
1784         /* Read USB device max power consumption */
1785         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
1786                  SYSFS_USBDEV, usb_device, SYSFS_BMAXPOWER);
1787         if ((fp = fopen(filename, "r")) != NULL) {
1788                 fscanf(fp, "%u",
1789                        &st_pwr_usb->bmaxpower);
1790                 fclose(fp);
1791         }
1792
1793         /* Read USB device manufacturer */
1794         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
1795                  SYSFS_USBDEV, usb_device, SYSFS_MANUFACTURER);
1796         if ((fp = fopen(filename, "r")) != NULL) {
1797                 fgets(st_pwr_usb->manufacturer, MAX_MANUF_LEN - 1, fp);
1798                 fclose(fp);
1799                 if ((l = strlen(st_pwr_usb->manufacturer)) > 0) {
1800                         /* Remove trailing CR */
1801                         st_pwr_usb->manufacturer[l - 1] = '\0';
1802                 }
1803         }
1804
1805         /* Read USB device product */
1806         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
1807                  SYSFS_USBDEV, usb_device, SYSFS_PRODUCT);
1808         if ((fp = fopen(filename, "r")) != NULL) {
1809                 fgets(st_pwr_usb->product, MAX_PROD_LEN - 1, fp);
1810                 fclose(fp);
1811                 if ((l = strlen(st_pwr_usb->product)) > 0) {
1812                         /* Remove trailing CR */
1813                         st_pwr_usb->product[l - 1] = '\0';
1814                 }
1815         }
1816 }
1817
1818 /*
1819  ***************************************************************************
1820  * Read USB devices statistics.
1821  *
1822  * IN:
1823  * @st_pwr_usb          Structure where stats will be saved.
1824  * @nbr                 Total number of USB devices.
1825  *
1826  * OUT:
1827  * @st_pwr_usb          Structure with statistics.
1828  ***************************************************************************
1829  */
1830 void read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, int nbr)
1831 {
1832         DIR *dir;
1833         struct dirent *drd;
1834         struct stats_pwr_usb *st_pwr_usb_j;
1835         int j = 0;
1836
1837         /* Open relevant /sys directory */
1838         if ((dir = opendir(SYSFS_USBDEV)) == NULL)
1839                 return;
1840
1841         /* Get current file entry */
1842         while ((drd = readdir(dir)) != NULL) {
1843
1844                 if (isdigit(drd->d_name[0]) && !strchr(drd->d_name, ':')) {
1845                         if (j < nbr) {
1846                                 /* Read current USB device data */
1847                                 st_pwr_usb_j = st_pwr_usb + j;
1848                                 read_usb_stats(st_pwr_usb_j, drd->d_name);
1849                                 j++;
1850                         }
1851                         else
1852                                 break;
1853                 }
1854         }
1855
1856         /* Close directory */
1857         closedir(dir);
1858 }
1859
1860 /*
1861  ***************************************************************************
1862  * Read machine uptime, independently of the number of processors.
1863  *
1864  * OUT:
1865  * @uptime      Uptime value in jiffies.
1866  ***************************************************************************
1867  */
1868 void read_uptime(unsigned long long *uptime)
1869 {
1870         FILE *fp;
1871         char line[128];
1872         unsigned long up_sec, up_cent;
1873
1874         if ((fp = fopen(UPTIME, "r")) == NULL)
1875                 return;
1876
1877         if (fgets(line, 128, fp) == NULL) {
1878                 fclose(fp);
1879                 return;
1880         }
1881
1882         sscanf(line, "%lu.%lu", &up_sec, &up_cent);
1883         *uptime = (unsigned long long) up_sec * HZ +
1884                   (unsigned long long) up_cent * HZ / 100;
1885
1886         fclose(fp);
1887
1888 }
1889
1890 /*
1891  ***************************************************************************
1892  * Count number of interrupts that are in /proc/stat file.
1893  *
1894  * RETURNS:
1895  * Number of interrupts, including total number of interrupts.
1896  ***************************************************************************
1897  */
1898 int get_irq_nr(void)
1899 {
1900         FILE *fp;
1901         char line[8192];
1902         int in = 0;
1903         int pos = 4;
1904
1905         if ((fp = fopen(STAT, "r")) == NULL)
1906                 return 0;
1907
1908         while (fgets(line, 8192, fp) != NULL) {
1909
1910                 if (!strncmp(line, "intr ", 5)) {
1911
1912                         while (pos < strlen(line)) {
1913                                 in++;
1914                                 pos += strcspn(line + pos + 1, " ") + 1;
1915                         }
1916                 }
1917         }
1918
1919         fclose(fp);
1920
1921         return in;
1922 }
1923
1924 /*
1925  ***************************************************************************
1926  * Find number of serial lines that support tx/rx accounting
1927  * in /proc/tty/driver/serial file.
1928  *
1929  * RETURNS:
1930  * Number of serial lines supporting tx/rx accouting.
1931  ***************************************************************************
1932  */
1933 int get_serial_nr(void)
1934 {
1935         FILE *fp;
1936         char line[256];
1937         int sl = 0;
1938
1939         if ((fp = fopen(SERIAL, "r")) == NULL)
1940                 return 0;       /* No SERIAL file */
1941
1942         while (fgets(line, 256, fp) != NULL) {
1943                 /*
1944                  * tx/rx statistics are always present,
1945                  * except when serial line is unknown.
1946                  */
1947                 if (strstr(line, "tx:") != NULL) {
1948                         sl++;
1949                 }
1950         }
1951
1952         fclose(fp);
1953
1954         return sl;
1955 }
1956
1957 /*
1958  ***************************************************************************
1959  * Find number of interfaces (network devices) that are in /proc/net/dev
1960  * file.
1961  *
1962  * RETURNS:
1963  * Number of network interfaces.
1964  ***************************************************************************
1965  */
1966 int get_iface_nr(void)
1967 {
1968         FILE *fp;
1969         char line[128];
1970         int iface = 0;
1971
1972         if ((fp = fopen(NET_DEV, "r")) == NULL)
1973                 return 0;       /* No network device file */
1974
1975         while (fgets(line, 128, fp) != NULL) {
1976                 if (strchr(line, ':')) {
1977                         iface++;
1978                 }
1979         }
1980
1981         fclose(fp);
1982
1983         return iface;
1984 }
1985
1986 /*
1987  ***************************************************************************
1988  * Find number of devices and partitions available in /proc/diskstats.
1989  *
1990  * IN:
1991  * @count_part          Set to TRUE if devices _and_ partitions are to be
1992  *                      counted.
1993  * @only_used_dev       When counting devices, set to TRUE if only devices
1994  *                      with non zero stats must be counted.
1995  *
1996  * RETURNS:
1997  * Number of devices (and partitions).
1998  ***************************************************************************
1999  */
2000 int get_diskstats_dev_nr(int count_part, int only_used_dev)
2001 {
2002         FILE *fp;
2003         char line[256];
2004         char dev_name[MAX_NAME_LEN];
2005         int dev = 0, i;
2006         unsigned long rd_ios, wr_ios;
2007
2008         if ((fp = fopen(DISKSTATS, "r")) == NULL)
2009                 /* File non-existent */
2010                 return 0;
2011
2012         /*
2013          * Counting devices and partitions is simply a matter of counting
2014          * the number of lines...
2015          */
2016         while (fgets(line, 256, fp) != NULL) {
2017                 if (!count_part) {
2018                         i = sscanf(line, "%*d %*d %s %lu %*u %*u %*u %lu",
2019                                    dev_name, &rd_ios, &wr_ios);
2020                         if ((i == 2) || !is_device(dev_name, ACCEPT_VIRTUAL_DEVICES))
2021                                 /* It was a partition and not a device */
2022                                 continue;
2023                         if (only_used_dev && !rd_ios && !wr_ios)
2024                                 /* Unused device */
2025                                 continue;
2026                 }
2027                 dev++;
2028         }
2029
2030         fclose(fp);
2031
2032         return dev;
2033 }
2034
2035 /*
2036  ***************************************************************************
2037  * Get number of devices in /proc/diskstats.
2038  *
2039  * IN:
2040  * @f   Non zero (true) if disks *and* partitions should be counted, and
2041  *      zero (false) if only disks must be counted.
2042  *
2043  * RETURNS:
2044  * Number of devices.
2045  ***************************************************************************
2046  */
2047 int get_disk_nr(unsigned int f)
2048 {
2049         int disk_nr;
2050
2051         /*
2052          * Partitions are taken into account by sar -d only with
2053          * kernels 2.6.25 and later.
2054          */
2055         disk_nr = get_diskstats_dev_nr(f, CNT_USED_DEV);
2056
2057         return disk_nr;
2058 }
2059
2060 /*
2061  ***************************************************************************
2062  * Count number of processors in /sys.
2063  *
2064  * RETURNS:
2065  * Number of processors (online and offline).
2066  * A value of 0 means that /sys was not mounted.
2067  * A value of N (!=0) means N processor(s) (cpu0 .. cpu(N-1)).
2068  ***************************************************************************
2069  */
2070 int get_sys_cpu_nr(void)
2071 {
2072         DIR *dir;
2073         struct dirent *drd;
2074         struct stat buf;
2075         char line[MAX_PF_NAME];
2076         int proc_nr = 0;
2077
2078         /* Open relevant /sys directory */
2079         if ((dir = opendir(SYSFS_DEVCPU)) == NULL)
2080                 return 0;
2081
2082         /* Get current file entry */
2083         while ((drd = readdir(dir)) != NULL) {
2084
2085                 if (!strncmp(drd->d_name, "cpu", 3) && isdigit(drd->d_name[3])) {
2086                         snprintf(line, MAX_PF_NAME, "%s/%s", SYSFS_DEVCPU, drd->d_name);
2087                         line[MAX_PF_NAME - 1] = '\0';
2088                         if (stat(line, &buf) < 0)
2089                                 continue;
2090                         if (S_ISDIR(buf.st_mode)) {
2091                                 proc_nr++;
2092                         }
2093                 }
2094         }
2095
2096         /* Close directory */
2097         closedir(dir);
2098
2099         return proc_nr;
2100 }
2101
2102 /*
2103  ***************************************************************************
2104  * Count number of processors in /proc/stat.
2105  *
2106  * RETURNS:
2107  * Number of processors. The returned value is greater than or equal to the
2108  * number of online processors.
2109  * A value of 0 means one processor and non SMP kernel.
2110  * A value of N (!=0) means N processor(s) (0 .. N-1) with SMP kernel.
2111  ***************************************************************************
2112  */
2113 int get_proc_cpu_nr(void)
2114 {
2115         FILE *fp;
2116         char line[16];
2117         int num_proc, proc_nr = -1;
2118
2119         if ((fp = fopen(STAT, "r")) == NULL) {
2120                 fprintf(stderr, _("Cannot open %s: %s\n"), STAT, strerror(errno));
2121                 exit(1);
2122         }
2123
2124         while (fgets(line, 16, fp) != NULL) {
2125
2126                 if (strncmp(line, "cpu ", 4) && !strncmp(line, "cpu", 3)) {
2127                         sscanf(line + 3, "%d", &num_proc);
2128                         if (num_proc > proc_nr) {
2129                                 proc_nr = num_proc;
2130                         }
2131                 }
2132         }
2133
2134         fclose(fp);
2135
2136         return (proc_nr + 1);
2137 }
2138
2139 /*
2140  ***************************************************************************
2141  * Count the number of processors on the machine.
2142  * Try to use /sys for that, or /proc/stat if /sys doesn't exist.
2143  *
2144  * IN:
2145  * @max_nr_cpus Maximum number of proc that sysstat can handle.
2146  *
2147  * RETURNS:
2148  * Number of processors.
2149  * 0: one proc and non SMP kernel.
2150  * 1: one proc and SMP kernel (NB: On SMP machines where all the CPUs but
2151  *    one have been disabled, we get the total number of proc since we use
2152  *    /sys to count them).
2153  * 2: two proc...
2154  ***************************************************************************
2155  */
2156 int get_cpu_nr(unsigned int max_nr_cpus)
2157 {
2158         int cpu_nr;
2159
2160         if ((cpu_nr = get_sys_cpu_nr()) == 0) {
2161                 /* /sys may be not mounted. Use /proc/stat instead */
2162                 cpu_nr = get_proc_cpu_nr();
2163         }
2164
2165         if (cpu_nr > max_nr_cpus) {
2166                 fprintf(stderr, _("Cannot handle so many processors!\n"));
2167                 exit(1);
2168         }
2169
2170         return cpu_nr;
2171 }
2172
2173 /*
2174  ***************************************************************************
2175  * Find number of interrupts available per processor (use
2176  * /proc/interrupts file or /proc/softirqs).
2177  *
2178  * IN:
2179  * @file                /proc file to read (interrupts or softirqs).
2180  * @max_nr_irqcpu       Maximum number of interrupts per processor that
2181  *                      sadc can handle.
2182  * @cpu_nr              Number of processors.
2183  *
2184  * RETURNS:
2185  * Number of interrupts per processor + a pre-allocation constant.
2186  ***************************************************************************
2187  */
2188 int get_irqcpu_nr(char *file, int max_nr_irqcpu, int cpu_nr)
2189 {
2190         FILE *fp;
2191         char *line = NULL;
2192         unsigned int irq = 0;
2193         int p;
2194
2195         if ((fp = fopen(file, "r")) == NULL)
2196                 return 0;       /* No interrupts file */
2197
2198         SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
2199
2200         while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr , fp) != NULL) &&
2201                (irq < max_nr_irqcpu)) {
2202                 p = strcspn(line, ":");
2203                 if ((p > 0) && (p < 16)) {
2204                         irq++;
2205                 }
2206         }
2207
2208         fclose(fp);
2209
2210         if (line) {
2211                 free(line);
2212         }
2213
2214         return irq;
2215 }
2216
2217 /*
2218  ***************************************************************************
2219  * Count number of possible frequencies for CPU#0.
2220  *
2221  * RETURNS:
2222  * Number of frequencies.
2223  ***************************************************************************
2224  */
2225 int get_freq_nr(void)
2226 {
2227         FILE *fp;
2228         char filename[MAX_PF_NAME];
2229         char line[128];
2230         int freq = 0;
2231
2232         snprintf(filename, MAX_PF_NAME, "%s/cpu0/%s",
2233                  SYSFS_DEVCPU, SYSFS_TIME_IN_STATE);
2234         if ((fp = fopen(filename, "r")) == NULL)
2235                 return 0;       /* No time_in_state file for CPU#0 */
2236
2237         while (fgets(line, 128, fp) != NULL) {
2238                 freq++;
2239         }
2240
2241         fclose(fp);
2242
2243         return freq;
2244 }
2245
2246 /*
2247  ***************************************************************************
2248  * Count number of USB devices in /sys/bus/usb/devices.
2249  *
2250  * RETURNS:
2251  * Number of USB devices plugged into the system.
2252  * Don't count USB root hubs.
2253  * Return -1 if directory doesn't exist in sysfs.
2254  ***************************************************************************
2255  */
2256 int get_usb_nr(void)
2257 {
2258         DIR *dir;
2259         struct dirent *drd;
2260         int usb = 0;
2261
2262         /* Open relevant /sys directory */
2263         if ((dir = opendir(SYSFS_USBDEV)) == NULL)
2264                 return -1;
2265
2266         /* Get current file entry */
2267         while ((drd = readdir(dir)) != NULL) {
2268
2269                 if (isdigit(drd->d_name[0]) && !strchr(drd->d_name, ':')) {
2270                         usb++;
2271                 }
2272         }
2273
2274         /* Close directory */
2275         closedir(dir);
2276
2277         return usb;
2278 }