]> granicus.if.org Git - sysstat/blob - rd_stats.c
iostat: Add initial support for discard I/O
[sysstat] / rd_stats.c
1 /*
2  * rd_stats.c: Read system statistics
3  * (C) 1999-2018 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, rd_sec, wr_sec;
726
727         if ((fp = fopen(DISKSTATS, "r")) == NULL)
728                 return 0;
729
730         while (fgets(line, sizeof(line), fp) != NULL) {
731
732                 if (sscanf(line, "%u %u %s %lu %*u %lu %*u %lu %*u %lu",
733                            &major, &minor, dev_name,
734                            &rd_ios, &rd_sec, &wr_ios, &wr_sec) == 7) {
735
736                         if (is_device(dev_name, IGNORE_VIRTUAL_DEVICES)) {
737                                 /*
738                                  * OK: It's a (real) device and not a partition.
739                                  * Note: Structure should have been initialized first!
740                                  */
741                                 st_io->dk_drive      += (unsigned long long) rd_ios + (unsigned long long) wr_ios;
742                                 st_io->dk_drive_rio  += rd_ios;
743                                 st_io->dk_drive_rblk += rd_sec;
744                                 st_io->dk_drive_wio  += wr_ios;
745                                 st_io->dk_drive_wblk += wr_sec;
746                         }
747                 }
748         }
749
750         fclose(fp);
751         return 1;
752 }
753
754 /*
755  ***************************************************************************
756  * Read block devices statistics from /proc/diskstats.
757  *
758  * IN:
759  * @st_disk     Structure where stats will be saved.
760  * @nr_alloc    Total number of structures allocated. Value is >= 1.
761  * @read_part   True if disks *and* partitions should be read; False if only
762  *              disks are read.
763  *
764  * OUT:
765  * @st_disk     Structure with statistics.
766  *
767  * RETURNS:
768  * Number of block devices read, or -1 if the buffer was too small and
769  * needs to be reallocated.
770  ***************************************************************************
771  */
772 __nr_t read_diskstats_disk(struct stats_disk *st_disk, __nr_t nr_alloc,
773                            int read_part)
774 {
775         FILE *fp;
776         char line[1024];
777         char dev_name[MAX_NAME_LEN];
778         struct stats_disk *st_disk_i;
779         unsigned int major, minor, rd_ticks, wr_ticks, tot_ticks, rq_ticks;
780         unsigned long rd_ios, wr_ios, rd_sec, wr_sec;
781         __nr_t dsk_read = 0;
782
783         if ((fp = fopen(DISKSTATS, "r")) == NULL)
784                 return 0;
785
786         while (fgets(line, sizeof(line), fp) != NULL) {
787
788                 if (sscanf(line, "%u %u %s %lu %*u %lu %u %lu %*u %lu"
789                            " %u %*u %u %u",
790                            &major, &minor, dev_name,
791                            &rd_ios, &rd_sec, &rd_ticks, &wr_ios, &wr_sec, &wr_ticks,
792                            &tot_ticks, &rq_ticks) == 11) {
793
794                         if (!rd_ios && !wr_ios)
795                                 /* Unused device: Ignore it */
796                                 continue;
797                         if (read_part || is_device(dev_name, ACCEPT_VIRTUAL_DEVICES)) {
798
799                                 if (dsk_read + 1 > nr_alloc) {
800                                         dsk_read = -1;
801                                         break;
802                                 }
803
804                                 st_disk_i = st_disk + dsk_read++;
805                                 st_disk_i->major     = major;
806                                 st_disk_i->minor     = minor;
807                                 st_disk_i->nr_ios    = (unsigned long long) rd_ios + (unsigned long long) wr_ios;
808                                 st_disk_i->rd_sect   = rd_sec;
809                                 st_disk_i->wr_sect   = wr_sec;
810                                 st_disk_i->rd_ticks  = rd_ticks;
811                                 st_disk_i->wr_ticks  = wr_ticks;
812                                 st_disk_i->tot_ticks = tot_ticks;
813                                 st_disk_i->rq_ticks  = rq_ticks;
814                         }
815                 }
816         }
817
818         fclose(fp);
819         return dsk_read;
820 }
821
822 /*
823  ***************************************************************************
824  * Read serial lines statistics from /proc/tty/driver/serial.
825  *
826  * IN:
827  * @st_serial   Structure where stats will be saved.
828  * @nr_alloc    Total number of structures allocated. Value is >= 1.
829  *
830  * OUT:
831  * @st_serial   Structure with statistics.
832  *
833  * RETURNS:
834  * Number of serial lines read, or -1 if the buffer was too small and
835  * needs to be reallocated.
836  ***************************************************************************
837  */
838 __nr_t read_tty_driver_serial(struct stats_serial *st_serial, __nr_t nr_alloc)
839 {
840         FILE *fp;
841         struct stats_serial *st_serial_i;
842         char line[256];
843         char *p;
844         __nr_t sl_read = 0;
845
846         if ((fp = fopen(SERIAL, "r")) == NULL)
847                 return 0;
848
849         while (fgets(line, sizeof(line), fp) != NULL ) {
850
851                 if ((p = strstr(line, "tx:")) != NULL) {
852
853                         if (sl_read + 1 > nr_alloc) {
854                                 sl_read = -1;
855                                 break;
856                         }
857
858                         st_serial_i = st_serial + sl_read++;
859                         /* Read serial line number */
860                         sscanf(line, "%u", &st_serial_i->line);
861                         /*
862                          * Read the number of chars transmitted and received by
863                          * current serial line.
864                          */
865                         sscanf(p + 3, "%u", &st_serial_i->tx);
866                         if ((p = strstr(line, "rx:")) != NULL) {
867                                 sscanf(p + 3, "%u", &st_serial_i->rx);
868                         }
869                         if ((p = strstr(line, "fe:")) != NULL) {
870                                 sscanf(p + 3, "%u", &st_serial_i->frame);
871                         }
872                         if ((p = strstr(line, "pe:")) != NULL) {
873                                 sscanf(p + 3, "%u", &st_serial_i->parity);
874                         }
875                         if ((p = strstr(line, "brk:")) != NULL) {
876                                 sscanf(p + 4, "%u", &st_serial_i->brk);
877                         }
878                         if ((p = strstr(line, "oe:")) != NULL) {
879                                 sscanf(p + 3, "%u", &st_serial_i->overrun);
880                         }
881                 }
882         }
883
884         fclose(fp);
885         return sl_read;
886 }
887
888 /*
889  ***************************************************************************
890  * Read kernel tables statistics from various system files.
891  *
892  * IN:
893  * @st_ktables  Structure where stats will be saved.
894  *
895  * OUT:
896  * @st_ktables  Structure with statistics.
897  *
898  * RETURNS:
899  * 1 (always success).
900  ***************************************************************************
901  */
902 __nr_t read_kernel_tables(struct stats_ktables *st_ktables)
903 {
904         FILE *fp;
905         unsigned long long parm;
906         int rc = 0;
907
908         /* Open /proc/sys/fs/dentry-state file */
909         if ((fp = fopen(FDENTRY_STATE, "r")) != NULL) {
910                 rc = fscanf(fp, "%*d %llu",
911                             &st_ktables->dentry_stat);
912                 fclose(fp);
913                 if (rc == 0) {
914                         st_ktables->dentry_stat = 0;
915                 }
916         }
917
918         /* Open /proc/sys/fs/file-nr file */
919         if ((fp = fopen(FFILE_NR, "r")) != NULL) {
920                 rc = fscanf(fp, "%llu %llu",
921                             &st_ktables->file_used, &parm);
922                 fclose(fp);
923                 /*
924                  * The number of used handles is the number of allocated ones
925                  * minus the number of free ones.
926                  */
927                 if (rc == 2) {
928                         st_ktables->file_used -= parm;
929                 }
930                 else {
931                         st_ktables->file_used = 0;
932                 }
933         }
934
935         /* Open /proc/sys/fs/inode-state file */
936         if ((fp = fopen(FINODE_STATE, "r")) != NULL) {
937                 rc = fscanf(fp, "%llu %llu",
938                             &st_ktables->inode_used, &parm);
939                 fclose(fp);
940                 /*
941                  * The number of inuse inodes is the number of allocated ones
942                  * minus the number of free ones.
943                  */
944                 if (rc == 2) {
945                         st_ktables->inode_used -= parm;
946                 }
947                 else {
948                         st_ktables->inode_used = 0;
949                 }
950         }
951
952         /* Open /proc/sys/kernel/pty/nr file */
953         if ((fp = fopen(PTY_NR, "r")) != NULL) {
954                 rc = fscanf(fp, "%llu",
955                             &st_ktables->pty_nr);
956                 fclose(fp);
957                 if (rc == 0) {
958                         st_ktables->pty_nr = 0;
959                 }
960         }
961
962         return 1;
963 }
964
965 /*
966  ***************************************************************************
967  * Read network interfaces statistics from /proc/net/dev.
968  *
969  * IN:
970  * @st_net_dev  Structure where stats will be saved.
971  * @nr_alloc    Total number of structures allocated. Value is >= 1.
972  *
973  * OUT:
974  * @st_net_dev  Structure with statistics.
975  *
976  * RETURNS:
977  * Number of interfaces read, or -1 if the buffer was too small and
978  * needs to be reallocated.
979  ***************************************************************************
980  */
981 __nr_t read_net_dev(struct stats_net_dev *st_net_dev, __nr_t nr_alloc)
982 {
983         FILE *fp;
984         struct stats_net_dev *st_net_dev_i;
985         char line[256];
986         char iface[MAX_IFACE_LEN];
987         __nr_t dev_read = 0;
988         int pos;
989
990         if ((fp = fopen(NET_DEV, "r")) == NULL)
991                 return 0;
992
993         while (fgets(line, sizeof(line), fp) != NULL) {
994
995                 pos = strcspn(line, ":");
996                 if (pos < strlen(line)) {
997
998                         if (dev_read + 1 > nr_alloc) {
999                                 dev_read = -1;
1000                                 break;
1001                         }
1002
1003                         st_net_dev_i = st_net_dev + dev_read++;
1004                         strncpy(iface, line, MINIMUM(pos, MAX_IFACE_LEN - 1));
1005                         iface[MINIMUM(pos, MAX_IFACE_LEN - 1)] = '\0';
1006                         sscanf(iface, "%s", st_net_dev_i->interface); /* Skip heading spaces */
1007                         sscanf(line + pos + 1, "%llu %llu %*u %*u %*u %*u %llu %llu %llu %llu "
1008                                "%*u %*u %*u %*u %*u %llu",
1009                                &st_net_dev_i->rx_bytes,
1010                                &st_net_dev_i->rx_packets,
1011                                &st_net_dev_i->rx_compressed,
1012                                &st_net_dev_i->multicast,
1013                                &st_net_dev_i->tx_bytes,
1014                                &st_net_dev_i->tx_packets,
1015                                &st_net_dev_i->tx_compressed);
1016                 }
1017         }
1018
1019         fclose(fp);
1020         return dev_read;
1021 }
1022
1023 /*
1024  ***************************************************************************
1025  * Read duplex and speed data for network interface cards.
1026  *
1027  * IN:
1028  * @st_net_dev  Structure where stats will be saved.
1029  * @nbr         Number of network interfaces to read.
1030  *
1031  * OUT:
1032  * @st_net_dev  Structure with statistics.
1033  ***************************************************************************
1034  */
1035 void read_if_info(struct stats_net_dev *st_net_dev, int nbr)
1036 {
1037         FILE *fp;
1038         struct stats_net_dev *st_net_dev_i;
1039         char filename[128], duplex[32];
1040         int dev, n;
1041
1042         for (dev = 0; dev < nbr; dev++) {
1043
1044                 st_net_dev_i = st_net_dev + dev;
1045
1046                 /* Read speed info */
1047                 sprintf(filename, IF_DUPLEX, st_net_dev_i->interface);
1048
1049                 if ((fp = fopen(filename, "r")) == NULL)
1050                         /* Cannot read NIC duplex */
1051                         continue;
1052
1053                 n = fscanf(fp, "%31s", duplex);
1054
1055                 fclose(fp);
1056
1057                 if (n != 1)
1058                         /* Cannot read NIC duplex */
1059                         continue;
1060
1061                 if (!strcmp(duplex, K_DUPLEX_FULL)) {
1062                         st_net_dev_i->duplex = C_DUPLEX_FULL;
1063                 }
1064                 else if (!strcmp(duplex, K_DUPLEX_HALF)) {
1065                         st_net_dev_i->duplex = C_DUPLEX_HALF;
1066                 }
1067                 else
1068                         continue;
1069
1070                 /* Read speed info */
1071                 sprintf(filename, IF_SPEED, st_net_dev_i->interface);
1072
1073                 if ((fp = fopen(filename, "r")) == NULL)
1074                         /* Cannot read NIC speed */
1075                         continue;
1076
1077                 n = fscanf(fp, "%u", &st_net_dev_i->speed);
1078
1079                 fclose(fp);
1080
1081                 if (n != 1) {
1082                         st_net_dev_i->speed = 0;
1083                 }
1084         }
1085 }
1086
1087
1088 /*
1089  ***************************************************************************
1090  * Read network interfaces errors statistics from /proc/net/dev.
1091  *
1092  * IN:
1093  * @st_net_edev Structure where stats will be saved.
1094  * @nr_alloc    Total number of structures allocated. Value is >= 1.
1095  *
1096  * OUT:
1097  * @st_net_edev Structure with statistics.
1098  *
1099  * RETURNS:
1100  * Number of interfaces read, or -1 if the buffer was too small and
1101  * needs to be reallocated.
1102  ***************************************************************************
1103  */
1104 __nr_t read_net_edev(struct stats_net_edev *st_net_edev, __nr_t nr_alloc)
1105 {
1106         FILE *fp;
1107         struct stats_net_edev *st_net_edev_i;
1108         static char line[256];
1109         char iface[MAX_IFACE_LEN];
1110         __nr_t dev_read = 0;
1111         int pos;
1112
1113         if ((fp = fopen(NET_DEV, "r")) == NULL)
1114                 return 0;
1115
1116         while (fgets(line, sizeof(line), fp) != NULL) {
1117
1118                 pos = strcspn(line, ":");
1119                 if (pos < strlen(line)) {
1120
1121                         if (dev_read + 1 > nr_alloc) {
1122                                 dev_read = -1;
1123                                 break;
1124                         }
1125
1126                         st_net_edev_i = st_net_edev + dev_read++;
1127                         strncpy(iface, line, MINIMUM(pos, MAX_IFACE_LEN - 1));
1128                         iface[MINIMUM(pos, MAX_IFACE_LEN - 1)] = '\0';
1129                         sscanf(iface, "%s", st_net_edev_i->interface); /* Skip heading spaces */
1130                         sscanf(line + pos + 1, "%*u %*u %llu %llu %llu %llu %*u %*u %*u %*u "
1131                                "%llu %llu %llu %llu %llu",
1132                                &st_net_edev_i->rx_errors,
1133                                &st_net_edev_i->rx_dropped,
1134                                &st_net_edev_i->rx_fifo_errors,
1135                                &st_net_edev_i->rx_frame_errors,
1136                                &st_net_edev_i->tx_errors,
1137                                &st_net_edev_i->tx_dropped,
1138                                &st_net_edev_i->tx_fifo_errors,
1139                                &st_net_edev_i->collisions,
1140                                &st_net_edev_i->tx_carrier_errors);
1141                 }
1142         }
1143
1144         fclose(fp);
1145         return dev_read;
1146 }
1147
1148 /*
1149  ***************************************************************************
1150  * Read NFS client statistics from /proc/net/rpc/nfs.
1151  *
1152  * IN:
1153  * @st_net_nfs  Structure where stats will be saved.
1154  *
1155  * OUT:
1156  * @st_net_nfs  Structure with statistics.
1157  *
1158  * RETURNS:
1159  * 1 on success, 0 otherwise.
1160  ***************************************************************************
1161  */
1162 __nr_t read_net_nfs(struct stats_net_nfs *st_net_nfs)
1163 {
1164         FILE *fp;
1165         char line[256];
1166         unsigned int getattcnt = 0, accesscnt = 0, readcnt = 0, writecnt = 0;
1167
1168         if ((fp = fopen(NET_RPC_NFS, "r")) == NULL)
1169                 return 0;
1170
1171         memset(st_net_nfs, 0, STATS_NET_NFS_SIZE);
1172
1173         while (fgets(line, sizeof(line), fp) != NULL) {
1174
1175                 if (!strncmp(line, "rpc ", 4)) {
1176                         sscanf(line + 4, "%u %u",
1177                                &st_net_nfs->nfs_rpccnt, &st_net_nfs->nfs_rpcretrans);
1178                 }
1179                 else if (!strncmp(line, "proc3 ", 6)) {
1180                         sscanf(line + 6, "%*u %*u %u %*u %*u %u %*u %u %u",
1181                                &getattcnt, &accesscnt, &readcnt, &writecnt);
1182
1183                         st_net_nfs->nfs_getattcnt += getattcnt;
1184                         st_net_nfs->nfs_accesscnt += accesscnt;
1185                         st_net_nfs->nfs_readcnt   += readcnt;
1186                         st_net_nfs->nfs_writecnt  += writecnt;
1187                 }
1188                 else if (!strncmp(line, "proc4 ", 6)) {
1189                         sscanf(line + 6, "%*u %*u %u %u "
1190                                "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u %u",
1191                                &readcnt, &writecnt, &accesscnt, &getattcnt);
1192
1193                         st_net_nfs->nfs_getattcnt += getattcnt;
1194                         st_net_nfs->nfs_accesscnt += accesscnt;
1195                         st_net_nfs->nfs_readcnt   += readcnt;
1196                         st_net_nfs->nfs_writecnt  += writecnt;
1197                 }
1198         }
1199
1200         fclose(fp);
1201         return 1;
1202 }
1203
1204 /*
1205  ***************************************************************************
1206  * Read NFS server statistics from /proc/net/rpc/nfsd.
1207  *
1208  * IN:
1209  * @st_net_nfsd Structure where stats will be saved.
1210  *
1211  * OUT:
1212  * @st_net_nfsd Structure with statistics.
1213  *
1214  * RETURNS:
1215  * 1 on success, 0 otherwise.
1216  ***************************************************************************
1217  */
1218 __nr_t read_net_nfsd(struct stats_net_nfsd *st_net_nfsd)
1219 {
1220         FILE *fp;
1221         char line[256];
1222         unsigned int getattcnt = 0, accesscnt = 0, readcnt = 0, writecnt = 0;
1223
1224         if ((fp = fopen(NET_RPC_NFSD, "r")) == NULL)
1225                 return 0;
1226
1227         memset(st_net_nfsd, 0, STATS_NET_NFSD_SIZE);
1228
1229         while (fgets(line, sizeof(line), fp) != NULL) {
1230
1231                 if (!strncmp(line, "rc ", 3)) {
1232                         sscanf(line + 3, "%u %u",
1233                                &st_net_nfsd->nfsd_rchits, &st_net_nfsd->nfsd_rcmisses);
1234                 }
1235                 else if (!strncmp(line, "net ", 4)) {
1236                         sscanf(line + 4, "%u %u %u",
1237                                &st_net_nfsd->nfsd_netcnt, &st_net_nfsd->nfsd_netudpcnt,
1238                                &st_net_nfsd->nfsd_nettcpcnt);
1239                 }
1240                 else if (!strncmp(line, "rpc ", 4)) {
1241                         sscanf(line + 4, "%u %u",
1242                                &st_net_nfsd->nfsd_rpccnt, &st_net_nfsd->nfsd_rpcbad);
1243                 }
1244                 else if (!strncmp(line, "proc3 ", 6)) {
1245                         sscanf(line + 6, "%*u %*u %u %*u %*u %u %*u %u %u",
1246                                &getattcnt, &accesscnt, &readcnt, &writecnt);
1247
1248                         st_net_nfsd->nfsd_getattcnt += getattcnt;
1249                         st_net_nfsd->nfsd_accesscnt += accesscnt;
1250                         st_net_nfsd->nfsd_readcnt   += readcnt;
1251                         st_net_nfsd->nfsd_writecnt  += writecnt;
1252
1253                 }
1254                 else if (!strncmp(line, "proc4ops ", 9)) {
1255                         sscanf(line + 9, "%*u %*u %*u %*u %u "
1256                                "%*u %*u %*u %*u %*u %u "
1257                                "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u "
1258                                "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u",
1259                                &accesscnt, &getattcnt, &readcnt, &writecnt);
1260
1261                         st_net_nfsd->nfsd_getattcnt += getattcnt;
1262                         st_net_nfsd->nfsd_accesscnt += accesscnt;
1263                         st_net_nfsd->nfsd_readcnt   += readcnt;
1264                         st_net_nfsd->nfsd_writecnt  += writecnt;
1265                 }
1266         }
1267
1268         fclose(fp);
1269         return 1;
1270 }
1271
1272 /*
1273  ***************************************************************************
1274  * Read network sockets statistics from /proc/net/sockstat.
1275  *
1276  * IN:
1277  * @st_net_sock Structure where stats will be saved.
1278  *
1279  * OUT:
1280  * @st_net_sock Structure with statistics.
1281  *
1282  * RETURNS:
1283  * 1 on success, 0 otherwise.
1284  ***************************************************************************
1285  */
1286 __nr_t read_net_sock(struct stats_net_sock *st_net_sock)
1287 {
1288         FILE *fp;
1289         char line[96];
1290         char *p;
1291
1292         if ((fp = fopen(NET_SOCKSTAT, "r")) == NULL)
1293                 return 0;
1294
1295         while (fgets(line, sizeof(line), fp) != NULL) {
1296
1297                 if (!strncmp(line, "sockets:", 8)) {
1298                         /* Sockets */
1299                         sscanf(line + 14, "%u", &st_net_sock->sock_inuse);
1300                 }
1301                 else if (!strncmp(line, "TCP:", 4)) {
1302                         /* TCP sockets */
1303                         sscanf(line + 11, "%u", &st_net_sock->tcp_inuse);
1304                         if ((p = strstr(line, "tw")) != NULL) {
1305                                 sscanf(p + 2, "%u", &st_net_sock->tcp_tw);
1306                         }
1307                 }
1308                 else if (!strncmp(line, "UDP:", 4)) {
1309                         /* UDP sockets */
1310                         sscanf(line + 11, "%u", &st_net_sock->udp_inuse);
1311                 }
1312                 else if (!strncmp(line, "RAW:", 4)) {
1313                         /* RAW sockets */
1314                         sscanf(line + 11, "%u", &st_net_sock->raw_inuse);
1315                 }
1316                 else if (!strncmp(line, "FRAG:", 5)) {
1317                         /* FRAGments */
1318                         sscanf(line + 12, "%u", &st_net_sock->frag_inuse);
1319                 }
1320         }
1321
1322         fclose(fp);
1323         return 1;
1324 }
1325
1326 /*
1327  ***************************************************************************
1328  * Read IP network traffic statistics from /proc/net/snmp.
1329  *
1330  * IN:
1331  * @st_net_ip   Structure where stats will be saved.
1332  *
1333  * OUT:
1334  * @st_net_ip   Structure with statistics.
1335  *
1336  * RETURNS:
1337  * 1 on success, 0 otherwise.
1338  ***************************************************************************
1339  */
1340 __nr_t read_net_ip(struct stats_net_ip *st_net_ip)
1341 {
1342         FILE *fp;
1343         char line[1024];
1344         int sw = FALSE;
1345
1346         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1347                 return 0;
1348
1349         while (fgets(line, sizeof(line), fp) != NULL) {
1350
1351                 if (!strncmp(line, "Ip:", 3)) {
1352                         if (sw) {
1353                                 sscanf(line + 3, "%*u %*u %llu %*u %*u %llu %*u %*u "
1354                                        "%llu %llu %*u %*u %*u %llu %llu %*u %llu %*u %llu",
1355                                        &st_net_ip->InReceives,
1356                                        &st_net_ip->ForwDatagrams,
1357                                        &st_net_ip->InDelivers,
1358                                        &st_net_ip->OutRequests,
1359                                        &st_net_ip->ReasmReqds,
1360                                        &st_net_ip->ReasmOKs,
1361                                        &st_net_ip->FragOKs,
1362                                        &st_net_ip->FragCreates);
1363
1364                                 break;
1365                         }
1366                         else {
1367                                 sw = TRUE;
1368                         }
1369                 }
1370         }
1371
1372         fclose(fp);
1373         return 1;
1374 }
1375
1376 /*
1377  ***************************************************************************
1378  * Read IP network errors statistics from /proc/net/snmp.
1379  *
1380  * IN:
1381  * @st_net_eip  Structure where stats will be saved.
1382  *
1383  * OUT:
1384  * @st_net_eip  Structure with statistics.
1385  *
1386  * RETURNS:
1387  * 1 on success, 0 otherwise.
1388  ***************************************************************************
1389  */
1390 __nr_t read_net_eip(struct stats_net_eip *st_net_eip)
1391 {
1392         FILE *fp;
1393         char line[1024];
1394         int sw = FALSE;
1395
1396         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1397                 return 0;
1398
1399         while (fgets(line, sizeof(line), fp) != NULL) {
1400
1401                 if (!strncmp(line, "Ip:", 3)) {
1402                         if (sw) {
1403                                 sscanf(line + 3, "%*u %*u %*u %llu %llu %*u %llu %llu "
1404                                        "%*u %*u %llu %llu %*u %*u %*u %llu %*u %llu",
1405                                        &st_net_eip->InHdrErrors,
1406                                        &st_net_eip->InAddrErrors,
1407                                        &st_net_eip->InUnknownProtos,
1408                                        &st_net_eip->InDiscards,
1409                                        &st_net_eip->OutDiscards,
1410                                        &st_net_eip->OutNoRoutes,
1411                                        &st_net_eip->ReasmFails,
1412                                        &st_net_eip->FragFails);
1413
1414                                 break;
1415                         }
1416                         else {
1417                                 sw = TRUE;
1418                         }
1419                 }
1420         }
1421
1422         fclose(fp);
1423         return 1;
1424 }
1425
1426 /*
1427  ***************************************************************************
1428  * Read ICMP network traffic statistics from /proc/net/snmp.
1429  *
1430  * IN:
1431  * @st_net_icmp Structure where stats will be saved.
1432  *
1433  * OUT:
1434  * @st_net_icmp Structure with statistics.
1435  *
1436  * RETURNS:
1437  * 1 on success, 0 otherwise.
1438  ***************************************************************************
1439  */
1440 __nr_t read_net_icmp(struct stats_net_icmp *st_net_icmp)
1441 {
1442         FILE *fp;
1443         char line[1024];
1444         static char format[256] = "";
1445         int sw = FALSE;
1446
1447         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1448                 return 0;
1449
1450         while (fgets(line, sizeof(line), fp) != NULL) {
1451
1452                 if (!strncmp(line, "Icmp:", 5)) {
1453                         if (sw) {
1454                                 sscanf(line + 5, format,
1455                                        &st_net_icmp->InMsgs,
1456                                        &st_net_icmp->InEchos,
1457                                        &st_net_icmp->InEchoReps,
1458                                        &st_net_icmp->InTimestamps,
1459                                        &st_net_icmp->InTimestampReps,
1460                                        &st_net_icmp->InAddrMasks,
1461                                        &st_net_icmp->InAddrMaskReps,
1462                                        &st_net_icmp->OutMsgs,
1463                                        &st_net_icmp->OutEchos,
1464                                        &st_net_icmp->OutEchoReps,
1465                                        &st_net_icmp->OutTimestamps,
1466                                        &st_net_icmp->OutTimestampReps,
1467                                        &st_net_icmp->OutAddrMasks,
1468                                        &st_net_icmp->OutAddrMaskReps);
1469
1470                                 break;
1471                         }
1472                         else {
1473                                 if (!strlen(format)) {
1474                                         if (strstr(line, "InCsumErrors")) {
1475                                                 /*
1476                                                  * New format: InCsumErrors field exists at position #3.
1477                                                  * Capture: 1,9,10,11,12,13,14,15,22,23,24,25,26,27.
1478                                                  */
1479                                                 strcpy(format, "%lu %*u %*u %*u %*u %*u %*u %*u "
1480                                                                "%lu %lu %lu %lu %lu %lu %lu %*u %*u %*u %*u "
1481                                                                "%*u %*u %lu %lu %lu %lu %lu %lu");
1482                                         }
1483                                         else {
1484                                                 /*
1485                                                  * Old format: InCsumErrors field doesn't exist.
1486                                                  * Capture: 1,8,9,10,11,12,13,14,21,22,23,24,25,26.
1487                                                  */
1488                                                 strcpy(format, "%lu %*u %*u %*u %*u %*u %*u "
1489                                                                "%lu %lu %lu %lu %lu %lu %lu %*u %*u %*u %*u "
1490                                                                "%*u %*u %lu %lu %lu %lu %lu %lu");
1491                                         }
1492                                 }
1493                                 sw = TRUE;
1494                         }
1495                 }
1496         }
1497
1498         fclose(fp);
1499         return 1;
1500 }
1501
1502 /*
1503  ***************************************************************************
1504  * Read ICMP network errors statistics from /proc/net/snmp.
1505  *
1506  * IN:
1507  * @st_net_eicmp        Structure where stats will be saved.
1508  *
1509  * OUT:
1510  * @st_net_eicmp        Structure with statistics.
1511  *
1512  * RETURNS:
1513  * 1 on success, 0 otherwise.
1514  ***************************************************************************
1515  */
1516 __nr_t read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
1517 {
1518         FILE *fp;
1519         char line[1024];
1520         int sw = FALSE;
1521
1522         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1523                 return 0;
1524
1525         while (fgets(line, sizeof(line), fp) != NULL) {
1526
1527                 if (!strncmp(line, "Icmp:", 5)) {
1528                         if (sw) {
1529                                 sscanf(line + 5, "%*u %lu %lu %lu %lu %lu %lu %*u %*u "
1530                                        "%*u %*u %*u %*u %*u %lu %lu %lu %lu %lu %lu",
1531                                        &st_net_eicmp->InErrors,
1532                                        &st_net_eicmp->InDestUnreachs,
1533                                        &st_net_eicmp->InTimeExcds,
1534                                        &st_net_eicmp->InParmProbs,
1535                                        &st_net_eicmp->InSrcQuenchs,
1536                                        &st_net_eicmp->InRedirects,
1537                                        &st_net_eicmp->OutErrors,
1538                                        &st_net_eicmp->OutDestUnreachs,
1539                                        &st_net_eicmp->OutTimeExcds,
1540                                        &st_net_eicmp->OutParmProbs,
1541                                        &st_net_eicmp->OutSrcQuenchs,
1542                                        &st_net_eicmp->OutRedirects);
1543
1544                                 break;
1545                         }
1546                         else {
1547                                 sw = TRUE;
1548                         }
1549                 }
1550         }
1551
1552         fclose(fp);
1553         return 1;
1554 }
1555
1556 /*
1557  ***************************************************************************
1558  * Read TCP network traffic statistics from /proc/net/snmp.
1559  *
1560  * IN:
1561  * @st_net_tcp  Structure where stats will be saved.
1562  *
1563  * OUT:
1564  * @st_net_tcp  Structure with statistics.
1565  *
1566  * RETURNS:
1567  * 1 on success, 0 otherwise.
1568  ***************************************************************************
1569  */
1570 __nr_t read_net_tcp(struct stats_net_tcp *st_net_tcp)
1571 {
1572         FILE *fp;
1573         char line[1024];
1574         int sw = FALSE;
1575
1576         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1577                 return 0;
1578
1579         while (fgets(line, sizeof(line), fp) != NULL) {
1580
1581                 if (!strncmp(line, "Tcp:", 4)) {
1582                         if (sw) {
1583                                 sscanf(line + 4, "%*u %*u %*u %*d %lu %lu "
1584                                        "%*u %*u %*u %lu %lu",
1585                                        &st_net_tcp->ActiveOpens,
1586                                        &st_net_tcp->PassiveOpens,
1587                                        &st_net_tcp->InSegs,
1588                                        &st_net_tcp->OutSegs);
1589
1590                                 break;
1591                         }
1592                         else {
1593                                 sw = TRUE;
1594                         }
1595                 }
1596         }
1597
1598         fclose(fp);
1599         return 1;
1600 }
1601
1602 /*
1603  ***************************************************************************
1604  * Read TCP network errors statistics from /proc/net/snmp.
1605  *
1606  * IN:
1607  * @st_net_etcp Structure where stats will be saved.
1608  *
1609  * OUT:
1610  * @st_net_etcp Structure with statistics.
1611  *
1612  * RETURNS:
1613  * 1 on success, 0 otherwise.
1614  ***************************************************************************
1615  */
1616 __nr_t read_net_etcp(struct stats_net_etcp *st_net_etcp)
1617 {
1618         FILE *fp;
1619         char line[1024];
1620         int sw = FALSE;
1621
1622         if ((fp = fopen(NET_SNMP, "r")) == NULL)
1623                 return 0;
1624
1625         while (fgets(line, sizeof(line), fp) != NULL) {
1626
1627                 if (!strncmp(line, "Tcp:", 4)) {
1628                         if (sw) {
1629                                 sscanf(line + 4, "%*u %*u %*u %*d %*u %*u "
1630                                        "%lu %lu %*u %*u %*u %lu %lu %lu",
1631                                        &st_net_etcp->AttemptFails,
1632                                        &st_net_etcp->EstabResets,
1633                                        &st_net_etcp->RetransSegs,
1634                                        &st_net_etcp->InErrs,
1635                                        &st_net_etcp->OutRsts);
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 UDP network traffic statistics from /proc/net/snmp.
1652  *
1653  * IN:
1654  * @st_net_udp  Structure where stats will be saved.
1655  *
1656  * OUT:
1657  * @st_net_udp  Structure with statistics.
1658  *
1659  * RETURNS:
1660  * 1 on success, 0 otherwise.
1661  ***************************************************************************
1662  */
1663 __nr_t read_net_udp(struct stats_net_udp *st_net_udp)
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, "Udp:", 4)) {
1675                         if (sw) {
1676                                 sscanf(line + 4, "%lu %lu %lu %lu",
1677                                        &st_net_udp->InDatagrams,
1678                                        &st_net_udp->NoPorts,
1679                                        &st_net_udp->InErrors,
1680                                        &st_net_udp->OutDatagrams);
1681
1682                                 break;
1683                         }
1684                         else {
1685                                 sw = TRUE;
1686                         }
1687                 }
1688         }
1689
1690         fclose(fp);
1691         return 1;
1692 }
1693
1694 /*
1695  ***************************************************************************
1696  * Read IPv6 network sockets statistics from /proc/net/sockstat6.
1697  *
1698  * IN:
1699  * @st_net_sock6        Structure where stats will be saved.
1700  *
1701  * OUT:
1702  * @st_net_sock6        Structure with statistics.
1703  *
1704  * RETURNS:
1705  * 1 on success, 0 otherwise.
1706  ***************************************************************************
1707  */
1708 __nr_t read_net_sock6(struct stats_net_sock6 *st_net_sock6)
1709 {
1710         FILE *fp;
1711         char line[96];
1712
1713         if ((fp = fopen(NET_SOCKSTAT6, "r")) == NULL)
1714                 return 0;
1715
1716         while (fgets(line, sizeof(line), fp) != NULL) {
1717
1718                 if (!strncmp(line, "TCP6:", 5)) {
1719                         /* TCPv6 sockets */
1720                         sscanf(line + 12, "%u", &st_net_sock6->tcp6_inuse);
1721                 }
1722                 else if (!strncmp(line, "UDP6:", 5)) {
1723                         /* UDPv6 sockets */
1724                         sscanf(line + 12, "%u", &st_net_sock6->udp6_inuse);
1725                 }
1726                 else if (!strncmp(line, "RAW6:", 5)) {
1727                         /* IPv6 RAW sockets */
1728                         sscanf(line + 12, "%u", &st_net_sock6->raw6_inuse);
1729                 }
1730                 else if (!strncmp(line, "FRAG6:", 6)) {
1731                         /* IPv6 FRAGments */
1732                         sscanf(line + 13, "%u", &st_net_sock6->frag6_inuse);
1733                 }
1734         }
1735
1736         fclose(fp);
1737         return 1;
1738 }
1739
1740 /*
1741  ***************************************************************************
1742  * Read IPv6 network traffic statistics from /proc/net/snmp6.
1743  *
1744  * IN:
1745  * @st_net_ip6  Structure where stats will be saved.
1746  *
1747  * OUT:
1748  * @st_net_ip6  Structure with statistics.
1749  *
1750  * RETURNS:
1751  * 1 on success, 0 otherwise.
1752  ***************************************************************************
1753  */
1754 __nr_t read_net_ip6(struct stats_net_ip6 *st_net_ip6)
1755 {
1756         FILE *fp;
1757         char line[128];
1758
1759         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1760                 return 0;
1761
1762         while (fgets(line, sizeof(line), fp) != NULL) {
1763
1764                 if (!strncmp(line, "Ip6InReceives ", 14)) {
1765                         sscanf(line + 14, "%llu", &st_net_ip6->InReceives6);
1766                 }
1767                 else if (!strncmp(line, "Ip6OutForwDatagrams ", 20)) {
1768                         sscanf(line + 20, "%llu", &st_net_ip6->OutForwDatagrams6);
1769                 }
1770                 else if (!strncmp(line, "Ip6InDelivers ", 14)) {
1771                         sscanf(line + 14, "%llu", &st_net_ip6->InDelivers6);
1772                 }
1773                 else if (!strncmp(line, "Ip6OutRequests ", 15)) {
1774                         sscanf(line + 15, "%llu", &st_net_ip6->OutRequests6);
1775                 }
1776                 else if (!strncmp(line, "Ip6ReasmReqds ", 14)) {
1777                         sscanf(line + 14, "%llu", &st_net_ip6->ReasmReqds6);
1778                 }
1779                 else if (!strncmp(line, "Ip6ReasmOKs ", 12)) {
1780                         sscanf(line + 12, "%llu", &st_net_ip6->ReasmOKs6);
1781                 }
1782                 else if (!strncmp(line, "Ip6InMcastPkts ", 15)) {
1783                         sscanf(line + 15, "%llu", &st_net_ip6->InMcastPkts6);
1784                 }
1785                 else if (!strncmp(line, "Ip6OutMcastPkts ", 16)) {
1786                         sscanf(line + 16, "%llu", &st_net_ip6->OutMcastPkts6);
1787                 }
1788                 else if (!strncmp(line, "Ip6FragOKs ", 11)) {
1789                         sscanf(line + 11, "%llu", &st_net_ip6->FragOKs6);
1790                 }
1791                 else if (!strncmp(line, "Ip6FragCreates ", 15)) {
1792                         sscanf(line + 15, "%llu", &st_net_ip6->FragCreates6);
1793                 }
1794         }
1795
1796         fclose(fp);
1797         return 1;
1798 }
1799
1800 /*
1801  ***************************************************************************
1802  * Read IPv6 network errors statistics from /proc/net/snmp6.
1803  *
1804  * IN:
1805  * @st_net_eip6 Structure where stats will be saved.
1806  *
1807  * OUT:
1808  * @st_net_eip6 Structure with statistics.
1809  *
1810  * RETURNS:
1811  * 1 on success, 0 otherwise.
1812  ***************************************************************************
1813  */
1814 __nr_t read_net_eip6(struct stats_net_eip6 *st_net_eip6)
1815 {
1816         FILE *fp;
1817         char line[128];
1818
1819         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1820                 return 0;
1821
1822         while (fgets(line, sizeof(line), fp) != NULL) {
1823
1824                 if (!strncmp(line, "Ip6InHdrErrors ", 15)) {
1825                         sscanf(line + 15, "%llu", &st_net_eip6->InHdrErrors6);
1826                 }
1827                 else if (!strncmp(line, "Ip6InAddrErrors ", 16)) {
1828                         sscanf(line + 16, "%llu", &st_net_eip6->InAddrErrors6);
1829                 }
1830                 else if (!strncmp(line, "Ip6InUnknownProtos ", 19)) {
1831                         sscanf(line + 19, "%llu", &st_net_eip6->InUnknownProtos6);
1832                 }
1833                 else if (!strncmp(line, "Ip6InTooBigErrors ", 18)) {
1834                         sscanf(line + 18, "%llu", &st_net_eip6->InTooBigErrors6);
1835                 }
1836                 else if (!strncmp(line, "Ip6InDiscards ", 14)) {
1837                         sscanf(line + 14, "%llu", &st_net_eip6->InDiscards6);
1838                 }
1839                 else if (!strncmp(line, "Ip6OutDiscards ", 15)) {
1840                         sscanf(line + 15, "%llu", &st_net_eip6->OutDiscards6);
1841                 }
1842                 else if (!strncmp(line, "Ip6InNoRoutes ", 14)) {
1843                         sscanf(line + 14, "%llu", &st_net_eip6->InNoRoutes6);
1844                 }
1845                 else if (!strncmp(line, "Ip6OutNoRoutes ", 15)) {
1846                         sscanf(line + 15, "%llu", &st_net_eip6->OutNoRoutes6);
1847                 }
1848                 else if (!strncmp(line, "Ip6ReasmFails ", 14)) {
1849                         sscanf(line + 14, "%llu", &st_net_eip6->ReasmFails6);
1850                 }
1851                 else if (!strncmp(line, "Ip6FragFails ", 13)) {
1852                         sscanf(line + 13, "%llu", &st_net_eip6->FragFails6);
1853                 }
1854                 else if (!strncmp(line, "Ip6InTruncatedPkts ", 19)) {
1855                         sscanf(line + 19, "%llu", &st_net_eip6->InTruncatedPkts6);
1856                 }
1857         }
1858
1859         fclose(fp);
1860         return 1;
1861 }
1862
1863 /*
1864  ***************************************************************************
1865  * Read ICMPv6 network traffic statistics from /proc/net/snmp6.
1866  *
1867  * IN:
1868  * @st_net_icmp6        Structure where stats will be saved.
1869  *
1870  * OUT:
1871  * @st_net_icmp6        Structure with statistics.
1872  *
1873  * RETURNS:
1874  * 1 on success, 0 otherwise.
1875  ***************************************************************************
1876  */
1877 __nr_t read_net_icmp6(struct stats_net_icmp6 *st_net_icmp6)
1878 {
1879         FILE *fp;
1880         char line[128];
1881
1882         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1883                 return 0;
1884
1885         while (fgets(line, sizeof(line), fp) != NULL) {
1886
1887                 if (!strncmp(line, "Icmp6InMsgs ", 12)) {
1888                         sscanf(line + 12, "%lu", &st_net_icmp6->InMsgs6);
1889                 }
1890                 else if (!strncmp(line, "Icmp6OutMsgs ", 13)) {
1891                         sscanf(line + 13, "%lu", &st_net_icmp6->OutMsgs6);
1892                 }
1893                 else if (!strncmp(line, "Icmp6InEchos ", 13)) {
1894                         sscanf(line + 13, "%lu", &st_net_icmp6->InEchos6);
1895                 }
1896                 else if (!strncmp(line, "Icmp6InEchoReplies ", 19)) {
1897                         sscanf(line + 19, "%lu", &st_net_icmp6->InEchoReplies6);
1898                 }
1899                 else if (!strncmp(line, "Icmp6OutEchoReplies ", 20)) {
1900                         sscanf(line + 20, "%lu", &st_net_icmp6->OutEchoReplies6);
1901                 }
1902                 else if (!strncmp(line, "Icmp6InGroupMembQueries ", 24)) {
1903                         sscanf(line + 24, "%lu", &st_net_icmp6->InGroupMembQueries6);
1904                 }
1905                 else if (!strncmp(line, "Icmp6InGroupMembResponses ", 26)) {
1906                         sscanf(line + 26, "%lu", &st_net_icmp6->InGroupMembResponses6);
1907                 }
1908                 else if (!strncmp(line, "Icmp6OutGroupMembResponses ", 27)) {
1909                         sscanf(line + 27, "%lu", &st_net_icmp6->OutGroupMembResponses6);
1910                 }
1911                 else if (!strncmp(line, "Icmp6InGroupMembReductions ", 27)) {
1912                         sscanf(line + 27, "%lu", &st_net_icmp6->InGroupMembReductions6);
1913                 }
1914                 else if (!strncmp(line, "Icmp6OutGroupMembReductions ", 28)) {
1915                         sscanf(line + 28, "%lu", &st_net_icmp6->OutGroupMembReductions6);
1916                 }
1917                 else if (!strncmp(line, "Icmp6InRouterSolicits ", 22)) {
1918                         sscanf(line + 22, "%lu", &st_net_icmp6->InRouterSolicits6);
1919                 }
1920                 else if (!strncmp(line, "Icmp6OutRouterSolicits ", 23)) {
1921                         sscanf(line + 23, "%lu", &st_net_icmp6->OutRouterSolicits6);
1922                 }
1923                 else if (!strncmp(line, "Icmp6InRouterAdvertisements ", 28)) {
1924                         sscanf(line + 28, "%lu", &st_net_icmp6->InRouterAdvertisements6);
1925                 }
1926                 else if (!strncmp(line, "Icmp6InNeighborSolicits ", 24)) {
1927                         sscanf(line + 24, "%lu", &st_net_icmp6->InNeighborSolicits6);
1928                 }
1929                 else if (!strncmp(line, "Icmp6OutNeighborSolicits ", 25)) {
1930                         sscanf(line + 25, "%lu", &st_net_icmp6->OutNeighborSolicits6);
1931                 }
1932                 else if (!strncmp(line, "Icmp6InNeighborAdvertisements ", 30)) {
1933                         sscanf(line + 30, "%lu", &st_net_icmp6->InNeighborAdvertisements6);
1934                 }
1935                 else if (!strncmp(line, "Icmp6OutNeighborAdvertisements ", 31)) {
1936                         sscanf(line + 31, "%lu", &st_net_icmp6->OutNeighborAdvertisements6);
1937                 }
1938         }
1939
1940         fclose(fp);
1941         return 1;
1942 }
1943
1944 /*
1945  ***************************************************************************
1946  * Read ICMPv6 network errors statistics from /proc/net/snmp6.
1947  *
1948  * IN:
1949  * @st_net_eicmp6       Structure where stats will be saved.
1950  *
1951  * OUT:
1952  * @st_net_eicmp6       Structure with statistics.
1953  *
1954  * RETURNS:
1955  * 1 on success, 0 otherwise.
1956  ***************************************************************************
1957  */
1958 __nr_t read_net_eicmp6(struct stats_net_eicmp6 *st_net_eicmp6)
1959 {
1960         FILE *fp;
1961         char line[128];
1962
1963         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
1964                 return 0;
1965
1966         while (fgets(line, sizeof(line), fp) != NULL) {
1967
1968                 if (!strncmp(line, "Icmp6InErrors ", 14)) {
1969                         sscanf(line + 14, "%lu", &st_net_eicmp6->InErrors6);
1970                 }
1971                 else if (!strncmp(line, "Icmp6InDestUnreachs ", 20)) {
1972                         sscanf(line + 20, "%lu", &st_net_eicmp6->InDestUnreachs6);
1973                 }
1974                 else if (!strncmp(line, "Icmp6OutDestUnreachs ", 21)) {
1975                         sscanf(line + 21, "%lu", &st_net_eicmp6->OutDestUnreachs6);
1976                 }
1977                 else if (!strncmp(line, "Icmp6InTimeExcds ", 17)) {
1978                         sscanf(line + 17, "%lu", &st_net_eicmp6->InTimeExcds6);
1979                 }
1980                 else if (!strncmp(line, "Icmp6OutTimeExcds ", 18)) {
1981                         sscanf(line + 18, "%lu", &st_net_eicmp6->OutTimeExcds6);
1982                 }
1983                 else if (!strncmp(line, "Icmp6InParmProblems ", 20)) {
1984                         sscanf(line + 20, "%lu", &st_net_eicmp6->InParmProblems6);
1985                 }
1986                 else if (!strncmp(line, "Icmp6OutParmProblems ", 21)) {
1987                         sscanf(line + 21, "%lu", &st_net_eicmp6->OutParmProblems6);
1988                 }
1989                 else if (!strncmp(line, "Icmp6InRedirects ", 17)) {
1990                         sscanf(line + 17, "%lu", &st_net_eicmp6->InRedirects6);
1991                 }
1992                 else if (!strncmp(line, "Icmp6OutRedirects ", 18)) {
1993                         sscanf(line + 18, "%lu", &st_net_eicmp6->OutRedirects6);
1994                 }
1995                 else if (!strncmp(line, "Icmp6InPktTooBigs ", 18)) {
1996                         sscanf(line + 18, "%lu", &st_net_eicmp6->InPktTooBigs6);
1997                 }
1998                 else if (!strncmp(line, "Icmp6OutPktTooBigs ", 19)) {
1999                         sscanf(line + 19, "%lu", &st_net_eicmp6->OutPktTooBigs6);
2000                 }
2001         }
2002
2003         fclose(fp);
2004         return 1;
2005 }
2006
2007 /*
2008  ***************************************************************************
2009  * Read UDPv6 network traffic statistics from /proc/net/snmp6.
2010  *
2011  * IN:
2012  * @st_net_udp6 Structure where stats will be saved.
2013  *
2014  * OUT:
2015  * @st_net_udp6 Structure with statistics.
2016  *
2017  * RETURNS:
2018  * 1 on success, 0 otherwise.
2019  ***************************************************************************
2020  */
2021 __nr_t read_net_udp6(struct stats_net_udp6 *st_net_udp6)
2022 {
2023         FILE *fp;
2024         char line[128];
2025
2026         if ((fp = fopen(NET_SNMP6, "r")) == NULL)
2027                 return 0;
2028
2029         while (fgets(line, sizeof(line), fp) != NULL) {
2030
2031                 if (!strncmp(line, "Udp6InDatagrams ", 16)) {
2032                         sscanf(line + 16, "%lu", &st_net_udp6->InDatagrams6);
2033                 }
2034                 else if (!strncmp(line, "Udp6OutDatagrams ", 17)) {
2035                         sscanf(line + 17, "%lu", &st_net_udp6->OutDatagrams6);
2036                 }
2037                 else if (!strncmp(line, "Udp6NoPorts ", 12)) {
2038                         sscanf(line + 12, "%lu", &st_net_udp6->NoPorts6);
2039                 }
2040                 else if (!strncmp(line, "Udp6InErrors ", 13)) {
2041                         sscanf(line + 13, "%lu", &st_net_udp6->InErrors6);
2042                 }
2043         }
2044
2045         fclose(fp);
2046         return 1;
2047 }
2048
2049 /*
2050  ***************************************************************************
2051  * Read CPU frequency statistics.
2052  *
2053  * IN:
2054  * @st_pwr_cpufreq      Structure where stats will be saved.
2055  * @nr_alloc            Total number of structures allocated. Value is >= 1.
2056  *
2057  * OUT:
2058  * @st_pwr_cpufreq      Structure with statistics.
2059  *
2060  * RETURNS:
2061  * Highest CPU number for which statistics have been read.
2062  * 1 means CPU "all", 2 means CPU 0, 3 means CPU 1, etc.
2063  * Or -1 if the buffer was too small and needs to be reallocated.
2064  ***************************************************************************
2065  */
2066 __nr_t read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, __nr_t nr_alloc)
2067 {
2068         FILE *fp;
2069         struct stats_pwr_cpufreq *st_pwr_cpufreq_i;
2070         char line[1024];
2071         int nr = 0;
2072         __nr_t cpu_read = 1;    /* For CPU "all" */
2073         unsigned int proc_nr = 0, ifreq, dfreq;
2074
2075         if ((fp = fopen(CPUINFO, "r")) == NULL)
2076                 return 0;
2077
2078         st_pwr_cpufreq->cpufreq = 0;
2079
2080         while (fgets(line, sizeof(line), fp) != NULL) {
2081
2082                 if (!strncmp(line, "processor\t", 10)) {
2083                         sscanf(strchr(line, ':') + 1, "%u", &proc_nr);
2084
2085                         if (proc_nr + 2 > nr_alloc) {
2086                                 cpu_read = -1;
2087                                 break;
2088                         }
2089                 }
2090
2091                 /* Entry in /proc/cpuinfo is different between Intel and Power architectures */
2092                 else if (!strncmp(line, "cpu MHz\t", 8) ||
2093                          !strncmp(line, "clock\t", 6)) {
2094                         sscanf(strchr(line, ':') + 1, "%u.%u", &ifreq, &dfreq);
2095
2096                         /* Save current CPU frequency */
2097                         st_pwr_cpufreq_i = st_pwr_cpufreq + proc_nr + 1;
2098                         st_pwr_cpufreq_i->cpufreq = ifreq * 100 + dfreq / 10;
2099
2100                         /* Also save it to compute an average CPU frequency */
2101                         st_pwr_cpufreq->cpufreq += st_pwr_cpufreq_i->cpufreq;
2102                         nr++;
2103
2104                         if (proc_nr + 2 > cpu_read) {
2105                                 cpu_read = proc_nr + 2;
2106                         }
2107                 }
2108         }
2109
2110         fclose(fp);
2111
2112         if (nr) {
2113                 /* Compute average CPU frequency for this machine */
2114                 st_pwr_cpufreq->cpufreq /= nr;
2115         }
2116         return cpu_read;
2117 }
2118
2119 /*
2120  ***************************************************************************
2121  * Read hugepages statistics from /proc/meminfo.
2122  *
2123  * IN:
2124  * @st_huge     Structure where stats will be saved.
2125  *
2126  * OUT:
2127  * @st_huge     Structure with statistics.
2128  *
2129  * RETURNS:
2130  * 1 on success, 0 otherwise.
2131  ***************************************************************************
2132  */
2133 __nr_t read_meminfo_huge(struct stats_huge *st_huge)
2134 {
2135         FILE *fp;
2136         char line[128];
2137         unsigned long szhkb = 0;
2138
2139         if ((fp = fopen(MEMINFO, "r")) == NULL)
2140                 return 0;
2141
2142         while (fgets(line, sizeof(line), fp) != NULL) {
2143
2144                 if (!strncmp(line, "HugePages_Total:", 16)) {
2145                         /* Read the total number of huge pages */
2146                         sscanf(line + 16, "%llu", &st_huge->tlhkb);
2147                 }
2148                 else if (!strncmp(line, "HugePages_Free:", 15)) {
2149                         /* Read the number of free huge pages */
2150                         sscanf(line + 15, "%llu", &st_huge->frhkb);
2151                 }
2152                 else if (!strncmp(line, "HugePages_Rsvd:", 15)) {
2153                         /* Read the number of reserved huge pages */
2154                         sscanf(line + 15, "%llu", &st_huge->rsvdhkb);
2155                 }
2156                 else if (!strncmp(line, "HugePages_Surp:", 15)) {
2157                         /* Read the number of surplus huge pages */
2158                         sscanf(line + 15, "%llu", &st_huge->surphkb);
2159                 }
2160                 else if (!strncmp(line, "Hugepagesize:", 13)) {
2161                         /* Read the default size of a huge page in kB */
2162                         sscanf(line + 13, "%lu", &szhkb);
2163                 }
2164         }
2165
2166         fclose(fp);
2167
2168         /* We want huge pages stats in kB and not expressed in a number of pages */
2169         st_huge->tlhkb *= szhkb;
2170         st_huge->frhkb *= szhkb;
2171         st_huge->rsvdhkb *= szhkb;
2172         st_huge->surphkb *= szhkb;
2173
2174         return 1;
2175 }
2176
2177 /*
2178  ***************************************************************************
2179  * Read CPU average frequencies statistics.
2180  *
2181  * IN:
2182  * @st_pwr_wghfreq      Structure where stats will be saved.
2183  * @cpu_nr              CPU number for which time_in_state date will be read.
2184  * @nbr                 Total number of states (frequencies).
2185  *
2186  * OUT:
2187  * @st_pwr_wghfreq      Structure with statistics.
2188  *
2189  * RETURNS:
2190  * 1 on success, 0 otherwise.
2191  ***************************************************************************
2192  */
2193 int read_time_in_state(struct stats_pwr_wghfreq *st_pwr_wghfreq, int cpu_nr, int nbr)
2194 {
2195         FILE *fp;
2196         struct stats_pwr_wghfreq *st_pwr_wghfreq_j;
2197         char filename[MAX_PF_NAME];
2198         char line[128];
2199         int j = 0;
2200         unsigned long freq;
2201         unsigned long long time_in_state;
2202
2203         snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s",
2204                  SYSFS_DEVCPU, cpu_nr, SYSFS_TIME_IN_STATE);
2205         if ((fp = fopen(filename, "r")) == NULL)
2206                 return 0;
2207
2208         while (fgets(line, sizeof(line), fp) != NULL) {
2209
2210                 sscanf(line, "%lu %llu", &freq, &time_in_state);
2211
2212                 if (j < nbr) {
2213                         /* Save current frequency and time */
2214                         st_pwr_wghfreq_j = st_pwr_wghfreq + j;
2215                         st_pwr_wghfreq_j->freq = freq;
2216                         st_pwr_wghfreq_j->time_in_state = time_in_state;
2217                         j++;
2218                 }
2219         }
2220
2221         fclose(fp);
2222         return 1;
2223 }
2224
2225 /*
2226  ***************************************************************************
2227  * Read weighted CPU frequency statistics.
2228  *
2229  * IN:
2230  * @st_pwr_wghfreq      Structure where stats will be saved.
2231  * @nr_alloc            Total number of structures allocated. Value is >= 0.
2232  * @nr2                 Number of sub-items allocated per structure.
2233  *
2234  * OUT:
2235  * @st_pwr_wghfreq      Structure with statistics.
2236  *
2237  * RETURNS:
2238  * Number of CPU for which statistics have been read.
2239  * 1 means CPU "all", 2 means CPU "all" and 0, etc.
2240  * Or -1 if the buffer was to small and needs to be reallocated.
2241  ***************************************************************************
2242  */
2243 __nr_t read_cpu_wghfreq(struct stats_pwr_wghfreq *st_pwr_wghfreq, __nr_t nr_alloc,
2244                         __nr_t nr2)
2245 {
2246         __nr_t cpu_read = 0;
2247         int j;
2248         struct stats_pwr_wghfreq *st_pwr_wghfreq_i, *st_pwr_wghfreq_j, *st_pwr_wghfreq_all_j;
2249
2250         do {
2251                 if (cpu_read + 2 > nr_alloc)
2252                         return -1;
2253
2254                 /* Read current CPU time-in-state data */
2255                 st_pwr_wghfreq_i = st_pwr_wghfreq + (cpu_read + 1) * nr2;
2256                 if (!read_time_in_state(st_pwr_wghfreq_i, cpu_read, nr2))
2257                         break;
2258
2259                 /* Also save data for CPU 'all' */
2260                 for (j = 0; j < nr2; j++) {
2261                         st_pwr_wghfreq_j     = st_pwr_wghfreq_i + j;    /* CPU #cpu, state #j */
2262                         st_pwr_wghfreq_all_j = st_pwr_wghfreq   + j;    /* CPU #all, state #j */
2263                         if (!cpu_read) {
2264                                 /* Assume that possible frequencies are the same for all CPUs */
2265                                 st_pwr_wghfreq_all_j->freq = st_pwr_wghfreq_j->freq;
2266                         }
2267                         st_pwr_wghfreq_all_j->time_in_state += st_pwr_wghfreq_j->time_in_state;
2268                 }
2269                 cpu_read++;
2270         }
2271         while (1);
2272
2273         if (cpu_read > 0) {
2274                 for (j = 0; j < nr2; j++) {
2275                         st_pwr_wghfreq_all_j = st_pwr_wghfreq + j;      /* CPU #all, state #j */
2276                         st_pwr_wghfreq_all_j->time_in_state /= cpu_read;
2277                 }
2278
2279                 return cpu_read + 1; /* For CPU "all" */
2280         }
2281
2282         return 0;
2283 }
2284
2285 /*
2286  ***************************************************************************
2287  * Read current USB device data.
2288  *
2289  * IN:
2290  * @st_pwr_usb          Structure where stats will be saved.
2291  * @usb_device          File name for current USB device.
2292  *
2293  * OUT:
2294  * @st_pwr_usb          Structure with statistics.
2295  ***************************************************************************
2296  */
2297 void read_usb_stats(struct stats_pwr_usb *st_pwr_usb, char *usb_device)
2298 {
2299         int l, rc;
2300         FILE *fp;
2301         char * rs;
2302         char filename[MAX_PF_NAME];
2303
2304         /* Get USB device bus number */
2305         sscanf(usb_device, "%u", &st_pwr_usb->bus_nr);
2306
2307         /* Read USB device vendor ID */
2308         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
2309                  SYSFS_USBDEV, usb_device, SYSFS_IDVENDOR);
2310         if ((fp = fopen(filename, "r")) != NULL) {
2311                 rc = fscanf(fp, "%x",
2312                             &st_pwr_usb->vendor_id);
2313                 fclose(fp);
2314                 if (rc == 0) {
2315                         st_pwr_usb->vendor_id = 0;
2316                 }
2317         }
2318
2319         /* Read USB device product ID */
2320         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
2321                  SYSFS_USBDEV, usb_device, SYSFS_IDPRODUCT);
2322         if ((fp = fopen(filename, "r")) != NULL) {
2323                 rc = fscanf(fp, "%x",
2324                             &st_pwr_usb->product_id);
2325                 fclose(fp);
2326                 if (rc == 0) {
2327                         st_pwr_usb->product_id = 0;
2328                 }
2329         }
2330
2331         /* Read USB device max power consumption */
2332         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
2333                  SYSFS_USBDEV, usb_device, SYSFS_BMAXPOWER);
2334         if ((fp = fopen(filename, "r")) != NULL) {
2335                 rc = fscanf(fp, "%u",
2336                             &st_pwr_usb->bmaxpower);
2337                 fclose(fp);
2338                 if (rc == 0) {
2339                         st_pwr_usb->bmaxpower = 0;
2340                 }
2341         }
2342
2343         /* Read USB device manufacturer */
2344         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
2345                  SYSFS_USBDEV, usb_device, SYSFS_MANUFACTURER);
2346         if ((fp = fopen(filename, "r")) != NULL) {
2347                 rs = fgets(st_pwr_usb->manufacturer,
2348                            MAX_MANUF_LEN - 1, fp);
2349                 fclose(fp);
2350                 if ((rs != NULL) &&
2351                     (l = strlen(st_pwr_usb->manufacturer)) > 0) {
2352                         /* Remove trailing CR */
2353                         st_pwr_usb->manufacturer[l - 1] = '\0';
2354                 }
2355         }
2356
2357         /* Read USB device product */
2358         snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
2359                  SYSFS_USBDEV, usb_device, SYSFS_PRODUCT);
2360         if ((fp = fopen(filename, "r")) != NULL) {
2361                 rs = fgets(st_pwr_usb->product,
2362                            MAX_PROD_LEN - 1, fp);
2363                 fclose(fp);
2364                 if ((rs != NULL) &&
2365                     (l = strlen(st_pwr_usb->product)) > 0) {
2366                         /* Remove trailing CR */
2367                         st_pwr_usb->product[l - 1] = '\0';
2368                 }
2369         }
2370 }
2371
2372 /*
2373  ***************************************************************************
2374  * Read USB devices statistics.
2375  *
2376  * IN:
2377  * @st_pwr_usb          Structure where stats will be saved.
2378  * @nr_alloc            Total number of structures allocated. Value is >= 0.
2379  *
2380  * OUT:
2381  * @st_pwr_usb          Structure with statistics.
2382  *
2383  * RETURNS:
2384  * Number of USB devices read, or -1 if the buffer was too small and
2385  * needs to be reallocated.
2386  ***************************************************************************
2387  */
2388 __nr_t read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, __nr_t nr_alloc)
2389 {
2390         DIR *dir;
2391         struct dirent *drd;
2392         struct stats_pwr_usb *st_pwr_usb_i;
2393         __nr_t usb_read = 0;
2394
2395         /* Open relevant /sys directory */
2396         if ((dir = opendir(SYSFS_USBDEV)) == NULL)
2397                 return 0;
2398
2399         /* Get current file entry */
2400         while ((drd = readdir(dir)) != NULL) {
2401
2402                 if (isdigit(drd->d_name[0]) && !strchr(drd->d_name, ':')) {
2403
2404                         if (usb_read + 1 > nr_alloc) {
2405                                 usb_read = -1;
2406                                 break;
2407                         }
2408
2409                         /* Read current USB device data */
2410                         st_pwr_usb_i = st_pwr_usb + usb_read++;
2411                         read_usb_stats(st_pwr_usb_i, drd->d_name);
2412                 }
2413         }
2414
2415         /* Close directory */
2416         closedir(dir);
2417         return usb_read;
2418 }
2419
2420 /*
2421  ***************************************************************************
2422  * Read filesystems statistics.
2423  *
2424  * IN:
2425  * @st_filesystem       Structure where stats will be saved.
2426  * @nr_alloc            Total number of structures allocated. Value is >= 0.
2427  *
2428  * OUT:
2429  * @st_filesystem       Structure with statistics.
2430  *
2431  * RETURNS:
2432  * Number of filesystems read, or -1 if the buffer was too small and
2433  * needs to be reallocated.
2434  ***************************************************************************
2435  */
2436 __nr_t read_filesystem(struct stats_filesystem *st_filesystem, __nr_t nr_alloc)
2437 {
2438         FILE *fp;
2439         char line[512], fs_name[128], mountp[256];
2440         int skip = 0, skip_next = 0;
2441         char *pos = 0;
2442         __nr_t fs_read = 0;
2443         struct stats_filesystem *st_filesystem_i;
2444         struct statvfs buf;
2445
2446         if ((fp = fopen(MTAB, "r")) == NULL)
2447                 return 0;
2448
2449         while (fgets(line, sizeof(line), fp) != NULL) {
2450                 /*
2451                  * Ignore line if the preceding line did not contain '\n'.
2452                  * (Some very long lines may be found for instance when
2453                  * overlay2 filesystem with docker is used).
2454                  */
2455                 skip = skip_next;
2456                 skip_next = (strchr(line, '\n') == NULL);
2457                 if (skip)
2458                         continue;
2459
2460                 if (line[0] == '/') {
2461                         /* Find field separator position */
2462                         pos = strchr(line, ' ');
2463                         if (pos == NULL)
2464                                 continue;
2465
2466                         /* Read current filesystem name */
2467                         sscanf(line, "%127s", fs_name);
2468                         /*
2469                          * And now read the corresponding mount point.
2470                          * Read fs name and mount point in two distinct operations.
2471                          * Indeed, if fs name length is greater than 127 chars,
2472                          * previous scanf() will read only the first 127 chars, and
2473                          * mount point name will be read using the remaining chars
2474                          * from the fs name. This will result in a bogus name
2475                          * and following statvfs() function will always fail.
2476                          */
2477                         sscanf(pos + 1, "%255s", mountp);
2478
2479                         /* Replace octal codes */
2480                         oct2chr(mountp);
2481
2482                         /*
2483                          * It's important to have read the whole mount point name
2484                          * for statvfs() to work properly (see above).
2485                          */
2486                         if ((statvfs(mountp, &buf) < 0) || (!buf.f_blocks))
2487                                 continue;
2488
2489                         if (fs_read + 1 > nr_alloc) {
2490                                 fs_read = -1;
2491                                 break;
2492                         }
2493
2494                         st_filesystem_i = st_filesystem + fs_read++;
2495                         st_filesystem_i->f_blocks = (unsigned long long) buf.f_blocks * (unsigned long long) buf.f_frsize;
2496                         st_filesystem_i->f_bfree  = (unsigned long long) buf.f_bfree * (unsigned long long) buf.f_frsize;
2497                         st_filesystem_i->f_bavail = (unsigned long long) buf.f_bavail * (unsigned long long) buf.f_frsize;
2498                         st_filesystem_i->f_files  = (unsigned long long) buf.f_files;
2499                         st_filesystem_i->f_ffree  = (unsigned long long) buf.f_ffree;
2500                         strncpy(st_filesystem_i->fs_name, fs_name, MAX_FS_LEN);
2501                         st_filesystem_i->fs_name[MAX_FS_LEN - 1] = '\0';
2502                         strncpy(st_filesystem_i->mountp, mountp, MAX_FS_LEN);
2503                         st_filesystem_i->mountp[MAX_FS_LEN - 1] = '\0';
2504                 }
2505         }
2506
2507         fclose(fp);
2508         return fs_read;
2509 }
2510
2511 /*
2512  ***************************************************************************
2513  * Read Fibre Channel HBA statistics.
2514  *
2515  * IN:
2516  * @st_fc       Structure where stats will be saved.
2517  * @nr_alloc    Total number of structures allocated. Value is >= 0.
2518  *
2519  * OUT:
2520  * @st_fc       Structure with statistics.
2521  *
2522  * RETURNS:
2523  * Number of FC hosts read, or -1 if the buffer was too small and needs to
2524  * be reallocated.
2525  ***************************************************************************
2526  */
2527 __nr_t read_fchost(struct stats_fchost *st_fc, __nr_t nr_alloc)
2528 {
2529         DIR *dir;
2530         FILE *fp;
2531         struct dirent *drd;
2532         struct stats_fchost *st_fc_i;
2533         __nr_t fch_read = 0;
2534         char fcstat_filename[MAX_PF_NAME];
2535         char line[256];
2536         unsigned long rx_frames, tx_frames, rx_words, tx_words;
2537
2538         /* Each host, if present, will have its own hostX entry within SYSFS_FCHOST */
2539         if ((dir = opendir(SYSFS_FCHOST)) == NULL)
2540                 return 0; /* No FC hosts */
2541
2542         /*
2543          * Read each of the counters via sysfs, where they are
2544          * returned as hex values (e.g. 0x72400).
2545          */
2546         while ((drd = readdir(dir)) != NULL) {
2547                 rx_frames = tx_frames = rx_words = tx_words = 0;
2548
2549                 if (!strncmp(drd->d_name, "host", 4)) {
2550
2551                         if (fch_read + 1 > nr_alloc) {
2552                                 fch_read = -1;
2553                                 break;
2554                         }
2555
2556                         snprintf(fcstat_filename, MAX_PF_NAME, FC_RX_FRAMES,
2557                                  SYSFS_FCHOST, drd->d_name);
2558                         if ((fp = fopen(fcstat_filename, "r"))) {
2559                                 if (fgets(line, sizeof(line), fp)) {
2560                                         sscanf(line, "%lx", &rx_frames);
2561                                 }
2562                                 fclose(fp);
2563                         }
2564
2565                         snprintf(fcstat_filename, MAX_PF_NAME, FC_TX_FRAMES,
2566                                  SYSFS_FCHOST, drd->d_name);
2567                         if ((fp = fopen(fcstat_filename, "r"))) {
2568                                 if (fgets(line, sizeof(line), fp)) {
2569                                         sscanf(line, "%lx", &tx_frames);
2570                                 }
2571                                 fclose(fp);
2572                         }
2573
2574                         snprintf(fcstat_filename, MAX_PF_NAME, FC_RX_WORDS,
2575                                  SYSFS_FCHOST, drd->d_name);
2576                         if ((fp = fopen(fcstat_filename, "r"))) {
2577                                 if (fgets(line, sizeof(line), fp)) {
2578                                         sscanf(line, "%lx", &rx_words);
2579                                 }
2580                                 fclose(fp);
2581                         }
2582
2583                         snprintf(fcstat_filename, MAX_PF_NAME, FC_TX_WORDS,
2584                                  SYSFS_FCHOST, drd->d_name);
2585                         if ((fp = fopen(fcstat_filename, "r"))) {
2586                                 if (fgets(line, sizeof(line), fp)) {
2587                                         sscanf(line, "%lx", &tx_words);
2588                                 }
2589                                 fclose(fp);
2590                         }
2591
2592                         st_fc_i = st_fc + fch_read++;
2593                         st_fc_i->f_rxframes = rx_frames;
2594                         st_fc_i->f_txframes = tx_frames;
2595                         st_fc_i->f_rxwords  = rx_words;
2596                         st_fc_i->f_txwords  = tx_words;
2597                         strncpy(st_fc_i->fchost_name, drd->d_name, MAX_FCH_LEN);
2598                         st_fc_i->fchost_name[MAX_FCH_LEN - 1] = '\0';
2599                 }
2600         }
2601
2602         closedir(dir);
2603         return fch_read;
2604 }
2605
2606 /*
2607  ***************************************************************************
2608  * Read softnet statistics.
2609  *
2610  * IN:
2611  * @st_softnet  Structure where stats will be saved.
2612  * @nr_alloc    Total number of structures allocated. Value is >= 0.
2613  * @online_cpu_bitmap
2614  *              Bitmap listing online CPU.
2615  *
2616  * OUT:
2617  * @st_softnet  Structure with statistics.
2618  *
2619  * RETURNS:
2620  * 1 if stats have been sucessfully read, or 0 otherwise.
2621  ***************************************************************************
2622  */
2623 int read_softnet(struct stats_softnet *st_softnet, __nr_t nr_alloc,
2624                   unsigned char online_cpu_bitmap[])
2625 {
2626         FILE *fp;
2627         struct stats_softnet *st_softnet_i;
2628         char line[1024];
2629         int cpu;
2630
2631         /* Open /proc/net/softnet_stat file */
2632         if ((fp = fopen(NET_SOFTNET, "r")) == NULL)
2633                 return 0;
2634
2635         for (cpu = 1; cpu < nr_alloc; cpu++) {
2636                 if (!(online_cpu_bitmap[(cpu - 1) >> 3] & (1 << ((cpu - 1) & 0x07))))
2637                         /* CPU is offline */
2638                         continue;
2639
2640                 if (fgets(line, sizeof(line), fp) == NULL)
2641                         break;
2642
2643                 st_softnet_i = st_softnet + cpu;
2644                 sscanf(line, "%x %x %x %*x %*x %*x %*x %*x %*x %x %x",
2645                        &st_softnet_i->processed,
2646                        &st_softnet_i->dropped,
2647                        &st_softnet_i->time_squeeze,
2648                        &st_softnet_i->received_rps,
2649                        &st_softnet_i->flow_limit);
2650         }
2651
2652         fclose(fp);
2653         return 1;
2654 }
2655
2656 /*------------------ END: FUNCTIONS USED BY SADC ONLY ---------------------*/
2657 #endif /* SOURCE_SADC */