]> granicus.if.org Git - sysstat/commitdiff
sar/sadf: On-the-fly endianness conversion
authorSebastien GODARD <sysstat@users.noreply.github.com>
Sun, 17 Sep 2017 08:54:34 +0000 (10:54 +0200)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Sun, 17 Sep 2017 08:54:34 +0000 (10:54 +0200)
This patch aims at making sar and sadf able to read and process files
created on machines with a different endian type. It will now be
possible e.g., to read a file with sar on a little-endian machine even
if this has been created on a big-endian machine.
Yet it will still not be allowed to append (write) data with sar to a
file with a different endianness type.

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

index 6acf5fe12a0eaaccaeef69f5030ccc260a2f2731..f3eda2fbcaffe06dceb90da719839dbc6eb85139 100644 (file)
  ***************************************************************************
  */
 
-#define ULL_ALIGNMENT_WIDTH 8
-#define UL_ALIGNMENT_WIDTH 8
-#define U_ALIGNMENT_WIDTH 4
+#define SIZEOF_LONG_64BIT      8
+#define ULL_ALIGNMENT_WIDTH    8
+#define UL_ALIGNMENT_WIDTH     SIZEOF_LONG_64BIT
+#define U_ALIGNMENT_WIDTH      4
 
 /*
  * Structure for CPU statistics.
diff --git a/sa.h b/sa.h
index 88bd38ecf4f3a405b476dd1e8bc593f204e516e4..a79c48edf0992477340c8abc202dfe89f3d278bb 100644 (file)
--- a/sa.h
+++ b/sa.h
@@ -352,6 +352,7 @@ struct svg_hdr_parm {
  * Indicate that the file was created by sysstat.
  */
 #define SYSSTAT_MAGIC  0xd596
+#define SYSSTAT_MAGIC_SWAPPED  (((SYSSTAT_MAGIC << 8) | (SYSSTAT_MAGIC >> 8)) & 0xffff)
 
 /*
  * Datafile format magic number.
@@ -359,6 +360,7 @@ struct svg_hdr_parm {
  * no longer compatible with that of previous sysstat versions.
  */
 #define FORMAT_MAGIC   0x2175
+#define FORMAT_MAGIC_SWAPPED   (((FORMAT_MAGIC << 8) | (FORMAT_MAGIC >> 8)) & 0xffff)
 
 /* Previous datafile format magic number used by older sysstat versions */
 #define PREVIOUS_FORMAT_MAGIC  0x2173
@@ -454,6 +456,9 @@ struct file_header {
 };
 
 #define FILE_HEADER_SIZE       (sizeof(struct file_header))
+#define FILE_HEADER_ULL_NR     0       /* Nr of unsigned long long in file_header structure */
+#define FILE_HEADER_UL_NR      1       /* Nr of unsigned long in file_header structure */
+#define FILE_HEADER_U_NR       3       /* 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
@@ -494,6 +499,9 @@ struct file_activity {
 };
 
 #define FILE_ACTIVITY_SIZE     (sizeof(struct file_activity))
+#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     5       /* Nr of [unsigned] int in file_activity structure */
 
 
 /* Record type */
@@ -550,6 +558,9 @@ struct record_header {
 };
 
 #define RECORD_HEADER_SIZE     (sizeof(struct record_header))
+#define RECORD_HEADER_ULL_NR   2       /* Nr of unsigned long long in record_header structure */
+#define RECORD_HEADER_UL_NR    1       /* Nr of unsigned long in record_header structure */
+#define RECORD_HEADER_U_NR     0       /* Nr of unsigned int in record_header structure */
 
 
 /*
@@ -1121,7 +1132,7 @@ int check_disk_reg
        (struct activity *, int, int, int);
 void check_file_actlst
        (int *, char *, struct activity * [], struct file_magic *, struct file_header *,
-        struct file_activity **, unsigned int [], int);
+        struct file_activity **, unsigned int [], int, int *, int *);
 int check_net_dev_reg
        (struct activity *, int, int, int);
 int check_net_edev_reg
@@ -1176,11 +1187,11 @@ void print_sar_restart
 int print_special_record
        (struct record_header *, unsigned int, struct tstamp *, struct tstamp *,
         int, int, struct tm *, struct tm *, char *, int, struct file_magic *,
-        struct file_header *, struct activity * [], struct report_format *);
+        struct file_header *, struct activity * [], struct report_format *, int, int);
 void read_file_stat_bunch
-       (struct activity * [], int, int, int, struct file_activity *);
+       (struct activity * [], int, int, int, struct file_activity *, int, int);
 __nr_t read_vol_act_structures
-       (int, struct activity * [], char *, struct file_magic *, unsigned int);
+       (int, struct activity * [], char *, struct file_magic *, unsigned int, int, int);
 int reallocate_vol_act_structures
        (struct activity * [], unsigned int, unsigned int);
 void replace_nonprintable_char
@@ -1190,7 +1201,7 @@ int sa_fread
 int sa_get_record_timestamp_struct
        (unsigned int, struct record_header *, struct tm *, struct tm *);
 int sa_open_read_magic
-       (int *, char *, struct file_magic *, int);
+       (int *, char *, struct file_magic *, int, int *);
 void select_all_activities
        (struct activity * []);
 void select_default_activity
index 87d16e87e092a038a7fbd758cfb3b6602de89d9f..d7cb66e627420901b9b8951dde566ea0aeee9ec2 100644 (file)
@@ -50,6 +50,9 @@
 int default_file_used = FALSE;
 extern struct act_bitmap cpu_bitmap;
 
+int hdr_types_nr[] = {FILE_HEADER_ULL_NR, FILE_HEADER_UL_NR, FILE_HEADER_U_NR};
+int act_types_nr[] = {FILE_ACTIVITY_ULL_NR, FILE_ACTIVITY_UL_NR, FILE_ACTIVITY_U_NR};
+
 /*
  ***************************************************************************
  * Allocate structures.
@@ -1106,27 +1109,17 @@ void display_sa_file_version(FILE *st, struct file_magic *file_magic)
 void handle_invalid_sa_file(int *fd, struct file_magic *file_magic, char *file,
                            int n)
 {
-       unsigned short sm;
-
        fprintf(stderr, _("Invalid system activity file: %s\n"), file);
 
        if (n == FILE_MAGIC_SIZE) {
-               sm = (file_magic->sysstat_magic << 8) | (file_magic->sysstat_magic >> 8);
-               if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (sm == SYSSTAT_MAGIC)) {
-                       /*
-                        * This is a sysstat file, but this file has an old format
-                        * or its internal endian format doesn't match.
-                        */
+               if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (file_magic->sysstat_magic == SYSSTAT_MAGIC_SWAPPED)) {
+                       /* This is a sysstat file, but this file has an old format */
                        display_sa_file_version(stderr, file_magic);
 
-                       if (sm == SYSSTAT_MAGIC) {
-                               fprintf(stderr, _("Endian format mismatch\n"));
-                       }
-                       else {
-                               fprintf(stderr,
-                                       _("Current sysstat version cannot read the format of this file (%#x)\n"),
-                                       file_magic->format_magic);
-                       }
+                       fprintf(stderr,
+                               _("Current sysstat version cannot read the format of this file (%#x)\n"),
+                               file_magic->sysstat_magic == SYSSTAT_MAGIC ?
+                               file_magic->format_magic : __builtin_bswap16(file_magic->format_magic));
                }
        }
 
@@ -1178,10 +1171,14 @@ void copy_structures(struct activity *act[], unsigned int id_seq[],
  * @ifd                Input file descriptor.
  * @act_nr     Number of activities in file.
  * @file_actlst        Activity list in file.
+ * @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 read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
-                         struct file_activity *file_actlst)
+                         struct file_activity *file_actlst, int endian_mismatch,
+                         int arch_64)
 {
        int i, j, p;
        struct file_activity *fal = file_actlst;
@@ -1219,6 +1216,14 @@ void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
                else {
                        PANIC(p);
                }
+
+               /* Normalize endianness for current activity's structures */
+               if (endian_mismatch) {
+                       for (j = 0; j < (act[p]->nr * act[p]->nr2); j++) {
+                               swap_struct(act[p]->gtypes_nr, (char *) act[p]->buf[curr] + j * act[p]->msize,
+                                           arch_64);
+                       }
+               }
        }
 }
 
@@ -1229,20 +1234,22 @@ void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
  * IN:
  * @dfile      Name of system activity data file.
  * @ignore     Set to 1 if a true sysstat activity file but with a bad
- *             format should not yield an error message. Useful with
- *             sadf -H and sadf -c.
+ *             format should not yield an error message. Useful with
+ *             sadf -H and sadf -c.
  *
  * OUT:
  * @fd         System activity data file descriptor.
  * @file_magic file_magic structure containing data read from file magic
  *             header.
+ * @endian_mismatch
+ *             TRUE if file's data don't match current machine's endianness.
  *
  * RETURNS:
  * -1 if data file is a sysstat file with an old format, 0 otherwise.
  ***************************************************************************
  */
 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
-                      int ignore)
+                      int ignore, int *endian_mismatch)
 {
        int n;
 
@@ -1262,11 +1269,20 @@ int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
        n = read(*fd, file_magic, FILE_MAGIC_SIZE);
 
        if ((n != FILE_MAGIC_SIZE) ||
-           (file_magic->sysstat_magic != SYSSTAT_MAGIC) ||
-           ((file_magic->format_magic != FORMAT_MAGIC) && !ignore)) {
+           ((file_magic->sysstat_magic != SYSSTAT_MAGIC) && (file_magic->sysstat_magic != SYSSTAT_MAGIC_SWAPPED)) ||
+           ((file_magic->format_magic != FORMAT_MAGIC) && (file_magic->format_magic != FORMAT_MAGIC_SWAPPED) && !ignore)) {
                /* Display error message and exit */
                handle_invalid_sa_file(fd, file_magic, dfile, n);
        }
+
+       *endian_mismatch = (file_magic->sysstat_magic != SYSSTAT_MAGIC);
+       if (*endian_mismatch) {
+               /* Swap bytes for file_magic fields */
+               file_magic->sysstat_magic = __builtin_bswap16(file_magic->sysstat_magic);
+               file_magic->format_magic  = __builtin_bswap16(file_magic->format_magic);
+               file_magic->header_size   = __builtin_bswap32(file_magic->header_size);
+       }
+
        if ((file_magic->sysstat_version > 10) ||
            ((file_magic->sysstat_version == 10) && (file_magic->sysstat_patchlevel >= 3))) {
                /* header_size field exists only for sysstat versions 10.3.1 and later */
@@ -1292,23 +1308,26 @@ int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
  * @dfile      Name of system activity data file.
  * @act                Array of activities.
  * @ignore     Set to 1 if a true sysstat activity file but with a bad
- *             format should not yield an error message. Useful with
- *             sadf -H and sadf -c.
+ *             format should not yield an error message. Useful with
+ *             sadf -H and sadf -c.
  *
  * OUT:
  * @ifd                System activity data file descriptor.
  * @file_magic file_magic structure containing data read from file magic
  *             header.
  * @file_hdr   file_hdr structure containing data read from file standard
- *             header.
+ *             header.
  * @file_actlst        Acvtivity list in file.
  * @id_seq     Activity sequence.
+ * @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 check_file_actlst(int *ifd, char *dfile, struct activity *act[],
                       struct file_magic *file_magic, struct file_header *file_hdr,
                       struct file_activity **file_actlst, unsigned int id_seq[],
-                      int ignore)
+                      int ignore, int *endian_mismatch, int *arch_64)
 {
        int i, j, p;
        unsigned int a_cpu = FALSE;
@@ -1316,7 +1335,7 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
        void *buffer = NULL;
 
        /* Open sa data file and read its magic structure */
-       if (sa_open_read_magic(ifd, dfile, file_magic, ignore) < 0)
+       if (sa_open_read_magic(ifd, dfile, file_magic, ignore, endian_mismatch) < 0)
                return;
 
        SREALLOC(buffer, char, file_magic->header_size);
@@ -1330,6 +1349,12 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
        memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
        free(buffer);
 
+       /* Normalize endianness for file_hdr structure */
+       *arch_64 = (file_hdr->sa_sizeof_long == SIZEOF_LONG_64BIT);
+       if (*endian_mismatch) {
+               swap_struct(hdr_types_nr, file_hdr, *arch_64);
+       }
+
        /*
         * Sanity check.
         * Compare against MAX_NR_ACT and not NR_ACT because
@@ -1350,6 +1375,11 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
 
                sa_fread(*ifd, fal, FILE_ACTIVITY_SIZE, HARD_SIZE);
 
+               /* Normalize endianness for file_activity structures */
+               if (*endian_mismatch) {
+                       swap_struct(act_types_nr, fal, *arch_64);
+               }
+
                /*
                 * Every activity, known or unknown, should have
                 * at least one item and sub-item.
@@ -1500,6 +1530,9 @@ int reallocate_vol_act_structures(struct activity *act[], unsigned int act_nr,
  * @file       Name of file being read.
  * @file_magic file_magic structure filled with file magic header data.
  * @vol_act_nr Number of volatile activities structures to read.
+ * @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.
  *
  * RETURNS:
  * New number of items.
@@ -1510,7 +1543,8 @@ int reallocate_vol_act_structures(struct activity *act[], unsigned int act_nr,
  */
 __nr_t read_vol_act_structures(int ifd, struct activity *act[], char *file,
                               struct file_magic *file_magic,
-                              unsigned int vol_act_nr)
+                              unsigned int vol_act_nr, int endian_mismatch,
+                              int arch_64)
 {
        struct file_activity file_act;
        int item_nr = 0;
@@ -1520,6 +1554,11 @@ __nr_t read_vol_act_structures(int ifd, struct activity *act[], char *file,
 
                sa_fread(ifd, &file_act, FILE_ACTIVITY_SIZE, HARD_SIZE);
 
+               /* Normalize endianness for file_activity structures */
+               if (endian_mismatch) {
+                       swap_struct(act_types_nr, &file_act, arch_64);
+               }
+
                if (file_act.id) {
                        rc = reallocate_vol_act_structures(act, file_act.nr, file_act.id);
                        if ((rc == 0) && !item_nr) {
@@ -2201,7 +2240,7 @@ void set_record_timestamp_string(unsigned int l_flags, struct record_header *rec
  * @rtype      Record type (R_RESTART or R_COMMENT).
  * @ifd                Input file descriptor.
  * @rectime    Structure where timestamp (expressed in local time or in UTC
- *             depending on whether options -T/-t have been used or not) can
+ *             depending on whether options -T/-t have been used or not) can
  *             be saved for current record.
  * @loctime    Structure where timestamp (expressed in local time) can be
  *             saved for current record. May be NULL.
@@ -2210,13 +2249,16 @@ void set_record_timestamp_string(unsigned int l_flags, struct record_header *rec
  * @file_magic file_magic structure filled with file magic header data.
  * @file_hdr   System activity file standard header.
  * @act                Array of activities.
- * @ofmt               Pointer on report output format structure.
+ * @ofmt       Pointer on report output format structure.
+ * @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.
  *
  * OUT:
- * @rectime            Structure where timestamp (expressed in local time
- *                     or in UTC) has been saved.
- * @loctime            Structure where timestamp (expressed in local time)
- *                     has been saved (if requested).
+ * @rectime    Structure where timestamp (expressed in local time or in UTC)
+ *             has been saved.
+ * @loctime    Structure where timestamp (expressed in local time) has been
+ *             saved (if requested).
  *
  * RETURNS:
  * 1 if the record has been successfully displayed, and 0 otherwise.
@@ -2226,7 +2268,8 @@ int print_special_record(struct record_header *record_hdr, unsigned int l_flags,
                         struct tstamp *tm_start, struct tstamp *tm_end, int rtype, int ifd,
                         struct tm *rectime, struct tm *loctime, char *file, int tab,
                         struct file_magic *file_magic, struct file_header *file_hdr,
-                        struct activity *act[], struct report_format *ofmt)
+                        struct activity *act[], struct report_format *ofmt,
+                        int endian_mismatch, int arch_64)
 {
        char cur_date[TIMESTAMP_LEN], cur_time[TIMESTAMP_LEN];
        int dp = 1;
@@ -2256,7 +2299,8 @@ int print_special_record(struct record_header *record_hdr, unsigned int l_flags,
        if (rtype == R_RESTART) {
                /* Don't forget to read the volatile activities structures */
                new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic,
-                                                    file_hdr->sa_vol_act_nr);
+                                                    file_hdr->sa_vol_act_nr,
+                                                    endian_mismatch, arch_64);
 
                if (!dp)
                        return 0;
index 8475e2a23e845c1e6fc0fc0874ea87134ee87466..f22f7682a2b387334969edf25e460510789d9f55 100644 (file)
--- a/sa_conv.c
+++ b/sa_conv.c
@@ -38,6 +38,8 @@
 # define _(string) (string)
 #endif
 
+extern int endian_mismatch;
+
 /*
  ***************************************************************************
  * Read and upgrade file's magic data section.
@@ -62,7 +64,7 @@ int upgrade_magic_section(char dfile[], int *fd, int stdfd,
        struct file_magic fm;
 
        /* Open and read sa magic structure */
-       sa_open_read_magic(fd, dfile, file_magic, TRUE);
+       sa_open_read_magic(fd, dfile, file_magic, TRUE, &endian_mismatch);
 
        if ((file_magic->format_magic != FORMAT_MAGIC) &&
            (file_magic->format_magic != PREVIOUS_FORMAT_MAGIC)) {
diff --git a/sadf.c b/sadf.c
index d33d4ee55b3d6a4cb32cfab3ebe2b284853fe069..b6148710279082f9d640180d11cd9c606db472a6 100644 (file)
--- a/sadf.c
+++ b/sadf.c
@@ -48,6 +48,13 @@ char *sccsid(void) { return (SCCSID); }
 
 long interval = -1, count = 0;
 
+/* TRUE if data read from file don't match current machine's endianness */
+int endian_mismatch = FALSE;
+/* TRUE if file's data come from a 64 bit machine */
+int arch_64 = FALSE;
+
+int rec_types_nr[] = {RECORD_HEADER_ULL_NR, RECORD_HEADER_UL_NR, RECORD_HEADER_U_NR};
+
 unsigned int flags = 0;
 unsigned int dm_major;         /* Device-mapper major number */
 unsigned int format = 0;       /* Output format */
@@ -269,6 +276,11 @@ int read_next_sample(int ifd, int action, int curr, char *file, int *rtype, int
        *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 */
@@ -284,7 +296,8 @@ int read_next_sample(int ifd, int action, int curr, char *file, int *rtype, int
                                /* Display COMMENT record */
                                print_special_record(&record_hdr[curr], flags, &tm_start, &tm_end,
                                                     *rtype, ifd, rectime, loctime, file, tab,
-                                                    file_magic, &file_hdr, act, fmt[f_position]);
+                                                    file_magic, &file_hdr, act, fmt[f_position],
+                                                    endian_mismatch, arch_64);
                        }
                }
                else if (*rtype == R_RESTART) {
@@ -297,7 +310,8 @@ int read_next_sample(int ifd, int action, int curr, char *file, int *rtype, int
                                 */
                                if (!(action & DONT_READ_VOLATILE)) {
                                        read_vol_act_structures(ifd, act, file, file_magic,
-                                                               file_hdr.sa_vol_act_nr);
+                                                               file_hdr.sa_vol_act_nr,
+                                                               endian_mismatch, arch_64);
                                }
                                if (action & SET_TIMESTAMPS) {
                                        sa_get_record_timestamp_struct(flags, &record_hdr[curr],
@@ -308,7 +322,8 @@ int read_next_sample(int ifd, int action, int curr, char *file, int *rtype, int
                                /* Display RESTART record */
                                print_special_record(&record_hdr[curr], flags, &tm_start, &tm_end,
                                                     *rtype, ifd, rectime, loctime, file, tab,
-                                                    file_magic, &file_hdr, act, fmt[f_position]);
+                                                    file_magic, &file_hdr, act, fmt[f_position],
+                                                    endian_mismatch, arch_64);
                        }
                }
                else {
@@ -317,7 +332,7 @@ int read_next_sample(int ifd, int action, int curr, char *file, int *rtype, int
                         * So read now the extra fields.
                         */
                        read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
-                                            file_actlst);
+                                            file_actlst, endian_mismatch, arch_64);
                        sa_get_record_timestamp_struct(flags, &record_hdr[curr], rectime, loctime);
                }
        }
@@ -1253,7 +1268,8 @@ void logic2_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_
                if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
                        print_special_record(&record_hdr[curr], flags, &tm_start, &tm_end,
                                             R_RESTART, ifd, rectime, loctime, file, 0,
-                                            file_magic, &file_hdr, act, fmt[f_position]);
+                                            file_magic, &file_hdr, act, fmt[f_position],
+                                            endian_mismatch, arch_64);
                }
        }
        while (!eosaf);
@@ -1414,7 +1430,7 @@ void read_stats_from_file(char dfile[])
        /* Prepare file for reading and read its headers */
        ignore = ACCEPT_BAD_FILE_FORMAT(fmt[f_position]->options);
        check_file_actlst(&ifd, dfile, act, &file_magic, &file_hdr,
-                         &file_actlst, id_seq, ignore);
+                         &file_actlst, id_seq, ignore, &endian_mismatch, &arch_64);
 
        /* Now pick up number of proc for this file */
        cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr;
diff --git a/sar.c b/sar.c
index f8a1e548973415373a8ce8bb71a728e30dcfe5cd..a72e0f468994c6e52f9d9716bba7f71dc8093884 100644 (file)
--- a/sar.c
+++ b/sar.c
@@ -52,11 +52,16 @@ long interval = -1, count = 0;
 
 /* TRUE if a header line must be printed */
 int dis = TRUE;
+/* TRUE if data read from file don't match current machine's endianness */
+int endian_mismatch = FALSE;
+/* TRUE if file's data come from a 64 bit machine */
+int arch_64 = FALSE;
 
 unsigned int flags = 0;
 unsigned int dm_major; /* Device-mapper major number */
 
 char timestamp[2][TIMESTAMP_LEN];
+int rec_types_nr[] = {RECORD_HEADER_ULL_NR, RECORD_HEADER_UL_NR, RECORD_HEADER_U_NR};
 
 unsigned long avg_count = 0;
 
@@ -680,19 +685,23 @@ 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.
+ * @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.
  *
  * OUT:
  * @curr       Index in array for next sample statistics.
  * @cnt                Number of remaining lines of stats to write.
  * @eosaf      Set to TRUE if EOF (end of file) has been reached.
- * @reset      Set to TRUE if last_uptime variable should be
- *             reinitialized (used in next_slice() function).
+ * @reset      Set to TRUE if last_uptime variable should be reinitialized
+ *             (used in next_slice() function).
  ***************************************************************************
  */
 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)
+                          struct file_magic *file_magic, int endian_mismatch,
+                          int arch_64)
 {
        int p, reset_cd;
        unsigned long lines = 0;
@@ -728,11 +737,17 @@ void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf
                /* 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);
+               }
                rtype = record_hdr[*curr].record_type;
 
                if (!*eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
                        /* Read the extra fields since it's not a special record */
-                       read_file_stat_bunch(act, *curr, ifd, file_hdr.sa_act_nr, file_actlst);
+                       read_file_stat_bunch(act, *curr, ifd, file_hdr.sa_act_nr, file_actlst,
+                                            endian_mismatch, arch_64);
                }
 
                if ((lines >= rows) || !lines) {
@@ -749,7 +764,8 @@ void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf
                                next = print_special_record(&record_hdr[*curr], flags + S_F_LOCAL_TIME,
                                                            &tm_start, &tm_end, R_COMMENT, ifd,
                                                            &rectime, NULL, file, 0,
-                                                           file_magic, &file_hdr, act, &sar_fmt);
+                                                           file_magic, &file_hdr, act, &sar_fmt,
+                                                           endian_mismatch, arch_64);
                                if (next) {
                                        /* A line of comment was actually displayed */
                                        lines++;
@@ -892,7 +908,7 @@ void read_stats_from_file(char from_file[])
 
        /* Read file headers and activity list */
        check_file_actlst(&ifd, from_file, act, &file_magic, &file_hdr,
-                         &file_actlst, id_seq, FALSE);
+                         &file_actlst, id_seq, FALSE, &endian_mismatch, &arch_64);
 
        /* Perform required allocations */
        allocate_structures(act);
@@ -912,12 +928,17 @@ void read_stats_from_file(char from_file[])
                                /* 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 ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
                                print_special_record(&record_hdr[0], flags + S_F_LOCAL_TIME,
                                                     &tm_start, &tm_end, rtype, ifd,
                                                     &rectime, NULL, from_file, 0, &file_magic,
-                                                    &file_hdr, act, &sar_fmt);
+                                                    &file_hdr, act, &sar_fmt, endian_mismatch, arch_64);
                        }
                        else {
                                /*
@@ -925,7 +946,7 @@ void read_stats_from_file(char from_file[])
                                 * So read now the extra fields.
                                 */
                                read_file_stat_bunch(act, 0, ifd, file_hdr.sa_act_nr,
-                                                    file_actlst);
+                                                    file_actlst, endian_mismatch, arch_64);
                                if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME,
                                                                   &record_hdr[0],
                                                                   &rectime, NULL))
@@ -967,7 +988,7 @@ 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);
+                                                     from_file, &file_magic, endian_mismatch, arch_64);
                        }
                        else {
                                unsigned int optf, msk;
@@ -981,7 +1002,8 @@ void read_stats_from_file(char from_file[])
                                                handle_curr_act_stats(ifd, fpos, &curr, &cnt,
                                                                      &eosaf, rows, act[p]->id,
                                                                      &reset, file_actlst,
-                                                                     from_file, &file_magic);
+                                                                     from_file, &file_magic,
+                                                                     endian_mismatch, arch_64);
                                                act[p]->opt_flags = optf;
                                        }
                                }
@@ -993,17 +1015,24 @@ void read_stats_from_file(char from_file[])
                        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);
+                               }
                                rtype = record_hdr[curr].record_type;
+
                                if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
                                        read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
-                                                            file_actlst);
+                                                            file_actlst, endian_mismatch, arch_64);
                                }
                                else if (!eosaf && (rtype == R_COMMENT)) {
                                        /* This was a COMMENT record: print it */
                                        print_special_record(&record_hdr[curr], flags + S_F_LOCAL_TIME,
                                                             &tm_start, &tm_end, R_COMMENT, ifd,
                                                             &rectime, NULL, from_file, 0,
-                                                            &file_magic, &file_hdr, act, &sar_fmt);
+                                                            &file_magic, &file_hdr, act, &sar_fmt,
+                                                            endian_mismatch, arch_64);
                                }
                        }
                        while (!eosaf && (rtype != R_RESTART));
@@ -1014,7 +1043,8 @@ void read_stats_from_file(char from_file[])
                        print_special_record(&record_hdr[curr], flags + S_F_LOCAL_TIME,
                                             &tm_start, &tm_end, R_RESTART, ifd,
                                             &rectime, NULL, from_file, 0,
-                                            &file_magic, &file_hdr, act, &sar_fmt);
+                                            &file_magic, &file_hdr, act, &sar_fmt,
+                                            endian_mismatch, arch_64);
                }
        }
        while (!eosaf);