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