]> granicus.if.org Git - sysstat/blob - sa_common.c
5b4aeac2ebf1b1b3ed00c7e30b90979f5a1e007c
[sysstat] / sa_common.c
1 /*
2  * sar and sadf common routines.
3  * (C) 1999-2022 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 <stdint.h>
26 #include <time.h>
27 #include <errno.h>
28 #include <unistd.h>     /* For STDOUT_FILENO, among others */
29 #include <dirent.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <libgen.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <ctype.h>
36
37 #include "version.h"
38 #include "sa.h"
39 #include "ioconf.h"
40
41 #ifdef USE_NLS
42 #include <locale.h>
43 #include <libintl.h>
44 #define _(string) gettext(string)
45 #else
46 #define _(string) (string)
47 #endif
48
49 int default_file_used = FALSE;
50 extern struct act_bitmap cpu_bitmap;
51 extern unsigned int dm_major;
52
53 unsigned int hdr_types_nr[] = {FILE_HEADER_ULL_NR, FILE_HEADER_UL_NR, FILE_HEADER_U_NR};
54 unsigned int act_types_nr[] = {FILE_ACTIVITY_ULL_NR, FILE_ACTIVITY_UL_NR, FILE_ACTIVITY_U_NR};
55 unsigned int rec_types_nr[] = {RECORD_HEADER_ULL_NR, RECORD_HEADER_UL_NR, RECORD_HEADER_U_NR};
56 unsigned int extra_desc_types_nr[] = {EXTRA_DESC_ULL_NR, EXTRA_DESC_UL_NR, EXTRA_DESC_U_NR};
57
58 /*
59  ***************************************************************************
60  * Look for activity in array.
61  *
62  * IN:
63  * @act         Array of activities.
64  * @act_flag    Activity flag to look for.
65  * @stop        TRUE if sysstat should exit when activity is not found.
66  *
67  * RETURNS:
68  * Position of activity in array, or -1 if not found (this may happen when
69  * reading data from a system activity file created by another version of
70  * sysstat).
71  ***************************************************************************
72  */
73 int get_activity_position(struct activity *act[], unsigned int act_flag, int stop)
74 {
75         int i;
76
77         for (i = 0; i < NR_ACT; i++) {
78                 if (act[i]->id == act_flag)
79                         return i;
80         }
81
82         if (stop) {
83                 PANIC((int) act_flag);
84         }
85
86         return -1;
87 }
88
89 /*
90  ***************************************************************************
91  * Count number of activities with given option.
92  *
93  * IN:
94  * @act         Array of activities.
95  * @option      Option that activities should have to be counted
96  *              (eg. AO_COLLECTED...)
97  * @count       Set to COUNT_OUTPUTS if each output should be counted for
98  *              activities with multiple outputs.
99  *
100  * RETURNS:
101  * Number of selected activities
102  ***************************************************************************
103  */
104 int get_activity_nr(struct activity *act[], unsigned int option, enum count_mode count)
105 {
106         int i, n = 0;
107         unsigned int msk;
108
109         for (i = 0; i < NR_ACT; i++) {
110                 if ((act[i]->options & option) == option) {
111
112                         if (HAS_MULTIPLE_OUTPUTS(act[i]->options) && (count == COUNT_OUTPUTS)) {
113                                 for (msk = 1; msk < 0x100; msk <<= 1) {
114                                         if ((act[i]->opt_flags & 0xff) & msk) {
115                                                 n++;
116                                         }
117                                 }
118                         }
119                         else {
120                                 n++;
121                         }
122                 }
123         }
124
125         return n;
126 }
127
128 /*
129  ***************************************************************************
130  * Look for the most recent of saDD and saYYYYMMDD to decide which one to
131  * use. If neither exists then use saDD by default.
132  *
133  * IN:
134  * @sa_dir      Directory where standard daily data files are saved.
135  * @rectime     Structure containing the current date.
136  *
137  * OUT:
138  * @sa_name     0 to use saDD data files,
139  *              1 to use saYYYYMMDD data files.
140  ***************************************************************************
141  */
142 void guess_sa_name(char *sa_dir, struct tm *rectime, int *sa_name)
143 {
144         char filename[MAX_FILE_LEN];
145         struct stat sb;
146         time_t sa_mtime;
147         long nsec;
148
149         /* Use saDD by default */
150         *sa_name = 0;
151
152         /* Look for saYYYYMMDD */
153         snprintf(filename, sizeof(filename),
154                  "%s/sa%04d%02d%02d", sa_dir,
155                  rectime->tm_year + 1900,
156                  rectime->tm_mon + 1,
157                  rectime->tm_mday);
158         filename[sizeof(filename) - 1] = '\0';
159
160         if (stat(filename, &sb) < 0)
161                 /* Cannot find or access saYYYYMMDD, so use saDD */
162                 return;
163         sa_mtime = sb.st_mtime;
164         nsec = sb.st_mtim.tv_nsec;
165
166         /* Look for saDD */
167         snprintf(filename, sizeof(filename),
168                  "%s/sa%02d", sa_dir,
169                  rectime->tm_mday);
170         filename[sizeof(filename) - 1] = '\0';
171
172         if (stat(filename, &sb) < 0) {
173                 /* Cannot find or access saDD, so use saYYYYMMDD */
174                 *sa_name = 1;
175                 return;
176         }
177
178         if ((sa_mtime > sb.st_mtime) ||
179             ((sa_mtime == sb.st_mtime) && (nsec > sb.st_mtim.tv_nsec))) {
180                 /* saYYYYMMDD is more recent than saDD, so use it */
181                 *sa_name = 1;
182         }
183 }
184
185 /*
186  ***************************************************************************
187  * Set current daily data file name.
188  *
189  * IN:
190  * @datafile    If not an empty string then this is the alternate directory
191  *              location where daily data files will be saved.
192  * @d_off       Day offset (number of days to go back in the past).
193  * @sa_name     0 for saDD data files,
194  *              1 for saYYYYMMDD data files,
195  *              -1 if unknown. In this case, will look for the most recent
196  *              of saDD and saYYYYMMDD and use it.
197  *
198  * OUT:
199  * @datafile    Name of daily data file.
200  ***************************************************************************
201  */
202 void set_default_file(char *datafile, int d_off, int sa_name)
203 {
204         char sa_dir[MAX_FILE_LEN];
205         struct tm rectime = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL};
206         int err = 0;
207
208         /* Set directory where daily data files will be saved */
209         if (datafile[0]) {
210                 strncpy(sa_dir, datafile, sizeof(sa_dir));
211         }
212         else {
213                 strncpy(sa_dir, SA_DIR, sizeof(sa_dir));
214         }
215         sa_dir[sizeof(sa_dir) - 1] = '\0';
216
217         get_time(&rectime, d_off);
218         if (sa_name < 0) {
219                 /*
220                  * Look for the most recent of saDD and saYYYYMMDD
221                  * and use it. If neither exists then use saDD.
222                  * sa_name is set accordingly.
223                  */
224                 guess_sa_name(sa_dir, &rectime, &sa_name);
225         }
226         if (sa_name) {
227                 /* Using saYYYYMMDD data files */
228                 err = snprintf(datafile, MAX_FILE_LEN,
229                                "%s/sa%04d%02d%02d", sa_dir,
230                                rectime.tm_year + 1900,
231                                rectime.tm_mon + 1,
232                                rectime.tm_mday);
233         }
234         else {
235                 /* Using saDD data files */
236                 err = snprintf(datafile, MAX_FILE_LEN,
237                                "%s/sa%02d", sa_dir,
238                                rectime.tm_mday);
239         }
240         datafile[MAX_FILE_LEN - 1] = '\0';
241
242         if ((err < 0) || (err >= MAX_FILE_LEN)) {
243                 fprintf(stderr, "%s: %s\n", __FUNCTION__, datafile);
244                 exit(1);
245         }
246
247         default_file_used = TRUE;
248
249 #ifdef DEBUG
250         fprintf(stderr, "%s: Datafile: %s\n", __FUNCTION__, datafile);
251 #endif
252 }
253
254 /*
255  ***************************************************************************
256  * Check data file type. If it is a directory then this is the alternate
257  * location where daily data files will be saved.
258  *
259  * IN:
260  * @datafile    Name of the daily data file. May be a directory.
261  * @d_off       Day offset (number of days to go back in the past).
262  * @sa_name     0 for saDD data files,
263  *              1 for saYYYYMMDD data files,
264  *              -1 if unknown. In this case, will look for the most recent
265  *              of saDD and saYYYYMMDD and use it.
266  *
267  *
268  * OUT:
269  * @datafile    Name of the daily data file. This is now a plain file, not
270  *              a directory.
271  *
272  * RETURNS:
273  * 1 if @datafile was a directory, and 0 otherwise.
274  ***************************************************************************
275  */
276 int check_alt_sa_dir(char *datafile, int d_off, int sa_name)
277 {
278         if (check_dir(datafile)) {
279                 /*
280                  * This is a directory: So append
281                  * the default file name to it.
282                  */
283                 set_default_file(datafile, d_off, sa_name);
284                 return 1;
285         }
286
287         return 0;
288 }
289
290 /*
291  ***************************************************************************
292  * Display sysstat version used to create system activity data file.
293  *
294  * IN:
295  * @st          Output stream (stderr or stdout).
296  * @file_magic  File magic header.
297  ***************************************************************************
298  */
299 void display_sa_file_version(FILE *st, struct file_magic *file_magic)
300 {
301         fprintf(st, _("File created by sar/sadc from sysstat version %d.%d.%d"),
302                 file_magic->sysstat_version,
303                 file_magic->sysstat_patchlevel,
304                 file_magic->sysstat_sublevel);
305
306         if (file_magic->sysstat_extraversion) {
307                 fprintf(st, ".%d", file_magic->sysstat_extraversion);
308         }
309         fprintf(st, "\n");
310 }
311
312 /*
313  ***************************************************************************
314  * An invalid system activity file has been opened for reading.
315  * If this file was created by an old version of sysstat, tell it to the
316  * user...
317  *
318  * IN:
319  * @fd          Descriptor of the file that has been opened.
320  * @file_magic  file_magic structure filled with file magic header data.
321  *              May contain invalid data.
322  * @file        Name of the file being read.
323  * @n           Number of bytes read while reading file magic header.
324  *              This function may also be called after failing to read file
325  *              standard header, or if CPU activity has not been found in
326  *              file. In this case, n is set to 0.
327  ***************************************************************************
328  */
329 void handle_invalid_sa_file(int fd, struct file_magic *file_magic, char *file,
330                             int n)
331 {
332         unsigned short fmt_magic;
333
334         fprintf(stderr, _("Invalid system activity file: %s\n"), file);
335
336         if (n == FILE_MAGIC_SIZE) {
337                 if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (file_magic->sysstat_magic == SYSSTAT_MAGIC_SWAPPED)) {
338                         /* This is a sysstat file, but this file has an old format */
339                         display_sa_file_version(stderr, file_magic);
340
341                         fmt_magic = file_magic->sysstat_magic == SYSSTAT_MAGIC ?
342                                     file_magic->format_magic : __builtin_bswap16(file_magic->format_magic);
343                         fprintf(stderr,
344                                 _("Current sysstat version cannot read the format of this file (%#x)\n"),
345                                 fmt_magic);
346                         if (fmt_magic >= FORMAT_MAGIC_2171) {
347                                 fprintf(stderr,
348                                         _("Try to convert it to current format. Enter:\n\n"));
349                                 fprintf(stderr, "sadf -c %s > %s.new\n\n", file, file);
350                                 fprintf(stderr,
351                                         _("You should then be able to read the new file created (%s.new)\n"),
352                                         file);
353                         }
354                 }
355         }
356
357         close (fd);
358         exit(3);
359 }
360
361 /*
362  ***************************************************************************
363  * Display an error message then exit.
364  ***************************************************************************
365  */
366 void print_collect_error(void)
367 {
368         fprintf(stderr, _("Requested activities not available\n"));
369         exit(1);
370 }
371
372 /*
373  ***************************************************************************
374  * Fill system activity file magic header.
375  *
376  * IN:
377  * @file_magic  System activity file magic header.
378  ***************************************************************************
379  */
380 void enum_version_nr(struct file_magic *fm)
381 {
382         char *v;
383         char version[16];
384
385         fm->sysstat_extraversion = 0;
386
387         strcpy(version, VERSION);
388
389         /* Get version number */
390         if ((v = strtok(version, ".")) == NULL)
391                 return;
392         fm->sysstat_version = atoi(v) & 0xff;
393
394         /* Get patchlevel number */
395         if ((v = strtok(NULL, ".")) == NULL)
396                 return;
397         fm->sysstat_patchlevel = atoi(v) & 0xff;
398
399         /* Get sublevel number */
400         if ((v = strtok(NULL, ".")) == NULL)
401                 return;
402         fm->sysstat_sublevel = atoi(v) & 0xff;
403
404         /* Get extraversion number. Don't necessarily exist */
405         if ((v = strtok(NULL, ".")) == NULL)
406                 return;
407         fm->sysstat_extraversion = atoi(v) & 0xff;
408 }
409
410 /*
411  ***************************************************************************
412  * Write data to file. If the write() call was interrupted by a signal, try
413  * again so that the whole buffer can be written.
414  *
415  * IN:
416  * @fd          Output file descriptor.
417  * @buf         Data buffer.
418  * @nr_bytes    Number of bytes to write.
419  *
420  * RETURNS:
421  * Number of bytes written to file, or -1 on error.
422  ***************************************************************************
423  */
424 int write_all(int fd, const void *buf, int nr_bytes)
425 {
426         int block, offset = 0;
427         char *buffer = (char *) buf;
428
429         while (nr_bytes > 0) {
430
431                 block = write(fd, &buffer[offset], nr_bytes);
432
433                 if (block < 0) {
434                         if (errno == EINTR)
435                                 continue;
436                         return block;
437                 }
438                 if (block == 0)
439                         return offset;
440
441                 offset += block;
442                 nr_bytes -= block;
443         }
444
445         return offset;
446 }
447
448 #ifndef SOURCE_SADC
449 /*
450  ***************************************************************************
451  * Allocate structures.
452  *
453  * IN:
454  * @act Array of activities.
455  ***************************************************************************
456  */
457 void allocate_structures(struct activity *act[])
458 {
459         int i, j;
460
461         for (i = 0; i < NR_ACT; i++) {
462
463                 if (act[i]->nr_ini > 0) {
464
465                         /* Look for a possible overflow */
466                         check_overflow((unsigned int) act[i]->msize,
467                                        (unsigned int) act[i]->nr_ini,
468                                        (unsigned int) act[i]->nr2);
469
470                         for (j = 0; j < 3; j++) {
471                                 SREALLOC(act[i]->buf[j], void,
472                                                 (size_t) act[i]->msize * (size_t) act[i]->nr_ini * (size_t) act[i]->nr2);
473                         }
474                         act[i]->nr_allocated = act[i]->nr_ini;
475                 }
476         }
477 }
478
479 /*
480  ***************************************************************************
481  * Free structures.
482  *
483  * IN:
484  * @act Array of activities.
485  ***************************************************************************
486  */
487 void free_structures(struct activity *act[])
488 {
489         int i, j;
490
491         for (i = 0; i < NR_ACT; i++) {
492                 if (act[i]->nr_allocated > 0) {
493                         for (j = 0; j < 3; j++) {
494                                 if (act[i]->buf[j]) {
495                                         free(act[i]->buf[j]);
496                                         act[i]->buf[j] = NULL;
497                                 }
498                         }
499                         act[i]->nr_allocated = 0;
500                 }
501         }
502 }
503
504 /*
505  ***************************************************************************
506  * Reallocate all the buffers for a given activity.
507  *
508  * IN:
509  * @a           Activity whose buffers need to be reallocated.
510  * @nr_min      Minimum number of items that the new buffers should be able
511  *              to receive.
512  ***************************************************************************
513  */
514 void reallocate_all_buffers(struct activity *a, __nr_t nr_min)
515 {
516         int j;
517         size_t nr_realloc;
518
519         if (nr_min <= 0) {
520                 nr_min = 1;
521         }
522         if (!a->nr_allocated) {
523                 nr_realloc = nr_min;
524         }
525         else {
526                 nr_realloc = a->nr_allocated;
527                 do {
528                         nr_realloc = nr_realloc * 2;
529                 }
530                 while (nr_realloc < nr_min);
531         }
532
533         /* Look for a possible overflow */
534         check_overflow((unsigned int) a->msize, (unsigned int) nr_realloc,
535                        (unsigned int) a->nr2);
536
537         for (j = 0; j < 3; j++) {
538                 SREALLOC(a->buf[j], void,
539                         (size_t) a->msize * nr_realloc * (size_t) a->nr2);
540                 /* Init additional space which has been allocated */
541                 if (a->nr_allocated) {
542                         memset(a->buf[j] + a->msize * a->nr_allocated * a->nr2, 0,
543                                (size_t) a->msize * (size_t) (nr_realloc - a->nr_allocated) * (size_t) a->nr2);
544                 }
545         }
546
547         a->nr_allocated = nr_realloc;
548 }
549
550 /*
551  ***************************************************************************
552  * Check if we are close enough to desired interval.
553  *
554  * IN:
555  * @uptime_ref  Uptime used as reference. This is the system uptime for the
556  *              first sample statistics, or the first system uptime after a
557  *              LINUX RESTART (in 1/100th of a second).
558  * @uptime      Current system uptime (in 1/100th of a second).
559  * @reset       TRUE if @last_uptime should be reset with @uptime_ref.
560  * @interval    Interval of time.
561  *
562  * RETURNS:
563  * TRUE if we are actually close enough to desired interval, FALSE otherwise.
564  ***************************************************************************
565 */
566 int next_slice(unsigned long long uptime_ref, unsigned long long uptime,
567                int reset, long interval)
568 {
569         unsigned long file_interval, entry;
570         static unsigned long long last_uptime = 0;
571         int min, max, pt1, pt2;
572         double f;
573
574         /* uptime is expressed in 1/100th of a second */
575         if (!last_uptime || reset) {
576                 last_uptime = uptime_ref;
577         }
578
579         /* Interval cannot be greater than 0xffffffff here */
580         f = ((double) ((uptime - last_uptime) & 0xffffffff)) / 100;
581         file_interval = (unsigned long) f;
582         if ((f * 10) - (file_interval * 10) >= 5) {
583                 file_interval++; /* Rounding to correct value */
584         }
585
586         last_uptime = uptime;
587
588         if (interval == 1)
589                 /* Smallest time interval: Always close enough to desired interval */
590                 return TRUE;
591
592         /*
593          * A few notes about the "algorithm" used here to display selected entries
594          * from the system activity file (option -f with -i flag):
595          * Let Iu be the interval value given by the user on the command line,
596          *     In the interval between current and previous sample,
597          * and En the current sample (identified by its time stamp) in the file.
598          * En will ne displayed if there is an integer p so that:
599          * p * Iu belongs to [En - In/2, En + In/2[.
600          */
601         f = ((double) ((uptime - uptime_ref) & 0xffffffff)) / 100;
602         entry = (unsigned long) f;
603         if ((f * 10) - (entry * 10) >= 5) {
604                 entry++;
605         }
606
607         min = entry - (file_interval / 2);
608         max = entry + (file_interval / 2) + (file_interval & 0x1);
609         pt1 = (entry / interval) * interval;
610         pt2 = ((entry / interval) + 1) * interval;
611
612         return (((pt1 >= min) && (pt1 < max)) || ((pt2 >= min) && (pt2 < max)));
613 }
614
615 /*
616  ***************************************************************************
617  * Use time stamp to fill tstamp structure.
618  *
619  * IN:
620  * @timestamp   Timestamp to decode (format: HH:MM:SS).
621  *
622  * OUT:
623  * @tse         Structure containing the decoded timestamp.
624  *
625  * RETURNS:
626  * 0 if the timestamp has been successfully decoded, 1 otherwise.
627  ***************************************************************************
628  */
629 int decode_timestamp(char timestamp[], struct tstamp *tse)
630 {
631         timestamp[2] = timestamp[5] = '\0';
632         tse->tm_sec  = atoi(&timestamp[6]);
633         tse->tm_min  = atoi(&timestamp[3]);
634         tse->tm_hour = atoi(timestamp);
635
636         if ((tse->tm_sec < 0) || (tse->tm_sec > 59) ||
637             (tse->tm_min < 0) || (tse->tm_min > 59) ||
638             (tse->tm_hour < 0) || (tse->tm_hour > 23))
639                 return 1;
640
641         tse->use = TRUE;
642
643         return 0;
644 }
645
646 /*
647  ***************************************************************************
648  * Compare two timestamps.
649  *
650  * IN:
651  * @rectime     Date and time for current sample.
652  * @tse         Timestamp used as reference.
653  * @cross_day   TRUE if a new day has been started.
654  *
655  * RETURNS:
656  * A positive value if @rectime is greater than @tse,
657  * a negative one otherwise.
658  ***************************************************************************
659  */
660 int datecmp(struct tm *rectime, struct tstamp *tse, int cross_day)
661 {
662         int tm_hour = rectime->tm_hour;
663
664         if (cross_day) {
665                 /*
666                  * This is necessary if we want to properly handle something like:
667                  * sar -s time_start -e time_end with
668                  * time_start(day D) > time_end(day D+1)
669                  */
670                 tm_hour += 24;
671         }
672
673         if (tm_hour == tse->tm_hour) {
674                 if (rectime->tm_min == tse->tm_min)
675                         return (rectime->tm_sec - tse->tm_sec);
676                 else
677                         return (rectime->tm_min - tse->tm_min);
678         }
679         else
680                 return (tm_hour - tse->tm_hour);
681 }
682
683 /*
684  ***************************************************************************
685  * Parse a timestamp entered on the command line (hh:mm[:ss]) and decode it.
686  *
687  * IN:
688  * @argv                Arguments list.
689  * @opt                 Index in the arguments list.
690  * @def_timestamp       Default timestamp to use.
691  *
692  * OUT:
693  * @tse                 Structure containing the decoded timestamp.
694  *
695  * RETURNS:
696  * 0 if the timestamp has been successfully decoded, 1 otherwise.
697  ***************************************************************************
698  */
699 int parse_timestamp(char *argv[], int *opt, struct tstamp *tse,
700                     const char *def_timestamp)
701 {
702         char timestamp[9];
703
704         if (argv[++(*opt)]) {
705                 switch (strlen(argv[*opt])) {
706
707                         case 5:
708                                 strncpy(timestamp, argv[(*opt)++], 5);
709                                 timestamp[5] = '\0';
710                                 strcat(timestamp, ":00");
711                                 break;
712
713                         case 8:
714                                 strncpy(timestamp, argv[(*opt)++], 8);
715                                 break;
716
717                         default:
718                                 strncpy(timestamp, def_timestamp, 8);
719                                 break;
720                 }
721         } else {
722                 strncpy(timestamp, def_timestamp, 8);
723         }
724         timestamp[8] = '\0';
725
726         return decode_timestamp(timestamp, tse);
727 }
728
729 /*
730  ***************************************************************************
731  * Set interval value.
732  *
733  * IN:
734  * @record_hdr_curr     Record with current sample statistics.
735  * @record_hdr_prev     Record with previous sample statistics.
736  *
737  * OUT:
738  * @itv                 Interval of time in 1/100th of a second.
739  ***************************************************************************
740  */
741 void get_itv_value(struct record_header *record_hdr_curr,
742                    struct record_header *record_hdr_prev,
743                    unsigned long long *itv)
744 {
745         /* Interval value in jiffies */
746         *itv = get_interval(record_hdr_prev->uptime_cs,
747                             record_hdr_curr->uptime_cs);
748 }
749
750 /*
751  ***************************************************************************
752  * Fill the rectime structure with the file's creation date, based on file's
753  * time data saved in file header.
754  * The resulting timestamp is expressed in the locale of the file creator or
755  * in the user's own locale, depending on whether option -t has been used
756  * or not.
757  *
758  * IN:
759  * @flags       Flags for common options and system state.
760  * @file_hdr    System activity file standard header.
761  *
762  * OUT:
763  * @rectime     Date (and possibly time) from file header. Only the date,
764  *              not the time, should be used by the caller.
765  ***************************************************************************
766  */
767 void get_file_timestamp_struct(uint64_t flags, struct tm *rectime,
768                                struct file_header *file_hdr)
769 {
770         time_t t = file_hdr->sa_ust_time;
771
772         if (PRINT_TRUE_TIME(flags)) {
773                 /* Get local time. This is just to fill fields with a default value. */
774                 get_time(rectime, 0);
775
776                 rectime->tm_mday = file_hdr->sa_day;
777                 rectime->tm_mon  = file_hdr->sa_month;
778                 rectime->tm_year = file_hdr->sa_year;
779                 /*
780                  * Call mktime() to set DST (Daylight Saving Time) flag.
781                  * Has anyone a better way to do it?
782                  */
783                 rectime->tm_hour = rectime->tm_min = rectime->tm_sec = 0;
784                 mktime(rectime);
785         }
786         else {
787                 localtime_r(&t, rectime);
788         }
789 }
790
791 /*
792  ***************************************************************************
793  * Print report header.
794  *
795  * IN:
796  * @flags       Flags for common options and system state.
797  * @file_hdr    System activity file standard header.
798  *
799  * OUT:
800  * @rectime     Date and time from file header.
801  ***************************************************************************
802  */
803 void print_report_hdr(uint64_t flags, struct tm *rectime,
804                       struct file_header *file_hdr)
805 {
806
807         /* Get date of file creation */
808         get_file_timestamp_struct(flags, rectime, file_hdr);
809
810         /*
811          * Display the header.
812          * NB: Number of CPU (value in [1, NR_CPUS + 1]).
813          *      1 means that there is only one proc and non SMP kernel.
814          *      2 means one proc and SMP kernel. Etc.
815          */
816         print_gal_header(rectime, file_hdr->sa_sysname, file_hdr->sa_release,
817                          file_hdr->sa_nodename, file_hdr->sa_machine,
818                          file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
819                          PLAIN_OUTPUT);
820 }
821
822 /*
823  ***************************************************************************
824  * Network interfaces may now be registered (and unregistered) dynamically.
825  * This is what we try to guess here.
826  *
827  * IN:
828  * @a           Activity structure with statistics.
829  * @curr        Index in array for current sample statistics.
830  * @ref         Index in array for sample statistics used as reference.
831  * @pos         Index on current network interface.
832  *
833  * RETURNS:
834  * Position of current network interface in array of sample statistics used
835  * as reference.
836  * -1 if it is a new interface (it was not present in array of stats used
837  * as reference).
838  * -2 if it is a known interface but which has been unregistered then
839  * registered again on the interval.
840  ***************************************************************************
841  */
842 int check_net_dev_reg(struct activity *a, int curr, int ref, int pos)
843 {
844         struct stats_net_dev *sndc, *sndp;
845         int j0, j = pos;
846
847         if (!a->nr[ref])
848                 /*
849                  * No items found in previous iteration:
850                  * Current interface is necessarily new.
851                  */
852                 return -1;
853
854         if (j >= a->nr[ref]) {
855                 j = a->nr[ref] - 1;
856         }
857         j0 = j;
858
859         sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + pos * a->msize);
860
861         do {
862                 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + j * a->msize);
863
864                 if (!strcmp(sndc->interface, sndp->interface)) {
865                         /*
866                          * Network interface found.
867                          * If a counter has decreased, then we may assume that the
868                          * corresponding interface was unregistered, then registered again.
869                          */
870                         if ((sndc->rx_packets    < sndp->rx_packets)    ||
871                             (sndc->tx_packets    < sndp->tx_packets)    ||
872                             (sndc->rx_bytes      < sndp->rx_bytes)      ||
873                             (sndc->tx_bytes      < sndp->tx_bytes)      ||
874                             (sndc->rx_compressed < sndp->rx_compressed) ||
875                             (sndc->tx_compressed < sndp->tx_compressed) ||
876                             (sndc->multicast     < sndp->multicast)) {
877
878                                 /*
879                                  * Special processing for rx_bytes (_packets) and
880                                  * tx_bytes (_packets) counters: If the number of
881                                  * bytes (packets) has decreased, whereas the number of
882                                  * packets (bytes) has increased, then assume that the
883                                  * relevant counter has met an overflow condition, and that
884                                  * the interface was not unregistered, which is all the
885                                  * more plausible that the previous value for the counter
886                                  * was > ULLONG_MAX/2.
887                                  * NB: the average value displayed will be wrong in this case...
888                                  *
889                                  * If such an overflow is detected, just set the flag. There is no
890                                  * need to handle this in a special way: the difference is still
891                                  * properly calculated if the result is of the same type (i.e.
892                                  * unsigned long) as the two values.
893                                  */
894                                 int ovfw = FALSE;
895
896                                 if ((sndc->rx_bytes   < sndp->rx_bytes)   &&
897                                     (sndc->rx_packets > sndp->rx_packets) &&
898                                     (sndp->rx_bytes   > (~0ULL >> 1))) {
899                                         ovfw = TRUE;
900                                 }
901                                 if ((sndc->tx_bytes   < sndp->tx_bytes)   &&
902                                     (sndc->tx_packets > sndp->tx_packets) &&
903                                     (sndp->tx_bytes   > (~0ULL >> 1))) {
904                                         ovfw = TRUE;
905                                 }
906                                 if ((sndc->rx_packets < sndp->rx_packets) &&
907                                     (sndc->rx_bytes   > sndp->rx_bytes)   &&
908                                     (sndp->rx_packets > (~0ULL >> 1))) {
909                                         ovfw = TRUE;
910                                 }
911                                 if ((sndc->tx_packets < sndp->tx_packets) &&
912                                     (sndc->tx_bytes   > sndp->tx_bytes)   &&
913                                     (sndp->tx_packets > (~0ULL >> 1))) {
914                                         ovfw = TRUE;
915                                 }
916
917                                 if (!ovfw)
918                                         /*
919                                          * OK: Assume here that the device was
920                                          * actually unregistered.
921                                          */
922                                         return -2;
923                         }
924                         return j;
925                 }
926                 if (++j >= a->nr[ref]) {
927                         j = 0;
928                 }
929         }
930         while (j != j0);
931
932         /* This is a newly registered interface */
933         return -1;
934 }
935
936 /*
937  ***************************************************************************
938  * Network interfaces may now be registered (and unregistered) dynamically.
939  * This is what we try to guess here.
940  *
941  * IN:
942  * @a           Activity structure with statistics.
943  * @curr        Index in array for current sample statistics.
944  * @ref         Index in array for sample statistics used as reference.
945  * @pos         Index on current network interface.
946  *
947  * RETURNS:
948  * Position of current network interface in array of sample statistics used
949  * as reference.
950  * -1 if it is a newly registered interface.
951  * -2 if it is a known interface but which has been unregistered then
952  * registered again on the interval.
953  ***************************************************************************
954  */
955 int check_net_edev_reg(struct activity *a, int curr, int ref, int pos)
956 {
957         struct stats_net_edev *snedc, *snedp;
958         int j0, j = pos;
959
960         if (!a->nr[ref])
961                 /*
962                  * No items found in previous iteration:
963                  * Current interface is necessarily new.
964                  */
965                 return -1;
966
967         if (j >= a->nr[ref]) {
968                 j = a->nr[ref] - 1;
969         }
970         j0 = j;
971
972         snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + pos * a->msize);
973
974         do {
975                 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + j * a->msize);
976
977                 if (!strcmp(snedc->interface, snedp->interface)) {
978                         /*
979                          * Network interface found.
980                          * If a counter has decreased, then we may assume that the
981                          * corresponding interface was unregistered, then registered again.
982                          */
983                         if ((snedc->tx_errors         < snedp->tx_errors)         ||
984                             (snedc->collisions        < snedp->collisions)        ||
985                             (snedc->rx_dropped        < snedp->rx_dropped)        ||
986                             (snedc->tx_dropped        < snedp->tx_dropped)        ||
987                             (snedc->tx_carrier_errors < snedp->tx_carrier_errors) ||
988                             (snedc->rx_frame_errors   < snedp->rx_frame_errors)   ||
989                             (snedc->rx_fifo_errors    < snedp->rx_fifo_errors)    ||
990                             (snedc->tx_fifo_errors    < snedp->tx_fifo_errors))
991                                 /*
992                                  * OK: assume here that the device was
993                                  * actually unregistered.
994                                  */
995                                 return -2;
996
997                         return j;
998                 }
999                 if (++j >= a->nr[ref]) {
1000                         j = 0;
1001                 }
1002         }
1003         while (j != j0);
1004
1005         /* This is a newly registered interface */
1006         return -1;
1007 }
1008
1009 /*
1010  ***************************************************************************
1011  * Disks may be registered dynamically (true in /proc/diskstats file).
1012  * This is what we try to guess here.
1013  *
1014  * IN:
1015  * @a           Activity structure with statistics.
1016  * @curr        Index in array for current sample statistics.
1017  * @ref         Index in array for sample statistics used as reference.
1018  * @pos         Index on current disk.
1019  *
1020  * RETURNS:
1021  * Position of current disk in array of sample statistics used as reference
1022  * -1 if it is a newly registered device.
1023  * -2 if it is a known device but which has been unregistered then registered
1024  * again on the interval.
1025  ***************************************************************************
1026  */
1027 int check_disk_reg(struct activity *a, int curr, int ref, int pos)
1028 {
1029         struct stats_disk *sdc, *sdp;
1030         int j0, j = pos;
1031
1032         if (!a->nr[ref])
1033                 /*
1034                  * No items found in previous iteration:
1035                  * Current interface is necessarily new.
1036                  */
1037                 return -1;
1038
1039         if (j >= a->nr[ref]) {
1040                 j = a->nr[ref] - 1;
1041         }
1042         j0 = j;
1043
1044         sdc = (struct stats_disk *) ((char *) a->buf[curr] + pos * a->msize);
1045
1046         do {
1047                 sdp = (struct stats_disk *) ((char *) a->buf[ref] + j * a->msize);
1048
1049                 if ((sdc->major == sdp->major) &&
1050                     (sdc->minor == sdp->minor)) {
1051                         /*
1052                          * Disk found.
1053                          * If all the counters have decreased then the likelyhood
1054                          * is that the disk has been unregistered and a new disk inserted.
1055                          * If only one or two have decreased then the likelyhood
1056                          * is that the counter has simply wrapped.
1057                          * Don't take into account a counter if its previous value was 0
1058                          * (this may be a read-only device, or a kernel that doesn't
1059                          * support discard stats yet...)
1060                          */
1061                         if ((sdc->nr_ios < sdp->nr_ios) &&
1062                             (!sdp->rd_sect || (sdc->rd_sect < sdp->rd_sect)) &&
1063                             (!sdp->wr_sect || (sdc->wr_sect < sdp->wr_sect)) &&
1064                             (!sdp->dc_sect || (sdc->dc_sect < sdp->dc_sect)))
1065                                 /* Same device registered again */
1066                                 return -2;
1067
1068                         return j;
1069                 }
1070                 if (++j >= a->nr[ref]) {
1071                         j = 0;
1072                 }
1073         }
1074         while (j != j0);
1075
1076         /* This is a newly registered device */
1077         return -1;
1078 }
1079
1080 /*
1081  ***************************************************************************
1082  * Allocate bitmaps for activities that have one.
1083  *
1084  * IN:
1085  * @act         Array of activities.
1086  ***************************************************************************
1087  */
1088 void allocate_bitmaps(struct activity *act[])
1089 {
1090         int i;
1091
1092         for (i = 0; i < NR_ACT; i++) {
1093                 /*
1094                  * If current activity has a bitmap which has not already
1095                  * been allocated, then allocate it.
1096                  * Note that a same bitmap may be used by several activities.
1097                  */
1098                 if (act[i]->bitmap && !act[i]->bitmap->b_array) {
1099                         SREALLOC(act[i]->bitmap->b_array, unsigned char,
1100                                  BITMAP_SIZE(act[i]->bitmap->b_size));
1101                 }
1102         }
1103 }
1104
1105 /*
1106  ***************************************************************************
1107  * Free bitmaps for activities that have one.
1108  *
1109  * IN:
1110  * @act         Array of activities.
1111  ***************************************************************************
1112  */
1113 void free_bitmaps(struct activity *act[])
1114 {
1115         int i;
1116
1117         for (i = 0; i < NR_ACT; i++) {
1118                 if (act[i]->bitmap && act[i]->bitmap->b_array) {
1119                         free(act[i]->bitmap->b_array);
1120                         /* Set pointer to NULL to prevent it from being freed again */
1121                         act[i]->bitmap->b_array = NULL;
1122                 }
1123         }
1124 }
1125
1126 /*
1127  ***************************************************************************
1128  * Select all activities, even if they have no associated items.
1129  *
1130  * IN:
1131  * @act         Array of activities.
1132  *
1133  * OUT:
1134  * @act         Array of activities, all of the being selected.
1135  ***************************************************************************
1136  */
1137 void select_all_activities(struct activity *act[])
1138 {
1139         int i;
1140
1141         for (i = 0; i < NR_ACT; i++) {
1142                 act[i]->options |= AO_SELECTED;
1143         }
1144 }
1145
1146 /*
1147  ***************************************************************************
1148  * Select CPU activity if no other activities have been explicitly selected.
1149  * Also select CPU "all" if no other CPU has been selected.
1150  *
1151  * IN:
1152  * @act         Array of activities.
1153  *
1154  * OUT:
1155  * @act         Array of activities with CPU activity selected if needed.
1156  ***************************************************************************
1157  */
1158 void select_default_activity(struct activity *act[])
1159 {
1160         int p;
1161
1162         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1163
1164         /* Default is CPU activity... */
1165         if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1166                 /*
1167                  * Yet A_CPU activity may not be available in file
1168                  * since the user can choose not to collect it.
1169                  */
1170                 act[p]->options |= AO_SELECTED;
1171         }
1172
1173         /*
1174          * If no CPU's have been selected then select CPU "all".
1175          * cpu_bitmap bitmap may be used by several activities (A_CPU, A_PWR_CPU...)
1176          */
1177         if (!count_bits(cpu_bitmap.b_array, BITMAP_SIZE(cpu_bitmap.b_size))) {
1178                 cpu_bitmap.b_array[0] |= 0x01;
1179         }
1180 }
1181
1182 /*
1183  ***************************************************************************
1184  * Swap bytes for every numerical field in structure. Used to convert from
1185  * one endianness type (big-endian or little-endian) to the other.
1186  *
1187  * IN:
1188  * @types_nr    Number of fields in structure for each following types:
1189  *              unsigned long long, unsigned long and int.
1190  * @ps          Pointer on structure.
1191  * @is64bit     TRUE if data come from a 64-bit machine.
1192  ***************************************************************************
1193  */
1194 void swap_struct(unsigned int types_nr[], void *ps, int is64bit)
1195 {
1196         int i;
1197         uint64_t *x;
1198         uint32_t *y;
1199
1200         x = (uint64_t *) ps;
1201         /* For each field of type long long (or double) */
1202         for (i = 0; i < types_nr[0]; i++) {
1203                 *x = __builtin_bswap64(*x);
1204                 x = (uint64_t *) ((char *) x + ULL_ALIGNMENT_WIDTH);
1205         }
1206
1207         y = (uint32_t *) x;
1208         /* For each field of type long */
1209         for (i = 0; i < types_nr[1]; i++) {
1210                 if (is64bit) {
1211                         *x = __builtin_bswap64(*x);
1212                         x = (uint64_t *) ((char *) x + UL_ALIGNMENT_WIDTH);
1213                 }
1214                 else {
1215                         *y = __builtin_bswap32(*y);
1216                         y = (uint32_t *) ((char *) y + UL_ALIGNMENT_WIDTH);
1217                 }
1218         }
1219
1220         if (is64bit) {
1221                 y = (uint32_t *) x;
1222         }
1223         /* For each field of type int */
1224         for (i = 0; i < types_nr[2]; i++) {
1225                 *y = __builtin_bswap32(*y);
1226                 y = (uint32_t *) ((char *) y + U_ALIGNMENT_WIDTH);
1227         }
1228 }
1229
1230 /*
1231  ***************************************************************************
1232  * Map the fields of a structure containing statistics read from a file to
1233  * those of the structure known by current sysstat version.
1234  * Each structure (either read from file or from current sysstat version)
1235  * is described by 3 values: The number of [unsigned] long long integers,
1236  * the number of [unsigned] long integers following in the structure, and
1237  * last the number of [unsigned] integers.
1238  * We assume that those numbers will *never* decrease with newer sysstat
1239  * versions.
1240  *
1241  * IN:
1242  * @gtypes_nr   Structure description as expected for current sysstat version.
1243  * @ftypes_nr   Structure description as read from file.
1244  * @ps          Pointer on structure containing statistics.
1245  * @f_size      Size of the structure containing statistics. This is the
1246  *              size of the structure *read from file*.
1247  * @g_size      Size of the structure expected by current sysstat version.
1248  * @b_size      Size of the buffer pointed by @ps.
1249  *
1250  * RETURNS:
1251  * -1 if an error has been encountered, or 0 otherwise.
1252  ***************************************************************************
1253  */
1254 int remap_struct(unsigned int gtypes_nr[], unsigned int ftypes_nr[],
1255                  void *ps, unsigned int f_size, unsigned int g_size, size_t b_size)
1256 {
1257         int d;
1258         size_t n;
1259
1260         /* Sanity check */
1261         if (MAP_SIZE(ftypes_nr) > f_size)
1262                 return -1;
1263
1264         /* Remap [unsigned] long fields */
1265         d = gtypes_nr[0] - ftypes_nr[0];
1266         if (d) {
1267                 if (ftypes_nr[0] * ULL_ALIGNMENT_WIDTH < ftypes_nr[0])
1268                         /* Overflow */
1269                         return -1;
1270
1271                 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1272                             g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH);
1273                 if ((ftypes_nr[0] * ULL_ALIGNMENT_WIDTH >= b_size) ||
1274                     (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH + n > b_size) ||
1275                     (ftypes_nr[0] * ULL_ALIGNMENT_WIDTH + n > b_size))
1276                         return -1;
1277
1278                 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1279                         ((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH, n);
1280                 if (d > 0) {
1281                         memset(((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1282                                0, d * ULL_ALIGNMENT_WIDTH);
1283                 }
1284         }
1285         /* Remap [unsigned] int fields */
1286         d = gtypes_nr[1] - ftypes_nr[1];
1287         if (d) {
1288                 if (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1289                     ftypes_nr[1] * UL_ALIGNMENT_WIDTH < ftypes_nr[1])
1290                         /* Overflow */
1291                         return -1;
1292
1293                 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
1294                                    - ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
1295                             g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1296                                    - gtypes_nr[1] * UL_ALIGNMENT_WIDTH);
1297                 if ((gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1298                      ftypes_nr[1] * UL_ALIGNMENT_WIDTH >= b_size) ||
1299                     (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1300                      gtypes_nr[1] * UL_ALIGNMENT_WIDTH + n > b_size) ||
1301                     (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1302                      ftypes_nr[1] * UL_ALIGNMENT_WIDTH + n > b_size))
1303                         return -1;
1304
1305                 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1306                                       + gtypes_nr[1] * UL_ALIGNMENT_WIDTH,
1307                         ((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1308                                       + ftypes_nr[1] * UL_ALIGNMENT_WIDTH, n);
1309                 if (d > 0) {
1310                         memset(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1311                                              + ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
1312                                0, d * UL_ALIGNMENT_WIDTH);
1313                 }
1314         }
1315         /* Remap possible fields (like strings of chars) following int fields */
1316         d = gtypes_nr[2] - ftypes_nr[2];
1317         if (d) {
1318                 if (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1319                     gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1320                     ftypes_nr[2] * U_ALIGNMENT_WIDTH < ftypes_nr[2])
1321                         /* Overflow */
1322                         return -1;
1323
1324                 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
1325                                    - ftypes_nr[1] * UL_ALIGNMENT_WIDTH
1326                                    - ftypes_nr[2] * U_ALIGNMENT_WIDTH,
1327                             g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1328                                    - gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1329                                    - gtypes_nr[2] * U_ALIGNMENT_WIDTH);
1330                 if ((gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1331                      gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1332                      ftypes_nr[2] * U_ALIGNMENT_WIDTH >= b_size) ||
1333                     (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1334                      gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1335                      gtypes_nr[2] * U_ALIGNMENT_WIDTH + n > b_size) ||
1336                     (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1337                      gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1338                      ftypes_nr[2] * U_ALIGNMENT_WIDTH + n > b_size))
1339                         return -1;
1340
1341                 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1342                                       + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1343                                       + gtypes_nr[2] * U_ALIGNMENT_WIDTH,
1344                         ((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1345                                       + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1346                                       + ftypes_nr[2] * U_ALIGNMENT_WIDTH, n);
1347                 if (d > 0) {
1348                         memset(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1349                                              + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1350                                              + ftypes_nr[2] * U_ALIGNMENT_WIDTH,
1351                                0, d * U_ALIGNMENT_WIDTH);
1352                 }
1353         }
1354         return 0;
1355 }
1356
1357 /*
1358  ***************************************************************************
1359  * Read data from a system activity data file.
1360  *
1361  * IN:
1362  * @ifd         Input file descriptor.
1363  * @buffer      Buffer where data are read.
1364  * @size        Number of bytes to read.
1365  * @mode        If set to HARD_SIZE, indicate that an EOF should be considered
1366  *              as an error.
1367  * @oneof       Set to UEOF_CONT if an unexpected end of file should not make
1368  *              sadf stop. Default behavior is to stop on unexpected EOF.
1369  *
1370  * RETURNS:
1371  * 1 if EOF has been reached,
1372  * 2 if an unexpected EOF has been reached (and sadf was told to continue),
1373  * 0 otherwise.
1374  ***************************************************************************
1375  */
1376 int sa_fread(int ifd, void *buffer, size_t size, enum size_mode mode, enum on_eof oneof)
1377 {
1378         ssize_t n;
1379
1380         if ((n = read(ifd, buffer, size)) < 0) {
1381                 fprintf(stderr, _("Error while reading system activity file: %s\n"),
1382                         strerror(errno));
1383                 close(ifd);
1384                 exit(2);
1385         }
1386
1387         if (!n && (mode == SOFT_SIZE))
1388                 return 1;       /* EOF */
1389
1390         if (n < size) {
1391                 fprintf(stderr, _("End of system activity file unexpected\n"));
1392                 if (oneof == UEOF_CONT)
1393                         return 2;
1394                 close(ifd);
1395                 exit(2);
1396         }
1397
1398         return 0;
1399 }
1400
1401 /*
1402  ***************************************************************************
1403  * Skip unknown extra structures present in file.
1404  *
1405  * IN:
1406  * @ifd         System activity data file descriptor.
1407  * @endian_mismatch
1408  *              TRUE if file's data don't match current machine's endianness.
1409  * @arch_64     TRUE if file's data come from a 64 bit machine.
1410  *
1411  * RETURNS:
1412  * -1 on error, 0 otherwise.
1413  ***************************************************************************
1414  */
1415 int skip_extra_struct(int ifd, int endian_mismatch, int arch_64)
1416 {
1417         int i;
1418         struct extra_desc xtra_d;
1419
1420         do {
1421                 /* Read extra structure description */
1422                 sa_fread(ifd, &xtra_d, EXTRA_DESC_SIZE, HARD_SIZE, UEOF_STOP);
1423
1424                 /*
1425                  * We don't need to remap as the extra_desc structure won't change,
1426                  * but we may need to normalize endianness anyway.
1427                  */
1428                 if (endian_mismatch) {
1429                         swap_struct(extra_desc_types_nr, &xtra_d, arch_64);
1430                 }
1431
1432                 /* Check values consistency */
1433                 if (MAP_SIZE(xtra_d.extra_types_nr) > xtra_d.extra_size) {
1434 #ifdef DEBUG
1435                         fprintf(stderr, "%s: extra_size=%u types=%d,%d,%d\n",
1436                                 __FUNCTION__, xtra_d.extra_size,
1437                                 xtra_d.extra_types_nr[0], xtra_d.extra_types_nr[1], xtra_d.extra_types_nr[2]);
1438 #endif
1439                         return -1;
1440                 }
1441
1442                 if ((xtra_d.extra_nr > MAX_EXTRA_NR) || (xtra_d.extra_size > MAX_EXTRA_SIZE)) {
1443 #ifdef DEBUG
1444                         fprintf(stderr, "%s: extra_size=%u extra_nr=%u\n",
1445                                 __FUNCTION__, xtra_d.extra_size, xtra_d.extra_size);
1446 #endif
1447                         return -1;
1448                 }
1449
1450                 /* Ignore current unknown extra structures */
1451                 for (i = 0; i < xtra_d.extra_nr; i++) {
1452                         if (lseek(ifd, xtra_d.extra_size, SEEK_CUR) < xtra_d.extra_size)
1453                                 return -1;
1454                 }
1455         }
1456         while (xtra_d.extra_next);
1457
1458         return 0;
1459 }
1460
1461 /*
1462  ***************************************************************************
1463  * Read the record header of current sample and process it.
1464  *
1465  * IN:
1466  * @ifd         Input file descriptor.
1467  * @buffer      Buffer where data will be read.
1468  * @record_hdr  Structure where record header will be saved.
1469  * @file_hdr    file_hdr structure containing data read from file standard
1470  *              header.
1471  * @arch_64     TRUE if file's data come from a 64-bit machine.
1472  * @endian_mismatch
1473  *              TRUE if data read from file don't match current machine's
1474  *              endianness.
1475  * @oneof       Set to EOF_CONT if an unexpected end of file should not make
1476  *              sadf stop. Default behavior is to stop on unexpected EOF.
1477  * @b_size      @buffer size.
1478  * @flags       Flags for common options and system state.
1479  * @ofmt        Pointer on report output format structure.
1480  *
1481  * OUT:
1482  * @record_hdr  Record header for current sample.
1483  *
1484  * RETURNS:
1485  * 1 if EOF has been reached,
1486  * 2 if an error has been encountered (e.g. unexpected EOF),
1487  * 0 otherwise.
1488  ***************************************************************************
1489  */
1490 int read_record_hdr(int ifd, void *buffer, struct record_header *record_hdr,
1491                     struct file_header *file_hdr, int arch_64, int endian_mismatch,
1492                     int oneof, size_t b_size, uint64_t flags, struct report_format *ofmt)
1493 {
1494         int rc;
1495
1496         do {
1497                 if ((rc = sa_fread(ifd, buffer, (size_t) file_hdr->rec_size, SOFT_SIZE, oneof)) != 0)
1498                         /* End of sa data file */
1499                         return rc;
1500
1501                 /* Remap record header structure to that expected by current version */
1502                 if (remap_struct(rec_types_nr, file_hdr->rec_types_nr, buffer,
1503                                  file_hdr->rec_size, RECORD_HEADER_SIZE, b_size) < 0)
1504                         return 2;
1505                 memcpy(record_hdr, buffer, RECORD_HEADER_SIZE);
1506
1507                 /* Normalize endianness */
1508                 if (endian_mismatch) {
1509                         swap_struct(rec_types_nr, record_hdr, arch_64);
1510                 }
1511
1512                 /* Raw output in debug mode */
1513                 if (DISPLAY_DEBUG_MODE(flags) && (ofmt->id == F_RAW_OUTPUT)) {
1514                         char out[128];
1515
1516                         sprintf(out, "# uptime_cs; %llu; ust_time; %llu; extra_next; %u; record_type; %d; HH:MM:SS; %02d:%02d:%02d\n",
1517                                record_hdr->uptime_cs, record_hdr->ust_time,
1518                                record_hdr->extra_next, record_hdr->record_type,
1519                                record_hdr->hour, record_hdr->minute, record_hdr->second);
1520                         cprintf_s(IS_COMMENT, "%s", out);
1521                 }
1522
1523                 /* Sanity checks */
1524                 if ((record_hdr->record_type <= 0) || (record_hdr->record_type > R_EXTRA_MAX) ||
1525                     (record_hdr->hour > 23) || (record_hdr->minute > 59) || (record_hdr->second > 60)) {
1526 #ifdef DEBUG
1527                         fprintf(stderr, "%s: record_type=%d HH:MM:SS=%02d:%02d:%02d\n",
1528                                 __FUNCTION__, record_hdr->record_type,
1529                                 record_hdr->hour, record_hdr->minute, record_hdr->second);
1530 #endif
1531                         return 2;
1532                 }
1533
1534                 /*
1535                  * Skip unknown extra structures if present.
1536                  * This will be done later for R_COMMENT and R_RESTART records, as extra structures
1537                  * are saved after the comment or the number of CPU.
1538                  */
1539                 if ((record_hdr->record_type != R_COMMENT) && (record_hdr->record_type != R_RESTART) &&
1540                     record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
1541                         return 2;
1542         }
1543         while ((record_hdr->record_type >= R_EXTRA_MIN) && (record_hdr->record_type <= R_EXTRA_MAX)) ;
1544
1545         return 0;
1546 }
1547
1548 /*
1549  ***************************************************************************
1550  * Move structures data.
1551  *
1552  * IN:
1553  * @act         Array of activities.
1554  * @id_seq      Activity sequence in file.
1555  * @record_hdr  Current record header.
1556  * @dest        Index in array where stats have to be copied to.
1557  * @src         Index in array where stats to copy are.
1558  ***************************************************************************
1559  */
1560 void copy_structures(struct activity *act[], unsigned int id_seq[],
1561                      struct record_header record_hdr[], int dest, int src)
1562 {
1563         int i, p;
1564
1565         memcpy(&record_hdr[dest], &record_hdr[src], RECORD_HEADER_SIZE);
1566
1567         for (i = 0; i < NR_ACT; i++) {
1568
1569                 if (!id_seq[i])
1570                         continue;
1571
1572                 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1573
1574                 memcpy(act[p]->buf[dest], act[p]->buf[src],
1575                        (size_t) act[p]->msize * (size_t) act[p]->nr_allocated * (size_t) act[p]->nr2);
1576                 act[p]->nr[dest] = act[p]->nr[src];
1577         }
1578 }
1579
1580 /*
1581  ***************************************************************************
1582  * Read an __nr_t value from file.
1583  * Such a value can be the new number of CPU saved after a RESTART record,
1584  * or the number of structures to read saved before the structures containing
1585  * statistics for an activity with a varying number of items in file.
1586  *
1587  * IN:
1588  * @ifd         Input file descriptor.
1589  * @file        Name of file being read.
1590  * @file_magic  file_magic structure filled with file magic header data.
1591  * @endian_mismatch
1592  *              TRUE if file's data don't match current machine's endianness.
1593  * @arch_64     TRUE if file's data come from a 64 bit machine.
1594  * @non_zero    TRUE if value should not be zero.
1595  *
1596  * RETURNS:
1597  * __nr_t value, as read from file.
1598  ***************************************************************************
1599  */
1600 __nr_t read_nr_value(int ifd, char *file, struct file_magic *file_magic,
1601                      int endian_mismatch, int arch_64, int non_zero)
1602 {
1603         __nr_t value;
1604         unsigned int nr_types_nr[]  = {0, 0, 1};
1605
1606         sa_fread(ifd, &value, sizeof(__nr_t), HARD_SIZE, UEOF_STOP);
1607
1608         /* Normalize endianness for file_activity structures */
1609         if (endian_mismatch) {
1610                 swap_struct(nr_types_nr, &value, arch_64);
1611         }
1612
1613         if ((non_zero && !value) || (value < 0)) {
1614 #ifdef DEBUG
1615                 fprintf(stderr, "%s: Value=%d\n",
1616                         __FUNCTION__, value);
1617 #endif
1618                 /* Value number cannot be zero or negative */
1619                 handle_invalid_sa_file(ifd, file_magic, file, 0);
1620         }
1621
1622         return value;
1623 }
1624
1625 /*
1626  ***************************************************************************
1627  * Read varying part of the statistics from a daily data file.
1628  *
1629  * IN:
1630  * @act         Array of activities.
1631  * @curr        Index in array for current sample statistics.
1632  * @ifd         Input file descriptor.
1633  * @act_nr      Number of activities in file.
1634  * @file_actlst Activity list in file.
1635  * @endian_mismatch
1636  *              TRUE if file's data don't match current machine's endianness.
1637  * @arch_64     TRUE if file's data come from a 64 bit machine.
1638  * @dfile       Name of system activity data file.
1639  * @file_magic  file_magic structure containing data read from file magic
1640  *              header.
1641  * @oneof       Set to UEOF_CONT if an unexpected end of file should not make
1642  *              sadf stop. Default behavior is to stop on unexpected EOF.
1643  *
1644  * RETURNS:
1645  * 2 if an error has been encountered (e.g. unexpected EOF),
1646  * 0 otherwise.
1647  ***************************************************************************
1648  */
1649 int read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
1650                          struct file_activity *file_actlst, int endian_mismatch,
1651                          int arch_64, char *dfile, struct file_magic *file_magic,
1652                          enum on_eof oneof)
1653 {
1654         int i, j, p;
1655         struct file_activity *fal = file_actlst;
1656         off_t offset;
1657         __nr_t nr_value;
1658
1659         for (i = 0; i < act_nr; i++, fal++) {
1660
1661                 /* Read __nr_t value preceding statistics structures if it exists */
1662                 if (fal->has_nr) {
1663                         nr_value = read_nr_value(ifd, dfile, file_magic,
1664                                                  endian_mismatch, arch_64, FALSE);
1665                 }
1666                 else {
1667                         nr_value = fal->nr;
1668                 }
1669
1670                 if (nr_value > NR_MAX) {
1671 #ifdef DEBUG
1672                         fprintf(stderr, "%s: Value=%d Max=%d\n", __FUNCTION__, nr_value, NR_MAX);
1673 #endif
1674                         handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1675                 }
1676
1677                 if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
1678                     (act[p]->magic != fal->magic)) {
1679                         /*
1680                          * Ignore current activity in file, which is unknown to
1681                          * current sysstat version or has an unknown format.
1682                          */
1683                         if (nr_value) {
1684                                 offset = (off_t) fal->size * (off_t) nr_value * (off_t) fal->nr2;
1685                                 if (lseek(ifd, offset, SEEK_CUR) < offset) {
1686                                         close(ifd);
1687                                         perror("lseek");
1688                                         if (oneof == UEOF_CONT)
1689                                                 return 2;
1690                                         exit(2);
1691                                 }
1692                         }
1693                         continue;
1694                 }
1695
1696                 if (nr_value > act[p]->nr_max) {
1697 #ifdef DEBUG
1698                         fprintf(stderr, "%s: %s: Value=%d Max=%d\n",
1699                                 __FUNCTION__, act[p]->name, nr_value, act[p]->nr_max);
1700 #endif
1701                         handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1702                 }
1703                 act[p]->nr[curr] = nr_value;
1704
1705                 /* Reallocate buffers if needed */
1706                 if (nr_value > act[p]->nr_allocated) {
1707                         reallocate_all_buffers(act[p], nr_value);
1708                 }
1709
1710                 /*
1711                  * For persistent activities, we must make sure that no statistics
1712                  * from a previous iteration remain, especially if the number
1713                  * of structures read is smaller than @nr_ini.
1714                  */
1715                 if (HAS_PERSISTENT_VALUES(act[p]->options)) {
1716                     memset(act[p]->buf[curr], 0,
1717                            (size_t) act[p]->msize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
1718                 }
1719
1720                 /* OK, this is a known activity: Read the stats structures */
1721                 if ((nr_value > 0) &&
1722                     ((nr_value > 1) || (act[p]->nr2 > 1)) &&
1723                     (act[p]->msize > act[p]->fsize)) {
1724
1725                         for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1726                                 if (sa_fread(ifd, (char *) act[p]->buf[curr] + j * act[p]->msize,
1727                                          (size_t) act[p]->fsize, HARD_SIZE, oneof) > 0)
1728                                         /* Unexpected EOF */
1729                                         return 2;
1730                         }
1731                 }
1732                 else if (nr_value > 0) {
1733                         /*
1734                          * Note: If msize was smaller than fsize,
1735                          * then it has been set to fsize in check_file_actlst().
1736                          */
1737                         if (sa_fread(ifd, act[p]->buf[curr],
1738                                  (size_t) act[p]->fsize * (size_t) nr_value * (size_t) act[p]->nr2,
1739                                  HARD_SIZE, oneof) > 0)
1740                                 /* Unexpected EOF */
1741                                 return 2;
1742                 }
1743                 else {
1744                         /* nr_value == 0: Nothing to read */
1745                         continue;
1746                 }
1747
1748                 /* Normalize endianness for current activity's structures */
1749                 if (endian_mismatch) {
1750                         for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1751                                 swap_struct(act[p]->ftypes_nr, (char *) act[p]->buf[curr] + j * act[p]->msize,
1752                                             arch_64);
1753                         }
1754                 }
1755
1756                 /* Remap structure's fields to those known by current sysstat version */
1757                 for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1758                         if (remap_struct(act[p]->gtypes_nr, act[p]->ftypes_nr,
1759                                          (char *) act[p]->buf[curr] + j * act[p]->msize,
1760                                          act[p]->fsize, act[p]->msize, act[p]->msize) < 0)
1761                                 return 2;
1762                 }
1763         }
1764
1765         return 0;
1766 }
1767
1768 /*
1769  ***************************************************************************
1770  * Open a sysstat activity data file and read its magic structure.
1771  *
1772  * IN:
1773  * @dfile       Name of system activity data file.
1774  * @ignore      Set to 1 if a true sysstat activity file but with a bad
1775  *              format should not yield an error message. Useful with
1776  *              sadf -H and sadf -c.
1777  *
1778  * OUT:
1779  * @fd          System activity data file descriptor.
1780  * @file_magic  file_magic structure containing data read from file magic
1781  *              header.
1782  * @endian_mismatch
1783  *              TRUE if file's data don't match current machine's endianness.
1784  * @do_swap     TRUE if endianness should be normalized for sysstat_magic
1785  *              and format_magic numbers.
1786  *
1787  * RETURNS:
1788  * -1 if data file is a sysstat file with an old format (which we cannot
1789  * read), 0 otherwise.
1790  ***************************************************************************
1791  */
1792 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
1793                        int ignore, int *endian_mismatch, int do_swap)
1794 {
1795         int n;
1796         unsigned int fm_types_nr[] = {FILE_MAGIC_ULL_NR, FILE_MAGIC_UL_NR, FILE_MAGIC_U_NR};
1797
1798         /* Open sa data file */
1799         if ((*fd = open(dfile, O_RDONLY)) < 0) {
1800                 int saved_errno = errno;
1801
1802                 fprintf(stderr, _("Cannot open %s: %s\n"), dfile, strerror(errno));
1803
1804                 if ((saved_errno == ENOENT) && default_file_used) {
1805                         fprintf(stderr, _("Please check if data collecting is enabled\n"));
1806                 }
1807                 exit(2);
1808         }
1809
1810         /* Read file magic data */
1811         n = read(*fd, file_magic, FILE_MAGIC_SIZE);
1812
1813         if ((n != FILE_MAGIC_SIZE) ||
1814             ((file_magic->sysstat_magic != SYSSTAT_MAGIC) && (file_magic->sysstat_magic != SYSSTAT_MAGIC_SWAPPED)) ||
1815             ((file_magic->format_magic != FORMAT_MAGIC) && (file_magic->format_magic != FORMAT_MAGIC_SWAPPED) && !ignore)) {
1816 #ifdef DEBUG
1817                 fprintf(stderr, "%s: Bytes read=%d sysstat_magic=%x format_magic=%x\n",
1818                         __FUNCTION__, n, file_magic->sysstat_magic, file_magic->format_magic);
1819 #endif
1820                 /* Display error message and exit */
1821                 handle_invalid_sa_file(*fd, file_magic, dfile, n);
1822         }
1823
1824         *endian_mismatch = (file_magic->sysstat_magic != SYSSTAT_MAGIC);
1825         if (*endian_mismatch) {
1826                 if (do_swap) {
1827                         /* Swap bytes for file_magic fields */
1828                         file_magic->sysstat_magic = SYSSTAT_MAGIC;
1829                         file_magic->format_magic  = __builtin_bswap16(file_magic->format_magic);
1830                 }
1831                 /*
1832                  * Start swapping at field "header_size" position.
1833                  * May not exist for older versions but in this case, it won't be used.
1834                  */
1835                 swap_struct(fm_types_nr, &file_magic->header_size, 0);
1836         }
1837
1838         if ((file_magic->sysstat_version > 10) ||
1839             ((file_magic->sysstat_version == 10) && (file_magic->sysstat_patchlevel >= 3))) {
1840                 /* header_size field exists only for sysstat versions 10.3.1 and later */
1841                 if ((file_magic->header_size <= MIN_FILE_HEADER_SIZE) ||
1842                     (file_magic->header_size > MAX_FILE_HEADER_SIZE)) {
1843 #ifdef DEBUG
1844                         fprintf(stderr, "%s: header_size=%u\n",
1845                                 __FUNCTION__, file_magic->header_size);
1846 #endif
1847                         /* Display error message and exit */
1848                         handle_invalid_sa_file(*fd, file_magic, dfile, n);
1849                 }
1850         }
1851         if ((file_magic->sysstat_version > 11) ||
1852             ((file_magic->sysstat_version == 11) && (file_magic->sysstat_patchlevel >= 7))) {
1853                 /* hdr_types_nr field exists only for sysstat versions 11.7.1 and later */
1854                 if (MAP_SIZE(file_magic->hdr_types_nr) > file_magic->header_size) {
1855 #ifdef DEBUG
1856                         fprintf(stderr, "%s: map_size=%u header_size=%u\n",
1857                                 __FUNCTION__, MAP_SIZE(file_magic->hdr_types_nr), file_magic->header_size);
1858 #endif
1859                         handle_invalid_sa_file(*fd, file_magic, dfile, n);
1860                 }
1861         }
1862
1863         if ((file_magic->format_magic != FORMAT_MAGIC) &&
1864             (file_magic->format_magic != FORMAT_MAGIC_SWAPPED))
1865                 /*
1866                  * This is an old (or new) sa datafile format to
1867                  * be read by sadf (since @ignore was set to TRUE).
1868                  */
1869                 return -1;
1870
1871         return 0;
1872 }
1873
1874 /*
1875  ***************************************************************************
1876  * Open a data file, and perform various checks before reading.
1877  * NB: This is called only when reading a datafile (sar and sadf), never
1878  * when writing or appending data to a datafile.
1879  *
1880  * IN:
1881  * @dfile       Name of system activity data file.
1882  * @act         Array of activities.
1883  * @flags       Flags for common options and system state.
1884  *
1885  * OUT:
1886  * @ifd         System activity data file descriptor.
1887  * @file_magic  file_magic structure containing data read from file magic
1888  *              header.
1889  * @file_hdr    file_hdr structure containing data read from file standard
1890  *              header.
1891  * @file_actlst Acvtivity list in file.
1892  * @id_seq      Activity sequence.
1893  * @endian_mismatch
1894  *              TRUE if file's data don't match current machine's endianness.
1895  * @arch_64     TRUE if file's data come from a 64 bit machine.
1896  ***************************************************************************
1897  */
1898 void check_file_actlst(int *ifd, char *dfile, struct activity *act[], uint64_t flags,
1899                        struct file_magic *file_magic, struct file_header *file_hdr,
1900                        struct file_activity **file_actlst, unsigned int id_seq[],
1901                        int *endian_mismatch, int *arch_64)
1902 {
1903         int i, j, k, p, skip;
1904         struct file_activity *fal;
1905         void *buffer = NULL;
1906         size_t bh_size = FILE_HEADER_SIZE;
1907         size_t ba_size = FILE_ACTIVITY_SIZE;
1908
1909         /* Open sa data file and read its magic structure */
1910         if (sa_open_read_magic(ifd, dfile, file_magic,
1911                                DISPLAY_HDR_ONLY(flags), endian_mismatch, TRUE) < 0)
1912                 /*
1913                  * Not current sysstat's format.
1914                  * Return now so that sadf -H can display at least
1915                  * file's version and magic number.
1916                  */
1917                 return;
1918
1919         /*
1920          * We know now that we have a *compatible* sysstat datafile format
1921          * (correct FORMAT_MAGIC value), and in this case, we should have
1922          * checked header_size value. Anyway, with a corrupted datafile,
1923          * this may not be the case. So check again.
1924          */
1925         if ((file_magic->header_size <= MIN_FILE_HEADER_SIZE) ||
1926             (file_magic->header_size > MAX_FILE_HEADER_SIZE)) {
1927 #ifdef DEBUG
1928                 fprintf(stderr, "%s: header_size=%u\n",
1929                         __FUNCTION__, file_magic->header_size);
1930 #endif
1931                 goto format_error;
1932         }
1933
1934         /* Allocate buffer for file_header structure */
1935         if (file_magic->header_size > FILE_HEADER_SIZE) {
1936                 bh_size = file_magic->header_size;
1937         }
1938         SREALLOC(buffer, char, bh_size);
1939
1940         /* Read sa data file standard header and allocate activity list */
1941         sa_fread(*ifd, buffer, (size_t) file_magic->header_size, HARD_SIZE, UEOF_STOP);
1942         /*
1943          * Data file header size (file_magic->header_size) may be greater or
1944          * smaller than FILE_HEADER_SIZE. Remap the fields of the file header
1945          * then copy its contents to the expected structure.
1946          */
1947         if (remap_struct(hdr_types_nr, file_magic->hdr_types_nr, buffer,
1948                          file_magic->header_size, FILE_HEADER_SIZE, bh_size) < 0)
1949                 goto format_error;
1950
1951         memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
1952         free(buffer);
1953         buffer = NULL;
1954
1955         /* Tell that data come from a 64 bit machine */
1956         *arch_64 = (file_hdr->sa_sizeof_long == SIZEOF_LONG_64BIT);
1957
1958         /* Normalize endianness for file_hdr structure */
1959         if (*endian_mismatch) {
1960                 swap_struct(hdr_types_nr, file_hdr, *arch_64);
1961         }
1962
1963         /*
1964          * Sanity checks.
1965          * NB: Compare against MAX_NR_ACT and not NR_ACT because
1966          * we are maybe reading a datafile from a future sysstat version
1967          * with more activities than known today.
1968          */
1969         if ((file_hdr->sa_act_nr > MAX_NR_ACT) ||
1970             (file_hdr->act_size > MAX_FILE_ACTIVITY_SIZE) ||
1971             (file_hdr->rec_size > MAX_RECORD_HEADER_SIZE) ||
1972             (MAP_SIZE(file_hdr->act_types_nr) > file_hdr->act_size) ||
1973             (MAP_SIZE(file_hdr->rec_types_nr) > file_hdr->rec_size)) {
1974 #ifdef DEBUG
1975                 fprintf(stderr, "%s: sa_act_nr=%d act_size=%u rec_size=%u map_size(act)=%u map_size(rec)=%u\n",
1976                         __FUNCTION__, file_hdr->sa_act_nr, file_hdr->act_size, file_hdr->rec_size,
1977                         MAP_SIZE(file_hdr->act_types_nr), MAP_SIZE(file_hdr->rec_types_nr));
1978 #endif
1979                 /* Maybe a "false positive" sysstat datafile? */
1980                 goto format_error;
1981         }
1982
1983         /* Allocate buffer for file_activity structures */
1984         if (file_hdr->act_size > FILE_ACTIVITY_SIZE) {
1985                 ba_size = file_hdr->act_size;
1986         }
1987         SREALLOC(buffer, char, ba_size);
1988         SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
1989         fal = *file_actlst;
1990
1991         /* Read activity list */
1992         j = 0;
1993         for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1994
1995                 /* Read current file_activity structure from file */
1996                 sa_fread(*ifd, buffer, (size_t) file_hdr->act_size, HARD_SIZE, UEOF_STOP);
1997
1998                 /*
1999                  * Data file_activity size (file_hdr->act_size) may be greater or
2000                  * smaller than FILE_ACTIVITY_SIZE. Remap the fields of the file's structure
2001                  * then copy its contents to the expected structure.
2002                  */
2003                 if (remap_struct(act_types_nr, file_hdr->act_types_nr, buffer,
2004                              file_hdr->act_size, FILE_ACTIVITY_SIZE, ba_size) < 0)
2005                         goto format_error;
2006                 memcpy(fal, buffer, FILE_ACTIVITY_SIZE);
2007
2008                 /* Normalize endianness for file_activity structures */
2009                 if (*endian_mismatch) {
2010                         swap_struct(act_types_nr, fal, *arch_64);
2011                 }
2012
2013                 /*
2014                  * Every activity, known or unknown, should have
2015                  * at least one item and sub-item, and a size value in
2016                  * a defined range.
2017                  * Also check that the number of items and sub-items
2018                  * doesn't exceed a max value. This is necessary
2019                  * because we will use @nr and @nr2 to
2020                  * allocate memory to read the file contents. So we
2021                  * must make sure the file is not corrupted.
2022                  * NB: Another check will be made below for known
2023                  * activities which have each a specific max value.
2024                  */
2025                 if ((fal->nr < 1) || (fal->nr2 < 1) ||
2026                     (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX) ||
2027                     (fal->size <= 0) || (fal->size > MAX_ITEM_STRUCT_SIZE)) {
2028 #ifdef DEBUG
2029                         fprintf(stderr, "%s: id=%d nr=%d nr2=%d size=%d\n",
2030                                 __FUNCTION__, fal->id, fal->nr, fal->nr2, fal->size);
2031 #endif
2032                         goto format_error;
2033                 }
2034
2035                 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0)
2036                         /* Unknown activity */
2037                         continue;
2038
2039                 if ((fal->magic != act[p]->magic) && !DISPLAY_HDR_ONLY(flags)) {
2040                         skip = TRUE;
2041                 }
2042                 else {
2043                         skip = FALSE;
2044                 }
2045
2046                 /* Check max value for known activities */
2047                 if (fal->nr > act[p]->nr_max) {
2048 #ifdef DEBUG
2049                         fprintf(stderr, "%s: id=%d nr=%d nr_max=%d\n",
2050                                 __FUNCTION__, fal->id, fal->nr, act[p]->nr_max);
2051 #endif
2052                         goto format_error;
2053                 }
2054
2055                 /*
2056                  * Number of fields of each type ("long long", or "long"
2057                  * or "int") composing the structure with statistics may
2058                  * only increase with new sysstat versions, unless we change
2059                  * the activity's magic number. Here, we may
2060                  * be reading a file created by current sysstat version,
2061                  * or by an older or a newer version.
2062                  */
2063                 if (!(((fal->types_nr[0] >= act[p]->gtypes_nr[0]) &&
2064                      (fal->types_nr[1] >= act[p]->gtypes_nr[1]) &&
2065                      (fal->types_nr[2] >= act[p]->gtypes_nr[2]))
2066                      ||
2067                      ((fal->types_nr[0] <= act[p]->gtypes_nr[0]) &&
2068                      (fal->types_nr[1] <= act[p]->gtypes_nr[1]) &&
2069                      (fal->types_nr[2] <= act[p]->gtypes_nr[2]))) &&
2070                      (fal->magic == act[p]->magic) && !DISPLAY_HDR_ONLY(flags)) {
2071 #ifdef DEBUG
2072                         fprintf(stderr, "%s: id=%d file=%d,%d,%d activity=%d,%d,%d\n",
2073                                 __FUNCTION__, fal->id, fal->types_nr[0], fal->types_nr[1], fal->types_nr[2],
2074                                 act[p]->gtypes_nr[0], act[p]->gtypes_nr[1], act[p]->gtypes_nr[2]);
2075 #endif
2076                         goto format_error;
2077                 }
2078
2079                 if (MAP_SIZE(fal->types_nr) > fal->size) {
2080 #ifdef DEBUG
2081                 fprintf(stderr, "%s: id=%d size=%u map_size=%u\n",
2082                         __FUNCTION__, fal->id, fal->size, MAP_SIZE(fal->types_nr));
2083 #endif
2084                         goto format_error;
2085                 }
2086
2087                 for (k = 0; k < 3; k++) {
2088                         act[p]->ftypes_nr[k] = fal->types_nr[k];
2089                 }
2090
2091                 if (fal->size > act[p]->msize) {
2092                         act[p]->msize = fal->size;
2093                 }
2094
2095                 act[p]->nr_ini = fal->nr;
2096                 act[p]->nr2    = fal->nr2;
2097                 act[p]->fsize  = fal->size;
2098
2099                 /*
2100                  * This is a known activity with a known format
2101                  * (magical number). Only such activities will be displayed.
2102                  * (Well, this may also be an unknown format if we have entered sadf -H.)
2103                  */
2104                 if (!skip) {
2105                         id_seq[j++] = fal->id;
2106                 }
2107         }
2108
2109         while (j < NR_ACT) {
2110                 id_seq[j++] = 0;
2111         }
2112
2113         free(buffer);
2114         buffer = NULL;
2115
2116         /* Check that at least one activity selected by the user is available in file */
2117         for (i = 0; i < NR_ACT; i++) {
2118
2119                 if (!IS_SELECTED(act[i]->options))
2120                         continue;
2121
2122                 /* Here is a selected activity: Does it exist in file? */
2123                 fal = *file_actlst;
2124                 for (j = 0; j < file_hdr->sa_act_nr; j++, fal++) {
2125                         if (act[i]->id == fal->id)
2126                                 break;
2127                 }
2128                 if (j == file_hdr->sa_act_nr) {
2129                         /* No: Unselect it */
2130                         act[i]->options &= ~AO_SELECTED;
2131                 }
2132         }
2133
2134         /*
2135          * None of selected activities exist in file: Abort.
2136          * NB: Error is ignored if we only want to display
2137          * datafile header (sadf -H).
2138          */
2139         if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES) && !DISPLAY_HDR_ONLY(flags)) {
2140                 fprintf(stderr, _("Requested activities not available in file %s\n"),
2141                         dfile);
2142                 close(*ifd);
2143                 exit(1);
2144         }
2145
2146         /*
2147          * Check if there are some extra structures.
2148          * We will just skip them as they are unknown for now.
2149          */
2150         if (file_hdr->extra_next && (skip_extra_struct(*ifd, *endian_mismatch, *arch_64) < 0))
2151                 goto format_error;
2152
2153         return;
2154
2155 format_error:
2156         if (buffer) {
2157                 free(buffer);
2158         }
2159         handle_invalid_sa_file(*ifd, file_magic, dfile, 0);
2160 }
2161
2162 /*
2163  ***************************************************************************
2164  * Look for item in list.
2165  *
2166  * IN:
2167  * @list        Pointer on the start of the linked list.
2168  * @item_name   Item name to look for.
2169  *
2170  * RETURNS:
2171  * 1 if item found in list, 0 otherwise.
2172  ***************************************************************************
2173  */
2174 int search_list_item(struct sa_item *list, char *item_name)
2175 {
2176         while (list != NULL) {
2177                 if (!strcmp(list->item_name, item_name))
2178                         return 1;       /* Item found in list */
2179                 list = list->next;
2180         }
2181
2182         /* Item not found */
2183         return 0;
2184 }
2185
2186 /*
2187  ***************************************************************************
2188  * Add item to the list.
2189  *
2190  * IN:
2191  * @list        Address of pointer on the start of the linked list.
2192  * @item_name   Name of the item.
2193  * @max_len     Max length of an item.
2194  *
2195  * RETURNS:
2196  * 1 if item has been added to the list (since it was not previously there),
2197  * and 0 otherwise (item already in list or item name too long).
2198  ***************************************************************************
2199  */
2200 int add_list_item(struct sa_item **list, char *item_name, int max_len)
2201 {
2202         struct sa_item *e;
2203         int len;
2204
2205         if ((len = strnlen(item_name, max_len)) == max_len)
2206                 /* Item too long */
2207                 return 0;
2208
2209         while (*list != NULL) {
2210                 e = *list;
2211                 if (!strcmp(e->item_name, item_name))
2212                         return 0;       /* Item found in list */
2213                 list = &(e->next);
2214         }
2215
2216         /* Item not found: Add it to the list */
2217         SREALLOC(*list, struct sa_item, sizeof(struct sa_item));
2218         e = *list;
2219         if ((e->item_name = (char *) malloc(len + 1)) == NULL) {
2220                 perror("malloc");
2221                 exit(4);
2222         }
2223         strcpy(e->item_name, item_name);
2224
2225         return 1;
2226 }
2227
2228 /*
2229  ***************************************************************************
2230  * Parse sar activities options (also used by sadf).
2231  *
2232  * IN:
2233  * @argv        Arguments list.
2234  * @opt         Index in list of arguments.
2235  * @caller      Indicate whether it's sar or sadf that called this function.
2236  *
2237  * OUT:
2238  * @act         Array of selected activities.
2239  * @flags       Common flags and system state.
2240  *
2241  * RETURNS:
2242  * 0 on success.
2243  ***************************************************************************
2244  */
2245 int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
2246                   uint64_t *flags, int caller)
2247 {
2248         int i, p;
2249
2250         for (i = 1; *(argv[*opt] + i); i++) {
2251                 /*
2252                  * Note: argv[*opt] contains something like "-BruW"
2253                  *     *(argv[*opt] + i) will contain 'B', 'r', etc.
2254                  */
2255
2256                 switch (*(argv[*opt] + i)) {
2257
2258                 case 'A':
2259                         select_all_activities(act);
2260                         *flags |= S_F_OPTION_A;
2261
2262                         /*
2263                          * Force '-r ALL -u ALL -F'.
2264                          * Setting -F is compulsory because corresponding activity
2265                          * has AO_MULTIPLE_OUTPUTS flag set.
2266                          * -P ALL will be set only if corresponding option has
2267                          * not been exlicitly entered on the command line.
2268                          */
2269                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2270                         act[p]->opt_flags |= AO_F_MEMORY + AO_F_SWAP + AO_F_MEM_ALL;
2271
2272                         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2273                         act[p]->opt_flags = AO_F_CPU_ALL;
2274
2275                         p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
2276                         act[p]->opt_flags = AO_F_FILESYSTEM;
2277                         break;
2278
2279                 case 'B':
2280                         SELECT_ACTIVITY(A_PAGE);
2281                         break;
2282
2283                 case 'b':
2284                         SELECT_ACTIVITY(A_IO);
2285                         break;
2286
2287                 case 'C':
2288                         *flags |= S_F_COMMENT;
2289                         break;
2290
2291                 case 'd':
2292                         SELECT_ACTIVITY(A_DISK);
2293                         break;
2294
2295                 case 'F':
2296                         p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
2297                         act[p]->options |= AO_SELECTED;
2298                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_MOUNT)) {
2299                                 (*opt)++;
2300                                 act[p]->opt_flags |= AO_F_MOUNT;
2301                                 return 0;
2302                         }
2303                         else {
2304                                 act[p]->opt_flags |= AO_F_FILESYSTEM;
2305                         }
2306                         break;
2307
2308                 case 'H':
2309                         SELECT_ACTIVITY(A_HUGE);
2310                         break;
2311
2312                 case 'h':
2313                         /* Option -h is equivalent to --pretty --human */
2314                         *flags |= S_F_PRETTY + S_F_UNIT;
2315                         break;
2316
2317                 case 'I':
2318                         p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
2319                         act[p]->options |= AO_SELECTED;
2320
2321                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] &&
2322                             (!strcmp(argv[*opt + 1], K_ALL) || !strcmp(argv[*opt + 1], K_SUM))) {
2323                                 (*opt)++;
2324                                 /* Select int "sum". Keyword ALL is ignored */
2325                                 if (!strcmp(argv[*opt], K_SUM)) {
2326                                         act[p]->item_list_sz += add_list_item(&(act[p]->item_list), K_LOWERSUM, MAX_SA_IRQ_LEN);
2327                                         act[p]->options |= AO_LIST_ON_CMDLINE;
2328                                 }
2329                                 return 0;
2330                         }
2331                         break;
2332
2333                 case 'j':
2334                         if (!argv[*opt + 1]) {
2335                                 return 1;
2336                         }
2337                         (*opt)++;
2338                         if (!strcmp(argv[*opt], K_SID)) {
2339                                 *flags |= S_F_DEV_SID + S_F_PRETTY;
2340                                 return 0;
2341                         }
2342
2343                         if (strnlen(argv[*opt], sizeof(persistent_name_type)) >= sizeof(persistent_name_type) - 1)
2344                                 return 1;
2345
2346                         strncpy(persistent_name_type, argv[*opt], sizeof(persistent_name_type) - 1);
2347                         persistent_name_type[sizeof(persistent_name_type) - 1] = '\0';
2348                         strtolower(persistent_name_type);
2349                         if (!get_persistent_type_dir(persistent_name_type)) {
2350                                 fprintf(stderr, _("Invalid type of persistent device name\n"));
2351                                 return 2;
2352                         }
2353                         /* Pretty print report (option -j implies option -p) */
2354                         *flags |= S_F_PERSIST_NAME + S_F_PRETTY;
2355                         return 0;
2356                         break;
2357
2358                 case 'p':
2359                         *flags |= S_F_PRETTY;
2360                         break;
2361
2362                 case 'q':
2363                         /* Option -q grouped with other ones */
2364                         SELECT_ACTIVITY(A_QUEUE);
2365                         break;
2366
2367                 case 'r':
2368                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2369                         act[p]->options   |= AO_SELECTED;
2370                         act[p]->opt_flags |= AO_F_MEMORY;
2371                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
2372                                 (*opt)++;
2373                                 act[p]->opt_flags |= AO_F_MEM_ALL;
2374                                 return 0;
2375                         }
2376                         break;
2377
2378                 case 'S':
2379                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2380                         act[p]->options   |= AO_SELECTED;
2381                         act[p]->opt_flags |= AO_F_SWAP;
2382                         break;
2383
2384                 case 't':
2385                         /*
2386                          * Check sar option -t here (as it can be combined
2387                          * with other ones, eg. "sar -rtu ..."
2388                          * But sadf option -t is checked in sadf.c as it won't
2389                          * be entered as a sar option after "--".
2390                          */
2391                         if (caller != C_SAR) {
2392                                 return 1;
2393                         }
2394                         *flags |= S_F_TRUE_TIME;
2395                         break;
2396
2397                 case 'u':
2398                         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2399                         act[p]->options |= AO_SELECTED;
2400                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
2401                                 (*opt)++;
2402                                 act[p]->opt_flags = AO_F_CPU_ALL;
2403                                 return 0;
2404                         }
2405                         else {
2406                                 act[p]->opt_flags = AO_F_CPU_DEF;
2407                         }
2408                         break;
2409
2410                 case 'v':
2411                         SELECT_ACTIVITY(A_KTABLES);
2412                         break;
2413
2414                 case 'w':
2415                         SELECT_ACTIVITY(A_PCSW);
2416                         break;
2417
2418                 case 'W':
2419                         SELECT_ACTIVITY(A_SWAP);
2420                         break;
2421
2422                 case 'y':
2423                         SELECT_ACTIVITY(A_SERIAL);
2424                         break;
2425
2426                 case 'z':
2427                         *flags |= S_F_ZERO_OMIT;
2428                         break;
2429
2430                 case 'V':
2431                         print_version();
2432                         break;
2433
2434                 default:
2435                         return 1;
2436                 }
2437         }
2438         return 0;
2439 }
2440
2441 /*
2442  ***************************************************************************
2443  * Parse sar "-m" option.
2444  *
2445  * IN:
2446  * @argv        Arguments list.
2447  * @opt         Index in list of arguments.
2448  *
2449  * OUT:
2450  * @act         Array of selected activities.
2451  *
2452  * RETURNS:
2453  * 0 on success, 1 otherwise.
2454  ***************************************************************************
2455  */
2456 int parse_sar_m_opt(char *argv[], int *opt, struct activity *act[])
2457 {
2458         char *t;
2459
2460         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2461                 if (!strcmp(t, K_CPU)) {
2462                         SELECT_ACTIVITY(A_PWR_CPU);
2463                 }
2464                 else if (!strcmp(t, K_FAN)) {
2465                         SELECT_ACTIVITY(A_PWR_FAN);
2466                 }
2467                 else if (!strcmp(t, K_IN)) {
2468                         SELECT_ACTIVITY(A_PWR_IN);
2469                 }
2470                 else if (!strcmp(t, K_TEMP)) {
2471                         SELECT_ACTIVITY(A_PWR_TEMP);
2472                 }
2473                 else if (!strcmp(t, K_FREQ)) {
2474                         SELECT_ACTIVITY(A_PWR_FREQ);
2475                 }
2476                 else if (!strcmp(t, K_USB)) {
2477                         SELECT_ACTIVITY(A_PWR_USB);
2478                 }
2479                 else if (!strcmp(t, K_ALL)) {
2480                         SELECT_ACTIVITY(A_PWR_CPU);
2481                         SELECT_ACTIVITY(A_PWR_FAN);
2482                         SELECT_ACTIVITY(A_PWR_IN);
2483                         SELECT_ACTIVITY(A_PWR_TEMP);
2484                         SELECT_ACTIVITY(A_PWR_FREQ);
2485                         SELECT_ACTIVITY(A_PWR_USB);
2486                 }
2487                 else
2488                         return 1;
2489         }
2490
2491         (*opt)++;
2492         return 0;
2493 }
2494
2495 /*
2496  ***************************************************************************
2497  * Parse sar "-n" option.
2498  *
2499  * IN:
2500  * @argv        Arguments list.
2501  * @opt         Index in list of arguments.
2502  *
2503  * OUT:
2504  * @act         Array of selected activities.
2505  *
2506  * RETURNS:
2507  * 0 on success, 1 otherwise.
2508  ***************************************************************************
2509  */
2510 int parse_sar_n_opt(char *argv[], int *opt, struct activity *act[])
2511 {
2512         char *t;
2513
2514         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2515                 if (!strcmp(t, K_DEV)) {
2516                         SELECT_ACTIVITY(A_NET_DEV);
2517                 }
2518                 else if (!strcmp(t, K_EDEV)) {
2519                         SELECT_ACTIVITY(A_NET_EDEV);
2520                 }
2521                 else if (!strcmp(t, K_SOCK)) {
2522                         SELECT_ACTIVITY(A_NET_SOCK);
2523                 }
2524                 else if (!strcmp(t, K_NFS)) {
2525                         SELECT_ACTIVITY(A_NET_NFS);
2526                 }
2527                 else if (!strcmp(t, K_NFSD)) {
2528                         SELECT_ACTIVITY(A_NET_NFSD);
2529                 }
2530                 else if (!strcmp(t, K_IP)) {
2531                         SELECT_ACTIVITY(A_NET_IP);
2532                 }
2533                 else if (!strcmp(t, K_EIP)) {
2534                         SELECT_ACTIVITY(A_NET_EIP);
2535                 }
2536                 else if (!strcmp(t, K_ICMP)) {
2537                         SELECT_ACTIVITY(A_NET_ICMP);
2538                 }
2539                 else if (!strcmp(t, K_EICMP)) {
2540                         SELECT_ACTIVITY(A_NET_EICMP);
2541                 }
2542                 else if (!strcmp(t, K_TCP)) {
2543                         SELECT_ACTIVITY(A_NET_TCP);
2544                 }
2545                 else if (!strcmp(t, K_ETCP)) {
2546                         SELECT_ACTIVITY(A_NET_ETCP);
2547                 }
2548                 else if (!strcmp(t, K_UDP)) {
2549                         SELECT_ACTIVITY(A_NET_UDP);
2550                 }
2551                 else if (!strcmp(t, K_SOCK6)) {
2552                         SELECT_ACTIVITY(A_NET_SOCK6);
2553                 }
2554                 else if (!strcmp(t, K_IP6)) {
2555                         SELECT_ACTIVITY(A_NET_IP6);
2556                 }
2557                 else if (!strcmp(t, K_EIP6)) {
2558                         SELECT_ACTIVITY(A_NET_EIP6);
2559                 }
2560                 else if (!strcmp(t, K_ICMP6)) {
2561                         SELECT_ACTIVITY(A_NET_ICMP6);
2562                 }
2563                 else if (!strcmp(t, K_EICMP6)) {
2564                         SELECT_ACTIVITY(A_NET_EICMP6);
2565                 }
2566                 else if (!strcmp(t, K_UDP6)) {
2567                         SELECT_ACTIVITY(A_NET_UDP6);
2568                 }
2569                 else if (!strcmp(t, K_FC)) {
2570                         SELECT_ACTIVITY(A_NET_FC);
2571                 }
2572                 else if (!strcmp(t, K_SOFT)) {
2573                         SELECT_ACTIVITY(A_NET_SOFT);
2574                 }
2575                 else if (!strcmp(t, K_ALL)) {
2576                         SELECT_ACTIVITY(A_NET_DEV);
2577                         SELECT_ACTIVITY(A_NET_EDEV);
2578                         SELECT_ACTIVITY(A_NET_SOCK);
2579                         SELECT_ACTIVITY(A_NET_NFS);
2580                         SELECT_ACTIVITY(A_NET_NFSD);
2581                         SELECT_ACTIVITY(A_NET_IP);
2582                         SELECT_ACTIVITY(A_NET_EIP);
2583                         SELECT_ACTIVITY(A_NET_ICMP);
2584                         SELECT_ACTIVITY(A_NET_EICMP);
2585                         SELECT_ACTIVITY(A_NET_TCP);
2586                         SELECT_ACTIVITY(A_NET_ETCP);
2587                         SELECT_ACTIVITY(A_NET_UDP);
2588                         SELECT_ACTIVITY(A_NET_SOCK6);
2589                         SELECT_ACTIVITY(A_NET_IP6);
2590                         SELECT_ACTIVITY(A_NET_EIP6);
2591                         SELECT_ACTIVITY(A_NET_ICMP6);
2592                         SELECT_ACTIVITY(A_NET_EICMP6);
2593                         SELECT_ACTIVITY(A_NET_UDP6);
2594                         SELECT_ACTIVITY(A_NET_FC);
2595                         SELECT_ACTIVITY(A_NET_SOFT);
2596                 }
2597                 else
2598                         return 1;
2599         }
2600
2601         (*opt)++;
2602         return 0;
2603 }
2604
2605 /*
2606  ***************************************************************************
2607  * Parse sar "-q" option.
2608  *
2609  * IN:
2610  * @argv        Arguments list.
2611  * @opt         Index in list of arguments.
2612  *
2613  * OUT:
2614  * @act         Array of selected activities.
2615  *
2616  * RETURNS:
2617  * 0 on success, 1 otherwise.
2618  ***************************************************************************
2619  */
2620 int parse_sar_q_opt(char *argv[], int *opt, struct activity *act[])
2621 {
2622         char *t;
2623
2624         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2625                 if (!strcmp(t, K_LOAD)) {
2626                         SELECT_ACTIVITY(A_QUEUE);
2627                 }
2628                 else if (!strcmp(t, K_PSI_CPU)) {
2629                         SELECT_ACTIVITY(A_PSI_CPU);
2630                 }
2631                 else if (!strcmp(t, K_PSI_IO)) {
2632                         SELECT_ACTIVITY(A_PSI_IO);
2633                 }
2634                 else if (!strcmp(t, K_PSI_MEM)) {
2635                         SELECT_ACTIVITY(A_PSI_MEM);
2636                 }
2637                 else if (!strcmp(t, K_PSI)) {
2638                         SELECT_ACTIVITY(A_PSI_CPU);
2639                         SELECT_ACTIVITY(A_PSI_IO);
2640                         SELECT_ACTIVITY(A_PSI_MEM);
2641                 }
2642                 else if (!strcmp(t, K_ALL)) {
2643                         SELECT_ACTIVITY(A_QUEUE);
2644                         SELECT_ACTIVITY(A_PSI_CPU);
2645                         SELECT_ACTIVITY(A_PSI_IO);
2646                         SELECT_ACTIVITY(A_PSI_MEM);
2647                 }
2648                 else
2649                         return 1;
2650         }
2651
2652         (*opt)++;
2653         return 0;
2654 }
2655
2656 /*
2657  ***************************************************************************
2658  * Parse sar and sadf "-P" option.
2659  *
2660  * IN:
2661  * @argv        Arguments list.
2662  * @opt         Index in list of arguments.
2663  * @act         Array of activities.
2664  *
2665  * OUT:
2666  * @flags       Common flags and system state.
2667  * @act         Array of activities, with CPUs selected.
2668  *
2669  * RETURNS:
2670  * 0 on success, 1 otherwise.
2671  ***************************************************************************
2672  */
2673 int parse_sa_P_opt(char *argv[], int *opt, uint64_t *flags, struct activity *act[])
2674 {
2675         int p;
2676
2677         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2678
2679         if (argv[++(*opt)]) {
2680                 if (parse_values(argv[*opt], act[p]->bitmap->b_array,
2681                              act[p]->bitmap->b_size, K_LOWERALL))
2682                         return 1;
2683                 (*opt)++;
2684                 *flags |= S_F_OPTION_P;
2685                 return 0;
2686         }
2687
2688         return 1;
2689 }
2690
2691 /*
2692  ***************************************************************************
2693  * If option -A has been used, force -P ALL only if corresponding
2694  * option has not been explicitly entered on the command line.
2695  *
2696  * IN:
2697  * @flags       Common flags and system state.
2698  *
2699  * OUT:
2700  * @act         Array of selected activities.
2701  ***************************************************************************
2702  */
2703 void set_bitmaps(struct activity *act[], uint64_t *flags)
2704 {
2705         int p;
2706
2707         if (!USE_OPTION_P(*flags)) {
2708                 /* Force -P ALL */
2709                 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2710                 memset(act[p]->bitmap->b_array, ~0,
2711                        BITMAP_SIZE(act[p]->bitmap->b_size));
2712         }
2713 }
2714
2715 /*
2716  ***************************************************************************
2717  * Parse devices entered on the command line and save them in activity's
2718  * list.
2719  *
2720  * IN:
2721  * @argv        Argument with list of devices.
2722  * @a           Activity for which devices are entered on the command line.
2723  * @max_len     Max length of a device name.
2724  * @opt         Index in list of arguments.
2725  * @pos         Position is string where is located the first device.
2726  * @max_val     If > 0 then ranges of values are allowed (e.g. 3-5,9-, etc.)
2727  *              Values are in range [0..@max_val].
2728  *
2729  * OUT:
2730  * @opt         Index on next argument.
2731  ***************************************************************************
2732  */
2733 void parse_sa_devices(char *argv, struct activity *a, int max_len, int *opt, int pos,
2734                       int max_val)
2735 {
2736         int i, val_low, val;
2737         char *t;
2738         char svalue[9];
2739
2740         for (t = strtok(argv + pos, ","); t; t = strtok(NULL, ",")) {
2741
2742                 /* Test ranges of values, if allowed */
2743                 if ((max_val > 0) && (strlen(t) <= 16) && (strspn(t, XDIGITS) == strlen(t))) {
2744                         if (parse_range_values(t, max_val, &val_low, &val) == 0) {
2745                                 /* This is a real range of values: Save each if its values */
2746                                 for (i = val_low; i <= val; i++) {
2747                                         snprintf(svalue, sizeof(svalue), "%d", i);
2748                                         svalue[sizeof(svalue) - 1] = '\0';
2749                                         a->item_list_sz += add_list_item(&(a->item_list), svalue, max_len);
2750                                 }
2751                                 continue;
2752                         }
2753                 }
2754                 a->item_list_sz += add_list_item(&(a->item_list), t, max_len);
2755         }
2756         if (a->item_list_sz) {
2757                 a->options |= AO_LIST_ON_CMDLINE;
2758         }
2759         (*opt)++;
2760 }
2761
2762 /*
2763  ***************************************************************************
2764  * Compute network interface utilization.
2765  *
2766  * IN:
2767  * @st_net_dev  Structure with network interface stats.
2768  * @rx          Number of bytes received per second.
2769  * @tx          Number of bytes transmitted per second.
2770  *
2771  * RETURNS:
2772  * NIC utilization (0-100%).
2773  ***************************************************************************
2774  */
2775 double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx)
2776 {
2777         unsigned long long speed;
2778
2779         if (st_net_dev->speed) {
2780
2781                 speed = (unsigned long long) st_net_dev->speed * 1000000;
2782
2783                 if (st_net_dev->duplex == C_DUPLEX_FULL) {
2784                         /* Full duplex */
2785                         if (rx > tx) {
2786                                 return (rx * 800 / speed);
2787                         }
2788                         else {
2789                                 return (tx * 800 / speed);
2790                         }
2791                 }
2792                 else {
2793                         /* Half duplex */
2794                         return ((rx + tx) * 800 / speed);
2795                 }
2796         }
2797
2798         return 0;
2799 }
2800
2801 /*
2802  ***************************************************************************
2803  * Read and replace unprintable characters in comment with ".".
2804  *
2805  * IN:
2806  * @ifd         Input file descriptor.
2807  * @comment     Comment.
2808  ***************************************************************************
2809  */
2810 void replace_nonprintable_char(int ifd, char *comment)
2811 {
2812         int i;
2813
2814         /* Read comment */
2815         sa_fread(ifd, comment, MAX_COMMENT_LEN, HARD_SIZE, UEOF_STOP);
2816         comment[MAX_COMMENT_LEN - 1] = '\0';
2817
2818         /* Replace non printable chars */
2819         for (i = 0; i < strlen(comment); i++) {
2820                 if (!isprint(comment[i]))
2821                         comment[i] = '.';
2822         }
2823 }
2824
2825 /*
2826  ***************************************************************************
2827  * Fill the rectime and loctime structures with current record's date and
2828  * time, based on current record's "number of seconds since the epoch" saved
2829  * in file.
2830  * For loctime (if given): The timestamp is expressed in local time.
2831  * For rectime: The timestamp is expressed in UTC, in local time, or in the
2832  * time of the file's creator depending on options entered by the user on the
2833  * command line.
2834  *
2835  * IN:
2836  * @l_flags     Flags indicating the type of time expected by the user.
2837  *              S_F_LOCAL_TIME means time should be expressed in local time.
2838  *              S_F_TRUE_TIME means time should be expressed in time of
2839  *              file's creator.
2840  *              Default is time expressed in UTC (except for sar, where it
2841  *              is local time).
2842  * @record_hdr  Record header containing the number of seconds since the
2843  *              epoch, and the HH:MM:SS of the file's creator.
2844  *
2845  * OUT:
2846  * @rectime     Structure where timestamp for current record has been saved
2847  *              (in local time, in UTC or in time of file's creator
2848  *              depending on options used).
2849  *
2850  * RETURNS:
2851  * 1 if an error was detected, or 0 otherwise.
2852  ***************************************************************************
2853 */
2854 int sa_get_record_timestamp_struct(uint64_t l_flags, struct record_header *record_hdr,
2855                                    struct tm *rectime)
2856 {
2857         struct tm *ltm;
2858         time_t t = record_hdr->ust_time;
2859         int rc = 0;
2860
2861         /*
2862          * Fill generic rectime structure in local time.
2863          * Done so that we have some default values.
2864          */
2865         ltm = localtime_r(&t, rectime);
2866
2867         if (!PRINT_LOCAL_TIME(l_flags) && !PRINT_TRUE_TIME(l_flags)) {
2868                 /*
2869                  * Get time in UTC
2870                  * (the user doesn't want local time nor time of file's creator).
2871                  */
2872                 ltm = gmtime_r(&t, rectime);
2873         }
2874
2875         if (!ltm) {
2876                 rc = 1;
2877         }
2878
2879         if (PRINT_TRUE_TIME(l_flags)) {
2880                 /* Time of file's creator */
2881                 rectime->tm_hour = record_hdr->hour;
2882                 rectime->tm_min  = record_hdr->minute;
2883                 rectime->tm_sec  = record_hdr->second;
2884         }
2885
2886         return rc;
2887 }
2888
2889 /*
2890  ***************************************************************************
2891  * Set current record's timestamp strings (date and time) using the time
2892  * data saved in @rectime structure. The string may be the number of seconds
2893  * since the epoch if flag S_F_SEC_EPOCH has been set.
2894  *
2895  * IN:
2896  * @l_flags     Flags indicating the type of time expected by the user.
2897  *              S_F_SEC_EPOCH means the time should be expressed in seconds
2898  *              since the epoch (01/01/1970).
2899  * @record_hdr  Record header containing the number of seconds since the
2900  *              epoch.
2901  * @cur_date    String where timestamp's date will be saved. May be NULL.
2902  * @cur_time    String where timestamp's time will be saved.
2903  * @len         Maximum length of timestamp strings.
2904  * @rectime     Structure with current timestamp (expressed in local time or
2905  *              in UTC depending on whether options -T or -t have been used
2906  *              or not) that should be broken down in date and time strings.
2907  *
2908  * OUT:
2909  * @cur_date    Timestamp's date string (if expected).
2910  * @cur_time    Timestamp's time string. May contain the number of seconds
2911  *              since the epoch (01-01-1970) if corresponding option has
2912  *              been used.
2913  ***************************************************************************
2914 */
2915 void set_record_timestamp_string(uint64_t l_flags, struct record_header *record_hdr,
2916                                  char *cur_date, char *cur_time, int len, struct tm *rectime)
2917 {
2918         /* Set cur_time date value */
2919         if (PRINT_SEC_EPOCH(l_flags) && cur_date) {
2920                 sprintf(cur_time, "%llu", record_hdr->ust_time);
2921                 strcpy(cur_date, "");
2922         }
2923         else {
2924                 /*
2925                  * If options -T or -t have been used then cur_time is
2926                  * expressed in local time. Else it is expressed in UTC.
2927                  */
2928                 if (cur_date) {
2929                         strftime(cur_date, len, "%Y-%m-%d", rectime);
2930                 }
2931                 if (USE_PREFD_TIME_OUTPUT(l_flags)) {
2932                         strftime(cur_time, len, "%X", rectime);
2933                 }
2934                 else {
2935                         strftime(cur_time, len, "%H:%M:%S", rectime);
2936                 }
2937         }
2938 }
2939
2940 /*
2941  ***************************************************************************
2942  * Print contents of a special (RESTART or COMMENT) record.
2943  * Note: This function is called only when reading a file.
2944  *
2945  * IN:
2946  * @record_hdr  Current record header.
2947  * @l_flags     Flags for common options.
2948  * @tm_start    Structure filled when option -s has been used.
2949  * @tm_end      Structure filled when option -e has been used.
2950  * @rtype       Record type (R_RESTART or R_COMMENT).
2951  * @ifd         Input file descriptor.
2952  * @rectime     Structure where timestamp (expressed in local time or in UTC
2953  *              depending on whether options -T/-t have been used or not) can
2954  *              be saved for current record.
2955  * @file        Name of file being read.
2956  * @tab         Number of tabulations to print.
2957  * @my_tz       Current timezone.
2958  * @file_magic  file_magic structure filled with file magic header data.
2959  * @file_hdr    System activity file standard header.
2960  * @act         Array of activities.
2961  * @ofmt        Pointer on report output format structure.
2962  * @endian_mismatch
2963  *              TRUE if file's data don't match current machine's endianness.
2964  * @arch_64     TRUE if file's data come from a 64 bit machine.
2965  *
2966  * OUT:
2967  * @rectime     Structure where timestamp (expressed in local time or in UTC)
2968  *              has been saved.
2969  *
2970  * RETURNS:
2971  * 1 if the record has been successfully displayed, and 0 otherwise.
2972  ***************************************************************************
2973  */
2974 int print_special_record(struct record_header *record_hdr, uint64_t l_flags,
2975                          struct tstamp *tm_start, struct tstamp *tm_end, int rtype, int ifd,
2976                          struct tm *rectime, char *file, int tab, char *my_tz,
2977                          struct file_magic *file_magic, struct file_header *file_hdr,
2978                          struct activity *act[], struct report_format *ofmt,
2979                          int endian_mismatch, int arch_64)
2980 {
2981         char cur_date[TIMESTAMP_LEN], cur_time[TIMESTAMP_LEN];
2982         int dp = 1;
2983         int p;
2984
2985         /* Fill timestamp structure (rectime) for current record */
2986         if (sa_get_record_timestamp_struct(l_flags, record_hdr, rectime))
2987                 return 0;
2988
2989         /* The record must be in the interval specified by -s/-e options */
2990         if ((tm_start->use && (datecmp(rectime, tm_start, FALSE) < 0)) ||
2991             (tm_end->use && (datecmp(rectime, tm_end, FALSE) > 0))) {
2992                 /* Will not display the special record */
2993                 dp = 0;
2994         }
2995         else {
2996                 /* Set date and time strings to be displayed for current record */
2997                 set_record_timestamp_string(l_flags, record_hdr,
2998                                             cur_date, cur_time, TIMESTAMP_LEN, rectime);
2999         }
3000
3001         if (rtype == R_RESTART) {
3002                 /* Read new cpu number following RESTART record */
3003                 file_hdr->sa_cpu_nr = read_nr_value(ifd, file, file_magic,
3004                                                     endian_mismatch, arch_64, TRUE);
3005
3006                 /*
3007                  * We don't know if CPU related activities will be displayed or not.
3008                  * But if it is the case, @nr_ini will be used in the loop
3009                  * to process all CPUs. So update their value here and
3010                  * reallocate buffers if needed.
3011                  * NB: We may have nr_allocated=0 here if the activity has
3012                  * not been collected in file (or if it has an unknown format).
3013                  */
3014                 for (p = 0; p < NR_ACT; p++) {
3015                         if (HAS_PERSISTENT_VALUES(act[p]->options) && (act[p]->nr_ini > 0)) {
3016                                 act[p]->nr_ini = file_hdr->sa_cpu_nr;
3017                                 if (act[p]->nr_ini > act[p]->nr_allocated) {
3018                                         reallocate_all_buffers(act[p], act[p]->nr_ini);
3019                                 }
3020                         }
3021                 }
3022
3023                 /* Ignore unknown extra structures if present */
3024                 if (record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
3025                         return 0;
3026
3027                 if (!dp)
3028                         return 0;
3029
3030                 if (*ofmt->f_restart) {
3031                         (*ofmt->f_restart)(&tab, F_MAIN, cur_date, cur_time, my_tz, file_hdr, record_hdr);
3032                 }
3033         }
3034         else if (rtype == R_COMMENT) {
3035                 char file_comment[MAX_COMMENT_LEN];
3036
3037                 /* Read and replace non printable chars in comment */
3038                 replace_nonprintable_char(ifd, file_comment);
3039
3040                 /* Ignore unknown extra structures if present */
3041                 if (record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
3042                         return 0;
3043
3044                 if (!dp || !DISPLAY_COMMENT(l_flags))
3045                         return 0;
3046
3047                 if (*ofmt->f_comment) {
3048                         (*ofmt->f_comment)(&tab, F_MAIN, cur_date, cur_time, my_tz,
3049                                            file_comment, file_hdr, record_hdr);
3050                 }
3051         }
3052
3053         return 1;
3054 }
3055
3056 /*
3057  ***************************************************************************
3058  * Compute global CPU statistics as the sum of individual CPU ones, and
3059  * calculate interval for global CPU.
3060  * Also identify offline CPU.
3061  *
3062  * IN:
3063  * @a           Activity structure with statistics.
3064  * @prev        Index in array where stats used as reference are.
3065  * @curr        Index in array for current sample statistics.
3066  * @flags       Flags for common options and system state.
3067  * @offline_cpu_bitmap
3068  *              CPU bitmap for offline CPU.
3069  *
3070  * OUT:
3071  * @a           Activity structure with updated statistics (those for global
3072  *              CPU, and also those for offline CPU).
3073  * @offline_cpu_bitmap
3074  *              CPU bitmap with offline CPU.
3075  *
3076  * RETURNS:
3077  * Interval for global CPU.
3078  ***************************************************************************
3079  */
3080 unsigned long long get_global_cpu_statistics(struct activity *a, int prev, int curr,
3081                                              uint64_t flags, unsigned char offline_cpu_bitmap[])
3082 {
3083         int i;
3084         unsigned long long tot_jiffies_c, tot_jiffies_p;
3085         unsigned long long deltot_jiffies = 0;
3086         struct stats_cpu *scc, *scp;
3087         struct stats_cpu *scc_all = (struct stats_cpu *) ((char *) a->buf[curr]);
3088         struct stats_cpu *scp_all = (struct stats_cpu *) ((char *) a->buf[prev]);
3089
3090         /*
3091          * Initial processing.
3092          * Compute CPU "all" as sum of all individual CPU. Done only on SMP machines (a->nr_ini > 1).
3093          * For UP machines we keep the values read from global CPU line in /proc/stat.
3094          * Also look for offline CPU: They won't be displayed, and some of their values may
3095          * have to be modified.
3096          */
3097         if (a->nr_ini > 1) {
3098                 memset(scc_all, 0, sizeof(struct stats_cpu));
3099                 memset(scp_all, 0, sizeof(struct stats_cpu));
3100         }
3101
3102         for (i = 1; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
3103
3104                 /*
3105                  * The size of a->buf[...] CPU structure may be different from the default
3106                  * sizeof(struct stats_cpu) value if data have been read from a file!
3107                  * That's why we don't use a syntax like:
3108                  * scc = (struct stats_cpu *) a->buf[...] + i;
3109                  */
3110                 scc = (struct stats_cpu *) ((char *) a->buf[curr] + i * a->msize);
3111                 scp = (struct stats_cpu *) ((char *) a->buf[prev] + i * a->msize);
3112
3113                 /*
3114                  * Compute the total number of jiffies spent by current processor.
3115                  * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
3116                  * already include them.
3117                  */
3118                 tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
3119                                 scc->cpu_sys + scc->cpu_idle +
3120                                 scc->cpu_iowait + scc->cpu_hardirq +
3121                                 scc->cpu_steal + scc->cpu_softirq;
3122                 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
3123                                 scp->cpu_sys + scp->cpu_idle +
3124                                 scp->cpu_iowait + scp->cpu_hardirq +
3125                                 scp->cpu_steal + scp->cpu_softirq;
3126
3127                 /*
3128                  * If the CPU is offline then it is omited from /proc/stat:
3129                  * All the fields couldn't have been read and the sum of them is zero.
3130                  */
3131                 if (tot_jiffies_c == 0) {
3132                         /*
3133                          * CPU is currently offline.
3134                          * Set current struct fields (which have been set to zero)
3135                          * to values from previous iteration. Hence their values won't
3136                          * jump from zero when the CPU comes back online.
3137                          * Note that this workaround no longer fully applies with recent kernels,
3138                          * as I have noticed that when a CPU comes back online, some fields
3139                          * restart from their previous value (e.g. user, nice, system)
3140                          * whereas others restart from zero (idle, iowait)! To deal with this,
3141                          * the get_per_cpu_interval() function will set these previous values
3142                          * to zero if necessary.
3143                          */
3144                         *scc = *scp;
3145
3146                         /*
3147                          * Mark CPU as offline to not display it
3148                          * (and thus it will not be confused with a tickless CPU).
3149                          */
3150                         offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3151                 }
3152
3153                 if ((tot_jiffies_p == 0) && !WANT_SINCE_BOOT(flags)) {
3154                         /*
3155                          * CPU has just come back online.
3156                          * Unfortunately, no reference values are available
3157                          * from a previous iteration, probably because it was
3158                          * already offline when the first sample has been taken.
3159                          * So don't display that CPU to prevent "jump-from-zero"
3160                          * output syndrome, and don't take it into account for CPU "all".
3161                          */
3162                         offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3163                         continue;
3164                 }
3165
3166                 /*
3167                  * Get interval for current CPU and add it to global CPU.
3168                  * Note: Previous idle and iowait values (saved in scp) may be modified here.
3169                  */
3170                 deltot_jiffies += get_per_cpu_interval(scc, scp);
3171
3172                 scc_all->cpu_user += scc->cpu_user;
3173                 scp_all->cpu_user += scp->cpu_user;
3174
3175                 scc_all->cpu_nice += scc->cpu_nice;
3176                 scp_all->cpu_nice += scp->cpu_nice;
3177
3178                 scc_all->cpu_sys += scc->cpu_sys;
3179                 scp_all->cpu_sys += scp->cpu_sys;
3180
3181                 scc_all->cpu_idle += scc->cpu_idle;
3182                 scp_all->cpu_idle += scp->cpu_idle;
3183
3184                 scc_all->cpu_iowait += scc->cpu_iowait;
3185                 scp_all->cpu_iowait += scp->cpu_iowait;
3186
3187                 scc_all->cpu_hardirq += scc->cpu_hardirq;
3188                 scp_all->cpu_hardirq += scp->cpu_hardirq;
3189
3190                 scc_all->cpu_steal += scc->cpu_steal;
3191                 scp_all->cpu_steal += scp->cpu_steal;
3192
3193                 scc_all->cpu_softirq += scc->cpu_softirq;
3194                 scp_all->cpu_softirq += scp->cpu_softirq;
3195
3196                 scc_all->cpu_guest += scc->cpu_guest;
3197                 scp_all->cpu_guest += scp->cpu_guest;
3198
3199                 scc_all->cpu_guest_nice += scc->cpu_guest_nice;
3200                 scp_all->cpu_guest_nice += scp->cpu_guest_nice;
3201         }
3202
3203         return deltot_jiffies;
3204 }
3205
3206 /*
3207  ***************************************************************************
3208  * Compute softnet statistics for CPU "all" as the sum of individual CPU
3209  * ones.
3210  * Also identify offline CPU.
3211  *
3212  * IN:
3213  * @a           Activity structure with statistics.
3214  * @prev        Index in array where stats used as reference are.
3215  * @curr        Index in array for current sample statistics.
3216  * @flags       Flags for common options and system state.
3217  * @offline_cpu_bitmap
3218  *              CPU bitmap for offline CPU.
3219  *
3220  * OUT:
3221  * @a           Activity structure with updated statistics (those for global
3222  *              CPU, and also those for offline CPU).
3223  * @offline_cpu_bitmap
3224  *              CPU bitmap with offline CPU.
3225  ***************************************************************************
3226  */
3227 void get_global_soft_statistics(struct activity *a, int prev, int curr,
3228                                 uint64_t flags, unsigned char offline_cpu_bitmap[])
3229 {
3230         int i;
3231         struct stats_softnet *ssnc, *ssnp;
3232         struct stats_softnet *ssnc_all = (struct stats_softnet *) ((char *) a->buf[curr]);
3233         struct stats_softnet *ssnp_all = (struct stats_softnet *) ((char *) a->buf[prev]);
3234
3235         /*
3236          * Init structures that will contain values for CPU "all".
3237          * CPU "all" doesn't exist in /proc/net/softnet_stat file, so
3238          * we compute its values as the sum of the values of each CPU.
3239          */
3240         memset(ssnc_all, 0, sizeof(struct stats_softnet));
3241         memset(ssnp_all, 0, sizeof(struct stats_softnet));
3242
3243         for (i = 1; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
3244
3245                 /*
3246                  * The size of a->buf[...] CPU structure may be different from the default
3247                  * sizeof(struct stats_softnet) value if data have been read from a file!
3248                  * That's why we don't use a syntax like:
3249                  * ssnc = (struct stats_softnet *) a->buf[...] + i;
3250                  */
3251                 ssnc = (struct stats_softnet *) ((char *) a->buf[curr] + i * a->msize);
3252                 ssnp = (struct stats_softnet *) ((char *) a->buf[prev] + i * a->msize);
3253
3254                 if ((ssnp->processed + ssnp->dropped + ssnp->time_squeeze +
3255                     ssnp->received_rps + ssnp->flow_limit + ssnp->backlog_len == 0) &&
3256                     !WANT_SINCE_BOOT(flags)) {
3257                         /*
3258                          * No previous sample for current CPU: Don't display it unless
3259                          * we want stats since last boot time.
3260                          * (CPU may be online but we don't display it because all
3261                          * its counters would appear to jump from zero...)
3262                          */
3263                         offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3264                         continue;
3265                 }
3266
3267                 if (ssnc->processed + ssnc->dropped + ssnc->time_squeeze +
3268                     ssnc->received_rps + ssnc->flow_limit + ssnc->backlog_len == 0) {
3269                         /* Assume current CPU is offline */
3270                         *ssnc = *ssnp;
3271                         offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3272                 }
3273
3274                 ssnc_all->processed += ssnc->processed;
3275                 ssnc_all->dropped += ssnc->dropped;
3276                 ssnc_all->time_squeeze += ssnc->time_squeeze;
3277                 ssnc_all->received_rps += ssnc->received_rps;
3278                 ssnc_all->flow_limit += ssnc->flow_limit;
3279                 ssnc_all->backlog_len += ssnc->backlog_len;
3280
3281                 ssnp_all->processed += ssnp->processed;
3282                 ssnp_all->dropped += ssnp->dropped;
3283                 ssnp_all->time_squeeze += ssnp->time_squeeze;
3284                 ssnp_all->received_rps += ssnp->received_rps;
3285                 ssnp_all->flow_limit += ssnp->flow_limit;
3286                 ssnp_all->backlog_len += ssnp->backlog_len;
3287         }
3288 }
3289
3290 /*
3291  ***************************************************************************
3292  * Identify offline CPU (those for which all interrupts are 0) and keep
3293  * interrupts statistics (their values are persistent). Include also CPU
3294  * which have not been selected (this is necessary so that the header of the
3295  * interrupts statistics report can be displayed).
3296  *
3297  * IN:
3298  * @a           Activity structure with statistics.
3299  * @prev        Index in array where stats used as reference are.
3300  * @curr        Index in array for current sample statistics.
3301  * @flags       Flags for common options and system state.
3302  * @masked_cpu_bitmap
3303  *              CPU bitmap for offline and unselected CPU.
3304  *
3305  * OUT:
3306  * @a           Activity structure with updated statistics (those for global
3307  *              CPU, and also those for offline CPU).
3308  * @masked_cpu_bitmap
3309  *              CPU bitmap with offline and unselected CPU.
3310  ***************************************************************************
3311  */
3312 void get_global_int_statistics(struct activity *a, int prev, int curr,
3313                                uint64_t flags, unsigned char masked_cpu_bitmap[])
3314 {
3315         int i;
3316         struct stats_irq *stc_cpu_sum, *stp_cpu_sum;
3317
3318         for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
3319
3320                 /*
3321                  * The size of a->buf[...] CPU structure may be different from the default
3322                  * sizeof(struct stats_irq) value if data have been read from a file!
3323                  * That's why we don't use a syntax like:
3324                  * stc_cpu_sum = (struct stats_irq *) a->buf[...] + i;
3325                  */
3326                 stc_cpu_sum = (struct stats_irq *) ((char *) a->buf[curr] + i * a->msize * a->nr2);
3327                 stp_cpu_sum = (struct stats_irq *) ((char *) a->buf[prev] + i * a->msize * a->nr2);
3328
3329                 /*
3330                  * Check if current CPU is back online but with no previous sample for it,
3331                  * or if it has not been selected.
3332                  */
3333                 if (((stp_cpu_sum->irq_nr == 0) && !WANT_SINCE_BOOT(flags)) ||
3334                     (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))) {
3335                         /* CPU should not be displayed */
3336                         masked_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3337                         continue;
3338                 }
3339
3340                 if (stc_cpu_sum->irq_nr == 0) {
3341                         /* Assume current CPU is offline */
3342                         masked_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3343                         memcpy(stc_cpu_sum, stp_cpu_sum, (size_t) a->msize * a->nr2);
3344                 }
3345
3346         }
3347 }
3348
3349 /*
3350  ***************************************************************************
3351  * Get filesystem name to display. This may be either the persistent name
3352  * if requested by the user, the standard filesystem name (e.g. /dev/sda1,
3353  * /dev/sdb3, etc.) or the mount point. This is used when displaying
3354  * filesystem statistics: sar -F or sadf -- -F).
3355  *
3356  * IN:
3357  * @a           Activity structure.
3358  * @flags       Flags for common options and system state.
3359  * @st_fs       Statistics for current filesystem.
3360  *
3361  * RETURNS:
3362  * Filesystem name to display.
3363  ***************************************************************************
3364  */
3365 char *get_fs_name_to_display(struct activity *a, uint64_t flags, struct stats_filesystem *st_fs)
3366 {
3367         char *pname = NULL, *persist_dev_name;
3368         char fname[MAX_FS_LEN];
3369
3370         if (DISPLAY_PERSIST_NAME_S(flags) && !DISPLAY_MOUNT(a->opt_flags)) {
3371                 strncpy(fname, st_fs->fs_name, sizeof(fname));
3372                 fname[sizeof(fname) - 1] = '\0';
3373                 if ((persist_dev_name = get_persistent_name_from_pretty(basename(fname))) != NULL) {
3374                         pname = persist_dev_name;
3375                 }
3376         }
3377         if (!pname) {
3378                 pname = DISPLAY_MOUNT(a->opt_flags) ? st_fs->mountp : st_fs->fs_name;
3379         }
3380         return pname;
3381 }
3382 #endif /* SOURCE_SADC undefined */