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