*/
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;
/*
#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
};
#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 */
};
#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 */
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
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};
/*
***************************************************************************
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.
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);
}
/*
- * 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;
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) {
* 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 */
}
/* 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
||
((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];
}
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++) {
close(*ifd);
exit(1);
}
+
+ return;
+
+format_error:
+ if (buffer) {
+ free(buffer);
+ }
+ handle_invalid_sa_file(ifd, file_magic, dfile, 0);
}
/*
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 *);
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).
*/
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 */
/* 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 */
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 */
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;
* @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.
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;
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)) {
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++) {
{
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;
* (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;
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;
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;
}
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)) {