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