]> granicus.if.org Git - sysstat/blob - sa_common.c
Use TIMESTAMP_LEN constant for timestamp buffers
[sysstat] / sa_common.c
1 /*
2  * sar and sadf common routines.
3  * (C) 1999-2016 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 <time.h>
26 #include <errno.h>
27 #include <unistd.h>     /* For STDOUT_FILENO, among others */
28 #include <dirent.h>
29 #include <fcntl.h>
30 #include <libgen.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <ctype.h>
34
35 #include "version.h"
36 #include "sa.h"
37 #include "common.h"
38 #include "ioconf.h"
39 #include "rd_stats.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
52 /*
53  ***************************************************************************
54  * Init a bitmap (CPU, IRQ, etc.).
55  *
56  * IN:
57  * @value       Value used to init bitmap.
58  * @sz          Size of the bitmap in bytes.
59  *
60  * OUT:
61  * @bitmap      Bitmap initialized.
62  ***************************************************************************
63  */
64 void set_bitmap(unsigned char bitmap[], unsigned char value, unsigned int sz)
65 {
66         register int i;
67
68         for (i = 0; i < sz; i++) {
69                 bitmap[i] = value;
70         }
71 }
72
73 /*
74  ***************************************************************************
75  * Allocate structures.
76  *
77  * IN:
78  * @act Array of activities.
79  ***************************************************************************
80  */
81 void allocate_structures(struct activity *act[])
82 {
83         int i, j;
84
85         for (i = 0; i < NR_ACT; i++) {
86                 if (act[i]->nr > 0) {
87                         for (j = 0; j < 3; j++) {
88                                 SREALLOC(act[i]->buf[j], void,
89                                                 (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
90                         }
91                 }
92         }
93 }
94
95 /*
96  ***************************************************************************
97  * Free structures.
98  *
99  * IN:
100  * @act Array of activities.
101  ***************************************************************************
102  */
103 void free_structures(struct activity *act[])
104 {
105         int i, j;
106
107         for (i = 0; i < NR_ACT; i++) {
108                 if (act[i]->nr > 0) {
109                         for (j = 0; j < 3; j++) {
110                                 if (act[i]->buf[j]) {
111                                         free(act[i]->buf[j]);
112                                         act[i]->buf[j] = NULL;
113                                 }
114                         }
115                 }
116         }
117 }
118
119 /*
120   ***************************************************************************
121   * Try to get device real name from sysfs tree.
122   *
123   * IN:
124   * @major      Major number of the device.
125   * @minor      Minor number of the device.
126   *
127   * RETURNS:
128   * The name of the device, which may be the real name (as it appears in /dev)
129   * or NULL.
130   ***************************************************************************
131   */
132 char *get_devname_from_sysfs(unsigned int major, unsigned int minor)
133 {
134         static char link[32], target[PATH_MAX];
135         char *devname;
136         ssize_t r;
137
138         snprintf(link, 32, "%s/%u:%u", SYSFS_DEV_BLOCK, major, minor);
139
140         /* Get full path to device knowing its major and minor numbers */
141         r = readlink(link, target, PATH_MAX);
142         if (r <= 0 || r >= PATH_MAX) {
143                 return (NULL);
144         }
145
146         target[r] = '\0';
147
148         /* Get device name */
149         devname = basename(target);
150         if (!devname || strnlen(devname, FILENAME_MAX) == 0) {
151                 return (NULL);
152         }
153
154         return (devname);
155 }
156
157 /*
158  ***************************************************************************
159  * Get device real name if possible.
160  * Warning: This routine may return a bad name on 2.4 kernels where
161  * disk activities are read from /proc/stat.
162  *
163  * IN:
164  * @major       Major number of the device.
165  * @minor       Minor number of the device.
166  * @pretty      TRUE if the real name of the device (as it appears in /dev)
167  *              should be returned.
168  *
169  * RETURNS:
170  * The name of the device, which may be the real name (as it appears in /dev)
171  * or a string with the following format devM-n.
172  ***************************************************************************
173  */
174 char *get_devname(unsigned int major, unsigned int minor, int pretty)
175 {
176         static char buf[32];
177         char *name;
178
179         snprintf(buf, 32, "dev%u-%u", major, minor);
180
181         if (!pretty)
182                 return (buf);
183
184         name = get_devname_from_sysfs(major, minor);
185         if (name != NULL)
186                 return (name);
187
188         name = ioc_name(major, minor);
189         if ((name != NULL) && strcmp(name, K_NODEV))
190                 return (name);
191
192         return (buf);
193 }
194
195 /*
196  ***************************************************************************
197  * Check if we are close enough to desired interval.
198  *
199  * IN:
200  * @uptime_ref  Uptime used as reference. This is the system uptime for the
201  *              first sample statistics, or the first system uptime after a
202  *              LINUX RESTART.
203  * @uptime      Current system uptime.
204  * @reset       TRUE if @last_uptime should be reset with @uptime_ref.
205  * @interval    Interval of time.
206  *
207  * RETURNS:
208  * 1 if we are actually close enough to desired interval, 0 otherwise.
209  ***************************************************************************
210 */
211 int next_slice(unsigned long long uptime_ref, unsigned long long uptime,
212                int reset, long interval)
213 {
214         unsigned long file_interval, entry;
215         static unsigned long long last_uptime = 0;
216         int min, max, pt1, pt2;
217         double f;
218
219         /* uptime is expressed in jiffies (basis of 1 processor) */
220         if (!last_uptime || reset) {
221                 last_uptime = uptime_ref;
222         }
223
224         /* Interval cannot be greater than 0xffffffff here */
225         f = ((double) ((uptime - last_uptime) & 0xffffffff)) / HZ;
226         file_interval = (unsigned long) f;
227         if ((f * 10) - (file_interval * 10) >= 5) {
228                 file_interval++; /* Rounding to correct value */
229         }
230
231         last_uptime = uptime;
232
233         /*
234          * A few notes about the "algorithm" used here to display selected entries
235          * from the system activity file (option -f with -i flag):
236          * Let 'Iu' be the interval value given by the user on the command line,
237          *     'If' the interval between current and previous line in the system
238          * activity file,
239          * and 'En' the nth entry (identified by its time stamp) of the file.
240          * We choose In = [ En - If/2, En + If/2 [ if If is even,
241          *        or In = [ En - If/2, En + If/2 ] if not.
242          * En will be displayed if
243          *       (Pn * Iu) or (P'n * Iu) belongs to In
244          * with  Pn = En / Iu and P'n = En / Iu + 1
245          */
246         f = ((double) ((uptime - uptime_ref) & 0xffffffff)) / HZ;
247         entry = (unsigned long) f;
248         if ((f * 10) - (entry * 10) >= 5) {
249                 entry++;
250         }
251
252         min = entry - (file_interval / 2);
253         max = entry + (file_interval / 2) + (file_interval & 0x1);
254         pt1 = (entry / interval) * interval;
255         pt2 = ((entry / interval) + 1) * interval;
256
257         return (((pt1 >= min) && (pt1 < max)) || ((pt2 >= min) && (pt2 < max)));
258 }
259
260 /*
261  ***************************************************************************
262  * Use time stamp to fill tstamp structure.
263  *
264  * IN:
265  * @timestamp   Timestamp to decode (format: HH:MM:SS).
266  *
267  * OUT:
268  * @tse         Structure containing the decoded timestamp.
269  *
270  * RETURNS:
271  * 0 if the timestamp has been successfully decoded, 1 otherwise.
272  ***************************************************************************
273  */
274 int decode_timestamp(char timestamp[], struct tstamp *tse)
275 {
276         timestamp[2] = timestamp[5] = '\0';
277         tse->tm_sec  = atoi(&timestamp[6]);
278         tse->tm_min  = atoi(&timestamp[3]);
279         tse->tm_hour = atoi(timestamp);
280
281         if ((tse->tm_sec < 0) || (tse->tm_sec > 59) ||
282             (tse->tm_min < 0) || (tse->tm_min > 59) ||
283             (tse->tm_hour < 0) || (tse->tm_hour > 23))
284                 return 1;
285
286         tse->use = TRUE;
287
288         return 0;
289 }
290
291 /*
292  ***************************************************************************
293  * Compare two timestamps.
294  *
295  * IN:
296  * @rectime     Date and time for current sample.
297  * @tse         Timestamp used as reference.
298  *
299  * RETURNS:
300  * A positive value if @rectime is greater than @tse,
301  * a negative one otherwise.
302  ***************************************************************************
303  */
304 int datecmp(struct tm *rectime, struct tstamp *tse)
305 {
306         if (rectime->tm_hour == tse->tm_hour) {
307                 if (rectime->tm_min == tse->tm_min)
308                         return (rectime->tm_sec - tse->tm_sec);
309                 else
310                         return (rectime->tm_min - tse->tm_min);
311         }
312         else
313                 return (rectime->tm_hour - tse->tm_hour);
314 }
315
316 /*
317  ***************************************************************************
318  * Parse a timestamp entered on the command line (hh:mm[:ss]) and decode it.
319  *
320  * IN:
321  * @argv                Arguments list.
322  * @opt                 Index in the arguments list.
323  * @def_timestamp       Default timestamp to use.
324  *
325  * OUT:
326  * @tse                 Structure containing the decoded timestamp.
327  *
328  * RETURNS:
329  * 0 if the timestamp has been successfully decoded, 1 otherwise.
330  ***************************************************************************
331  */
332 int parse_timestamp(char *argv[], int *opt, struct tstamp *tse,
333                     const char *def_timestamp)
334 {
335         char timestamp[9];
336
337         if (argv[++(*opt)]) {
338                 switch (strlen(argv[*opt])) {
339
340                         case 5:
341                                 strncpy(timestamp, argv[(*opt)++], 5);
342                                 strcat(timestamp,":00");
343                                 break;
344
345                         case 8:
346                                 strncpy(timestamp, argv[(*opt)++], 8);
347                                 break;
348
349                         default:
350                                 strncpy(timestamp, def_timestamp, 8);
351                                 break;
352                 }
353         } else {
354                 strncpy(timestamp, def_timestamp, 8);
355         }
356         timestamp[8] = '\0';
357
358         return decode_timestamp(timestamp, tse);
359 }
360
361 /*
362  ***************************************************************************
363  * Look for the most recent of saDD and saYYYYMMDD to decide which one to
364  * use. If neither exists then use saDD by default.
365  *
366  * IN:
367  * @sa_dir      Directory where standard daily data files are saved.
368  * @rectime     Structure containing the current date.
369  *
370  * OUT:
371  * @sa_name     0 to use saDD data files,
372  *              1 to use saYYYYMMDD data files.
373  ***************************************************************************
374  */
375 void guess_sa_name(char *sa_dir, struct tm *rectime, int *sa_name)
376 {
377         char filename[MAX_FILE_LEN];
378         struct stat sb;
379         time_t sa_mtime;
380
381         /* Use saDD by default */
382         *sa_name = 0;
383
384         /* Look for saYYYYMMDD */
385         snprintf(filename, MAX_FILE_LEN,
386                  "%s/sa%04d%02d%02d", sa_dir,
387                  rectime->tm_year + 1900,
388                  rectime->tm_mon + 1,
389                  rectime->tm_mday);
390         filename[MAX_FILE_LEN - 1] = '\0';
391
392         if (stat(filename, &sb) < 0)
393                 /* Cannot find or access saYYYYMMDD, so use saDD */
394                 return;
395         sa_mtime = sb.st_mtime;
396
397         /* Look for saDD */
398         snprintf(filename, MAX_FILE_LEN,
399                  "%s/sa%02d", sa_dir,
400                  rectime->tm_mday);
401         filename[MAX_FILE_LEN - 1] = '\0';
402
403         if (stat(filename, &sb) < 0) {
404                 /* Cannot find or access saDD, so use saYYYYMMDD */
405                 *sa_name = 1;
406                 return;
407         }
408
409         if (sa_mtime > sb.st_mtime) {
410                 /* saYYYYMMDD is more recent than saDD, so use it */
411                 *sa_name = 1;
412         }
413 }
414
415 /*
416  ***************************************************************************
417  * Set current daily data file name.
418  *
419  * IN:
420  * @datafile    If not an empty string then this is the alternate directory
421  *              location where daily data files will be saved.
422  * @d_off       Day offset (number of days to go back in the past).
423  * @sa_name     0 for saDD data files,
424  *              1 for saYYYYMMDD data files,
425  *              -1 if unknown. In this case, will look for the most recent
426  *              of saDD and saYYYYMMDD and use it.
427  *
428  * OUT:
429  * @datafile    Name of daily data file.
430  ***************************************************************************
431  */
432 void set_default_file(char *datafile, int d_off, int sa_name)
433 {
434         char sa_dir[MAX_FILE_LEN];
435         struct tm rectime = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL};
436
437         /* Set directory where daily data files will be saved */
438         if (datafile[0]) {
439                 strncpy(sa_dir, datafile, MAX_FILE_LEN);
440         }
441         else {
442                 strncpy(sa_dir, SA_DIR, MAX_FILE_LEN);
443         }
444         sa_dir[MAX_FILE_LEN - 1] = '\0';
445
446         get_time(&rectime, d_off);
447         if (sa_name < 0) {
448                 /*
449                  * Look for the most recent of saDD and saYYYYMMDD
450                  * and use it. If neither exists then use saDD.
451                  * sa_name is set accordingly.
452                  */
453                 guess_sa_name(sa_dir, &rectime, &sa_name);
454         }
455         if (sa_name) {
456                 /* Using saYYYYMMDD data files */
457                 snprintf(datafile, MAX_FILE_LEN,
458                          "%s/sa%04d%02d%02d", sa_dir,
459                          rectime.tm_year + 1900,
460                          rectime.tm_mon + 1,
461                          rectime.tm_mday);
462         }
463         else {
464                 /* Using saDD data files */
465                 snprintf(datafile, MAX_FILE_LEN,
466                          "%s/sa%02d", sa_dir,
467                          rectime.tm_mday);
468         }
469         datafile[MAX_FILE_LEN - 1] = '\0';
470         default_file_used = TRUE;
471 }
472
473 /*
474  ***************************************************************************
475  * Check data file type. If it is a directory then this is the alternate
476  * location where daily data files will be saved.
477  *
478  * IN:
479  * @datafile    Name of the daily data file. May be a directory.
480  * @d_off       Day offset (number of days to go back in the past).
481  * @sa_name     0 for saDD data files,
482  *              1 for saYYYYMMDD data files,
483  *              -1 if unknown. In this case, will look for the most recent
484  *              of saDD and saYYYYMMDD and use it.
485  *
486  *
487  * OUT:
488  * @datafile    Name of the daily data file. This is now a plain file, not
489  *              a directory.
490  *
491  * RETURNS:
492  * 1 if @datafile was a directory, and 0 otherwise.
493  ***************************************************************************
494  */
495 int check_alt_sa_dir(char *datafile, int d_off, int sa_name)
496 {
497         struct stat sb;
498
499         if (stat(datafile, &sb) == 0) {
500                 if (S_ISDIR(sb.st_mode)) {
501                         /*
502                          * This is a directory: So append
503                          * the default file name to it.
504                          */
505                         set_default_file(datafile, d_off, sa_name);
506                         return 1;
507                 }
508         }
509
510         return 0;
511 }
512
513 /*
514  ***************************************************************************
515  * Set interval value.
516  *
517  * IN:
518  * @record_hdr_curr     Record with current sample statistics.
519  * @record_hdr_prev     Record with previous sample statistics.
520  * @nr_proc             Number of CPU, including CPU "all".
521  *
522  * OUT:
523  * @itv                 Interval in jiffies.
524  * @g_itv               Interval in jiffies multiplied by the # of proc.
525  ***************************************************************************
526  */
527 void get_itv_value(struct record_header *record_hdr_curr,
528                    struct record_header *record_hdr_prev,
529                    unsigned int nr_proc,
530                    unsigned long long *itv, unsigned long long *g_itv)
531 {
532         /* Interval value in jiffies */
533         *g_itv = get_interval(record_hdr_prev->uptime,
534                               record_hdr_curr->uptime);
535
536         if (nr_proc > 2) {
537                 *itv = get_interval(record_hdr_prev->uptime0,
538                                     record_hdr_curr->uptime0);
539         }
540         else {
541                 *itv = *g_itv;
542         }
543 }
544
545 /*
546  ***************************************************************************
547  * Fill the rectime structure with the file's creation date, based on file's
548  * time data saved in file header.
549  * The resulting timestamp is expressed in the locale of the file creator or
550  * in the user's own locale, depending on whether option -t has been used
551  * or not.
552  *
553  * IN:
554  * @flags       Flags for common options and system state.
555  * @file_hdr    System activity file standard header.
556  *
557  * OUT:
558  * @rectime     Date (and possibly time) from file header. Only the date,
559  *              not the time, should be used by the caller.
560  ***************************************************************************
561  */
562 void get_file_timestamp_struct(unsigned int flags, struct tm *rectime,
563                                struct file_header *file_hdr)
564 {
565         struct tm *loc_t;
566
567         if (PRINT_TRUE_TIME(flags)) {
568                 /* Get local time. This is just to fill fields with a default value. */
569                 get_time(rectime, 0);
570
571                 rectime->tm_mday = file_hdr->sa_day;
572                 rectime->tm_mon  = file_hdr->sa_month;
573                 rectime->tm_year = file_hdr->sa_year;
574                 /*
575                  * Call mktime() to set DST (Daylight Saving Time) flag.
576                  * Has anyone a better way to do it?
577                  */
578                 rectime->tm_hour = rectime->tm_min = rectime->tm_sec = 0;
579                 mktime(rectime);
580         }
581         else {
582                 if ((loc_t = localtime((const time_t *) &file_hdr->sa_ust_time)) != NULL) {
583                         *rectime = *loc_t;
584                 }
585         }
586 }
587
588 /*
589  ***************************************************************************
590  * Print report header.
591  *
592  * IN:
593  * @flags       Flags for common options and system state.
594  * @file_hdr    System activity file standard header.
595  * @cpu_nr      Number of CPU (value in [1, NR_CPUS + 1]).
596  *              1 means that there is only one proc and non SMP kernel.
597  *              2 means one proc and SMP kernel.
598  *              Etc.
599  *
600  * OUT:
601  * @rectime     Date and time from file header.
602  ***************************************************************************
603  */
604 void print_report_hdr(unsigned int flags, struct tm *rectime,
605                       struct file_header *file_hdr, int cpu_nr)
606 {
607
608         /* Get date of file creation */
609         get_file_timestamp_struct(flags, rectime, file_hdr);
610
611         /* Display the header */
612         print_gal_header(rectime, file_hdr->sa_sysname, file_hdr->sa_release,
613                          file_hdr->sa_nodename, file_hdr->sa_machine,
614                          cpu_nr > 1 ? cpu_nr - 1 : 1,
615                          PLAIN_OUTPUT);
616 }
617
618 /*
619  ***************************************************************************
620  * Network interfaces may now be registered (and unregistered) dynamically.
621  * This is what we try to guess here.
622  *
623  * IN:
624  * @a           Activity structure with statistics.
625  * @curr        Index in array for current sample statistics.
626  * @ref         Index in array for sample statistics used as reference.
627  * @pos         Index on current network interface.
628  *
629  * RETURNS:
630  * Position of current network interface in array of sample statistics used
631  * as reference.
632  ***************************************************************************
633  */
634 unsigned int check_net_dev_reg(struct activity *a, int curr, int ref,
635                                unsigned int pos)
636 {
637         struct stats_net_dev *sndc, *sndp;
638         unsigned int index = 0;
639
640         sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + pos * a->msize);
641
642         while (index < a->nr) {
643                 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
644                 if (!strcmp(sndc->interface, sndp->interface)) {
645                         /*
646                          * Network interface found.
647                          * If a counter has decreased, then we may assume that the
648                          * corresponding interface was unregistered, then registered again.
649                          */
650                         if ((sndc->rx_packets    < sndp->rx_packets)    ||
651                             (sndc->tx_packets    < sndp->tx_packets)    ||
652                             (sndc->rx_bytes      < sndp->rx_bytes)      ||
653                             (sndc->tx_bytes      < sndp->tx_bytes)      ||
654                             (sndc->rx_compressed < sndp->rx_compressed) ||
655                             (sndc->tx_compressed < sndp->tx_compressed) ||
656                             (sndc->multicast     < sndp->multicast)) {
657
658                                 /*
659                                  * Special processing for rx_bytes (_packets) and
660                                  * tx_bytes (_packets) counters: If the number of
661                                  * bytes (packets) has decreased, whereas the number of
662                                  * packets (bytes) has increased, then assume that the
663                                  * relevant counter has met an overflow condition, and that
664                                  * the interface was not unregistered, which is all the
665                                  * more plausible that the previous value for the counter
666                                  * was > ULONG_MAX/2.
667                                  * NB: the average value displayed will be wrong in this case...
668                                  *
669                                  * If such an overflow is detected, just set the flag. There is no
670                                  * need to handle this in a special way: the difference is still
671                                  * properly calculated if the result is of the same type (i.e.
672                                  * unsigned long) as the two values.
673                                  */
674                                 int ovfw = FALSE;
675
676                                 if ((sndc->rx_bytes   < sndp->rx_bytes)   &&
677                                     (sndc->rx_packets > sndp->rx_packets) &&
678                                     (sndp->rx_bytes   > (~0UL >> 1))) {
679                                         ovfw = TRUE;
680                                 }
681                                 if ((sndc->tx_bytes   < sndp->tx_bytes)   &&
682                                     (sndc->tx_packets > sndp->tx_packets) &&
683                                     (sndp->tx_bytes   > (~0UL >> 1))) {
684                                         ovfw = TRUE;
685                                 }
686                                 if ((sndc->rx_packets < sndp->rx_packets) &&
687                                     (sndc->rx_bytes   > sndp->rx_bytes)   &&
688                                     (sndp->rx_packets > (~0UL >> 1))) {
689                                         ovfw = TRUE;
690                                 }
691                                 if ((sndc->tx_packets < sndp->tx_packets) &&
692                                     (sndc->tx_bytes   > sndp->tx_bytes)   &&
693                                     (sndp->tx_packets > (~0UL >> 1))) {
694                                         ovfw = TRUE;
695                                 }
696
697                                 if (!ovfw) {
698                                         /*
699                                          * OK: assume here that the device was
700                                          * actually unregistered.
701                                          */
702                                         memset(sndp, 0, STATS_NET_DEV_SIZE);
703                                         strncpy(sndp->interface, sndc->interface, MAX_IFACE_LEN - 1);
704                                 }
705                         }
706                         return index;
707                 }
708                 index++;
709         }
710
711         /* Network interface not found: Look for the first free structure */
712         for (index = 0; index < a->nr; index++) {
713                 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
714                 if (!strcmp(sndp->interface, ""))
715                         break;
716         }
717         if (index >= a->nr) {
718                 /* No free structure: Default is structure of same rank */
719                 index = pos;
720         }
721
722         sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
723         /* Since the name is not the same, reset all the structure */
724         memset(sndp, 0, STATS_NET_DEV_SIZE);
725         strncpy(sndp->interface, sndc->interface, MAX_IFACE_LEN - 1);
726
727         return  index;
728 }
729
730 /*
731  ***************************************************************************
732  * Network interfaces may now be registered (and unregistered) dynamically.
733  * This is what we try to guess here.
734  *
735  * IN:
736  * @a           Activity structure with statistics.
737  * @curr        Index in array for current sample statistics.
738  * @ref         Index in array for sample statistics used as reference.
739  * @pos         Index on current network interface.
740  *
741  * RETURNS:
742  * Position of current network interface in array of sample statistics used
743  * as reference.
744  ***************************************************************************
745  */
746 unsigned int check_net_edev_reg(struct activity *a, int curr, int ref,
747                                 unsigned int pos)
748 {
749         struct stats_net_edev *snedc, *snedp;
750         unsigned int index = 0;
751
752         snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + pos * a->msize);
753
754         while (index < a->nr) {
755                 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
756                 if (!strcmp(snedc->interface, snedp->interface)) {
757                         /*
758                          * Network interface found.
759                          * If a counter has decreased, then we may assume that the
760                          * corresponding interface was unregistered, then registered again.
761                          */
762                         if ((snedc->tx_errors         < snedp->tx_errors)         ||
763                             (snedc->collisions        < snedp->collisions)        ||
764                             (snedc->rx_dropped        < snedp->rx_dropped)        ||
765                             (snedc->tx_dropped        < snedp->tx_dropped)        ||
766                             (snedc->tx_carrier_errors < snedp->tx_carrier_errors) ||
767                             (snedc->rx_frame_errors   < snedp->rx_frame_errors)   ||
768                             (snedc->rx_fifo_errors    < snedp->rx_fifo_errors)    ||
769                             (snedc->tx_fifo_errors    < snedp->tx_fifo_errors)) {
770
771                                 /*
772                                  * OK: assume here that the device was
773                                  * actually unregistered.
774                                  */
775                                 memset(snedp, 0, STATS_NET_EDEV_SIZE);
776                                 strncpy(snedp->interface, snedc->interface, MAX_IFACE_LEN - 1);
777                         }
778                         return index;
779                 }
780                 index++;
781         }
782
783         /* Network interface not found: Look for the first free structure */
784         for (index = 0; index < a->nr; index++) {
785                 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
786                 if (!strcmp(snedp->interface, ""))
787                         break;
788         }
789         if (index >= a->nr) {
790                 /* No free structure: Default is structure of same rank */
791                 index = pos;
792         }
793
794         snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
795         /* Since the name is not the same, reset all the structure */
796         memset(snedp, 0, STATS_NET_EDEV_SIZE);
797         strncpy(snedp->interface, snedc->interface, MAX_IFACE_LEN - 1);
798
799         return  index;
800 }
801
802 /*
803  ***************************************************************************
804  * Disks may be registered dynamically (true in /proc/stat file).
805  * This is what we try to guess here.
806  *
807  * IN:
808  * @a           Activity structure with statistics.
809  * @curr        Index in array for current sample statistics.
810  * @ref         Index in array for sample statistics used as reference.
811  * @pos         Index on current disk.
812  *
813  * RETURNS:
814  * Position of current disk in array of sample statistics used as reference.
815  ***************************************************************************
816  */
817 int check_disk_reg(struct activity *a, int curr, int ref, int pos)
818 {
819         struct stats_disk *sdc, *sdp;
820         int index = 0;
821
822         sdc = (struct stats_disk *) ((char *) a->buf[curr] + pos * a->msize);
823
824         while (index < a->nr) {
825                 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
826                 if ((sdc->major == sdp->major) &&
827                     (sdc->minor == sdp->minor)) {
828                         /*
829                          * Disk found.
830                          * If all the counters have decreased then the likelyhood
831                          * is that the disk has been unregistered and a new disk inserted.
832                          * If only one or two have decreased then the likelyhood
833                          * is that the counter has simply wrapped.
834                          */
835                         if ((sdc->nr_ios < sdp->nr_ios) &&
836                             (sdc->rd_sect < sdp->rd_sect) &&
837                             (sdc->wr_sect < sdp->wr_sect)) {
838
839                                 memset(sdp, 0, STATS_DISK_SIZE);
840                                 sdp->major = sdc->major;
841                                 sdp->minor = sdc->minor;
842                         }
843                         return index;
844                 }
845                 index++;
846         }
847
848         /* Disk not found: Look for the first free structure */
849         for (index = 0; index < a->nr; index++) {
850                 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
851                 if (!(sdp->major + sdp->minor))
852                         break;
853         }
854         if (index >= a->nr) {
855                 /* No free structure found: Default is structure of same rank */
856                 index = pos;
857         }
858
859         sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
860         /* Since the device is not the same, reset all the structure */
861         memset(sdp, 0, STATS_DISK_SIZE);
862         sdp->major = sdc->major;
863         sdp->minor = sdc->minor;
864
865         return index;
866 }
867
868 /*
869  ***************************************************************************
870  * Allocate bitmaps for activities that have one.
871  *
872  * IN:
873  * @act         Array of activities.
874  ***************************************************************************
875  */
876 void allocate_bitmaps(struct activity *act[])
877 {
878         int i;
879
880         for (i = 0; i < NR_ACT; i++) {
881                 /*
882                  * If current activity has a bitmap which has not already
883                  * been allocated, then allocate it.
884                  * Note that a same bitmap may be used by several activities.
885                  */
886                 if (act[i]->bitmap && !act[i]->bitmap->b_array) {
887                         SREALLOC(act[i]->bitmap->b_array, unsigned char,
888                                  BITMAP_SIZE(act[i]->bitmap->b_size));
889                 }
890         }
891 }
892
893 /*
894  ***************************************************************************
895  * Free bitmaps for activities that have one.
896  *
897  * IN:
898  * @act         Array of activities.
899  ***************************************************************************
900  */
901 void free_bitmaps(struct activity *act[])
902 {
903         int i;
904
905         for (i = 0; i < NR_ACT; i++) {
906                 if (act[i]->bitmap && act[i]->bitmap->b_array) {
907                         free(act[i]->bitmap->b_array);
908                         /* Set pointer to NULL to prevent it from being freed again */
909                         act[i]->bitmap->b_array = NULL;
910                 }
911         }
912 }
913
914 /*
915  ***************************************************************************
916  * Look for activity in array.
917  *
918  * IN:
919  * @act         Array of activities.
920  * @act_flag    Activity flag to look for.
921  * @stop        TRUE if sysstat should exit when activity is not found.
922  *
923  * RETURNS:
924  * Position of activity in array, or -1 if not found (this may happen when
925  * reading data from a system activity file created by another version of
926  * sysstat).
927  ***************************************************************************
928  */
929 int get_activity_position(struct activity *act[], unsigned int act_flag, int stop)
930 {
931         int i;
932
933         for (i = 0; i < NR_ACT; i++) {
934                 if (act[i]->id == act_flag)
935                         return i;
936         }
937
938         if (stop) {
939                 PANIC((int) act_flag);
940         }
941
942         return -1;
943 }
944
945 /*
946  ***************************************************************************
947  * Count number of activities with given option.
948  *
949  * IN:
950  * @act                 Array of activities.
951  * @option              Option that activities should have to be counted
952  *                      (eg. AO_COLLECTED...)
953  * @count_outputs       TRUE if each output should be counted for activities with
954  *                      multiple outputs.
955  *
956  * RETURNS:
957  * Number of selected activities
958  ***************************************************************************
959  */
960 int get_activity_nr(struct activity *act[], unsigned int option, int count_outputs)
961 {
962         int i, n = 0;
963         unsigned int msk;
964
965         for (i = 0; i < NR_ACT; i++) {
966                 if ((act[i]->options & option) == option) {
967
968                         if (HAS_MULTIPLE_OUTPUTS(act[i]->options) && count_outputs) {
969                                 for (msk = 1; msk < 0x100; msk <<= 1) {
970                                         if ((act[i]->opt_flags & 0xff) & msk) {
971                                                 n++;
972                                         }
973                                 }
974                         }
975                         else {
976                                 n++;
977                         }
978                 }
979         }
980
981         return n;
982 }
983
984 /*
985  ***************************************************************************
986  * Select all activities, even if they have no associated items.
987  *
988  * IN:
989  * @act         Array of activities.
990  *
991  * OUT:
992  * @act         Array of activities, all of the being selected.
993  ***************************************************************************
994  */
995 void select_all_activities(struct activity *act[])
996 {
997         int i;
998
999         for (i = 0; i < NR_ACT; i++) {
1000                 act[i]->options |= AO_SELECTED;
1001         }
1002 }
1003
1004 /*
1005  ***************************************************************************
1006  * Select CPU activity if no other activities have been explicitly selected.
1007  * Also select CPU "all" if no other CPU has been selected.
1008  *
1009  * IN:
1010  * @act         Array of activities.
1011  *
1012  * OUT:
1013  * @act         Array of activities with CPU activity selected if needed.
1014  ***************************************************************************
1015  */
1016 void select_default_activity(struct activity *act[])
1017 {
1018         int p;
1019
1020         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1021
1022         /* Default is CPU activity... */
1023         if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1024                 /*
1025                  * Still OK even when reading stats from a file
1026                  * since A_CPU activity is always recorded.
1027                  */
1028                 act[p]->options |= AO_SELECTED;
1029         }
1030
1031         /*
1032          * If no CPU's have been selected then select CPU "all".
1033          * cpu_bitmap bitmap may be used by several activities (A_CPU, A_PWR_CPUFREQ...)
1034          */
1035         if (!count_bits(cpu_bitmap.b_array, BITMAP_SIZE(cpu_bitmap.b_size))) {
1036                 cpu_bitmap.b_array[0] |= 0x01;
1037         }
1038 }
1039
1040 /*
1041  ***************************************************************************
1042  * Read data from a system activity data file.
1043  *
1044  * IN:
1045  * @ifd         Input file descriptor.
1046  * @buffer      Buffer where data are read.
1047  * @size        Number of bytes to read.
1048  * @mode        If set to HARD_SIZE, indicate that an EOF should be considered
1049  *              as an error.
1050  *
1051  * RETURNS:
1052  * 1 if EOF has been reached, 0 otherwise.
1053  ***************************************************************************
1054  */
1055 int sa_fread(int ifd, void *buffer, int size, int mode)
1056 {
1057         int n;
1058
1059         if ((n = read(ifd, buffer, size)) < 0) {
1060                 fprintf(stderr, _("Error while reading system activity file: %s\n"),
1061                         strerror(errno));
1062                 close(ifd);
1063                 exit(2);
1064         }
1065
1066         if (!n && (mode == SOFT_SIZE))
1067                 return 1;       /* EOF */
1068
1069         if (n < size) {
1070                 fprintf(stderr, _("End of system activity file unexpected\n"));
1071                 close(ifd);
1072                 exit(2);
1073         }
1074
1075         return 0;
1076 }
1077
1078 /*
1079  ***************************************************************************
1080  * Display sysstat version used to create system activity data file.
1081  *
1082  * IN:
1083  * @st          Output stream (stderr or stdout).
1084  * @file_magic  File magic header.
1085  ***************************************************************************
1086  */
1087 void display_sa_file_version(FILE *st, struct file_magic *file_magic)
1088 {
1089         fprintf(st, _("File created by sar/sadc from sysstat version %d.%d.%d"),
1090                 file_magic->sysstat_version,
1091                 file_magic->sysstat_patchlevel,
1092                 file_magic->sysstat_sublevel);
1093
1094         if (file_magic->sysstat_extraversion) {
1095                 fprintf(st, ".%d", file_magic->sysstat_extraversion);
1096         }
1097         fprintf(st, "\n");
1098 }
1099
1100 /*
1101  ***************************************************************************
1102  * An invalid system activity file has been opened for reading.
1103  * If this file was created by an old version of sysstat, tell it to the
1104  * user...
1105  *
1106  * IN:
1107  * @fd          Descriptor of the file that has been opened.
1108  * @file_magic  file_magic structure filled with file magic header data.
1109  *              May contain invalid data.
1110  * @file        Name of the file being read.
1111  * @n           Number of bytes read while reading file magic header.
1112  *              This function may also be called after failing to read file
1113  *              standard header, or if CPU activity has not been found in
1114  *              file. In this case, n is set to 0.
1115  ***************************************************************************
1116  */
1117 void handle_invalid_sa_file(int *fd, struct file_magic *file_magic, char *file,
1118                             int n)
1119 {
1120         unsigned short sm;
1121
1122         fprintf(stderr, _("Invalid system activity file: %s\n"), file);
1123
1124         if (n == FILE_MAGIC_SIZE) {
1125                 sm = (file_magic->sysstat_magic << 8) | (file_magic->sysstat_magic >> 8);
1126                 if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (sm == SYSSTAT_MAGIC)) {
1127                         /*
1128                          * This is a sysstat file, but this file has an old format
1129                          * or its internal endian format doesn't match.
1130                          */
1131                         display_sa_file_version(stderr, file_magic);
1132
1133                         if (sm == SYSSTAT_MAGIC) {
1134                                 fprintf(stderr, _("Endian format mismatch\n"));
1135                         }
1136                         else {
1137                                 fprintf(stderr,
1138                                         _("Current sysstat version cannot read the format of this file (%#x)\n"),
1139                                         file_magic->format_magic);
1140                         }
1141                 }
1142         }
1143
1144         close (*fd);
1145         exit(3);
1146 }
1147
1148 /*
1149  ***************************************************************************
1150  * Move structures data.
1151  *
1152  * IN:
1153  * @act         Array of activities.
1154  * @id_seq      Activity sequence in file.
1155  * @record_hdr  Current record header.
1156  * @dest        Index in array where stats have to be copied to.
1157  * @src         Index in array where stats to copy are.
1158  ***************************************************************************
1159  */
1160 void copy_structures(struct activity *act[], unsigned int id_seq[],
1161                      struct record_header record_hdr[], int dest, int src)
1162 {
1163         int i, p;
1164
1165         memcpy(&record_hdr[dest], &record_hdr[src], RECORD_HEADER_SIZE);
1166
1167         for (i = 0; i < NR_ACT; i++) {
1168
1169                 if (!id_seq[i])
1170                         continue;
1171
1172                 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1173                 if ((act[p]->nr < 1) || (act[p]->nr2 < 1)) {
1174                         PANIC(1);
1175                 }
1176
1177                 memcpy(act[p]->buf[dest], act[p]->buf[src],
1178                        (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
1179         }
1180 }
1181
1182 /*
1183  ***************************************************************************
1184  * Read varying part of the statistics from a daily data file.
1185  *
1186  * IN:
1187  * @act         Array of activities.
1188  * @curr        Index in array for current sample statistics.
1189  * @ifd         Input file descriptor.
1190  * @act_nr      Number of activities in file.
1191  * @file_actlst Activity list in file.
1192  ***************************************************************************
1193  */
1194 void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
1195                           struct file_activity *file_actlst)
1196 {
1197         int i, j, k, p;
1198         struct file_activity *fal = file_actlst;
1199         off_t offset;
1200
1201         for (i = 0; i < act_nr; i++, fal++) {
1202
1203                 if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
1204                     (act[p]->magic != fal->magic)) {
1205                         /*
1206                          * Ignore current activity in file, which is unknown to
1207                          * current sysstat version or has an unknown format.
1208                          */
1209                         offset = (off_t) fal->size * (off_t) fal->nr * (off_t) fal->nr2;
1210                         if (lseek(ifd, offset, SEEK_CUR) < offset) {
1211                                 close(ifd);
1212                                 perror("lseek");
1213                                 exit(2);
1214                         }
1215                 }
1216                 else if ((act[p]->nr > 0) &&
1217                          ((act[p]->nr > 1) || (act[p]->nr2 > 1)) &&
1218                          (act[p]->msize > act[p]->fsize)) {
1219                         for (j = 0; j < act[p]->nr; j++) {
1220                                 for (k = 0; k < act[p]->nr2; k++) {
1221                                         sa_fread(ifd,
1222                                                  (char *) act[p]->buf[curr] + (j * act[p]->nr2 + k) * act[p]->msize,
1223                                                  act[p]->fsize, HARD_SIZE);
1224                                 }
1225                         }
1226                 }
1227                 else if (act[p]->nr > 0) {
1228                         sa_fread(ifd, act[p]->buf[curr], act[p]->fsize * act[p]->nr * act[p]->nr2, HARD_SIZE);
1229                 }
1230                 else {
1231                         PANIC(p);
1232                 }
1233         }
1234 }
1235
1236 /*
1237  ***************************************************************************
1238  * Open a sysstat activity data file and read its magic structure.
1239  *
1240  * IN:
1241  * @dfile       Name of system activity data file.
1242  * @ignore      Set to 1 if a true sysstat activity file but with a bad
1243  *              format should not yield an error message. Useful with
1244  *              sadf -H and sadf -c.
1245  *
1246  * OUT:
1247  * @fd          System activity data file descriptor.
1248  * @file_magic  file_magic structure containing data read from file magic
1249  *              header.
1250  *
1251  * RETURNS:
1252  * -1 if data file is a sysstat file with an old format, 0 otherwise.
1253  ***************************************************************************
1254  */
1255 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
1256                        int ignore)
1257 {
1258         int n;
1259
1260         /* Open sa data file */
1261         if ((*fd = open(dfile, O_RDONLY)) < 0) {
1262                 int saved_errno = errno;
1263
1264                 fprintf(stderr, _("Cannot open %s: %s\n"), dfile, strerror(errno));
1265
1266                 if ((saved_errno == ENOENT) && default_file_used) {
1267                         fprintf(stderr, _("Please check if data collecting is enabled\n"));
1268                 }
1269                 exit(2);
1270         }
1271
1272         /* Read file magic data */
1273         n = read(*fd, file_magic, FILE_MAGIC_SIZE);
1274
1275         if ((n != FILE_MAGIC_SIZE) ||
1276             (file_magic->sysstat_magic != SYSSTAT_MAGIC) ||
1277             ((file_magic->format_magic != FORMAT_MAGIC) && !ignore)) {
1278                 /* Display error message and exit */
1279                 handle_invalid_sa_file(fd, file_magic, dfile, n);
1280         }
1281         if ((file_magic->sysstat_version > 10) ||
1282             ((file_magic->sysstat_version == 10) && (file_magic->sysstat_patchlevel >= 3))) {
1283                 /* header_size field exists only for sysstat versions 10.3.1 and later */
1284                 if ((file_magic->header_size <= MIN_FILE_HEADER_SIZE) ||
1285                     (file_magic->header_size > MAX_FILE_HEADER_SIZE) ||
1286                     ((file_magic->header_size < FILE_HEADER_SIZE) && !ignore)) {
1287                         /* Display error message and exit */
1288                         handle_invalid_sa_file(fd, file_magic, dfile, n);
1289                 }
1290         }
1291         if (file_magic->format_magic != FORMAT_MAGIC)
1292                 /* This is an old sa datafile format */
1293                 return -1;
1294
1295         return 0;
1296 }
1297
1298 /*
1299  ***************************************************************************
1300  * Open a data file, and perform various checks before reading.
1301  *
1302  * IN:
1303  * @dfile       Name of system activity data file.
1304  * @act         Array of activities.
1305  * @ignore      Set to 1 if a true sysstat activity file but with a bad
1306  *              format should not yield an error message. Useful with
1307  *              sadf -H and sadf -c.
1308  *
1309  * OUT:
1310  * @ifd         System activity data file descriptor.
1311  * @file_magic  file_magic structure containing data read from file magic
1312  *              header.
1313  * @file_hdr    file_hdr structure containing data read from file standard
1314  *              header.
1315  * @file_actlst Acvtivity list in file.
1316  * @id_seq      Activity sequence.
1317  ***************************************************************************
1318  */
1319 void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
1320                        struct file_magic *file_magic, struct file_header *file_hdr,
1321                        struct file_activity **file_actlst, unsigned int id_seq[],
1322                        int ignore)
1323 {
1324         int i, j, p;
1325         unsigned int a_cpu = FALSE;
1326         struct file_activity *fal;
1327         void *buffer = NULL;
1328
1329         /* Open sa data file and read its magic structure */
1330         if (sa_open_read_magic(ifd, dfile, file_magic, ignore) < 0)
1331                 return;
1332
1333         SREALLOC(buffer, char, file_magic->header_size);
1334
1335         /* Read sa data file standard header and allocate activity list */
1336         sa_fread(*ifd, buffer, file_magic->header_size, HARD_SIZE);
1337         /*
1338          * Data file header size may be greater than FILE_HEADER_SIZE, but
1339          * anyway only the first FILE_HEADER_SIZE bytes can be interpreted.
1340          */
1341         memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
1342         free(buffer);
1343
1344         /*
1345          * Sanity check.
1346          * Compare against MAX_NR_ACT and not NR_ACT because
1347          * we are maybe reading a datafile from a future sysstat version
1348          * with more activities than known today.
1349          */
1350         if (file_hdr->sa_act_nr > MAX_NR_ACT) {
1351                 /* Maybe a "false positive" sysstat datafile? */
1352                 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1353         }
1354
1355         SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
1356         fal = *file_actlst;
1357
1358         /* Read activity list */
1359         j = 0;
1360         for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1361
1362                 sa_fread(*ifd, fal, FILE_ACTIVITY_SIZE, HARD_SIZE);
1363
1364                 /*
1365                  * Every activity, known or unknown, should have
1366                  * at least one item and sub-item.
1367                  * Also check that the number of items and sub-items
1368                  * doesn't exceed a max value. This is necessary
1369                  * because we will use @nr and @nr2 to
1370                  * allocate memory to read the file contents. So we
1371                  * must make sure the file is not corrupted.
1372                  * NB: Another check will be made below for known
1373                  * activities which have each a specific max value.
1374                  */
1375                 if ((fal->nr < 1) || (fal->nr2 < 1) ||
1376                     (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX)) {
1377                         handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1378                 }
1379
1380                 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0)
1381                         /* Unknown activity */
1382                         continue;
1383
1384                 if (act[p]->magic != fal->magic) {
1385                         /* Bad magical number */
1386                         if (ignore) {
1387                                 /*
1388                                  * This is how sadf -H knows that this
1389                                  * activity has an unknown format.
1390                                  */
1391                                 act[p]->magic = ACTIVITY_MAGIC_UNKNOWN;
1392                         }
1393                         else
1394                                 continue;
1395                 }
1396
1397                 /* Check max value for known activities */
1398                 if (fal->nr > act[p]->nr_max) {
1399                         handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1400                 }
1401
1402                 if (fal->id == A_CPU) {
1403                         a_cpu = TRUE;
1404                 }
1405
1406                 if (fal->size > act[p]->msize) {
1407                         act[p]->msize = fal->size;
1408                 }
1409                 /*
1410                  * NOTA BENE:
1411                  * If current activity is a volatile one then fal->nr is the
1412                  * number of items (CPU at the present time as only CPU related
1413                  * activities are volatile today) for the statistics located
1414                  * between the start of the data file and the first restart mark.
1415                  * Volatile activities have a number of items which can vary
1416                  * in file. In this case, a RESTART record is followed by the
1417                  * volatile activity structures.
1418                  */
1419                 act[p]->nr    = fal->nr;
1420                 act[p]->nr2   = fal->nr2;
1421                 act[p]->fsize = fal->size;
1422                 /*
1423                  * This is a known activity with a known format
1424                  * (magical number). Only such activities will be displayed.
1425                  * (Well, this may also be an unknown format if we have entered sadf -H.)
1426                  */
1427                 id_seq[j++] = fal->id;
1428         }
1429
1430         if (!a_cpu) {
1431                 /*
1432                  * CPU activity should always be in file
1433                  * and have a known format (expected magical number).
1434                  */
1435                 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1436         }
1437
1438         while (j < NR_ACT) {
1439                 id_seq[j++] = 0;
1440         }
1441
1442         /* Check that at least one selected activity is available in file */
1443         for (i = 0; i < NR_ACT; i++) {
1444
1445                 if (!IS_SELECTED(act[i]->options))
1446                         continue;
1447
1448                 /* Here is a selected activity: Does it exist in file? */
1449                 fal = *file_actlst;
1450                 for (j = 0; j < file_hdr->sa_act_nr; j++, fal++) {
1451                         if (act[i]->id == fal->id)
1452                                 break;
1453                 }
1454                 if (j == file_hdr->sa_act_nr) {
1455                         /* No: Unselect it */
1456                         act[i]->options &= ~AO_SELECTED;
1457                 }
1458         }
1459         if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1460                 fprintf(stderr, _("Requested activities not available in file %s\n"),
1461                         dfile);
1462                 close(*ifd);
1463                 exit(1);
1464         }
1465 }
1466
1467 /*
1468  ***************************************************************************
1469  * Set number of items for current volatile activity and reallocate its
1470  * structures accordingly.
1471  * NB: As only activities related to CPU can be volatile, the number of
1472  * items corresponds in fact to the number of CPU.
1473  *
1474  * IN:
1475  * @act         Array of activities.
1476  * @act_nr      Number of items for current volatile activity.
1477  * @act_id      Activity identification for current volatile activity.
1478  *
1479  * RETURN:
1480  * -1 if unknown activity and 0 otherwise.
1481  ***************************************************************************
1482  */
1483 int reallocate_vol_act_structures(struct activity *act[], unsigned int act_nr,
1484                                    unsigned int act_id)
1485 {
1486         int j, p;
1487
1488         if ((p = get_activity_position(act, act_id, RESUME_IF_NOT_FOUND)) < 0)
1489                 /* Ignore unknown activity */
1490                 return -1;
1491
1492         act[p]->nr = act_nr;
1493
1494         for (j = 0; j < 3; j++) {
1495                 SREALLOC(act[p]->buf[j], void,
1496                          (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
1497         }
1498
1499         return 0;
1500 }
1501
1502 /*
1503  ***************************************************************************
1504  * Read the volatile activities structures following a RESTART record.
1505  * Then set number of items for each corresponding activity and reallocate
1506  * structures.
1507  *
1508  * IN:
1509  * @ifd         Input file descriptor.
1510  * @act         Array of activities.
1511  * @file        Name of file being read.
1512  * @file_magic  file_magic structure filled with file magic header data.
1513  * @vol_act_nr  Number of volatile activities structures to read.
1514  *
1515  * RETURNS:
1516  * New number of items.
1517  *
1518  * NB: As only activities related to CPU can be volatile, the new number of
1519  * items corresponds in fact to the new number of CPU.
1520  ***************************************************************************
1521  */
1522 __nr_t read_vol_act_structures(int ifd, struct activity *act[], char *file,
1523                                struct file_magic *file_magic,
1524                                unsigned int vol_act_nr)
1525 {
1526         struct file_activity file_act;
1527         int item_nr = 0;
1528         int i, rc;
1529
1530         for (i = 0; i < vol_act_nr; i++) {
1531
1532                 sa_fread(ifd, &file_act, FILE_ACTIVITY_SIZE, HARD_SIZE);
1533
1534                 if (file_act.id) {
1535                         rc = reallocate_vol_act_structures(act, file_act.nr, file_act.id);
1536                         if ((rc == 0) && !item_nr) {
1537                                 item_nr = file_act.nr;
1538                         }
1539                 }
1540                 /* else ignore empty structures that may exist */
1541         }
1542
1543         if (!item_nr) {
1544                 /* All volatile activities structures cannot be empty */
1545                 handle_invalid_sa_file(&ifd, file_magic, file, 0);
1546         }
1547
1548         return item_nr;
1549 }
1550
1551 /*
1552  ***************************************************************************
1553  * Parse sar activities options (also used by sadf).
1554  *
1555  * IN:
1556  * @argv        Arguments list.
1557  * @opt         Index in list of arguments.
1558  * @caller      Indicate whether it's sar or sadf that called this function.
1559  *
1560  * OUT:
1561  * @act         Array of selected activities.
1562  * @flags       Common flags and system state.
1563  *
1564  * RETURNS:
1565  * 0 on success.
1566  ***************************************************************************
1567  */
1568 int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
1569                   unsigned int *flags, int caller)
1570 {
1571         int i, p;
1572
1573         for (i = 1; *(argv[*opt] + i); i++) {
1574                 /*
1575                  * Note: argv[*opt] contains something like "-BruW"
1576                  *     *(argv[*opt] + i) will contain 'B', 'r', etc.
1577                  */
1578
1579                 switch (*(argv[*opt] + i)) {
1580
1581                 case 'A':
1582                         select_all_activities(act);
1583
1584                         /*
1585                          * Force '-P ALL -I XALL -r ALL -u ALL -F'.
1586                          * Setting -F is compulsory because corresponding activity
1587                          * has AO_MULTIPLE_OUTPUTS flag set.
1588                          */
1589                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1590                         act[p]->opt_flags |= AO_F_MEM_AMT + AO_F_MEM_DIA +
1591                                              AO_F_MEM_SWAP + AO_F_MEM_ALL;
1592
1593                         p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1594                         set_bitmap(act[p]->bitmap->b_array, ~0,
1595                                    BITMAP_SIZE(act[p]->bitmap->b_size));
1596
1597                         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1598                         set_bitmap(act[p]->bitmap->b_array, ~0,
1599                                    BITMAP_SIZE(act[p]->bitmap->b_size));
1600                         act[p]->opt_flags = AO_F_CPU_ALL;
1601
1602                         p = get_activity_position(act, A_FILESYSTEM, EXIT_IF_NOT_FOUND);
1603                         act[p]->opt_flags = AO_F_FILESYSTEM;
1604                         break;
1605
1606                 case 'B':
1607                         SELECT_ACTIVITY(A_PAGE);
1608                         break;
1609
1610                 case 'b':
1611                         SELECT_ACTIVITY(A_IO);
1612                         break;
1613
1614                 case 'C':
1615                         *flags |= S_F_COMMENT;
1616                         break;
1617
1618                 case 'd':
1619                         SELECT_ACTIVITY(A_DISK);
1620                         break;
1621
1622                 case 'F':
1623                         p = get_activity_position(act, A_FILESYSTEM, EXIT_IF_NOT_FOUND);
1624                         act[p]->options |= AO_SELECTED;
1625                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_MOUNT)) {
1626                                 (*opt)++;
1627                                 act[p]->opt_flags |= AO_F_MOUNT;
1628                                 return 0;
1629                         }
1630                         else {
1631                                 act[p]->opt_flags |= AO_F_FILESYSTEM;
1632                         }
1633                         break;
1634
1635                 case 'H':
1636                         p = get_activity_position(act, A_HUGE, EXIT_IF_NOT_FOUND);
1637                         act[p]->options   |= AO_SELECTED;
1638                         break;
1639
1640                 case 'j':
1641                         if (argv[*opt + 1]) {
1642                                 (*opt)++;
1643                                 if (strnlen(argv[*opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1)
1644                                         return 1;
1645
1646                                 strncpy(persistent_name_type, argv[*opt], MAX_FILE_LEN - 1);
1647                                 persistent_name_type[MAX_FILE_LEN - 1] = '\0';
1648                                 strtolower(persistent_name_type);
1649                                 if (!get_persistent_type_dir(persistent_name_type)) {
1650                                         fprintf(stderr, _("Invalid type of persistent device name\n"));
1651                                         return 2;
1652                                 }
1653                                 /*
1654                                  * If persistent device name doesn't exist for device, use
1655                                  * its pretty name.
1656                                  */
1657                                 *flags |= S_F_PERSIST_NAME + S_F_DEV_PRETTY;
1658                                 return 0;
1659                         }
1660                         else {
1661                                 return 1;
1662                         }
1663                         break;
1664
1665                 case 'p':
1666                         *flags |= S_F_DEV_PRETTY;
1667                         break;
1668
1669                 case 'q':
1670                         SELECT_ACTIVITY(A_QUEUE);
1671                         break;
1672
1673                 case 'r':
1674                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1675                         act[p]->options   |= AO_SELECTED;
1676                         act[p]->opt_flags |= AO_F_MEM_AMT;
1677                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1678                                 (*opt)++;
1679                                 act[p]->opt_flags |= AO_F_MEM_ALL;
1680                                 return 0;
1681                         }
1682                         break;
1683
1684                 case 'R':
1685                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1686                         act[p]->options   |= AO_SELECTED;
1687                         act[p]->opt_flags |= AO_F_MEM_DIA;
1688                         break;
1689
1690                 case 'S':
1691                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1692                         act[p]->options   |= AO_SELECTED;
1693                         act[p]->opt_flags |= AO_F_MEM_SWAP;
1694                         break;
1695
1696                 case 't':
1697                         /*
1698                          * Check sar option -t here (as it can be combined
1699                          * with other ones, eg. "sar -rtu ..."
1700                          * But sadf option -t is checked in sadf.c as it won't
1701                          * be entered as a sar option after "--".
1702                          */
1703                         if (caller == C_SAR) {
1704                                 *flags |= S_F_TRUE_TIME;
1705                         }
1706                         else
1707                                 return 1;
1708                         break;
1709
1710                 case 'u':
1711                         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1712                         act[p]->options |= AO_SELECTED;
1713                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1714                                 (*opt)++;
1715                                 act[p]->opt_flags = AO_F_CPU_ALL;
1716                                 return 0;
1717                         }
1718                         else {
1719                                 act[p]->opt_flags = AO_F_CPU_DEF;
1720                         }
1721                         break;
1722
1723                 case 'v':
1724                         SELECT_ACTIVITY(A_KTABLES);
1725                         break;
1726
1727                 case 'w':
1728                         SELECT_ACTIVITY(A_PCSW);
1729                         break;
1730
1731                 case 'W':
1732                         SELECT_ACTIVITY(A_SWAP);
1733                         break;
1734
1735                 case 'y':
1736                         SELECT_ACTIVITY(A_SERIAL);
1737                         break;
1738
1739                 case 'V':
1740                         print_version();
1741                         break;
1742
1743                 default:
1744                         return 1;
1745                 }
1746         }
1747         return 0;
1748 }
1749
1750 /*
1751  ***************************************************************************
1752  * Parse sar "-m" option.
1753  *
1754  * IN:
1755  * @argv        Arguments list.
1756  * @opt         Index in list of arguments.
1757  *
1758  * OUT:
1759  * @act         Array of selected activities.
1760  *
1761  * RETURNS:
1762  * 0 on success, 1 otherwise.
1763  ***************************************************************************
1764  */
1765 int parse_sar_m_opt(char *argv[], int *opt, struct activity *act[])
1766 {
1767         char *t;
1768
1769         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1770                 if (!strcmp(t, K_CPU)) {
1771                         SELECT_ACTIVITY(A_PWR_CPUFREQ);
1772                 }
1773                 else if (!strcmp(t, K_FAN)) {
1774                         SELECT_ACTIVITY(A_PWR_FAN);
1775                 }
1776                 else if (!strcmp(t, K_IN)) {
1777                         SELECT_ACTIVITY(A_PWR_IN);
1778                 }
1779                 else if (!strcmp(t, K_TEMP)) {
1780                         SELECT_ACTIVITY(A_PWR_TEMP);
1781                 }
1782                 else if (!strcmp(t, K_FREQ)) {
1783                         SELECT_ACTIVITY(A_PWR_WGHFREQ);
1784                 }
1785                 else if (!strcmp(t, K_USB)) {
1786                         SELECT_ACTIVITY(A_PWR_USB);
1787                 }
1788                 else if (!strcmp(t, K_ALL)) {
1789                         SELECT_ACTIVITY(A_PWR_CPUFREQ);
1790                         SELECT_ACTIVITY(A_PWR_FAN);
1791                         SELECT_ACTIVITY(A_PWR_IN);
1792                         SELECT_ACTIVITY(A_PWR_TEMP);
1793                         SELECT_ACTIVITY(A_PWR_WGHFREQ);
1794                         SELECT_ACTIVITY(A_PWR_USB);
1795                 }
1796                 else
1797                         return 1;
1798         }
1799
1800         (*opt)++;
1801         return 0;
1802 }
1803
1804 /*
1805  ***************************************************************************
1806  * Parse sar "-n" option.
1807  *
1808  * IN:
1809  * @argv        Arguments list.
1810  * @opt         Index in list of arguments.
1811  *
1812  * OUT:
1813  * @act         Array of selected activities.
1814  *
1815  * RETURNS:
1816  * 0 on success, 1 otherwise.
1817  ***************************************************************************
1818  */
1819 int parse_sar_n_opt(char *argv[], int *opt, struct activity *act[])
1820 {
1821         char *t;
1822
1823         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1824                 if (!strcmp(t, K_DEV)) {
1825                         SELECT_ACTIVITY(A_NET_DEV);
1826                 }
1827                 else if (!strcmp(t, K_EDEV)) {
1828                         SELECT_ACTIVITY(A_NET_EDEV);
1829                 }
1830                 else if (!strcmp(t, K_SOCK)) {
1831                         SELECT_ACTIVITY(A_NET_SOCK);
1832                 }
1833                 else if (!strcmp(t, K_NFS)) {
1834                         SELECT_ACTIVITY(A_NET_NFS);
1835                 }
1836                 else if (!strcmp(t, K_NFSD)) {
1837                         SELECT_ACTIVITY(A_NET_NFSD);
1838                 }
1839                 else if (!strcmp(t, K_IP)) {
1840                         SELECT_ACTIVITY(A_NET_IP);
1841                 }
1842                 else if (!strcmp(t, K_EIP)) {
1843                         SELECT_ACTIVITY(A_NET_EIP);
1844                 }
1845                 else if (!strcmp(t, K_ICMP)) {
1846                         SELECT_ACTIVITY(A_NET_ICMP);
1847                 }
1848                 else if (!strcmp(t, K_EICMP)) {
1849                         SELECT_ACTIVITY(A_NET_EICMP);
1850                 }
1851                 else if (!strcmp(t, K_TCP)) {
1852                         SELECT_ACTIVITY(A_NET_TCP);
1853                 }
1854                 else if (!strcmp(t, K_ETCP)) {
1855                         SELECT_ACTIVITY(A_NET_ETCP);
1856                 }
1857                 else if (!strcmp(t, K_UDP)) {
1858                         SELECT_ACTIVITY(A_NET_UDP);
1859                 }
1860                 else if (!strcmp(t, K_SOCK6)) {
1861                         SELECT_ACTIVITY(A_NET_SOCK6);
1862                 }
1863                 else if (!strcmp(t, K_IP6)) {
1864                         SELECT_ACTIVITY(A_NET_IP6);
1865                 }
1866                 else if (!strcmp(t, K_EIP6)) {
1867                         SELECT_ACTIVITY(A_NET_EIP6);
1868                 }
1869                 else if (!strcmp(t, K_ICMP6)) {
1870                         SELECT_ACTIVITY(A_NET_ICMP6);
1871                 }
1872                 else if (!strcmp(t, K_EICMP6)) {
1873                         SELECT_ACTIVITY(A_NET_EICMP6);
1874                 }
1875                 else if (!strcmp(t, K_UDP6)) {
1876                         SELECT_ACTIVITY(A_NET_UDP6);
1877                 }
1878                 else if (!strcmp(t, K_FC)) {
1879                         SELECT_ACTIVITY(A_NET_FC);
1880                 }
1881                 else if (!strcmp(t, K_ALL)) {
1882                         SELECT_ACTIVITY(A_NET_DEV);
1883                         SELECT_ACTIVITY(A_NET_EDEV);
1884                         SELECT_ACTIVITY(A_NET_SOCK);
1885                         SELECT_ACTIVITY(A_NET_NFS);
1886                         SELECT_ACTIVITY(A_NET_NFSD);
1887                         SELECT_ACTIVITY(A_NET_IP);
1888                         SELECT_ACTIVITY(A_NET_EIP);
1889                         SELECT_ACTIVITY(A_NET_ICMP);
1890                         SELECT_ACTIVITY(A_NET_EICMP);
1891                         SELECT_ACTIVITY(A_NET_TCP);
1892                         SELECT_ACTIVITY(A_NET_ETCP);
1893                         SELECT_ACTIVITY(A_NET_UDP);
1894                         SELECT_ACTIVITY(A_NET_SOCK6);
1895                         SELECT_ACTIVITY(A_NET_IP6);
1896                         SELECT_ACTIVITY(A_NET_EIP6);
1897                         SELECT_ACTIVITY(A_NET_ICMP6);
1898                         SELECT_ACTIVITY(A_NET_EICMP6);
1899                         SELECT_ACTIVITY(A_NET_UDP6);
1900                         SELECT_ACTIVITY(A_NET_FC);
1901                 }
1902                 else
1903                         return 1;
1904         }
1905
1906         (*opt)++;
1907         return 0;
1908 }
1909
1910 /*
1911  ***************************************************************************
1912  * Parse sar "-I" option.
1913  *
1914  * IN:
1915  * @argv        Arguments list.
1916  * @opt         Index in list of arguments.
1917  * @act         Array of activities.
1918  *
1919  * OUT:
1920  * @act         Array of activities, with interrupts activity selected.
1921  *
1922  * RETURNS:
1923  * 0 on success, 1 otherwise.
1924  ***************************************************************************
1925  */
1926 int parse_sar_I_opt(char *argv[], int *opt, struct activity *act[])
1927 {
1928         int i, p;
1929         unsigned char c;
1930         char *t;
1931
1932         /* Select interrupt activity */
1933         p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1934         act[p]->options |= AO_SELECTED;
1935
1936         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1937                 if (!strcmp(t, K_SUM)) {
1938                         /* Select total number of interrupts */
1939                         act[p]->bitmap->b_array[0] |= 0x01;
1940                 }
1941                 else if (!strcmp(t, K_ALL)) {
1942                         /* Set bit for the first 16 individual interrupts */
1943                         act[p]->bitmap->b_array[0] |= 0xfe;
1944                         act[p]->bitmap->b_array[1] |= 0xff;
1945                         act[p]->bitmap->b_array[2] |= 0x01;
1946                 }
1947                 else if (!strcmp(t, K_XALL)) {
1948                         /* Set every bit except for total number of interrupts */
1949                         c = act[p]->bitmap->b_array[0];
1950                         set_bitmap(act[p]->bitmap->b_array, ~0,
1951                                    BITMAP_SIZE(act[p]->bitmap->b_size));
1952                         act[p]->bitmap->b_array[0] = 0xfe | c;
1953                 }
1954                 else {
1955                         /* Get irq number */
1956                         if (strspn(t, DIGITS) != strlen(t))
1957                                 return 1;
1958                         i = atoi(t);
1959                         if ((i < 0) || (i >= act[p]->bitmap->b_size))
1960                                 return 1;
1961                         act[p]->bitmap->b_array[(i + 1) >> 3] |= 1 << ((i + 1) & 0x07);
1962                 }
1963         }
1964
1965         (*opt)++;
1966         return 0;
1967 }
1968
1969 /*
1970  ***************************************************************************
1971  * Parse sar and sadf "-P" option.
1972  *
1973  * IN:
1974  * @argv        Arguments list.
1975  * @opt         Index in list of arguments.
1976  * @act         Array of activities.
1977  *
1978  * OUT:
1979  * @flags       Common flags and system state.
1980  * @act         Array of activities, with CPUs selected.
1981  *
1982  * RETURNS:
1983  * 0 on success, 1 otherwise.
1984  ***************************************************************************
1985  */
1986 int parse_sa_P_opt(char *argv[], int *opt, unsigned int *flags, struct activity *act[])
1987 {
1988         int i, p;
1989         char *t;
1990
1991         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1992
1993         if (argv[++(*opt)]) {
1994
1995                 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1996                         if (!strcmp(t, K_ALL)) {
1997                                 /*
1998                                  * Set bit for every processor.
1999                                  * We still don't know if we are going to read stats
2000                                  * from a file or not...
2001                                  */
2002                                 set_bitmap(act[p]->bitmap->b_array, ~0,
2003                                            BITMAP_SIZE(act[p]->bitmap->b_size));
2004                         }
2005                         else {
2006                                 /* Get cpu number */
2007                                 if (strspn(t, DIGITS) != strlen(t))
2008                                         return 1;
2009                                 i = atoi(t);
2010                                 if ((i < 0) || (i >= act[p]->bitmap->b_size))
2011                                         return 1;
2012                                 act[p]->bitmap->b_array[(i + 1) >> 3] |= 1 << ((i + 1) & 0x07);
2013                         }
2014                 }
2015                 (*opt)++;
2016         }
2017         else
2018                 return 1;
2019
2020         return 0;
2021 }
2022
2023 /*
2024  ***************************************************************************
2025  * Compute network interface utilization.
2026  *
2027  * IN:
2028  * @st_net_dev  Structure with network interface stats.
2029  * @rx          Number of bytes received per second.
2030  * @tx          Number of bytes transmitted per second.
2031  *
2032  * RETURNS:
2033  * NIC utilization (0-100%).
2034  ***************************************************************************
2035  */
2036 double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx)
2037 {
2038         unsigned long long speed;
2039
2040         if (st_net_dev->speed) {
2041
2042                 speed = (unsigned long long) st_net_dev->speed * 1000000;
2043
2044                 if (st_net_dev->duplex == C_DUPLEX_FULL) {
2045                         /* Full duplex */
2046                         if (rx > tx) {
2047                                 return (rx * 800 / speed);
2048                         }
2049                         else {
2050                                 return (tx * 800 / speed);
2051                         }
2052                 }
2053                 else {
2054                         /* Half duplex */
2055                         return ((rx + tx) * 800 / speed);
2056                 }
2057         }
2058
2059         return 0;
2060 }
2061
2062 /*
2063  ***************************************************************************
2064  * Fill system activity file magic header.
2065  *
2066  * IN:
2067  * @file_magic  System activity file magic header.
2068  ***************************************************************************
2069  */
2070 void enum_version_nr(struct file_magic *fm)
2071 {
2072         char *v;
2073         char version[16];
2074
2075         fm->sysstat_extraversion = 0;
2076
2077         strcpy(version, VERSION);
2078
2079         /* Get version number */
2080         if ((v = strtok(version, ".")) == NULL)
2081                 return;
2082         fm->sysstat_version = atoi(v) & 0xff;
2083
2084         /* Get patchlevel number */
2085         if ((v = strtok(NULL, ".")) == NULL)
2086                 return;
2087         fm->sysstat_patchlevel = atoi(v) & 0xff;
2088
2089         /* Get sublevel number */
2090         if ((v = strtok(NULL, ".")) == NULL)
2091                 return;
2092         fm->sysstat_sublevel = atoi(v) & 0xff;
2093
2094         /* Get extraversion number. Don't necessarily exist */
2095         if ((v = strtok(NULL, ".")) == NULL)
2096                 return;
2097         fm->sysstat_extraversion = atoi(v) & 0xff;
2098 }
2099
2100 /*
2101  ***************************************************************************
2102  * Read and replace unprintable characters in comment with ".".
2103  *
2104  * IN:
2105  * @ifd         Input file descriptor.
2106  * @comment     Comment.
2107  ***************************************************************************
2108  */
2109 void replace_nonprintable_char(int ifd, char *comment)
2110 {
2111         int i;
2112
2113         /* Read comment */
2114         sa_fread(ifd, comment, MAX_COMMENT_LEN, HARD_SIZE);
2115         comment[MAX_COMMENT_LEN - 1] = '\0';
2116
2117         /* Replace non printable chars */
2118         for (i = 0; i < strlen(comment); i++) {
2119                 if (!isprint(comment[i]))
2120                         comment[i] = '.';
2121         }
2122 }
2123
2124 /*
2125  ***************************************************************************
2126  * Fill the rectime and loctime structures with current record's date and
2127  * time, based on current record's "number of seconds since the epoch" saved
2128  * in file.
2129  * For loctime (if given): The timestamp is expressed in local time.
2130  * For rectime: The timestamp is expressed in UTC, in local time, or in the
2131  * time of the file's creator depending on options entered by the user on the
2132  * command line.
2133  *
2134  * IN:
2135  * @l_flags     Flags indicating the type of time expected by the user.
2136  *              S_F_LOCAL_TIME means time should be expressed in local time.
2137  *              S_F_TRUE_TIME means time should be expressed in time of
2138  *              file's creator.
2139  *              Default is time expressed in UTC (except for sar, where it
2140  *              is local time).
2141  * @record_hdr  Record header containing the number of seconds since the
2142  *              epoch, and the HH:MM:SS of the file's creator.
2143  *
2144  * OUT:
2145  * @rectime     Structure where timestamp for current record has been saved
2146  *              (in local time or in UTC depending on options used).
2147  * @loctime     If given, structure where timestamp for current record has
2148  *              been saved (expressed in local time). This field will be used
2149  *              for time comparison if options -s and/or -e have been used.
2150  *
2151  * RETURNS:
2152  * 1 if an error was detected, or 0 otherwise.
2153  ***************************************************************************
2154 */
2155 int sa_get_record_timestamp_struct(unsigned int l_flags, struct record_header *record_hdr,
2156                                    struct tm *rectime, struct tm *loctime)
2157 {
2158         struct tm *ltm = NULL;
2159         int rc = 0;
2160
2161         /* Fill localtime structure if given */
2162         if (loctime) {
2163                 if ((ltm = localtime((const time_t *) &(record_hdr->ust_time))) != NULL) {
2164                         *loctime = *ltm;
2165                 }
2166                 else {
2167                         rc = 1;
2168                 }
2169         }
2170
2171         /* Fill generic rectime structure */
2172         if (PRINT_LOCAL_TIME(l_flags) && !ltm) {
2173                 /* Get local time if not already done */
2174                 ltm = localtime((const time_t *) &(record_hdr->ust_time));
2175         }
2176
2177         if (!PRINT_LOCAL_TIME(l_flags) && !PRINT_TRUE_TIME(l_flags)) {
2178                 /*
2179                  * Get time in UTC
2180                  * (the user doesn't want local time nor time of file's creator).
2181                  */
2182                 ltm = gmtime((const time_t *) &(record_hdr->ust_time));
2183         }
2184
2185         if (ltm) {
2186                 /* Done even in true time mode so that we have some default values */
2187                 *rectime = *ltm;
2188         }
2189         else {
2190                 rc = 1;
2191         }
2192
2193         if (PRINT_TRUE_TIME(l_flags)) {
2194                 /* Time of file's creator */
2195                 rectime->tm_hour = record_hdr->hour;
2196                 rectime->tm_min  = record_hdr->minute;
2197                 rectime->tm_sec  = record_hdr->second;
2198         }
2199
2200         return rc;
2201 }
2202
2203 /*
2204  ***************************************************************************
2205  * Set current record's timestamp strings (date and time) using the time
2206  * data saved in @rectime structure. The string may be the number of seconds
2207  * since the epoch if flag S_F_SEC_EPOCH has been set.
2208  *
2209  * IN:
2210  * @l_flags     Flags indicating the type of time expected by the user.
2211  *              S_F_SEC_EPOCH means the time should be expressed in seconds
2212  *              since the epoch (01/01/1970).
2213  * @record_hdr  Record header containing the number of seconds since the
2214  *              epoch.
2215  * @cur_date    String where timestamp's date will be saved. May be NULL.
2216  * @cur_time    String where timestamp's time will be saved.
2217  * @len         Maximum length of timestamp strings.
2218  * @rectime     Structure with current timestamp (expressed in local time or
2219  *              in UTC depending on whether options -T or -t have been used
2220  *              or not) that should be broken down in date and time strings.
2221  *
2222  * OUT:
2223  * @cur_date    Timestamp's date string (if expected).
2224  * @cur_time    Timestamp's time string. May contain the number of seconds
2225  *              since the epoch (01-01-1970) if corresponding option has
2226  *              been used.
2227  ***************************************************************************
2228 */
2229 void set_record_timestamp_string(unsigned int l_flags, struct record_header *record_hdr,
2230                                  char *cur_date, char *cur_time, int len, struct tm *rectime)
2231 {
2232         /* Set cur_time date value */
2233         if (PRINT_SEC_EPOCH(l_flags) && cur_date) {
2234                 sprintf(cur_time, "%ld", record_hdr->ust_time);
2235                 strcpy(cur_date, "");
2236         }
2237         else {
2238                 /*
2239                  * If options -T or -t have been used then cur_time is
2240                  * expressed in local time. Else it is expressed in UTC.
2241                  */
2242                 if (cur_date) {
2243                         strftime(cur_date, len, "%Y-%m-%d", rectime);
2244                 }
2245                 if (USE_PREFD_TIME_OUTPUT(l_flags)) {
2246                         strftime(cur_time, len, "%X", rectime);
2247                 }
2248                 else {
2249                         strftime(cur_time, len, "%H:%M:%S", rectime);
2250                 }
2251         }
2252 }
2253
2254 /*
2255  ***************************************************************************
2256  * Print contents of a special (RESTART or COMMENT) record.
2257  *
2258  * IN:
2259  * @record_hdr  Current record header.
2260  * @l_flags     Flags for common options.
2261  * @tm_start    Structure filled when option -s has been used.
2262  * @tm_end      Structure filled when option -e has been used.
2263  * @rtype       Record type (R_RESTART or R_COMMENT).
2264  * @ifd         Input file descriptor.
2265  * @rectime     Structure where timestamp (expressed in local time or in UTC
2266  *              depending on whether options -T/-t have been used or not) can
2267  *              be saved for current record.
2268  * @loctime     Structure where timestamp (expressed in local time) can be
2269  *              saved for current record. May be NULL.
2270  * @file        Name of file being read.
2271  * @tab         Number of tabulations to print.
2272  * @file_magic  file_magic structure filled with file magic header data.
2273  * @file_hdr    System activity file standard header.
2274  * @act         Array of activities.
2275  * @ofmt                Pointer on report output format structure.
2276  *
2277  * OUT:
2278  * @rectime             Structure where timestamp (expressed in local time
2279  *                      or in UTC) has been saved.
2280  * @loctime             Structure where timestamp (expressed in local time)
2281  *                      has been saved (if requested).
2282  *
2283  * RETURNS:
2284  * 1 if the record has been successfully displayed, and 0 otherwise.
2285  ***************************************************************************
2286  */
2287 int print_special_record(struct record_header *record_hdr, unsigned int l_flags,
2288                          struct tstamp *tm_start, struct tstamp *tm_end, int rtype, int ifd,
2289                          struct tm *rectime, struct tm *loctime, char *file, int tab,
2290                          struct file_magic *file_magic, struct file_header *file_hdr,
2291                          struct activity *act[], struct report_format *ofmt)
2292 {
2293         char cur_date[TIMESTAMP_LEN], cur_time[TIMESTAMP_LEN];
2294         int dp = 1;
2295         unsigned int new_cpu_nr;
2296
2297         /* Fill timestamp structure (rectime) for current record */
2298         if (sa_get_record_timestamp_struct(l_flags, record_hdr, rectime, loctime))
2299                 return 0;
2300
2301         /* If loctime is NULL, then use rectime for comparison */
2302         if (!loctime) {
2303                 loctime = rectime;
2304         }
2305
2306         /* The record must be in the interval specified by -s/-e options */
2307         if ((tm_start->use && (datecmp(loctime, tm_start) < 0)) ||
2308             (tm_end->use && (datecmp(loctime, tm_end) > 0))) {
2309                 /* Will not display the special record */
2310                 dp = 0;
2311         }
2312         else {
2313                 /* Set date and time strings to be displayed for current record */
2314                 set_record_timestamp_string(l_flags, record_hdr,
2315                                             cur_date, cur_time, TIMESTAMP_LEN, rectime);
2316         }
2317
2318         if (rtype == R_RESTART) {
2319                 /* Don't forget to read the volatile activities structures */
2320                 new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic,
2321                                                      file_hdr->sa_vol_act_nr);
2322
2323                 if (!dp)
2324                         return 0;
2325
2326                 if (*ofmt->f_restart) {
2327                         (*ofmt->f_restart)(&tab, F_MAIN, cur_date, cur_time,
2328                                            !PRINT_LOCAL_TIME(l_flags) &&
2329                                            !PRINT_TRUE_TIME(l_flags), file_hdr,
2330                                            new_cpu_nr);
2331                 }
2332         }
2333         else if (rtype == R_COMMENT) {
2334                 char file_comment[MAX_COMMENT_LEN];
2335
2336                 /* Read and replace non printable chars in comment */
2337                 replace_nonprintable_char(ifd, file_comment);
2338
2339                 if (!dp || !DISPLAY_COMMENT(l_flags))
2340                         return 0;
2341
2342                 if (*ofmt->f_comment) {
2343                         (*ofmt->f_comment)(&tab, F_MAIN, cur_date, cur_time,
2344                                            !PRINT_LOCAL_TIME(l_flags) &&
2345                                            !PRINT_TRUE_TIME(l_flags), file_comment,
2346                                            file_hdr);
2347                 }
2348         }
2349
2350         return 1;
2351 }