From 65aeb5526caf0efbf5d847aa5e55e6a67869c566 Mon Sep 17 00:00:00 2001 From: Sebastien GODARD Date: Wed, 4 Oct 2017 09:25:55 +0200 Subject: [PATCH] sadc/sar: New format (part 6): Remap other structures 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 --- sa.h | 24 ++++++++++-- sa_common.c | 105 +++++++++++++++++++++++++++++++++++++++++----------- sadc.c | 21 +++++++++++ sadf.c | 11 ++---- sar.c | 54 +++++++++++++-------------- 5 files changed, 156 insertions(+), 59 deletions(-) diff --git a/sa.h b/sa.h index 1c8c4c4..70e55ff 100644 --- 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 4 /* 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 diff --git a/sa_common.c b/sa_common.c index ee2b972..8757030 100644 --- a/sa_common.c +++ b/sa_common.c @@ -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 e8928de..d28575a 100644 --- 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 473e155..17654df 100644 --- 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 a110a51..7833ce3 100644 --- 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 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)) { -- 2.40.0