]> granicus.if.org Git - sysstat/commitdiff
sadc/sar: New format (part 6): Remap other structures
authorSebastien GODARD <sysstat@users.noreply.github.com>
Wed, 4 Oct 2017 07:25:55 +0000 (09:25 +0200)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Wed, 4 Oct 2017 07:25:55 +0000 (09:25 +0200)
Remap file_activity and record_header structures from an older (or
newer) sysstat version to current sysstat version's format.

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
sa.h
sa_common.c
sadc.c
sadf.c
sar.c

diff --git a/sa.h b/sa.h
index 1c8c4c40a008afecdc461f75cfc1eef922d6294b..70e55ffe30f3362776fbf1ded0ec2e7e62964ace 100644 (file)
--- a/sa.h
+++ b/sa.h
@@ -441,11 +441,25 @@ struct file_header {
         */
        unsigned int sa_vol_act_nr;
        /*
-        * Current day, month and year.
+        * Current year.
+        */
+       int sa_year;
+       /*
+        * Description of the file_activity and record_header structures
+        * (nr of "long long", nr of "long" and nr of "int").
+        */
+       unsigned int act_types_nr[3];
+       unsigned int rec_types_nr[3];
+       /*
+        * Size of file_activity and record_header structures used by file.
+        */
+       unsigned int act_size;
+       unsigned int rec_size;
+       /*
+        * Current day and month.
         * No need to save DST (Daylight Saving Time) flag, since it is not taken
         * into account by the strftime() function used to print the timestamp.
         */
-       int sa_year;
        unsigned char sa_day;
        unsigned char sa_month;
        /*
@@ -474,7 +488,7 @@ struct file_header {
 #define FILE_HEADER_SIZE       (sizeof(struct file_header))
 #define FILE_HEADER_ULL_NR     1       /* Nr of unsigned long long in file_header structure */
 #define FILE_HEADER_UL_NR      0       /* Nr of unsigned long in file_header structure */
-#define FILE_HEADER_U_NR             /* Nr of [unsigned] int in file_header structure */
+#define FILE_HEADER_U_NR       12      /* Nr of [unsigned] int in file_header structure */
 /* The values below are used for sanity check */
 #define MIN_FILE_HEADER_SIZE   0
 #define MAX_FILE_HEADER_SIZE   8192
@@ -520,6 +534,7 @@ struct file_activity {
 };
 
 #define FILE_ACTIVITY_SIZE     (sizeof(struct file_activity))
+#define MAX_FILE_ACTIVITY_SIZE 1024    /* Used for sanity check */
 #define FILE_ACTIVITY_ULL_NR   0       /* Nr of unsigned long long in file_activity structure */
 #define FILE_ACTIVITY_UL_NR    0       /* Nr of unsigned long in file_activity structure */
 #define FILE_ACTIVITY_U_NR     8       /* Nr of [unsigned] int in file_activity structure */
@@ -579,6 +594,7 @@ struct record_header {
 };
 
 #define RECORD_HEADER_SIZE     (sizeof(struct record_header))
+#define MAX_RECORD_HEADER_SIZE 512     /* Used for sanity check */
 #define RECORD_HEADER_ULL_NR   3       /* Nr of unsigned long long in record_header structure */
 #define RECORD_HEADER_UL_NR    0       /* Nr of unsigned long in record_header structure */
 #define RECORD_HEADER_U_NR     0       /* Nr of unsigned int in record_header structure */
@@ -1217,6 +1233,8 @@ int print_special_record
         struct file_header *, struct activity * [], struct report_format *, int, int);
 void read_file_stat_bunch
        (struct activity * [], int, int, int, struct file_activity *, int, int);
+int read_record_hdr
+       (int, void *, struct record_header *, struct file_header *, int, int);
 __nr_t read_vol_act_structures
        (int, struct activity * [], char *, struct file_magic *, unsigned int, int, int);
 int reallocate_vol_act_structures
index ee2b972cd3ccc797d22a221a6957b306d9a3aaa3..8757030615a223790669c2488c74b507108c9a85 100644 (file)
@@ -52,6 +52,7 @@ extern struct act_bitmap cpu_bitmap;
 
 unsigned int hdr_types_nr[] = {FILE_HEADER_ULL_NR, FILE_HEADER_UL_NR, FILE_HEADER_U_NR};
 unsigned int act_types_nr[] = {FILE_ACTIVITY_ULL_NR, FILE_ACTIVITY_UL_NR, FILE_ACTIVITY_U_NR};
+unsigned int rec_types_nr[] = {RECORD_HEADER_ULL_NR, RECORD_HEADER_UL_NR, RECORD_HEADER_U_NR};
 
 /*
  ***************************************************************************
@@ -1143,6 +1144,47 @@ int sa_fread(int ifd, void *buffer, int size, int mode)
        return 0;
 }
 
+/*
+ ***************************************************************************
+ * Read the record header of current sample and process it.
+ *
+ * IN:
+ * @ifd                Input file descriptor.
+ * @buffer     Buffer where data will be read.
+ * @record_hdr Structure where record header will be saved.
+ * @file_hdr   file_hdr structure containing data read from file standard
+ *             header.
+ * @arch_64    TRUE if file's data come from a 64-bit machine.
+ * @endian_mismatch
+ *             TRUE if data read from file don't match current machine's
+ *             endianness.
+ *
+ * OUT:
+ * @record_hdr Record header for current sample.
+ *
+ * RETURNS:
+ * 1 if EOF has been reached, 0 otherwise.
+ ***************************************************************************
+ */
+int read_record_hdr(int ifd, void *buffer, struct record_header *record_hdr,
+                   struct file_header *file_hdr, int arch_64, int endian_mismatch)
+{
+       if (sa_fread(ifd, buffer, file_hdr->rec_size, SOFT_SIZE))
+               /* End of sa data file */
+               return 1;
+
+       /* Remap record header structure to that expected by current version */
+       remap_struct(rec_types_nr, file_hdr->rec_types_nr, buffer, file_hdr->rec_size);
+       memcpy(record_hdr, buffer, RECORD_HEADER_SIZE);
+
+       /* Normalize endianness */
+       if (endian_mismatch) {
+               swap_struct(rec_types_nr, record_hdr, arch_64);
+       }
+
+       return 0;
+}
+
 /*
  ***************************************************************************
  * Display sysstat version used to create system activity data file.
@@ -1450,6 +1492,7 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
        remap_struct(hdr_types_nr, file_magic->hdr_types_nr, buffer, file_magic->header_size);
        memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
        free(buffer);
+       buffer = NULL;
 
        /* Tell that data come from a 64 bit machine */
        *arch_64 = (file_hdr->sa_sizeof_long == SIZEOF_LONG_64BIT);
@@ -1460,16 +1503,20 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
        }
 
        /*
-        * Sanity check.
-        * Compare against MAX_NR_ACT and not NR_ACT because
+        * Sanity checks.
+        * NB: Compare against MAX_NR_ACT and not NR_ACT because
         * we are maybe reading a datafile from a future sysstat version
         * with more activities than known today.
         */
-       if (file_hdr->sa_act_nr > MAX_NR_ACT) {
+       if ((file_hdr->sa_act_nr > MAX_NR_ACT) ||
+           (file_hdr->act_size > MAX_FILE_ACTIVITY_SIZE) ||
+           (file_hdr->rec_size > MAX_RECORD_HEADER_SIZE) ||
+           (MAP_SIZE(file_hdr->act_types_nr) > file_hdr->act_size) ||
+           (MAP_SIZE(file_hdr->rec_types_nr) > file_hdr->rec_size))
                /* Maybe a "false positive" sysstat datafile? */
-               handle_invalid_sa_file(ifd, file_magic, dfile, 0);
-       }
+               goto format_error;
 
+       SREALLOC(buffer, char, file_hdr->act_size);
        SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
        fal = *file_actlst;
 
@@ -1477,7 +1524,15 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
        j = 0;
        for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
 
-               sa_fread(*ifd, fal, FILE_ACTIVITY_SIZE, HARD_SIZE);
+               /* Read current file_activity structure from file */
+               sa_fread(*ifd, buffer, file_hdr->act_size, HARD_SIZE);
+               /*
+               * Data file_activity size (file_hdr->act_size) may be greater or
+               * smaller than FILE_ACTIVITY_SIZE. Remap the fields of the file's structure
+               * then copy its contents to the expected  structure.
+               */
+               remap_struct(act_types_nr, file_hdr->act_types_nr, buffer, file_hdr->act_size);
+               memcpy(fal, buffer, FILE_ACTIVITY_SIZE);
 
                /* Normalize endianness for file_activity structures */
                if (*endian_mismatch) {
@@ -1496,9 +1551,8 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
                 * activities which have each a specific max value.
                 */
                if ((fal->nr < 1) || (fal->nr2 < 1) ||
-                   (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX)) {
-                       handle_invalid_sa_file(ifd, file_magic, dfile, 0);
-               }
+                   (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX))
+                       goto format_error;
 
                if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0)
                        /* Unknown activity */
@@ -1518,9 +1572,9 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
                }
 
                /* Check max value for known activities */
-               if (fal->nr > act[p]->nr_max) {
-                       handle_invalid_sa_file(ifd, file_magic, dfile, 0);
-               }
+               if (fal->nr > act[p]->nr_max)
+                       goto format_error;
+
                /*
                 * Number of fields of each type ("long long", or "long"
                 * or "int") composing the structure with statistics may
@@ -1534,12 +1588,12 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
                     ||
                     ((fal->types_nr[0] <= act[p]->gtypes_nr[0]) &&
                     (fal->types_nr[1] <= act[p]->gtypes_nr[1]) &&
-                    (fal->types_nr[2] <= act[p]->gtypes_nr[2])))) {
-                       handle_invalid_sa_file(ifd, file_magic, dfile, 0);
-               }
-               if (MAP_SIZE(fal->types_nr) > fal->size) {
-                       handle_invalid_sa_file(ifd, file_magic, dfile, 0);
-               }
+                    (fal->types_nr[2] <= act[p]->gtypes_nr[2]))))
+                       goto format_error;
+
+               if (MAP_SIZE(fal->types_nr) > fal->size)
+                       goto format_error;
+
                for (k = 0; k < 3; k++) {
                        act[p]->ftypes_nr[k] = fal->types_nr[k];
                }
@@ -1572,18 +1626,19 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
                id_seq[j++] = fal->id;
        }
 
-       if (!a_cpu) {
+       if (!a_cpu)
                /*
                 * CPU activity should always be in file
                 * and have a known format (expected magical number).
                 */
-               handle_invalid_sa_file(ifd, file_magic, dfile, 0);
-       }
+               goto format_error;
 
        while (j < NR_ACT) {
                id_seq[j++] = 0;
        }
 
+       free(buffer);
+
        /* Check that at least one selected activity is available in file */
        for (i = 0; i < NR_ACT; i++) {
 
@@ -1607,6 +1662,14 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
                close(*ifd);
                exit(1);
        }
+
+       return;
+
+format_error:
+       if (buffer) {
+               free(buffer);
+       }
+       handle_invalid_sa_file(ifd, file_magic, dfile, 0);
 }
 
 /*
diff --git a/sadc.c b/sadc.c
index e8928de86b7f71700d70ed8f5a2639ac4ccb1c30..d28575acc5817aeeb7828c17896ea401e47b2a57 100644 (file)
--- a/sadc.c
+++ b/sadc.c
@@ -73,6 +73,9 @@ unsigned int id_seq[NR_ACT];
 unsigned int vol_id_seq[NR_ACT];
 
 extern unsigned int hdr_types_nr[];
+extern unsigned int act_types_nr[];
+extern unsigned int rec_types_nr[];
+
 extern struct activity *act[];
 extern __nr_t (*f_count[]) (struct activity *);
 
@@ -512,6 +515,13 @@ void setup_file_hdr(int fd)
        file_hdr.sa_year        = rectime.tm_year;
        file_hdr.sa_sizeof_long = sizeof(long);
 
+       for (i = 0; i < 3; i++) {
+               file_hdr.act_types_nr[i] = act_types_nr[i];
+               file_hdr.rec_types_nr[i] = rec_types_nr[i];
+       }
+       file_hdr.act_size = FILE_ACTIVITY_SIZE;
+       file_hdr.rec_size = RECORD_HEADER_SIZE;
+
        /*
         * This is a new file (or stdout): Field sa_last_cpu_nr is set to the number
         * of CPU items of the machine (1 .. CPU_NR + 1).
@@ -915,6 +925,17 @@ void open_ofile(int *ofd, char ofile[], int restart_mark)
                 */
                goto append_error;
 
+       /* Other sanity checks ("strict writing" rule) */
+       if ((file_hdr.act_size != FILE_ACTIVITY_SIZE) ||
+           (file_hdr.act_types_nr[0] != FILE_ACTIVITY_ULL_NR) ||
+           (file_hdr.act_types_nr[1] != FILE_ACTIVITY_UL_NR) ||
+           (file_hdr.act_types_nr[2] != FILE_ACTIVITY_U_NR) ||
+           (file_hdr.rec_size != RECORD_HEADER_SIZE) ||
+           (file_hdr.rec_types_nr[0] != RECORD_HEADER_ULL_NR) ||
+           (file_hdr.rec_types_nr[1] != RECORD_HEADER_UL_NR) ||
+           (file_hdr.rec_types_nr[2] != RECORD_HEADER_U_NR))
+               goto append_error;
+
        for (i = 0; i < file_hdr.sa_act_nr; i++) {
 
                /* Read current activity in list */
diff --git a/sadf.c b/sadf.c
index 473e1558286f0243b8e5d78a86743dc96c86699b..17654dfcf24f981790c89453ae88aabfd9c0463e 100644 (file)
--- a/sadf.c
+++ b/sadf.c
@@ -53,7 +53,7 @@ int endian_mismatch = FALSE;
 /* TRUE if file's data come from a 64 bit machine */
 int arch_64 = FALSE;
 
-unsigned int rec_types_nr[] = {RECORD_HEADER_ULL_NR, RECORD_HEADER_UL_NR, RECORD_HEADER_U_NR};
+extern unsigned int rec_types_nr[];
 
 unsigned int flags = 0;
 unsigned int dm_major;         /* Device-mapper major number */
@@ -270,17 +270,14 @@ int read_next_sample(int ifd, int action, int curr, char *file, int *rtype, int
                     struct tm *rectime, struct tm *loctime)
 {
        int eosaf;
+       char rec_hdr_tmp[MAX_RECORD_HEADER_SIZE];
 
        /* Read current record */
-       eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE, SOFT_SIZE);
+       eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[curr], &file_hdr,
+                               arch_64, endian_mismatch);
        *rtype = record_hdr[curr].record_type;
 
        if (!eosaf) {
-               /* Normalize endianness for file_hdr structure */
-               if (endian_mismatch) {
-                       swap_struct(rec_types_nr, &record_hdr[curr], arch_64);
-               }
-
                if (*rtype == R_COMMENT) {
                        if (action & IGNORE_COMMENT) {
                                /* Ignore COMMENT record */
diff --git a/sar.c b/sar.c
index a110a51360c597a0645b25feb6cd712adbbf9912..7833ce3784356f298430ca9fdf3903101445260d 100644 (file)
--- a/sar.c
+++ b/sar.c
@@ -61,7 +61,7 @@ unsigned int flags = 0;
 unsigned int dm_major; /* Device-mapper major number */
 
 char timestamp[2][TIMESTAMP_LEN];
-unsigned int rec_types_nr[] = {RECORD_HEADER_ULL_NR, RECORD_HEADER_UL_NR, RECORD_HEADER_U_NR};
+extern unsigned int rec_types_nr[];
 
 unsigned long avg_count = 0;
 
@@ -685,6 +685,7 @@ void read_sadc_stat_bunch(int curr)
  * @file_actlst        List of activities in file.
  * @file       Name of file being read.
  * @file_magic file_magic structure filled with file magic header data.
+ * @rec_hdr_tmp        Temporary buffer where current record header will be saved.
  * @endian_mismatch
  *             TRUE if file's data don't match current machine's endianness.
  * @arch_64    TRUE if file's data come from a 64 bit machine.
@@ -700,8 +701,8 @@ void read_sadc_stat_bunch(int curr)
 void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
                           int rows, unsigned int act_id, int *reset,
                           struct file_activity *file_actlst, char *file,
-                          struct file_magic *file_magic, int endian_mismatch,
-                          int arch_64)
+                          struct file_magic *file_magic, void *rec_hdr_tmp,
+                          int endian_mismatch, int arch_64)
 {
        int p, reset_cd;
        unsigned long lines = 0;
@@ -734,14 +735,12 @@ void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf
        reset_cd = 1;
 
        do {
-               /* Display count lines of stats */
-               *eosaf = sa_fread(ifd, &record_hdr[*curr],
-                                 RECORD_HEADER_SIZE, SOFT_SIZE);
-
-               /* Normalize endianness for record_hdr structure */
-               if (endian_mismatch) {
-                       swap_struct(rec_types_nr, &record_hdr[*curr], arch_64);
-               }
+               /*
+                * Display <count> lines of stats.
+                * Start with reading current sample's record header.
+                */
+               *eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[*curr],
+                                        &file_hdr, arch_64, endian_mismatch);
                rtype = record_hdr[*curr].record_type;
 
                if (!*eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
@@ -844,9 +843,14 @@ void read_header_data(void)
                print_read_error();
        }
 
+       /* All activities are not necessarily selected, but NR_ACT is a max */
        if (file_hdr.sa_act_nr > NR_ACT)
                goto input_error;
 
+       if ((file_hdr.act_size != FILE_ACTIVITY_SIZE) ||
+           (file_hdr.rec_size != RECORD_HEADER_SIZE))
+               goto input_error;
+
        /* Read activity list */
        for (i = 0; i < file_hdr.sa_act_nr; i++) {
 
@@ -900,6 +904,7 @@ void read_stats_from_file(char from_file[])
 {
        struct file_magic file_magic;
        struct file_activity *file_actlst = NULL;
+       char rec_hdr_tmp[MAX_RECORD_HEADER_SIZE];
        int curr = 1, i, p;
        int ifd, rtype;
        int rows, eosaf = TRUE, reset = FALSE;
@@ -927,13 +932,10 @@ void read_stats_from_file(char from_file[])
                 * (try to) get another one.
                 */
                do {
-                       if (sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE))
+                       if (read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[0], &file_hdr,
+                                           arch_64, endian_mismatch)) {
                                /* End of sa data file */
                                return;
-
-                       /* Normalize endianness for file_hdr structure */
-                       if (endian_mismatch) {
-                               swap_struct(rec_types_nr, &record_hdr[0], arch_64);
                        }
 
                        rtype = record_hdr[0].record_type;
@@ -991,7 +993,8 @@ void read_stats_from_file(char from_file[])
                        if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
                                handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
                                                      act[p]->id, &reset, file_actlst,
-                                                     from_file, &file_magic, endian_mismatch, arch_64);
+                                                     from_file, &file_magic, rec_hdr_tmp,
+                                                     endian_mismatch, arch_64);
                        }
                        else {
                                unsigned int optf, msk;
@@ -1002,10 +1005,9 @@ void read_stats_from_file(char from_file[])
                                        if ((act[p]->opt_flags & 0xff) & msk) {
                                                act[p]->opt_flags &= (0xffffff00 + msk);
 
-                                               handle_curr_act_stats(ifd, fpos, &curr, &cnt,
-                                                                     &eosaf, rows, act[p]->id,
-                                                                     &reset, file_actlst,
-                                                                     from_file, &file_magic,
+                                               handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
+                                                                     rows, act[p]->id, &reset, file_actlst,
+                                                                     from_file, &file_magic, rec_hdr_tmp,
                                                                      endian_mismatch, arch_64);
                                                act[p]->opt_flags = optf;
                                        }
@@ -1016,13 +1018,9 @@ void read_stats_from_file(char from_file[])
                if (!cnt) {
                        /* Go to next Linux restart, if possible */
                        do {
-                               eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE,
-                                                SOFT_SIZE);
-
-                               /* Normalize endianness for file_hdr structure */
-                               if (endian_mismatch) {
-                                       swap_struct(rec_types_nr, &record_hdr[curr], arch_64);
-                               }
+                               /* Read next record header */
+                               eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[curr],
+                                                       &file_hdr, arch_64, endian_mismatch);
                                rtype = record_hdr[curr].record_type;
 
                                if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {