]> granicus.if.org Git - sysstat/blob - sa_common.c
SVG: Add SVG output for NFS client statistics
[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 }
616
617 /*
618  ***************************************************************************
619  * Network interfaces may now be registered (and unregistered) dynamically.
620  * This is what we try to guess here.
621  *
622  * IN:
623  * @a           Activity structure with statistics.
624  * @curr        Index in array for current sample statistics.
625  * @ref         Index in array for sample statistics used as reference.
626  * @pos         Index on current network interface.
627  *
628  * RETURNS:
629  * Position of current network interface in array of sample statistics used
630  * as reference.
631  ***************************************************************************
632  */
633 unsigned int check_net_dev_reg(struct activity *a, int curr, int ref,
634                                unsigned int pos)
635 {
636         struct stats_net_dev *sndc, *sndp;
637         unsigned int index = 0;
638
639         sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + pos * a->msize);
640
641         while (index < a->nr) {
642                 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
643                 if (!strcmp(sndc->interface, sndp->interface)) {
644                         /*
645                          * Network interface found.
646                          * If a counter has decreased, then we may assume that the
647                          * corresponding interface was unregistered, then registered again.
648                          */
649                         if ((sndc->rx_packets    < sndp->rx_packets)    ||
650                             (sndc->tx_packets    < sndp->tx_packets)    ||
651                             (sndc->rx_bytes      < sndp->rx_bytes)      ||
652                             (sndc->tx_bytes      < sndp->tx_bytes)      ||
653                             (sndc->rx_compressed < sndp->rx_compressed) ||
654                             (sndc->tx_compressed < sndp->tx_compressed) ||
655                             (sndc->multicast     < sndp->multicast)) {
656
657                                 /*
658                                  * Special processing for rx_bytes (_packets) and
659                                  * tx_bytes (_packets) counters: If the number of
660                                  * bytes (packets) has decreased, whereas the number of
661                                  * packets (bytes) has increased, then assume that the
662                                  * relevant counter has met an overflow condition, and that
663                                  * the interface was not unregistered, which is all the
664                                  * more plausible that the previous value for the counter
665                                  * was > ULONG_MAX/2.
666                                  * NB: the average value displayed will be wrong in this case...
667                                  *
668                                  * If such an overflow is detected, just set the flag. There is no
669                                  * need to handle this in a special way: the difference is still
670                                  * properly calculated if the result is of the same type (i.e.
671                                  * unsigned long) as the two values.
672                                  */
673                                 int ovfw = FALSE;
674
675                                 if ((sndc->rx_bytes   < sndp->rx_bytes)   &&
676                                     (sndc->rx_packets > sndp->rx_packets) &&
677                                     (sndp->rx_bytes   > (~0UL >> 1))) {
678                                         ovfw = TRUE;
679                                 }
680                                 if ((sndc->tx_bytes   < sndp->tx_bytes)   &&
681                                     (sndc->tx_packets > sndp->tx_packets) &&
682                                     (sndp->tx_bytes   > (~0UL >> 1))) {
683                                         ovfw = TRUE;
684                                 }
685                                 if ((sndc->rx_packets < sndp->rx_packets) &&
686                                     (sndc->rx_bytes   > sndp->rx_bytes)   &&
687                                     (sndp->rx_packets > (~0UL >> 1))) {
688                                         ovfw = TRUE;
689                                 }
690                                 if ((sndc->tx_packets < sndp->tx_packets) &&
691                                     (sndc->tx_bytes   > sndp->tx_bytes)   &&
692                                     (sndp->tx_packets > (~0UL >> 1))) {
693                                         ovfw = TRUE;
694                                 }
695
696                                 if (!ovfw) {
697                                         /*
698                                          * OK: assume here that the device was
699                                          * actually unregistered.
700                                          */
701                                         memset(sndp, 0, STATS_NET_DEV_SIZE);
702                                         strcpy(sndp->interface, sndc->interface);
703                                 }
704                         }
705                         return index;
706                 }
707                 index++;
708         }
709
710         /* Network interface not found: Look for the first free structure */
711         for (index = 0; index < a->nr; index++) {
712                 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
713                 if (!strcmp(sndp->interface, ""))
714                         break;
715         }
716         if (index >= a->nr) {
717                 /* No free structure: Default is structure of same rank */
718                 index = pos;
719         }
720
721         sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
722         /* Since the name is not the same, reset all the structure */
723         memset(sndp, 0, STATS_NET_DEV_SIZE);
724         strcpy(sndp->interface, sndc->interface);
725
726         return  index;
727 }
728
729 /*
730  ***************************************************************************
731  * Network interfaces may now be registered (and unregistered) dynamically.
732  * This is what we try to guess here.
733  *
734  * IN:
735  * @a           Activity structure with statistics.
736  * @curr        Index in array for current sample statistics.
737  * @ref         Index in array for sample statistics used as reference.
738  * @pos         Index on current network interface.
739  *
740  * RETURNS:
741  * Position of current network interface in array of sample statistics used
742  * as reference.
743  ***************************************************************************
744  */
745 unsigned int check_net_edev_reg(struct activity *a, int curr, int ref,
746                                 unsigned int pos)
747 {
748         struct stats_net_edev *snedc, *snedp;
749         unsigned int index = 0;
750
751         snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + pos * a->msize);
752
753         while (index < a->nr) {
754                 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
755                 if (!strcmp(snedc->interface, snedp->interface)) {
756                         /*
757                          * Network interface found.
758                          * If a counter has decreased, then we may assume that the
759                          * corresponding interface was unregistered, then registered again.
760                          */
761                         if ((snedc->tx_errors         < snedp->tx_errors)         ||
762                             (snedc->collisions        < snedp->collisions)        ||
763                             (snedc->rx_dropped        < snedp->rx_dropped)        ||
764                             (snedc->tx_dropped        < snedp->tx_dropped)        ||
765                             (snedc->tx_carrier_errors < snedp->tx_carrier_errors) ||
766                             (snedc->rx_frame_errors   < snedp->rx_frame_errors)   ||
767                             (snedc->rx_fifo_errors    < snedp->rx_fifo_errors)    ||
768                             (snedc->tx_fifo_errors    < snedp->tx_fifo_errors)) {
769
770                                 /*
771                                  * OK: assume here that the device was
772                                  * actually unregistered.
773                                  */
774                                 memset(snedp, 0, STATS_NET_EDEV_SIZE);
775                                 strcpy(snedp->interface, snedc->interface);
776                         }
777                         return index;
778                 }
779                 index++;
780         }
781
782         /* Network interface not found: Look for the first free structure */
783         for (index = 0; index < a->nr; index++) {
784                 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
785                 if (!strcmp(snedp->interface, ""))
786                         break;
787         }
788         if (index >= a->nr) {
789                 /* No free structure: Default is structure of same rank */
790                 index = pos;
791         }
792
793         snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
794         /* Since the name is not the same, reset all the structure */
795         memset(snedp, 0, STATS_NET_EDEV_SIZE);
796         strcpy(snedp->interface, snedc->interface);
797
798         return  index;
799 }
800
801 /*
802  ***************************************************************************
803  * Disks may be registered dynamically (true in /proc/stat file).
804  * This is what we try to guess here.
805  *
806  * IN:
807  * @a           Activity structure with statistics.
808  * @curr        Index in array for current sample statistics.
809  * @ref         Index in array for sample statistics used as reference.
810  * @pos         Index on current disk.
811  *
812  * RETURNS:
813  * Position of current disk in array of sample statistics used as reference.
814  ***************************************************************************
815  */
816 int check_disk_reg(struct activity *a, int curr, int ref, int pos)
817 {
818         struct stats_disk *sdc, *sdp;
819         int index = 0;
820
821         sdc = (struct stats_disk *) ((char *) a->buf[curr] + pos * a->msize);
822
823         while (index < a->nr) {
824                 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
825                 if ((sdc->major == sdp->major) &&
826                     (sdc->minor == sdp->minor)) {
827                         /*
828                          * Disk found.
829                          * If all the counters have decreased then the likelyhood
830                          * is that the disk has been unregistered and a new disk inserted.
831                          * If only one or two have decreased then the likelyhood
832                          * is that the counter has simply wrapped.
833                          */
834                         if ((sdc->nr_ios < sdp->nr_ios) &&
835                             (sdc->rd_sect < sdp->rd_sect) &&
836                             (sdc->wr_sect < sdp->wr_sect)) {
837
838                                 memset(sdp, 0, STATS_DISK_SIZE);
839                                 sdp->major = sdc->major;
840                                 sdp->minor = sdc->minor;
841                         }
842                         return index;
843                 }
844                 index++;
845         }
846
847         /* Disk not found: Look for the first free structure */
848         for (index = 0; index < a->nr; index++) {
849                 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
850                 if (!(sdp->major + sdp->minor))
851                         break;
852         }
853         if (index >= a->nr) {
854                 /* No free structure found: Default is structure of same rank */
855                 index = pos;
856         }
857
858         sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
859         /* Since the device is not the same, reset all the structure */
860         memset(sdp, 0, STATS_DISK_SIZE);
861         sdp->major = sdc->major;
862         sdp->minor = sdc->minor;
863
864         return index;
865 }
866
867 /*
868  ***************************************************************************
869  * Allocate bitmaps for activities that have one.
870  *
871  * IN:
872  * @act         Array of activities.
873  ***************************************************************************
874  */
875 void allocate_bitmaps(struct activity *act[])
876 {
877         int i;
878
879         for (i = 0; i < NR_ACT; i++) {
880                 /*
881                  * If current activity has a bitmap which has not already
882                  * been allocated, then allocate it.
883                  * Note that a same bitmap may be used by several activities.
884                  */
885                 if (act[i]->bitmap && !act[i]->bitmap->b_array) {
886                         SREALLOC(act[i]->bitmap->b_array, unsigned char,
887                                  BITMAP_SIZE(act[i]->bitmap->b_size));
888                 }
889         }
890 }
891
892 /*
893  ***************************************************************************
894  * Free bitmaps for activities that have one.
895  *
896  * IN:
897  * @act         Array of activities.
898  ***************************************************************************
899  */
900 void free_bitmaps(struct activity *act[])
901 {
902         int i;
903
904         for (i = 0; i < NR_ACT; i++) {
905                 if (act[i]->bitmap && act[i]->bitmap->b_array) {
906                         free(act[i]->bitmap->b_array);
907                         /* Set pointer to NULL to prevent it from being freed again */
908                         act[i]->bitmap->b_array = NULL;
909                 }
910         }
911 }
912
913 /*
914  ***************************************************************************
915  * Look for activity in array.
916  *
917  * IN:
918  * @act         Array of activities.
919  * @act_flag    Activity flag to look for.
920  * @stop        TRUE if sysstat should exit when activity is not found.
921  *
922  * RETURNS:
923  * Position of activity in array, or -1 if not found (this may happen when
924  * reading data from a system activity file created by another version of
925  * sysstat).
926  ***************************************************************************
927  */
928 int get_activity_position(struct activity *act[], unsigned int act_flag, int stop)
929 {
930         int i;
931
932         for (i = 0; i < NR_ACT; i++) {
933                 if (act[i]->id == act_flag)
934                         return i;
935         }
936
937         if (stop) {
938                 PANIC((int) act_flag);
939         }
940
941         return -1;
942 }
943
944 /*
945  ***************************************************************************
946  * Count number of activities with given option.
947  *
948  * IN:
949  * @act                 Array of activities.
950  * @option              Option that activities should have to be counted
951  *                      (eg. AO_COLLECTED...)
952  * @count_outputs       TRUE if each output should be counted for activities with
953  *                      multiple outputs.
954  *
955  * RETURNS:
956  * Number of selected activities
957  ***************************************************************************
958  */
959 int get_activity_nr(struct activity *act[], unsigned int option, int count_outputs)
960 {
961         int i, n = 0;
962         unsigned int msk;
963
964         for (i = 0; i < NR_ACT; i++) {
965                 if ((act[i]->options & option) == option) {
966
967                         if (HAS_MULTIPLE_OUTPUTS(act[i]->options) && count_outputs) {
968                                 for (msk = 1; msk < 0x100; msk <<= 1) {
969                                         if ((act[i]->opt_flags & 0xff) & msk) {
970                                                 n++;
971                                         }
972                                 }
973                         }
974                         else {
975                                 n++;
976                         }
977                 }
978         }
979
980         return n;
981 }
982
983 /*
984  ***************************************************************************
985  * Select all activities, even if they have no associated items.
986  *
987  * IN:
988  * @act         Array of activities.
989  *
990  * OUT:
991  * @act         Array of activities, all of the being selected.
992  ***************************************************************************
993  */
994 void select_all_activities(struct activity *act[])
995 {
996         int i;
997
998         for (i = 0; i < NR_ACT; i++) {
999                 act[i]->options |= AO_SELECTED;
1000         }
1001 }
1002
1003 /*
1004  ***************************************************************************
1005  * Select CPU activity if no other activities have been explicitly selected.
1006  * Also select CPU "all" if no other CPU has been selected.
1007  *
1008  * IN:
1009  * @act         Array of activities.
1010  *
1011  * OUT:
1012  * @act         Array of activities with CPU activity selected if needed.
1013  ***************************************************************************
1014  */
1015 void select_default_activity(struct activity *act[])
1016 {
1017         int p;
1018
1019         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1020
1021         /* Default is CPU activity... */
1022         if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1023                 /*
1024                  * Still OK even when reading stats from a file
1025                  * since A_CPU activity is always recorded.
1026                  */
1027                 act[p]->options |= AO_SELECTED;
1028         }
1029
1030         /*
1031          * If no CPU's have been selected then select CPU "all".
1032          * cpu_bitmap bitmap may be used by several activities (A_CPU, A_PWR_CPUFREQ...)
1033          */
1034         if (!count_bits(cpu_bitmap.b_array, BITMAP_SIZE(cpu_bitmap.b_size))) {
1035                 cpu_bitmap.b_array[0] |= 0x01;
1036         }
1037 }
1038
1039 /*
1040  ***************************************************************************
1041  * Read data from a system activity data file.
1042  *
1043  * IN:
1044  * @ifd         Input file descriptor.
1045  * @buffer      Buffer where data are read.
1046  * @size        Number of bytes to read.
1047  * @mode        If set to HARD_SIZE, indicate that an EOF should be considered
1048  *              as an error.
1049  *
1050  * RETURNS:
1051  * 1 if EOF has been reached, 0 otherwise.
1052  ***************************************************************************
1053  */
1054 int sa_fread(int ifd, void *buffer, int size, int mode)
1055 {
1056         int n;
1057
1058         if ((n = read(ifd, buffer, size)) < 0) {
1059                 fprintf(stderr, _("Error while reading system activity file: %s\n"),
1060                         strerror(errno));
1061                 close(ifd);
1062                 exit(2);
1063         }
1064
1065         if (!n && (mode == SOFT_SIZE))
1066                 return 1;       /* EOF */
1067
1068         if (n < size) {
1069                 fprintf(stderr, _("End of system activity file unexpected\n"));
1070                 close(ifd);
1071                 exit(2);
1072         }
1073
1074         return 0;
1075 }
1076
1077 /*
1078  ***************************************************************************
1079  * Display sysstat version used to create system activity data file.
1080  *
1081  * IN:
1082  * @st          Output stream (stderr or stdout).
1083  * @file_magic  File magic header.
1084  ***************************************************************************
1085  */
1086 void display_sa_file_version(FILE *st, struct file_magic *file_magic)
1087 {
1088         fprintf(st, _("File created by sar/sadc from sysstat version %d.%d.%d"),
1089                 file_magic->sysstat_version,
1090                 file_magic->sysstat_patchlevel,
1091                 file_magic->sysstat_sublevel);
1092
1093         if (file_magic->sysstat_extraversion) {
1094                 fprintf(st, ".%d", file_magic->sysstat_extraversion);
1095         }
1096         fprintf(st, "\n");
1097 }
1098
1099 /*
1100  ***************************************************************************
1101  * An invalid system activity file has been opened for reading.
1102  * If this file was created by an old version of sysstat, tell it to the
1103  * user...
1104  *
1105  * IN:
1106  * @fd          Descriptor of the file that has been opened.
1107  * @file_magic  file_magic structure filled with file magic header data.
1108  *              May contain invalid data.
1109  * @file        Name of the file being read.
1110  * @n           Number of bytes read while reading file magic header.
1111  *              This function may also be called after failing to read file
1112  *              standard header, or if CPU activity has not been found in
1113  *              file. In this case, n is set to 0.
1114  ***************************************************************************
1115  */
1116 void handle_invalid_sa_file(int *fd, struct file_magic *file_magic, char *file,
1117                             int n)
1118 {
1119         unsigned short sm;
1120
1121         fprintf(stderr, _("Invalid system activity file: %s\n"), file);
1122
1123         if (n == FILE_MAGIC_SIZE) {
1124                 sm = (file_magic->sysstat_magic << 8) | (file_magic->sysstat_magic >> 8);
1125                 if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (sm == SYSSTAT_MAGIC)) {
1126                         /*
1127                          * This is a sysstat file, but this file has an old format
1128                          * or its internal endian format doesn't match.
1129                          */
1130                         display_sa_file_version(stderr, file_magic);
1131
1132                         if (sm == SYSSTAT_MAGIC) {
1133                                 fprintf(stderr, _("Endian format mismatch\n"));
1134                         }
1135                         else {
1136                                 fprintf(stderr,
1137                                         _("Current sysstat version cannot read the format of this file (%#x)\n"),
1138                                         file_magic->format_magic);
1139                         }
1140                 }
1141         }
1142
1143         close (*fd);
1144         exit(3);
1145 }
1146
1147 /*
1148  ***************************************************************************
1149  * Move structures data.
1150  *
1151  * IN:
1152  * @act         Array of activities.
1153  * @id_seq      Activity sequence in file.
1154  * @record_hdr  Current record header.
1155  * @dest        Index in array where stats have to be copied to.
1156  * @src         Index in array where stats to copy are.
1157  ***************************************************************************
1158  */
1159 void copy_structures(struct activity *act[], unsigned int id_seq[],
1160                      struct record_header record_hdr[], int dest, int src)
1161 {
1162         int i, p;
1163
1164         memcpy(&record_hdr[dest], &record_hdr[src], RECORD_HEADER_SIZE);
1165
1166         for (i = 0; i < NR_ACT; i++) {
1167
1168                 if (!id_seq[i])
1169                         continue;
1170
1171                 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1172                 if ((act[p]->nr < 1) || (act[p]->nr2 < 1)) {
1173                         PANIC(1);
1174                 }
1175
1176                 memcpy(act[p]->buf[dest], act[p]->buf[src],
1177                        (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
1178         }
1179 }
1180
1181 /*
1182  ***************************************************************************
1183  * Read varying part of the statistics from a daily data file.
1184  *
1185  * IN:
1186  * @act         Array of activities.
1187  * @curr        Index in array for current sample statistics.
1188  * @ifd         Input file descriptor.
1189  * @act_nr      Number of activities in file.
1190  * @file_actlst Activity list in file.
1191  ***************************************************************************
1192  */
1193 void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
1194                           struct file_activity *file_actlst)
1195 {
1196         int i, j, k, p;
1197         struct file_activity *fal = file_actlst;
1198         off_t offset;
1199
1200         for (i = 0; i < act_nr; i++, fal++) {
1201
1202                 if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
1203                     (act[p]->magic != fal->magic)) {
1204                         /*
1205                          * Ignore current activity in file, which is unknown to
1206                          * current sysstat version or has an unknown format.
1207                          */
1208                         offset = (off_t) fal->size * (off_t) fal->nr * (off_t) fal->nr2;
1209                         if (lseek(ifd, offset, SEEK_CUR) < offset) {
1210                                 close(ifd);
1211                                 perror("lseek");
1212                                 exit(2);
1213                         }
1214                 }
1215                 else if ((act[p]->nr > 0) &&
1216                          ((act[p]->nr > 1) || (act[p]->nr2 > 1)) &&
1217                          (act[p]->msize > act[p]->fsize)) {
1218                         for (j = 0; j < act[p]->nr; j++) {
1219                                 for (k = 0; k < act[p]->nr2; k++) {
1220                                         sa_fread(ifd,
1221                                                  (char *) act[p]->buf[curr] + (j * act[p]->nr2 + k) * act[p]->msize,
1222                                                  act[p]->fsize, HARD_SIZE);
1223                                 }
1224                         }
1225                 }
1226                 else if (act[p]->nr > 0) {
1227                         sa_fread(ifd, act[p]->buf[curr], act[p]->fsize * act[p]->nr * act[p]->nr2, HARD_SIZE);
1228                 }
1229                 else {
1230                         PANIC(p);
1231                 }
1232         }
1233 }
1234
1235 /*
1236  ***************************************************************************
1237  * Open a sysstat activity data file and read its magic structure.
1238  *
1239  * IN:
1240  * @dfile       Name of system activity data file.
1241  * @ignore      Set to 1 if a true sysstat activity file but with a bad
1242  *              format should not yield an error message. Useful with
1243  *              sadf -H and sadf -c.
1244  *
1245  * OUT:
1246  * @fd          System activity data file descriptor.
1247  * @file_magic  file_magic structure containing data read from file magic
1248  *              header.
1249  *
1250  * RETURNS:
1251  * -1 if data file is a sysstat file with an old format, 0 otherwise.
1252  ***************************************************************************
1253  */
1254 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
1255                        int ignore)
1256 {
1257         int n;
1258
1259         /* Open sa data file */
1260         if ((*fd = open(dfile, O_RDONLY)) < 0) {
1261                 int saved_errno = errno;
1262
1263                 fprintf(stderr, _("Cannot open %s: %s\n"), dfile, strerror(errno));
1264
1265                 if ((saved_errno == ENOENT) && default_file_used) {
1266                         fprintf(stderr, _("Please check if data collecting is enabled\n"));
1267                 }
1268                 exit(2);
1269         }
1270
1271         /* Read file magic data */
1272         n = read(*fd, file_magic, FILE_MAGIC_SIZE);
1273
1274         if ((n != FILE_MAGIC_SIZE) ||
1275             (file_magic->sysstat_magic != SYSSTAT_MAGIC) ||
1276             ((file_magic->format_magic != FORMAT_MAGIC) && !ignore) ||
1277             (file_magic->header_size < MIN_FILE_HEADER_SIZE) ||
1278             (file_magic->header_size > MAX_FILE_HEADER_SIZE) ||
1279             ((file_magic->header_size < FILE_HEADER_SIZE) && !ignore)) {
1280                 /* Display error message and exit */
1281                 handle_invalid_sa_file(fd, file_magic, dfile, n);
1282         }
1283         if (file_magic->format_magic != FORMAT_MAGIC)
1284                 /* This is an old sa datafile format */
1285                 return -1;
1286
1287         return 0;
1288 }
1289
1290 /*
1291  ***************************************************************************
1292  * Open a data file, and perform various checks before reading.
1293  *
1294  * IN:
1295  * @dfile       Name of system activity data file.
1296  * @act         Array of activities.
1297  * @ignore      Set to 1 if a true sysstat activity file but with a bad
1298  *              format should not yield an error message. Useful with
1299  *              sadf -H and sadf -c.
1300  *
1301  * OUT:
1302  * @ifd         System activity data file descriptor.
1303  * @file_magic  file_magic structure containing data read from file magic
1304  *              header.
1305  * @file_hdr    file_hdr structure containing data read from file standard
1306  *              header.
1307  * @file_actlst Acvtivity list in file.
1308  * @id_seq      Activity sequence.
1309  ***************************************************************************
1310  */
1311 void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
1312                        struct file_magic *file_magic, struct file_header *file_hdr,
1313                        struct file_activity **file_actlst, unsigned int id_seq[],
1314                        int ignore)
1315 {
1316         int i, j, p;
1317         unsigned int a_cpu = FALSE;
1318         struct file_activity *fal;
1319         void *buffer = NULL;
1320
1321         /* Open sa data file and read its magic structure */
1322         if (sa_open_read_magic(ifd, dfile, file_magic, ignore) < 0)
1323                 return;
1324
1325         SREALLOC(buffer, char, file_magic->header_size);
1326
1327         /* Read sa data file standard header and allocate activity list */
1328         sa_fread(*ifd, buffer, file_magic->header_size, HARD_SIZE);
1329         /*
1330          * Data file header size may be greater than FILE_HEADER_SIZE, but
1331          * anyway only the first FILE_HEADER_SIZE bytes can be interpreted.
1332          */
1333         memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
1334         free(buffer);
1335
1336         /*
1337          * Sanity check.
1338          * Compare against MAX_NR_ACT and not NR_ACT because
1339          * we are maybe reading a datafile from a future sysstat version
1340          * with more activities than known today.
1341          */
1342         if (file_hdr->sa_act_nr > MAX_NR_ACT) {
1343                 /* Maybe a "false positive" sysstat datafile? */
1344                 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1345         }
1346
1347         SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
1348         fal = *file_actlst;
1349
1350         /* Read activity list */
1351         j = 0;
1352         for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1353
1354                 sa_fread(*ifd, fal, FILE_ACTIVITY_SIZE, HARD_SIZE);
1355
1356                 /*
1357                  * Every activity, known or unknown, should have
1358                  * at least one item and sub-item.
1359                  * Also check that the number of items and sub-items
1360                  * doesn't exceed a max value. This is necessary
1361                  * because we will use @nr and @nr2 to
1362                  * allocate memory to read the file contents. So we
1363                  * must make sure the file is not corrupted.
1364                  * NB: Another check will be made below for known
1365                  * activities which have each a specific max value.
1366                  */
1367                 if ((fal->nr < 1) || (fal->nr2 < 1) ||
1368                     (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX)) {
1369                         handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1370                 }
1371
1372                 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0)
1373                         /* Unknown activity */
1374                         continue;
1375
1376                 if (act[p]->magic != fal->magic) {
1377                         /* Bad magical number */
1378                         if (ignore) {
1379                                 /*
1380                                  * This is how sadf -H knows that this
1381                                  * activity has an unknown format.
1382                                  */
1383                                 act[p]->magic = ACTIVITY_MAGIC_UNKNOWN;
1384                         }
1385                         else
1386                                 continue;
1387                 }
1388
1389                 /* Check max value for known activities */
1390                 if (fal->nr > act[p]->nr_max) {
1391                         handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1392                 }
1393
1394                 if (fal->id == A_CPU) {
1395                         a_cpu = TRUE;
1396                 }
1397
1398                 if (fal->size > act[p]->msize) {
1399                         act[p]->msize = fal->size;
1400                 }
1401                 /*
1402                  * NOTA BENE:
1403                  * If current activity is a volatile one then fal->nr is the
1404                  * number of items (CPU at the present time as only CPU related
1405                  * activities are volatile today) for the statistics located
1406                  * between the start of the data file and the first restart mark.
1407                  * Volatile activities have a number of items which can vary
1408                  * in file. In this case, a RESTART record is followed by the
1409                  * volatile activity structures.
1410                  */
1411                 act[p]->nr    = fal->nr;
1412                 act[p]->nr2   = fal->nr2;
1413                 act[p]->fsize = fal->size;
1414                 /*
1415                  * This is a known activity with a known format
1416                  * (magical number). Only such activities will be displayed.
1417                  * (Well, this may also be an unknown format if we have entered sadf -H.)
1418                  */
1419                 id_seq[j++] = fal->id;
1420         }
1421
1422         if (!a_cpu) {
1423                 /*
1424                  * CPU activity should always be in file
1425                  * and have a known format (expected magical number).
1426                  */
1427                 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1428         }
1429
1430         while (j < NR_ACT) {
1431                 id_seq[j++] = 0;
1432         }
1433
1434         /* Check that at least one selected activity is available in file */
1435         for (i = 0; i < NR_ACT; i++) {
1436
1437                 if (!IS_SELECTED(act[i]->options))
1438                         continue;
1439
1440                 /* Here is a selected activity: Does it exist in file? */
1441                 fal = *file_actlst;
1442                 for (j = 0; j < file_hdr->sa_act_nr; j++, fal++) {
1443                         if (act[i]->id == fal->id)
1444                                 break;
1445                 }
1446                 if (j == file_hdr->sa_act_nr) {
1447                         /* No: Unselect it */
1448                         act[i]->options &= ~AO_SELECTED;
1449                 }
1450         }
1451         if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1452                 fprintf(stderr, _("Requested activities not available in file %s\n"),
1453                         dfile);
1454                 close(*ifd);
1455                 exit(1);
1456         }
1457 }
1458
1459 /*
1460  ***************************************************************************
1461  * Set number of items for current volatile activity and reallocate its
1462  * structures accordingly.
1463  * NB: As only activities related to CPU can be volatile, the number of
1464  * items corresponds in fact to the number of CPU.
1465  *
1466  * IN:
1467  * @act         Array of activities.
1468  * @act_nr      Number of items for current volatile activity.
1469  * @act_id      Activity identification for current volatile activity.
1470  *
1471  * RETURN:
1472  * -1 if unknown activity and 0 otherwise.
1473  ***************************************************************************
1474  */
1475 int reallocate_vol_act_structures(struct activity *act[], unsigned int act_nr,
1476                                    unsigned int act_id)
1477 {
1478         int j, p;
1479
1480         if ((p = get_activity_position(act, act_id, RESUME_IF_NOT_FOUND)) < 0)
1481                 /* Ignore unknown activity */
1482                 return -1;
1483
1484         act[p]->nr = act_nr;
1485
1486         for (j = 0; j < 3; j++) {
1487                 SREALLOC(act[p]->buf[j], void,
1488                          (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
1489         }
1490
1491         return 0;
1492 }
1493
1494 /*
1495  ***************************************************************************
1496  * Read the volatile activities structures following a RESTART record.
1497  * Then set number of items for each corresponding activity and reallocate
1498  * structures.
1499  *
1500  * IN:
1501  * @ifd         Input file descriptor.
1502  * @act         Array of activities.
1503  * @file        Name of file being read.
1504  * @file_magic  file_magic structure filled with file magic header data.
1505  * @vol_act_nr  Number of volatile activities structures to read.
1506  *
1507  * RETURNS:
1508  * New number of items.
1509  *
1510  * NB: As only activities related to CPU can be volatile, the new number of
1511  * items corresponds in fact to the new number of CPU.
1512  ***************************************************************************
1513  */
1514 __nr_t read_vol_act_structures(int ifd, struct activity *act[], char *file,
1515                                struct file_magic *file_magic,
1516                                unsigned int vol_act_nr)
1517 {
1518         struct file_activity file_act;
1519         int item_nr = 0;
1520         int i, rc;
1521
1522         for (i = 0; i < vol_act_nr; i++) {
1523
1524                 sa_fread(ifd, &file_act, FILE_ACTIVITY_SIZE, HARD_SIZE);
1525
1526                 if (file_act.id) {
1527                         rc = reallocate_vol_act_structures(act, file_act.nr, file_act.id);
1528                         if ((rc == 0) && !item_nr) {
1529                                 item_nr = file_act.nr;
1530                         }
1531                 }
1532                 /* else ignore empty structures that may exist */
1533         }
1534
1535         if (!item_nr) {
1536                 /* All volatile activities structures cannot be empty */
1537                 handle_invalid_sa_file(&ifd, file_magic, file, 0);
1538         }
1539
1540         return item_nr;
1541 }
1542
1543 /*
1544  ***************************************************************************
1545  * Parse sar activities options (also used by sadf).
1546  *
1547  * IN:
1548  * @argv        Arguments list.
1549  * @opt         Index in list of arguments.
1550  * @caller      Indicate whether it's sar or sadf that called this function.
1551  *
1552  * OUT:
1553  * @act         Array of selected activities.
1554  * @flags       Common flags and system state.
1555  *
1556  * RETURNS:
1557  * 0 on success.
1558  ***************************************************************************
1559  */
1560 int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
1561                   unsigned int *flags, int caller)
1562 {
1563         int i, p;
1564
1565         for (i = 1; *(argv[*opt] + i); i++) {
1566                 /*
1567                  * Note: argv[*opt] contains something like "-BruW"
1568                  *     *(argv[*opt] + i) will contain 'B', 'r', etc.
1569                  */
1570
1571                 switch (*(argv[*opt] + i)) {
1572
1573                 case 'A':
1574                         select_all_activities(act);
1575
1576                         /* Force '-P ALL -I XALL -r ALL -u ALL' */
1577
1578                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1579                         act[p]->opt_flags |= AO_F_MEM_AMT + AO_F_MEM_DIA +
1580                                              AO_F_MEM_SWAP + AO_F_MEM_ALL;
1581
1582                         p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1583                         set_bitmap(act[p]->bitmap->b_array, ~0,
1584                                    BITMAP_SIZE(act[p]->bitmap->b_size));
1585
1586                         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1587                         set_bitmap(act[p]->bitmap->b_array, ~0,
1588                                    BITMAP_SIZE(act[p]->bitmap->b_size));
1589                         act[p]->opt_flags = AO_F_CPU_ALL;
1590                         break;
1591
1592                 case 'B':
1593                         SELECT_ACTIVITY(A_PAGE);
1594                         break;
1595
1596                 case 'b':
1597                         SELECT_ACTIVITY(A_IO);
1598                         break;
1599
1600                 case 'C':
1601                         *flags |= S_F_COMMENT;
1602                         break;
1603
1604                 case 'd':
1605                         SELECT_ACTIVITY(A_DISK);
1606                         break;
1607
1608                 case 'F':
1609                         p = get_activity_position(act, A_FILESYSTEM, EXIT_IF_NOT_FOUND);
1610                         act[p]->options |= AO_SELECTED;
1611                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_MOUNT)) {
1612                                 (*opt)++;
1613                                 act[p]->opt_flags |= AO_F_MOUNT;
1614                                 return 0;
1615                         }
1616                         break;
1617
1618                 case 'H':
1619                         p = get_activity_position(act, A_HUGE, EXIT_IF_NOT_FOUND);
1620                         act[p]->options   |= AO_SELECTED;
1621                         break;
1622
1623                 case 'j':
1624                         if (argv[*opt + 1]) {
1625                                 (*opt)++;
1626                                 if (strnlen(argv[*opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1)
1627                                         return 1;
1628
1629                                 strncpy(persistent_name_type, argv[*opt], MAX_FILE_LEN - 1);
1630                                 persistent_name_type[MAX_FILE_LEN - 1] = '\0';
1631                                 strtolower(persistent_name_type);
1632                                 if (!get_persistent_type_dir(persistent_name_type)) {
1633                                         fprintf(stderr, _("Invalid type of persistent device name\n"));
1634                                         return 2;
1635                                 }
1636                                 /*
1637                                  * If persistent device name doesn't exist for device, use
1638                                  * its pretty name.
1639                                  */
1640                                 *flags |= S_F_PERSIST_NAME + S_F_DEV_PRETTY;
1641                                 return 0;
1642                         }
1643                         else {
1644                                 return 1;
1645                         }
1646                         break;
1647
1648                 case 'p':
1649                         *flags |= S_F_DEV_PRETTY;
1650                         break;
1651
1652                 case 'q':
1653                         SELECT_ACTIVITY(A_QUEUE);
1654                         break;
1655
1656                 case 'r':
1657                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1658                         act[p]->options   |= AO_SELECTED;
1659                         act[p]->opt_flags |= AO_F_MEM_AMT;
1660                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1661                                 (*opt)++;
1662                                 act[p]->opt_flags |= AO_F_MEM_ALL;
1663                                 return 0;
1664                         }
1665                         break;
1666
1667                 case 'R':
1668                         p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1669                         act[p]->options   |= AO_SELECTED;
1670                         act[p]->opt_flags |= AO_F_MEM_DIA;
1671                         break;
1672
1673                 case 'S':
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_SWAP;
1677                         break;
1678
1679                 case 't':
1680                         /*
1681                          * Check sar option -t here (as it can be combined
1682                          * with other ones, eg. "sar -rtu ..."
1683                          * But sadf option -t is checked in sadf.c as it won't
1684                          * be entered as a sar option after "--".
1685                          */
1686                         if (caller == C_SAR) {
1687                                 *flags |= S_F_TRUE_TIME;
1688                         }
1689                         else
1690                                 return 1;
1691                         break;
1692
1693                 case 'u':
1694                         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1695                         act[p]->options |= AO_SELECTED;
1696                         if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1697                                 (*opt)++;
1698                                 act[p]->opt_flags = AO_F_CPU_ALL;
1699                                 return 0;
1700                         }
1701                         else {
1702                                 act[p]->opt_flags = AO_F_CPU_DEF;
1703                         }
1704                         break;
1705
1706                 case 'v':
1707                         SELECT_ACTIVITY(A_KTABLES);
1708                         break;
1709
1710                 case 'w':
1711                         SELECT_ACTIVITY(A_PCSW);
1712                         break;
1713
1714                 case 'W':
1715                         SELECT_ACTIVITY(A_SWAP);
1716                         break;
1717
1718                 case 'y':
1719                         SELECT_ACTIVITY(A_SERIAL);
1720                         break;
1721
1722                 case 'V':
1723                         print_version();
1724                         break;
1725
1726                 default:
1727                         return 1;
1728                 }
1729         }
1730         return 0;
1731 }
1732
1733 /*
1734  ***************************************************************************
1735  * Parse sar "-m" option.
1736  *
1737  * IN:
1738  * @argv        Arguments list.
1739  * @opt         Index in list of arguments.
1740  *
1741  * OUT:
1742  * @act         Array of selected activities.
1743  *
1744  * RETURNS:
1745  * 0 on success, 1 otherwise.
1746  ***************************************************************************
1747  */
1748 int parse_sar_m_opt(char *argv[], int *opt, struct activity *act[])
1749 {
1750         char *t;
1751
1752         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1753                 if (!strcmp(t, K_CPU)) {
1754                         SELECT_ACTIVITY(A_PWR_CPUFREQ);
1755                 }
1756                 else if (!strcmp(t, K_FAN)) {
1757                         SELECT_ACTIVITY(A_PWR_FAN);
1758                 }
1759                 else if (!strcmp(t, K_IN)) {
1760                         SELECT_ACTIVITY(A_PWR_IN);
1761                 }
1762                 else if (!strcmp(t, K_TEMP)) {
1763                         SELECT_ACTIVITY(A_PWR_TEMP);
1764                 }
1765                 else if (!strcmp(t, K_FREQ)) {
1766                         SELECT_ACTIVITY(A_PWR_WGHFREQ);
1767                 }
1768                 else if (!strcmp(t, K_USB)) {
1769                         SELECT_ACTIVITY(A_PWR_USB);
1770                 }
1771                 else if (!strcmp(t, K_ALL)) {
1772                         SELECT_ACTIVITY(A_PWR_CPUFREQ);
1773                         SELECT_ACTIVITY(A_PWR_FAN);
1774                         SELECT_ACTIVITY(A_PWR_IN);
1775                         SELECT_ACTIVITY(A_PWR_TEMP);
1776                         SELECT_ACTIVITY(A_PWR_WGHFREQ);
1777                         SELECT_ACTIVITY(A_PWR_USB);
1778                 }
1779                 else
1780                         return 1;
1781         }
1782
1783         (*opt)++;
1784         return 0;
1785 }
1786
1787 /*
1788  ***************************************************************************
1789  * Parse sar "-n" option.
1790  *
1791  * IN:
1792  * @argv        Arguments list.
1793  * @opt         Index in list of arguments.
1794  *
1795  * OUT:
1796  * @act         Array of selected activities.
1797  *
1798  * RETURNS:
1799  * 0 on success, 1 otherwise.
1800  ***************************************************************************
1801  */
1802 int parse_sar_n_opt(char *argv[], int *opt, struct activity *act[])
1803 {
1804         char *t;
1805
1806         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1807                 if (!strcmp(t, K_DEV)) {
1808                         SELECT_ACTIVITY(A_NET_DEV);
1809                 }
1810                 else if (!strcmp(t, K_EDEV)) {
1811                         SELECT_ACTIVITY(A_NET_EDEV);
1812                 }
1813                 else if (!strcmp(t, K_SOCK)) {
1814                         SELECT_ACTIVITY(A_NET_SOCK);
1815                 }
1816                 else if (!strcmp(t, K_NFS)) {
1817                         SELECT_ACTIVITY(A_NET_NFS);
1818                 }
1819                 else if (!strcmp(t, K_NFSD)) {
1820                         SELECT_ACTIVITY(A_NET_NFSD);
1821                 }
1822                 else if (!strcmp(t, K_IP)) {
1823                         SELECT_ACTIVITY(A_NET_IP);
1824                 }
1825                 else if (!strcmp(t, K_EIP)) {
1826                         SELECT_ACTIVITY(A_NET_EIP);
1827                 }
1828                 else if (!strcmp(t, K_ICMP)) {
1829                         SELECT_ACTIVITY(A_NET_ICMP);
1830                 }
1831                 else if (!strcmp(t, K_EICMP)) {
1832                         SELECT_ACTIVITY(A_NET_EICMP);
1833                 }
1834                 else if (!strcmp(t, K_TCP)) {
1835                         SELECT_ACTIVITY(A_NET_TCP);
1836                 }
1837                 else if (!strcmp(t, K_ETCP)) {
1838                         SELECT_ACTIVITY(A_NET_ETCP);
1839                 }
1840                 else if (!strcmp(t, K_UDP)) {
1841                         SELECT_ACTIVITY(A_NET_UDP);
1842                 }
1843                 else if (!strcmp(t, K_SOCK6)) {
1844                         SELECT_ACTIVITY(A_NET_SOCK6);
1845                 }
1846                 else if (!strcmp(t, K_IP6)) {
1847                         SELECT_ACTIVITY(A_NET_IP6);
1848                 }
1849                 else if (!strcmp(t, K_EIP6)) {
1850                         SELECT_ACTIVITY(A_NET_EIP6);
1851                 }
1852                 else if (!strcmp(t, K_ICMP6)) {
1853                         SELECT_ACTIVITY(A_NET_ICMP6);
1854                 }
1855                 else if (!strcmp(t, K_EICMP6)) {
1856                         SELECT_ACTIVITY(A_NET_EICMP6);
1857                 }
1858                 else if (!strcmp(t, K_UDP6)) {
1859                         SELECT_ACTIVITY(A_NET_UDP6);
1860                 }
1861                 else if (!strcmp(t, K_FC)) {
1862                         SELECT_ACTIVITY(A_NET_FC);
1863                 }
1864                 else if (!strcmp(t, K_ALL)) {
1865                         SELECT_ACTIVITY(A_NET_DEV);
1866                         SELECT_ACTIVITY(A_NET_EDEV);
1867                         SELECT_ACTIVITY(A_NET_SOCK);
1868                         SELECT_ACTIVITY(A_NET_NFS);
1869                         SELECT_ACTIVITY(A_NET_NFSD);
1870                         SELECT_ACTIVITY(A_NET_IP);
1871                         SELECT_ACTIVITY(A_NET_EIP);
1872                         SELECT_ACTIVITY(A_NET_ICMP);
1873                         SELECT_ACTIVITY(A_NET_EICMP);
1874                         SELECT_ACTIVITY(A_NET_TCP);
1875                         SELECT_ACTIVITY(A_NET_ETCP);
1876                         SELECT_ACTIVITY(A_NET_UDP);
1877                         SELECT_ACTIVITY(A_NET_SOCK6);
1878                         SELECT_ACTIVITY(A_NET_IP6);
1879                         SELECT_ACTIVITY(A_NET_EIP6);
1880                         SELECT_ACTIVITY(A_NET_ICMP6);
1881                         SELECT_ACTIVITY(A_NET_EICMP6);
1882                         SELECT_ACTIVITY(A_NET_UDP6);
1883                         SELECT_ACTIVITY(A_NET_FC);
1884                 }
1885                 else
1886                         return 1;
1887         }
1888
1889         (*opt)++;
1890         return 0;
1891 }
1892
1893 /*
1894  ***************************************************************************
1895  * Parse sar "-I" option.
1896  *
1897  * IN:
1898  * @argv        Arguments list.
1899  * @opt         Index in list of arguments.
1900  * @act         Array of activities.
1901  *
1902  * OUT:
1903  * @act         Array of activities, with interrupts activity selected.
1904  *
1905  * RETURNS:
1906  * 0 on success, 1 otherwise.
1907  ***************************************************************************
1908  */
1909 int parse_sar_I_opt(char *argv[], int *opt, struct activity *act[])
1910 {
1911         int i, p;
1912         unsigned char c;
1913         char *t;
1914
1915         /* Select interrupt activity */
1916         p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1917         act[p]->options |= AO_SELECTED;
1918
1919         for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1920                 if (!strcmp(t, K_SUM)) {
1921                         /* Select total number of interrupts */
1922                         act[p]->bitmap->b_array[0] |= 0x01;
1923                 }
1924                 else if (!strcmp(t, K_ALL)) {
1925                         /* Set bit for the first 16 individual interrupts */
1926                         act[p]->bitmap->b_array[0] |= 0xfe;
1927                         act[p]->bitmap->b_array[1] |= 0xff;
1928                         act[p]->bitmap->b_array[2] |= 0x01;
1929                 }
1930                 else if (!strcmp(t, K_XALL)) {
1931                         /* Set every bit except for total number of interrupts */
1932                         c = act[p]->bitmap->b_array[0];
1933                         set_bitmap(act[p]->bitmap->b_array, ~0,
1934                                    BITMAP_SIZE(act[p]->bitmap->b_size));
1935                         act[p]->bitmap->b_array[0] = 0xfe | c;
1936                 }
1937                 else {
1938                         /* Get irq number */
1939                         if (strspn(t, DIGITS) != strlen(t))
1940                                 return 1;
1941                         i = atoi(t);
1942                         if ((i < 0) || (i >= act[p]->bitmap->b_size))
1943                                 return 1;
1944                         act[p]->bitmap->b_array[(i + 1) >> 3] |= 1 << ((i + 1) & 0x07);
1945                 }
1946         }
1947
1948         (*opt)++;
1949         return 0;
1950 }
1951
1952 /*
1953  ***************************************************************************
1954  * Parse sar and sadf "-P" option.
1955  *
1956  * IN:
1957  * @argv        Arguments list.
1958  * @opt         Index in list of arguments.
1959  * @act         Array of activities.
1960  *
1961  * OUT:
1962  * @flags       Common flags and system state.
1963  * @act         Array of activities, with CPUs selected.
1964  *
1965  * RETURNS:
1966  * 0 on success, 1 otherwise.
1967  ***************************************************************************
1968  */
1969 int parse_sa_P_opt(char *argv[], int *opt, unsigned int *flags, struct activity *act[])
1970 {
1971         int i, p;
1972         char *t;
1973
1974         p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1975
1976         if (argv[++(*opt)]) {
1977
1978                 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1979                         if (!strcmp(t, K_ALL)) {
1980                                 /*
1981                                  * Set bit for every processor.
1982                                  * We still don't know if we are going to read stats
1983                                  * from a file or not...
1984                                  */
1985                                 set_bitmap(act[p]->bitmap->b_array, ~0,
1986                                            BITMAP_SIZE(act[p]->bitmap->b_size));
1987                         }
1988                         else {
1989                                 /* Get cpu number */
1990                                 if (strspn(t, DIGITS) != strlen(t))
1991                                         return 1;
1992                                 i = atoi(t);
1993                                 if ((i < 0) || (i >= act[p]->bitmap->b_size))
1994                                         return 1;
1995                                 act[p]->bitmap->b_array[(i + 1) >> 3] |= 1 << ((i + 1) & 0x07);
1996                         }
1997                 }
1998                 (*opt)++;
1999         }
2000         else
2001                 return 1;
2002
2003         return 0;
2004 }
2005
2006 /*
2007  ***************************************************************************
2008  * Compute network interface utilization.
2009  *
2010  * IN:
2011  * @st_net_dev  Structure with network interface stats.
2012  * @rx          Number of bytes received per second.
2013  * @tx          Number of bytes transmitted per second.
2014  *
2015  * RETURNS:
2016  * NIC utilization (0-100%).
2017  ***************************************************************************
2018  */
2019 double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx)
2020 {
2021         unsigned long long speed;
2022
2023         if (st_net_dev->speed) {
2024
2025                 speed = (unsigned long long) st_net_dev->speed * 1000000;
2026
2027                 if (st_net_dev->duplex == C_DUPLEX_FULL) {
2028                         /* Full duplex */
2029                         if (rx > tx) {
2030                                 return (rx * 800 / speed);
2031                         }
2032                         else {
2033                                 return (tx * 800 / speed);
2034                         }
2035                 }
2036                 else {
2037                         /* Half duplex */
2038                         return ((rx + tx) * 800 / speed);
2039                 }
2040         }
2041
2042         return 0;
2043 }
2044
2045 /*
2046  ***************************************************************************
2047  * Fill system activity file magic header.
2048  *
2049  * IN:
2050  * @file_magic  System activity file magic header.
2051  ***************************************************************************
2052  */
2053 void enum_version_nr(struct file_magic *fm)
2054 {
2055         char *v;
2056         char version[16];
2057
2058         fm->sysstat_extraversion = 0;
2059
2060         strcpy(version, VERSION);
2061
2062         /* Get version number */
2063         if ((v = strtok(version, ".")) == NULL)
2064                 return;
2065         fm->sysstat_version = atoi(v) & 0xff;
2066
2067         /* Get patchlevel number */
2068         if ((v = strtok(NULL, ".")) == NULL)
2069                 return;
2070         fm->sysstat_patchlevel = atoi(v) & 0xff;
2071
2072         /* Get sublevel number */
2073         if ((v = strtok(NULL, ".")) == NULL)
2074                 return;
2075         fm->sysstat_sublevel = atoi(v) & 0xff;
2076
2077         /* Get extraversion number. Don't necessarily exist */
2078         if ((v = strtok(NULL, ".")) == NULL)
2079                 return;
2080         fm->sysstat_extraversion = atoi(v) & 0xff;
2081 }
2082
2083 /*
2084  ***************************************************************************
2085  * Read and replace unprintable characters in comment with ".".
2086  *
2087  * IN:
2088  * @ifd         Input file descriptor.
2089  * @comment     Comment.
2090  ***************************************************************************
2091  */
2092 void replace_nonprintable_char(int ifd, char *comment)
2093 {
2094         int i;
2095
2096         /* Read comment */
2097         sa_fread(ifd, comment, MAX_COMMENT_LEN, HARD_SIZE);
2098         comment[MAX_COMMENT_LEN - 1] = '\0';
2099
2100         /* Replace non printable chars */
2101         for (i = 0; i < strlen(comment); i++) {
2102                 if (!isprint(comment[i]))
2103                         comment[i] = '.';
2104         }
2105 }
2106
2107 /*
2108  ***************************************************************************
2109  * Fill the rectime and loctime structures with current record's date and
2110  * time, based on current record's "number of seconds since the epoch" saved
2111  * in file.
2112  * For loctime (if given): The timestamp is expressed in local time.
2113  * For rectime: The timestamp is expressed in UTC, in local time, or in the
2114  * time of the file's creator depending on options entered by the user on the
2115  * command line.
2116  *
2117  * IN:
2118  * @l_flags     Flags indicating the type of time expected by the user.
2119  *              S_F_LOCAL_TIME means time should be expressed in local time.
2120  *              S_F_TRUE_TIME means time should be expressed in time of
2121  *              file's creator.
2122  *              Default is time expressed in UTC (except for sar, where it
2123  *              is local time).
2124  * @record_hdr  Record header containing the number of seconds since the
2125  *              epoch, and the HH:MM:SS of the file's creator.
2126  *
2127  * OUT:
2128  * @rectime     Structure where timestamp for current record has been saved
2129  *              (in local time or in UTC depending on options used).
2130  * @loctime     If given, structure where timestamp for current record has
2131  *              been saved (expressed in local time). This field will be used
2132  *              for time comparison if options -s and/or -e have been used.
2133  *
2134  * RETURNS:
2135  * 1 if an error was detected, or 0 otherwise.
2136  ***************************************************************************
2137 */
2138 int sa_get_record_timestamp_struct(unsigned int l_flags, struct record_header *record_hdr,
2139                                    struct tm *rectime, struct tm *loctime)
2140 {
2141         struct tm *ltm = NULL;
2142         int rc = 0;
2143
2144         /* Fill localtime structure if given */
2145         if (loctime) {
2146                 if ((ltm = localtime((const time_t *) &(record_hdr->ust_time))) != NULL) {
2147                         *loctime = *ltm;
2148                 }
2149                 else {
2150                         rc = 1;
2151                 }
2152         }
2153
2154         /* Fill generic rectime structure */
2155         if (PRINT_LOCAL_TIME(l_flags) && !ltm) {
2156                 /* Get local time if not already done */
2157                 ltm = localtime((const time_t *) &(record_hdr->ust_time));
2158         }
2159
2160         if (!PRINT_LOCAL_TIME(l_flags) && !PRINT_TRUE_TIME(l_flags)) {
2161                 /*
2162                  * Get time in UTC
2163                  * (the user doesn't want local time nor time of file's creator).
2164                  */
2165                 ltm = gmtime((const time_t *) &(record_hdr->ust_time));
2166         }
2167
2168         if (ltm) {
2169                 /* Done even in true time mode so that we have some default values */
2170                 *rectime = *ltm;
2171         }
2172         else {
2173                 rc = 1;
2174         }
2175
2176         if (PRINT_TRUE_TIME(l_flags)) {
2177                 /* Time of file's creator */
2178                 rectime->tm_hour = record_hdr->hour;
2179                 rectime->tm_min  = record_hdr->minute;
2180                 rectime->tm_sec  = record_hdr->second;
2181         }
2182
2183         return rc;
2184 }
2185
2186 /*
2187  ***************************************************************************
2188  * Set current record's timestamp strings (date and time) using the time
2189  * data saved in @rectime structure. The string may be the number of seconds
2190  * since the epoch if flag S_F_SEC_EPOCH has been set.
2191  *
2192  * IN:
2193  * @l_flags     Flags indicating the type of time expected by the user.
2194  *              S_F_SEC_EPOCH means the time should be expressed in seconds
2195  *              since the epoch (01/01/1970).
2196  * @record_hdr  Record header containing the number of seconds since the
2197  *              epoch.
2198  * @cur_date    String where timestamp's date will be saved. May be NULL.
2199  * @cur_time    String where timestamp's time will be saved.
2200  * @len         Maximum length of timestamp strings.
2201  * @rectime     Structure with current timestamp (expressed in local time or
2202  *              in UTC depending on whether options -T or -t have been used
2203  *              or not) that should be broken down in date and time strings.
2204  *
2205  * OUT:
2206  * @cur_date    Timestamp's date string (if expected).
2207  * @cur_time    Timestamp's time string. May contain the number of seconds
2208  *              since the epoch (01-01-1970) if corresponding option has
2209  *              been used.
2210  ***************************************************************************
2211 */
2212 void set_record_timestamp_string(unsigned int l_flags, struct record_header *record_hdr,
2213                                  char *cur_date, char *cur_time, int len, struct tm *rectime)
2214 {
2215         /* Set cur_time date value */
2216         if (PRINT_SEC_EPOCH(l_flags) && cur_date) {
2217                 sprintf(cur_time, "%ld", record_hdr->ust_time);
2218                 strcpy(cur_date, "");
2219         }
2220         else {
2221                 /*
2222                  * If options -T or -t have been used then cur_time is
2223                  * expressed in local time. Else it is expressed in UTC.
2224                  */
2225                 if (cur_date) {
2226                         strftime(cur_date, len, "%Y-%m-%d", rectime);
2227                 }
2228                 if (USE_PREFD_TIME_OUTPUT(l_flags)) {
2229                         strftime(cur_time, len, "%X", rectime);
2230                 }
2231                 else {
2232                         strftime(cur_time, len, "%H:%M:%S", rectime);
2233                 }
2234         }
2235 }
2236
2237 /*
2238  ***************************************************************************
2239  * Print contents of a special (RESTART or COMMENT) record.
2240  *
2241  * IN:
2242  * @record_hdr  Current record header.
2243  * @l_flags     Flags for common options.
2244  * @tm_start    Structure filled when option -s has been used.
2245  * @tm_end      Structure filled when option -e has been used.
2246  * @rtype       Record type (R_RESTART or R_COMMENT).
2247  * @ifd         Input file descriptor.
2248  * @rectime     Structure where timestamp (expressed in local time or in UTC
2249  *              depending on whether options -T/-t have been used or not) can
2250  *              be saved for current record.
2251  * @loctime     Structure where timestamp (expressed in local time) can be
2252  *              saved for current record. May be NULL.
2253  * @file        Name of file being read.
2254  * @tab         Number of tabulations to print.
2255  * @file_magic  file_magic structure filled with file magic header data.
2256  * @file_hdr    System activity file standard header.
2257  * @act         Array of activities.
2258  * @ofmt                Pointer on report output format structure.
2259  *
2260  * OUT:
2261  * @rectime             Structure where timestamp (expressed in local time
2262  *                      or in UTC) has been saved.
2263  * @loctime             Structure where timestamp (expressed in local time)
2264  *                      has been saved (if requested).
2265  *
2266  * RETURNS:
2267  * 1 if the record has been successfully displayed, and 0 otherwise.
2268  ***************************************************************************
2269  */
2270 int print_special_record(struct record_header *record_hdr, unsigned int l_flags,
2271                          struct tstamp *tm_start, struct tstamp *tm_end, int rtype, int ifd,
2272                          struct tm *rectime, struct tm *loctime, char *file, int tab,
2273                          struct file_magic *file_magic, struct file_header *file_hdr,
2274                          struct activity *act[], struct report_format *ofmt)
2275 {
2276         char cur_date[32], cur_time[32];
2277         int dp = 1;
2278         unsigned int new_cpu_nr;
2279
2280         /* Fill timestamp structure (rectime) for current record */
2281         if (sa_get_record_timestamp_struct(l_flags, record_hdr, rectime, loctime))
2282                 return 0;
2283
2284         /* If loctime is NULL, then use rectime for comparison */
2285         if (!loctime) {
2286                 loctime = rectime;
2287         }
2288
2289         /* The record must be in the interval specified by -s/-e options */
2290         if ((tm_start->use && (datecmp(loctime, tm_start) < 0)) ||
2291             (tm_end->use && (datecmp(loctime, tm_end) > 0))) {
2292                 /* Will not display the special record */
2293                 dp = 0;
2294         }
2295         else {
2296                 /* Set date and time strings to be displayed for current record */
2297                 set_record_timestamp_string(l_flags, record_hdr,
2298                                             cur_date, cur_time, 32, rectime);
2299         }
2300
2301         if (rtype == R_RESTART) {
2302                 /* Don't forget to read the volatile activities structures */
2303                 new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic,
2304                                                      file_hdr->sa_vol_act_nr);
2305
2306                 if (!dp)
2307                         return 0;
2308
2309                 if (*ofmt->f_restart) {
2310                         (*ofmt->f_restart)(&tab, F_MAIN, cur_date, cur_time,
2311                                            !PRINT_LOCAL_TIME(l_flags) &&
2312                                            !PRINT_TRUE_TIME(l_flags), file_hdr,
2313                                            new_cpu_nr);
2314                 }
2315         }
2316         else if (rtype == R_COMMENT) {
2317                 char file_comment[MAX_COMMENT_LEN];
2318
2319                 /* Read and replace non printable chars in comment */
2320                 replace_nonprintable_char(ifd, file_comment);
2321
2322                 if (!dp || !DISPLAY_COMMENT(l_flags))
2323                         return 0;
2324
2325                 if (*ofmt->f_comment) {
2326                         (*ofmt->f_comment)(&tab, F_MAIN, cur_date, cur_time,
2327                                            !PRINT_LOCAL_TIME(l_flags) &&
2328                                            !PRINT_TRUE_TIME(l_flags), file_comment,
2329                                            file_hdr);
2330                 }
2331         }
2332
2333         return 1;
2334 }