]> granicus.if.org Git - sysstat/commitdiff
Option -c added to sadf: Upgrade an old sa datafile
authorSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 11 Jul 2014 07:56:06 +0000 (09:56 +0200)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 11 Jul 2014 07:56:06 +0000 (09:56 +0200)
This patch adds option -c to sadf. This option enables the user to
upgrade ("convert") an old system activity datafile (version 9.1.6 and
later) to the up-to-date format (11.1.1 as of today).
Enter "sadf -c old_datafile >new_datafile".

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
Makefile.in
format.c
sa.h
sa_common.c
sa_conv.c [new file with mode: 0644]
sa_conv.h [new file with mode: 0644]
sadc.c
sadf.c
sadf.h

index 7880270fd9bf647d41ba0d7995a89635d168ff1b..45bd14013a2206e484c333160e1d94548cbc95da 100644 (file)
@@ -208,6 +208,8 @@ format.o: format.c sadf.h
 
 sadf_misc.o: sadf_misc.c sadf.h sa.h
 
+sa_conv.o: sa_conv.c sadf.h sa.h sa_conv.h
+
 # Explicit rules needed to prevent possible file corruption
 # when using parallel execution.
 libsyscom.a: common.o ioconf.o
@@ -233,7 +235,7 @@ sar: sar.o act_sar.o sa_common.o pr_stats.o libsyscom.a
 
 sadf.o: sadf.c sadf.h version.h sa.h common.h ioconf.h sysconfig.h
 
-sadf: sadf.o act_sadf.o format.o sadf_misc.o rndr_stats.o xml_stats.o json_stats.o sa_common.o libsyscom.a
+sadf: sadf.o act_sadf.o format.o sadf_misc.o sa_conv.o rndr_stats.o xml_stats.o json_stats.o sa_common.o libsyscom.a
 
 iostat.o: iostat.c iostat.h version.h common.h ioconf.h sysconfig.h rd_stats.h count.h
 
index 9c331cfce663758716428ac1462302196158b595..6a957eac7fa18690455de9440a4c99e8e616c81a 100644 (file)
--- a/format.c
+++ b/format.c
@@ -94,6 +94,19 @@ struct report_format json_fmt = {
        .f_comment      = print_json_comment
 };
 
+/*
+ * Display only datafile header.
+ */
+struct report_format conv_fmt = {
+       .id             = F_CONV_OUTPUT,
+       .options        = FO_BAD_FILE_FORMAT,
+       .f_header       = NULL,
+       .f_statistics   = NULL,
+       .f_timestamp    = NULL,
+       .f_restart      = NULL,
+       .f_comment      = NULL
+};
+
 /*
  * Array of output formats.
  */
@@ -102,5 +115,6 @@ struct report_format *fmt[NR_FMT] = {
        &db_fmt,
        &ppc_fmt,
        &xml_fmt,
-       &json_fmt
+       &json_fmt,
+       &conv_fmt
 };
diff --git a/sa.h b/sa.h
index 4240b82825defc9ddb91b5413bb644a9fbb9ed24..3f970c05183b59272a96ee3af64fc55d6b34ccdc 100644 (file)
--- a/sa.h
+++ b/sa.h
@@ -487,6 +487,9 @@ struct activity {
  */
 #define FORMAT_MAGIC   0x2173
 
+/* Previous datafile format magic number used by older sysstat versions */
+#define PREVIOUS_FORMAT_MAGIC  0x2171
+
 /* Structure for file magic header data */
 struct file_magic {
        /*
@@ -508,10 +511,17 @@ struct file_magic {
         * Size of file's header (size of file_header structure used by file).
         */
        unsigned int header_size;
+       /*
+        * Set to non zero if data file has been converted with "sadf -c" from
+        * an old format (version x.y.z) to a newest format (version X.Y.Z).
+        * In this case, the value is: Y*16 + Z + 1.
+        * The FORMAT_MAGIC value of the file can be used to determine X.
+        */
+       unsigned char upgraded;
        /*
         * Padding. Reserved for future use while avoiding a format change.
         */
-       unsigned char pad[64];
+       unsigned char pad[63];
 };
 
 #define FILE_MAGIC_SIZE        (sizeof(struct file_magic))
@@ -829,6 +839,8 @@ extern int
        datecmp(struct tm *, struct tstamp *);
 extern void
        display_sa_file_version(FILE *, struct file_magic *);
+extern void
+       enum_version_nr(struct file_magic *);
 extern void
        free_bitmaps(struct activity * []);
 extern void
@@ -871,6 +883,8 @@ extern int
        reallocate_vol_act_structures(struct activity * [], unsigned int, unsigned int);
 extern int
        sa_fread(int, void *, int, int);
+extern int
+       sa_open_read_magic(int *, char *, struct file_magic *, int);
 extern void
        select_all_activities(struct activity * []);
 extern void
index 9f485a4baaa42cbb670e64b6546400a3dccb3003..66ebe43cb58fc55cd7ea74cbf06d56c33887134e 100644 (file)
@@ -31,6 +31,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#include "version.h"
 #include "sa.h"
 #include "common.h"
 #include "ioconf.h"
@@ -1209,37 +1210,30 @@ void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
 
 /*
  ***************************************************************************
- * Open a data file, and perform various checks before reading.
+ * Open a sysstat activity data file and read its magic structure.
  *
  * IN:
- * @dfile      Name of system activity data file
- * @act                Array of activities.
+ * @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.
  *
  * OUT:
- * @ifd                System activity data file descriptor
+ * @fd         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
- * @file_actlst        Acvtivity list in file.
- * @id_seq     Activity sequence.
+ *             header.
+ *
+ * RETURNS:
+ * -1 if data file is a sysstat file with an old format, 0 otherwise.
  ***************************************************************************
  */
-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 sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
                       int ignore)
 {
-       int i, j, n, p;
-       unsigned int a_cpu = FALSE;
-       struct file_activity *fal;
-       void *buffer = NULL;
+       int n;
 
        /* Open sa data file */
-       if ((*ifd = open(dfile, O_RDONLY)) < 0) {
+       if ((*fd = open(dfile, O_RDONLY)) < 0) {
                int saved_errno = errno;
 
                fprintf(stderr, _("Cannot open %s: %s\n"), dfile, strerror(errno));
@@ -1251,22 +1245,55 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
        }
 
        /* Read file magic data */
-       n = read(*ifd, file_magic, FILE_MAGIC_SIZE);
+       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)) {
-
-               if (ignore &&
-                   (n == FILE_MAGIC_SIZE) &&
-                   (file_magic->sysstat_magic == SYSSTAT_MAGIC))
-                       /* Don't display error message. This is for sadf -H */
-                       return;
-               else {
-                       /* Display error message and exit */
-                       handle_invalid_sa_file(ifd, file_magic, dfile, n);
-               }
+           ((file_magic->format_magic != FORMAT_MAGIC) && !ignore)) {
+               /* Display error message and exit */
+               handle_invalid_sa_file(fd, file_magic, dfile, n);
        }
+       if (file_magic->format_magic != FORMAT_MAGIC)
+               /* This is an old sa datafile format */
+               return -1;
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Open a data file, and perform various checks before reading.
+ *
+ * IN:
+ * @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.
+ *
+ * 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.
+ * @file_actlst        Acvtivity list in file.
+ * @id_seq     Activity sequence.
+ ***************************************************************************
+ */
+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 i, j, p;
+       unsigned int a_cpu = FALSE;
+       struct file_activity *fal;
+       void *buffer = NULL;
+
+       /* Open sa data file and read its magic structure */
+       if (sa_open_read_magic(ifd, dfile, file_magic, ignore) < 0)
+               return;
 
        SREALLOC(buffer, char, file_magic->header_size);
 
@@ -1940,3 +1967,40 @@ double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx)
        return 0;
 }
 
+/*
+ ***************************************************************************
+ * Fill system activity file magic header.
+ *
+ * IN:
+ * @file_magic System activity file magic header.
+ ***************************************************************************
+ */
+void enum_version_nr(struct file_magic *fm)
+{
+       char *v;
+       char version[16];
+
+       fm->sysstat_extraversion = 0;
+
+       strcpy(version, VERSION);
+
+       /* Get version number */
+       if ((v = strtok(version, ".")) == NULL)
+               return;
+       fm->sysstat_version = atoi(v) & 0xff;
+
+       /* Get patchlevel number */
+       if ((v = strtok(NULL, ".")) == NULL)
+               return;
+       fm->sysstat_patchlevel = atoi(v) & 0xff;
+
+       /* Get sublevel number */
+       if ((v = strtok(NULL, ".")) == NULL)
+               return;
+       fm->sysstat_sublevel = atoi(v) & 0xff;
+
+       /* Get extraversion number. Don't necessarily exist */
+       if ((v = strtok(NULL, ".")) == NULL)
+               return;
+       fm->sysstat_extraversion = atoi(v) & 0xff;
+}
diff --git a/sa_conv.c b/sa_conv.c
new file mode 100644 (file)
index 0000000..e2f7725
--- /dev/null
+++ b/sa_conv.c
@@ -0,0 +1,1003 @@
+/*
+ * sa_conv.c: Convert an old format sa file to the up-to-date format.
+ * (C) 1999-2014 by Sebastien GODARD (sysstat <at> orange.fr)
+ *
+ ***************************************************************************
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU General Public License as published  by  the *
+ * Free Software Foundation; either version 2 of the License, or (at  your *
+ * option) any later version.                                              *
+ *                                                                         *
+ * This program is distributed in the hope that it  will  be  useful,  but *
+ * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
+ * for more details.                                                       *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License along *
+ * with this program; if not, write to the Free Software Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                   *
+ ***************************************************************************
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "version.h"
+#include "sadf.h"
+#include "sa.h"
+#include "sa_conv.h"
+
+#ifdef USE_NLS
+# include <locale.h>
+# include <libintl.h>
+# define _(string) gettext(string)
+#else
+# define _(string) (string)
+#endif
+
+/*
+ ***************************************************************************
+ * Read and upgrade file's magic data section.
+ *
+ * IN:
+ * @dfile              System activity data file name.
+ * @stdfd              File descriptor for STDOUT.
+ *
+ * OUT:
+ * @fd                 File descriptor for sa datafile to convert.
+ * @file_magic         Pointer on file_magic structure.
+ * @previous_format    TRUE is sa datafile has an old format which is no
+ *                     longer compatible with current one.
+ *
+ * RETURNS:
+ * -1 on error, 0 otherwise.
+ ***************************************************************************
+ */
+int upgrade_magic_section(char dfile[], int *fd, int stdfd,
+                         struct file_magic *file_magic, int *previous_format)
+{
+       int n;
+       struct file_magic fm;
+
+       /* Open and read sa magic structure */
+       sa_open_read_magic(fd, dfile, file_magic, TRUE);
+
+       if ((file_magic->format_magic != FORMAT_MAGIC) &&
+           (file_magic->format_magic != PREVIOUS_FORMAT_MAGIC)) {
+               fprintf(stderr, _("Cannot convert the format of this file\n"));
+               return -1;
+       }
+
+       fprintf(stderr, "file_magic: ");
+       if (file_magic->format_magic == PREVIOUS_FORMAT_MAGIC) {
+               /*
+                * We have read too many bytes: file_magic structure
+                * was smaller with previous sysstat versions.
+                * Go back 4 (unsigned int header_size) + 64 (char pad[64]) bytes.
+                */
+               if (lseek(*fd, -68, SEEK_CUR) < 0) {
+                       fprintf(stderr, "\nlseek: %s\n", strerror(errno));
+                       return -1;
+               }
+               /* Set format magic number to that of current version */
+               *previous_format = TRUE;
+               file_magic->format_magic = FORMAT_MAGIC;
+
+               /* Fill new structure members */
+               file_magic->header_size = FILE_HEADER_SIZE;
+               memset(file_magic->pad, 0, 64);
+       }
+
+       /* Indicate that file has been upgraded */
+       enum_version_nr(&fm);
+       file_magic->upgraded = (fm.sysstat_patchlevel << 4) +
+                              fm.sysstat_sublevel + 1;
+
+       /* Write file_magic structure */
+       if ((n = write(stdfd, file_magic, FILE_MAGIC_SIZE)) != FILE_MAGIC_SIZE) {
+               fprintf(stderr, "\nwrite: %s\n", strerror(errno));
+               return -1;
+       }
+       fprintf(stderr, "OK\n");
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade file_header structure (from 0x2171 format to current format).
+ *
+ * IN:
+ * @buffer     Pointer on file's header structure (as read from file).
+ *
+ * OUT:
+ * @file_hdr   Pointer on file_header structure (up-to-date format).
+ ***************************************************************************
+ */
+void upgrade_file_header(void *buffer, struct file_header *file_hdr)
+{
+       struct file_header_2171 *f_hdr = (struct file_header_2171 *) buffer;
+
+       file_hdr->sa_ust_time = f_hdr->sa_ust_time;
+       file_hdr->sa_act_nr = f_hdr->sa_act_nr;
+       file_hdr->sa_day = f_hdr->sa_day;
+       file_hdr->sa_month = f_hdr->sa_month;
+       file_hdr->sa_year = f_hdr->sa_year;
+       file_hdr->sa_sizeof_long = f_hdr->sa_sizeof_long;
+       strncpy(file_hdr->sa_sysname, f_hdr->sa_sysname, UTSNAME_LEN);
+       file_hdr->sa_sysname[UTSNAME_LEN - 1] = '\0';
+       strncpy(file_hdr->sa_nodename, f_hdr->sa_nodename, UTSNAME_LEN);
+       file_hdr->sa_nodename[UTSNAME_LEN - 1] = '\0';
+       strncpy(file_hdr->sa_release, f_hdr->sa_release, UTSNAME_LEN);
+       file_hdr->sa_release[UTSNAME_LEN - 1] = '\0';
+       strncpy(file_hdr->sa_machine, f_hdr->sa_machine, UTSNAME_LEN);
+       file_hdr->sa_machine[UTSNAME_LEN - 1] = '\0';
+       /* The last two values below will be updated later */
+       file_hdr->sa_vol_act_nr = 0;
+       file_hdr->sa_last_cpu_nr = 0;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_io structure (from ACTIVITY_MAGIC_BASE format to
+ * ACTIVITY_MAGIC_BASE + 1 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ ***************************************************************************
+ */
+void upgrade_stats_io(struct activity *act[], int p)
+{
+       struct stats_io *sic = (struct stats_io *) act[p]->buf[1];
+       struct stats_io_8a *sip = (struct stats_io_8a *) act[p]->buf[0];
+
+       sic->dk_drive = (unsigned long long) sip->dk_drive;
+       sic->dk_drive_rio = (unsigned long long) sip->dk_drive_rio;
+       sic->dk_drive_wio = (unsigned long long) sip->dk_drive_wio;
+       sic->dk_drive_rblk = (unsigned long long) sip->dk_drive_rblk;
+       sic->dk_drive_wblk = (unsigned long long) sip->dk_drive_wblk;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_queue structure (from ACTIVITY_MAGIC_BASE format to
+ * ACTIVITY_MAGIC_BASE + 1 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ ***************************************************************************
+ */
+void upgrade_stats_queue(struct activity *act[], int p)
+{
+       struct stats_queue *sqc = (struct stats_queue *) act[p]->buf[1];
+       struct stats_queue_8a *sqp = (struct stats_queue_8a *) act[p]->buf[0];
+
+       sqc->nr_running = sqp->nr_running;
+       sqc->procs_blocked = 0; /* New field */
+       sqc->load_avg_1 = sqp->load_avg_1;
+       sqc->load_avg_5 = sqp->load_avg_5;
+       sqc->load_avg_15 = sqp->load_avg_15;
+       sqc->nr_threads = sqp->nr_threads;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_disk structure (from ACTIVITY_MAGIC_BASE format to
+ * ACTIVITY_MAGIC_BASE + 1 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ ***************************************************************************
+ */
+void upgrade_stats_disk(struct activity *act[], int p)
+{
+       int i;
+       struct stats_disk *sdc;
+       struct stats_disk_8a *sdp;
+
+       for (i = 0; i < act[p]->nr; i++) {
+               sdp = (struct stats_disk_8a *) ((char *) act[p]->buf[0] + i * act[p]->msize);
+               sdc = (struct stats_disk *)    ((char *) act[p]->buf[1] + i * act[p]->fsize);
+
+               sdc->nr_ios = (unsigned long long) sdp->nr_ios;
+               sdc->rd_sect = (unsigned long) sdp->rd_sect;
+               sdc->wr_sect = (unsigned long) sdp->wr_sect;
+               sdc->rd_ticks = (unsigned int) sdp->rd_ticks;
+               sdc->wr_ticks = (unsigned int) sdp->wr_ticks;
+               sdc->tot_ticks = (unsigned int) sdp->tot_ticks;
+               sdc->rq_ticks = (unsigned int) sdp->rq_ticks;
+               sdc->major = sdp->major;
+               sdc->minor = sdp->minor;
+       }
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_net_dev structure (from ACTIVITY_MAGIC_BASE or
+ * ACTIVITY_MAGIC_BASE + 1 format to ACTIVITY_MAGIC_BASE + 2 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ * @m_format   Structure format magic value.
+ ***************************************************************************
+ */
+void upgrade_stats_net_dev(struct activity *act[], int p, unsigned int m_format)
+{
+       int i;
+       struct stats_net_dev *sndc;
+
+       if (m_format == ACTIVITY_MAGIC_BASE) {
+               struct stats_net_dev_8a *sndp_a;
+
+               for (i = 0; i < act[p]->nr; i++) {
+                       sndp_a = (struct stats_net_dev_8a *) ((char *) act[p]->buf[0] + i * act[p]->msize);
+                       sndc = (struct stats_net_dev *) ((char *) act[p]->buf[1] + i * act[p]->fsize);
+
+                       sndc->rx_packets = (unsigned long long) sndp_a->rx_packets;
+                       sndc->tx_packets = (unsigned long long) sndp_a->tx_packets;
+                       sndc->rx_bytes = (unsigned long long) sndp_a->rx_bytes;
+                       sndc->tx_bytes = (unsigned long long) sndp_a->tx_bytes;
+                       sndc->rx_compressed = (unsigned long long) sndp_a->rx_compressed;
+                       sndc->tx_compressed = (unsigned long long) sndp_a->tx_compressed;
+                       sndc->multicast = (unsigned long long) sndp_a->multicast;
+                       sndc->speed = 0; /* New field */
+                       strncpy(sndc->interface, sndp_a->interface, MAX_IFACE_LEN);
+                       sndc->interface[MAX_IFACE_LEN - 1] = '\0';
+                       sndc->duplex = '\0'; /* New field */
+               }
+       }
+       else {
+               struct stats_net_dev_8b *sndp_b;
+
+               for (i = 0; i < act[p]->nr; i++) {
+                       sndp_b = (struct stats_net_dev_8b *) ((char *) act[p]->buf[0] + i * act[p]->msize);
+                       sndc = (struct stats_net_dev *) ((char *) act[p]->buf[1] + i * act[p]->fsize);
+
+                       sndc->rx_packets = sndp_b->rx_packets;
+                       sndc->tx_packets = sndp_b->tx_packets;
+                       sndc->rx_bytes = sndp_b->rx_bytes;
+                       sndc->tx_bytes = sndp_b->tx_bytes;
+                       sndc->rx_compressed = sndp_b->rx_compressed;
+                       sndc->tx_compressed = sndp_b->tx_compressed;
+                       sndc->multicast = sndp_b->multicast;
+                       sndc->speed = 0; /* New field */
+                       strncpy(sndc->interface, sndp_b->interface, MAX_IFACE_LEN);
+                       sndc->interface[MAX_IFACE_LEN - 1] = '\0';
+                       sndc->duplex = '\0'; /* New field */
+               }
+       }
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_net_edev structure (from ACTIVITY_MAGIC_BASE format to
+ * ACTIVITY_MAGIC_BASE + 1 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ ***************************************************************************
+ */
+void upgrade_stats_net_edev(struct activity *act[], int p)
+{
+       int i;
+       struct stats_net_edev *snedc;
+       struct stats_net_edev_8a *snedp;
+
+       for (i = 0; i < act[p]->nr; i++) {
+               snedp = (struct stats_net_edev_8a *) ((char *) act[p]->buf[0] + i * act[p]->msize);
+               snedc = (struct stats_net_edev *) ((char *) act[p]->buf[1] + i * act[p]->fsize);
+
+               snedc->collisions = (unsigned long long) snedp->collisions;
+               snedc->rx_errors = (unsigned long long) snedp->rx_errors;
+               snedc->tx_errors = (unsigned long long) snedp->tx_errors;
+               snedc->rx_dropped = (unsigned long long) snedp->rx_dropped;
+               snedc->tx_dropped = (unsigned long long) snedp->tx_dropped;
+               snedc->rx_fifo_errors = (unsigned long long) snedp->rx_fifo_errors;
+               snedc->tx_fifo_errors = (unsigned long long) snedp->tx_fifo_errors;
+               snedc->rx_frame_errors = (unsigned long long) snedp->rx_frame_errors;
+               snedc->tx_carrier_errors = (unsigned long long) snedp->tx_carrier_errors;
+               strncpy(snedc->interface, snedp->interface, MAX_IFACE_LEN);
+               snedc->interface[MAX_IFACE_LEN - 1] = '\0';
+       }
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_net_ip structure (from ACTIVITY_MAGIC_BASE format to
+ * ACTIVITY_MAGIC_BASE + 1 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ ***************************************************************************
+ */
+void upgrade_stats_net_ip(struct activity *act[], int p)
+{
+       struct stats_net_ip *snic = (struct stats_net_ip *) act[p]->buf[1];
+       struct stats_net_ip_8a *snip = (struct stats_net_ip_8a *) act[p]->buf[0];
+
+       snic->InReceives = (unsigned long long) snip->InReceives;
+       snic->ForwDatagrams = (unsigned long long) snip->ForwDatagrams;
+       snic->InDelivers = (unsigned long long) snip->InDelivers;
+       snic->OutRequests = (unsigned long long) snip->OutRequests;
+       snic->ReasmReqds = (unsigned long long) snip->ReasmReqds;
+       snic->ReasmOKs = (unsigned long long) snip->ReasmOKs;
+       snic->FragOKs = (unsigned long long) snip->FragOKs;
+       snic->FragCreates = (unsigned long long) snip->FragCreates;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_net_eip structure (from ACTIVITY_MAGIC_BASE format to
+ * ACTIVITY_MAGIC_BASE + 1 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ ***************************************************************************
+ */
+void upgrade_stats_net_eip(struct activity *act[], int p)
+{
+       struct stats_net_eip *sneic = (struct stats_net_eip *) act[p]->buf[1];
+       struct stats_net_eip_8a *sneip = (struct stats_net_eip_8a *) act[p]->buf[0];
+
+       sneic->InHdrErrors = (unsigned long long) sneip->InHdrErrors;
+       sneic->InAddrErrors = (unsigned long long) sneip->InAddrErrors;
+       sneic->InUnknownProtos = (unsigned long long) sneip->InUnknownProtos;
+       sneic->InDiscards = (unsigned long long) sneip->InDiscards;
+       sneic->OutDiscards = (unsigned long long) sneip->OutDiscards;
+       sneic->OutNoRoutes = (unsigned long long) sneip->OutNoRoutes;
+       sneic->ReasmFails = (unsigned long long) sneip->ReasmFails;
+       sneic->FragFails = (unsigned long long) sneip->FragFails;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_net_ip6 structure (from ACTIVITY_MAGIC_BASE format to
+ * ACTIVITY_MAGIC_BASE + 1 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ ***************************************************************************
+ */
+void upgrade_stats_net_ip6(struct activity *act[], int p)
+{
+       struct stats_net_ip6 *snic6 = (struct stats_net_ip6 *) act[p]->buf[1];
+       struct stats_net_ip6_8a *snip6 = (struct stats_net_ip6_8a *) act[p]->buf[0];
+
+       snic6->InReceives6 = (unsigned long long) snip6->InReceives6;
+       snic6->OutForwDatagrams6 = (unsigned long long) snip6->OutForwDatagrams6;
+       snic6->InDelivers6 = (unsigned long long) snip6->InDelivers6;
+       snic6->OutRequests6 = (unsigned long long) snip6->OutRequests6;
+       snic6->ReasmReqds6 = (unsigned long long) snip6->ReasmReqds6;
+       snic6->ReasmOKs6 = (unsigned long long) snip6->ReasmOKs6;
+       snic6->InMcastPkts6 = (unsigned long long) snip6->InMcastPkts6;
+       snic6->OutMcastPkts6 = (unsigned long long) snip6->OutMcastPkts6;
+       snic6->FragOKs6 = (unsigned long long) snip6->FragOKs6;
+       snic6->FragCreates6 = (unsigned long long) snip6->FragCreates6;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade stats_net_eip6 structure (from ACTIVITY_MAGIC_BASE format to
+ * ACTIVITY_MAGIC_BASE + 1 format).
+ *
+ * IN:
+ * @act                Array of activities.
+ * @p          Position of activity in array.
+ ***************************************************************************
+ */
+void upgrade_stats_net_eip6(struct activity *act[], int p)
+{
+       struct stats_net_eip6 *sneic6 = (struct stats_net_eip6 *) act[p]->buf[1];
+       struct stats_net_eip6_8a *sneip6 = (struct stats_net_eip6_8a *) act[p]->buf[0];
+
+       sneic6->InHdrErrors6 = (unsigned long long) sneip6->InHdrErrors6;
+       sneic6->InAddrErrors6 = (unsigned long long) sneip6->InAddrErrors6;
+       sneic6->InUnknownProtos6 = (unsigned long long) sneip6->InUnknownProtos6;
+       sneic6->InTooBigErrors6 = (unsigned long long) sneip6->InTooBigErrors6;
+       sneic6->InDiscards6 = (unsigned long long) sneip6->InDiscards6;
+       sneic6->OutDiscards6 = (unsigned long long) sneip6->OutDiscards6;
+       sneic6->InNoRoutes6 = (unsigned long long) sneip6->InNoRoutes6;
+       sneic6->OutNoRoutes6 = (unsigned long long) sneip6->OutNoRoutes6;
+       sneic6->ReasmFails6 = (unsigned long long) sneip6->ReasmFails6;
+       sneic6->FragFails6 = (unsigned long long) sneip6->FragFails6;
+       sneic6->InTruncatedPkts6 = (unsigned long long) sneip6->InTruncatedPkts6;
+}
+
+/*
+ ***************************************************************************
+ * Read and upgrade file's header section.
+ *
+ * IN:
+ * @dfile              System activity data file name.
+ * @fd                 File descriptor for sa datafile to convert.
+ * @stdfd              File descriptor for STDOUT.
+ * @act                        Array of activities.
+ * @file_magic         Pointer on file_magic structure.
+ * @previous_format    TRUE is sa datafile has an old format which is no
+ *                     longer compatible with current one.
+ *
+ * OUT:
+ * @file_hdr           Pointer on file_header structure.
+ * @file_actlst                Activity list in file.
+ * @vol_id_seq         Sequence of volatile activities.
+ *
+ * RETURNS:
+ * -1 on error, 0 otherwise.
+***************************************************************************
+ */
+int upgrade_header_section(char dfile[], int fd, int stdfd,
+                          struct activity *act[], struct file_magic *file_magic,
+                          struct file_header *file_hdr, int previous_format,
+                          struct file_activity **file_actlst, unsigned int vol_id_seq[])
+{
+       int i, j, n, p;
+       unsigned int a_cpu = FALSE;
+       void *buffer = NULL;
+       struct file_activity *fal;
+
+       /* Read file header structure */
+       fprintf(stderr, "file_header: ");
+
+       if (previous_format) {
+               /* Previous format had 2 unsigned int less */
+               n = FILE_HEADER_SIZE - 8;
+       }
+       else {
+               n = file_magic->header_size;
+       }
+
+       SREALLOC(buffer, char, n);
+
+       sa_fread(fd, buffer, n, HARD_SIZE);
+
+       if (previous_format) {
+               /* Upgrade file_header structure */
+               upgrade_file_header(buffer, file_hdr);
+       }
+       else {
+               memcpy(file_hdr, buffer, MINIMUM(n, FILE_HEADER_SIZE));
+       }
+
+       free(buffer);
+
+       /* Read file activity list */
+       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(fd, fal, FILE_ACTIVITY_SIZE, HARD_SIZE);
+
+               if ((fal->nr < 1) || (fal->nr2 < 1)) {
+                       /*
+                        * Every activity, known or unknown,
+                        * should have at least one item and sub-item.
+                        */
+                       fprintf(stderr, _("\nInvalid data found. Aborting...\n"));
+                       return -1;
+               }
+
+               if ((p = get_activity_position(act, fal->id)) >= 0) {
+                       /* This is a known activity, maybe with an unknown format */
+
+                       if (IS_VOLATILE(act[p]->options) && previous_format) {
+                               /*
+                                * Current activity is known by current version
+                                * as a volatile one: So increment the number of
+                                * volatile activities in file's header (but only
+                                * for old format data files, since up-to-date
+                                * format data files already have the right value here).
+                                */
+                               file_hdr->sa_vol_act_nr += 1;
+
+                               /*
+                                * Create the sequence of volatile activities.
+                                * Used only for old format datafiles.
+                                * For new format datafiles, this is not necessary
+                                * since this sequence already exists following
+                                * the RESTART record.
+                                */
+                               vol_id_seq[j++] = act[p]->id;
+                       }
+
+                       if (fal->id == A_CPU) {
+                               /*
+                                * Old format data files don't know volatile
+                                * activities. The number of CPU is a constant
+                                * all along the file.
+                                */
+                               if (previous_format) {
+                                       file_hdr->sa_last_cpu_nr = fal->nr;
+                               }
+                               a_cpu = TRUE;
+                       }
+
+                       /* Size of activity in file is larger than up-to-date activity size */
+                       if (fal->size > act[p]->msize) {
+                               act[p]->msize = fal->size;
+                       }
+
+                       /*
+                        * When upgrading a file:
+                        * fal->size    : Size of an item for current activity, as
+                        *                read from the file.
+                        * act[p]->msize: Size of the buffer in memory where an item
+                        *                for current activity, as read from the file,
+                        *                will be saved. We have:
+                        *                act[p]->msize >= {fal->size ; act[p]->fsize}
+                        * act[p]->fsize: Size of an item for current activity with
+                        *                up-to-date format.
+                        */
+                       act[p]->nr    = fal->nr;
+                       act[p]->nr2   = fal->nr2;
+                       /*
+                        * Don't set act[p]->fsize! Should retain the size of an item
+                        * for up-to-date format!
+                        */
+               }
+       }
+
+       if (!a_cpu) {
+               /*
+                * CPU activity should always be in file
+                * and have a known format (expected magical number).
+                */
+               fprintf(stderr, _("\nCPU activity not found in file. Aborting...\n"));
+               return -1;
+       }
+
+       /* Write file_header structure */
+       if ((n = write(stdfd, file_hdr, FILE_HEADER_SIZE)) != FILE_HEADER_SIZE) {
+               fprintf(stderr, "\nwrite: %s\n", strerror(errno));
+               return -1;
+       }
+
+       fprintf(stderr, "OK\n");
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade file's activity list section.
+ *
+ * IN:
+ * @stdfd              File descriptor for STDOUT.
+ * @act                        Array of activities.
+ * @file_hdr           Pointer on file_header structure.
+ * @file_actlst                Activity list in file.
+ *
+ * RETURNS:
+ * -1 on error, 0 otherwise.
+***************************************************************************
+ */
+int upgrade_activity_section(int stdfd, struct activity *act[],
+                            struct file_header *file_hdr,
+                            struct file_activity *file_actlst)
+{
+       int i, n, p;
+       struct file_activity file_act;
+       struct file_activity *fal;
+
+       fprintf(stderr, "file_activity: ");
+
+       fal = file_actlst;
+
+       for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
+
+               file_act = *fal;
+               if ((p = get_activity_position(act, fal->id)) >= 0) {
+                       /* Update activity magic number */
+                       file_act.magic = act[p]->magic;
+                       /* Also update its size, which may have changed with recent versions */
+                       file_act.size = act[p]->fsize;
+               }
+
+               /*
+                * Even unknown activities must be written
+                * (they are counted in sa_act_nr).
+                */
+               if ((n = write(stdfd, &file_act, FILE_ACTIVITY_SIZE))!= FILE_ACTIVITY_SIZE) {
+                       fprintf(stderr, "\nwrite: %s\n", strerror(errno));
+                       return -1;
+               }
+
+               fprintf(stderr, "%s ", act[p]->name);
+       }
+
+       fprintf(stderr, "OK\n");
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade a COMMENT record.
+ *
+ * IN:
+ * @fd         File descriptor for sa datafile to convert.
+ * @stdfd      File descriptor for STDOUT.
+ *
+ * RETURNS:
+ * -1 on error, 0 otherwise.
+***************************************************************************
+ */
+int upgrade_comment_record(int fd, int stdfd)
+{
+       int n;
+       char file_comment[MAX_COMMENT_LEN];
+
+       /* Read the COMMENT record */
+       sa_fread(fd, file_comment, MAX_COMMENT_LEN, HARD_SIZE);
+       file_comment[MAX_COMMENT_LEN - 1] = '\0';
+
+       /* Then write it. No changes at this time */
+       if ((n = write(stdfd, file_comment, MAX_COMMENT_LEN)) != MAX_COMMENT_LEN) {
+               fprintf(stderr, "\nwrite: %s\n", strerror(errno));
+               return -1;
+       }
+
+       fprintf(stderr, "C");
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade a RESTART record.
+ *
+ * IN:
+ * @fd                 File descriptor for sa datafile to convert.
+ * @stdfd              File descriptor for STDOUT.
+ * @act                        Array of activities.
+ * @file_hdr           Pointer on file_header structure.
+ * @previous_format    TRUE is sa datafile has an old format which is no
+ *                     longer compatible with current one.
+ * @vol_id_seq         Sequence of volatile activities.
+ *
+ * RETURNS:
+ * -1 on error, 0 otherwise.
+***************************************************************************
+ */
+int upgrade_restart_record(int fd, int stdfd, struct activity *act[],
+                          struct file_header *file_hdr, int previous_format,
+                          unsigned int vol_id_seq[])
+{
+       int i, n, p;
+       struct file_activity file_act;
+
+       /*
+        * This is a RESTART record.
+        * Only new format data file have additional structures
+        * to read here for volatile activities.
+        */
+       for (i = 0; i < file_hdr->sa_vol_act_nr; i++) {
+
+               if (!previous_format) {
+                       sa_fread(fd, &file_act, FILE_ACTIVITY_SIZE, HARD_SIZE);
+                       if (file_act.id) {
+                               reallocate_vol_act_structures(act, file_act.nr, file_act.id);
+                       }
+               }
+               else {
+                       memset(&file_act, 0, FILE_ACTIVITY_SIZE);
+
+                       /* Old format: Sequence of volatile activities is in vol_id_seq */
+                       p = get_activity_position(act, vol_id_seq[i]);
+
+                       /* Set only the necessary fields */
+                       file_act.id = act[p]->id;
+                       file_act.nr = act[p]->nr;
+               }
+
+               if ((n = write(stdfd, &file_act, FILE_ACTIVITY_SIZE)) != FILE_ACTIVITY_SIZE) {
+                       fprintf(stderr, "\nwrite: %s\n", strerror(errno));
+                       return -1;
+               }
+       }
+
+       fprintf(stderr, "R");
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade a record which is not a COMMENT or a RESTART one.
+ *
+ * IN:
+ * @fd                 File descriptor for sa datafile to convert.
+ * @stdfd              File descriptor for STDOUT.
+ * @act                        Array of activities.
+ * @file_hdr           Pointer on file_header structure.
+ * @file_actlst                Activity list in file.
+ *
+ * RETURNS:
+ * -1 on error, 0 otherwise.
+***************************************************************************
+ */
+int upgrade_common_record(int fd, int stdfd, struct activity *act[],
+                          struct file_header *file_hdr,
+                          struct file_activity *file_actlst)
+{
+       int i, j, k, n, p;
+       struct file_activity *fal;
+       void *buffer = NULL;
+
+       /*
+        * This is not a special record, so read the extra fields,
+        * even if the format of the activity is unknown.
+        */
+       fal = file_actlst;
+       for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
+
+               if ((p = get_activity_position(act, fal->id)) < 0) {
+                       /* An unknown activity should still be read and written */
+                       SREALLOC(buffer, void, fal->size * fal->nr * fal->nr2);
+                       sa_fread(fd, buffer, fal->size * fal->nr * fal->nr2, HARD_SIZE);
+                       if ((n = write(stdfd, (char *) buffer,
+                                      fal->size * fal->nr * fal->nr2)) !=
+                                      fal->size * fal->nr * fal->nr2) {
+                               fprintf(stderr, "\nwrite: %s\n", strerror(errno));
+                               return -1;
+                       }
+                       continue;
+               }
+
+               if ((act[p]->nr > 0) &&
+                   ((act[p]->nr > 1) || (act[p]->nr2 > 1)) &&
+                   (act[p]->msize > fal->size)) {
+
+                       for (j = 0; j < act[p]->nr; j++) {
+                               for (k = 0; k < act[p]->nr2; k++) {
+                                       sa_fread(fd,
+                                                (char *) act[p]->buf[0] + (j * act[p]->nr2 + k) * act[p]->msize,
+                                                fal->size, HARD_SIZE);
+                               }
+                       }
+               }
+
+               else if (act[p]->nr > 0) {
+                       sa_fread(fd, act[p]->buf[0], fal->size * act[p]->nr * act[p]->nr2, HARD_SIZE);
+               }
+
+               if (act[p]->magic != fal->magic) {
+
+                       /* Known activity but old format */
+                       switch (fal->id) {
+
+                               case A_IO:
+                                       upgrade_stats_io(act, p);
+                                       break;
+
+                               case A_QUEUE:
+                                       upgrade_stats_queue(act, p);
+                                       break;
+
+                               case A_DISK:
+                                       upgrade_stats_disk(act, p);
+                                       break;
+
+                               case A_NET_DEV:
+                                       upgrade_stats_net_dev(act, p, fal->magic);
+                                       break;
+
+                               case A_NET_EDEV:
+                                       upgrade_stats_net_edev(act, p);
+                                       break;
+
+                               case A_NET_IP:
+                                       upgrade_stats_net_ip(act, p);
+                                       break;
+
+                               case A_NET_EIP:
+                                       upgrade_stats_net_eip(act, p);
+                                       break;
+
+                               case A_NET_IP6:
+                                       upgrade_stats_net_ip6(act, p);
+                                       break;
+
+                               case A_NET_EIP6:
+                                       upgrade_stats_net_eip6(act, p);
+                                       break;
+                               }
+               }
+               else {
+                       /* Known activity with current up-to-date format */
+                       for (j = 0; j < act[p]->nr; j++) {
+                               for (k = 0; k < act[p]->nr2; k++) {
+                                       memcpy((char *) act[p]->buf[1] + (j * act[p]->nr2 + k) * act[p]->msize,
+                                              (char *) act[p]->buf[0] + (j * act[p]->nr2 + k) * act[p]->msize,
+                                              fal->size);
+                               }
+                       }
+               }
+
+               for (j = 0; j < act[p]->nr; j++) {
+                       for (k = 0; k < act[p]->nr2; k++) {
+                               if ((n = write(stdfd,
+                                              (char *) act[p]->buf[1] + (j * act[p]->nr2 + k) * act[p]->msize,
+                                              act[p]->fsize)) !=
+                                              act[p]->fsize) {
+                                       fprintf(stderr, "\nwrite: %s\n", strerror(errno));
+                                       return -1;
+                               }
+                       }
+               }
+       }
+
+       fprintf(stderr, ".");
+
+       if (buffer) {
+               free(buffer);
+       }
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Upgrade statistics records.
+ *
+ * IN:
+ * @fd                 File descriptor for sa datafile to convert.
+ * @stdfd              File descriptor for STDOUT.
+ * @act                        Array of activities.
+ * @file_hdr           Pointer on file_header structure.
+ * @previous_format    TRUE is sa datafile has an old format which is no
+ *                     longer compatible with current one.
+ * @file_actlst                Activity list in file.
+ * @vol_id_seq         Sequence of volatile activities.
+ *
+ * RETURNS:
+ * -1 on error, 0 otherwise.
+***************************************************************************
+ */
+int upgrade_stat_records(int fd, int stdfd, struct activity *act[],
+                        struct file_header *file_hdr, int previous_format,
+                        struct file_activity *file_actlst, unsigned int vol_id_seq[])
+{
+       int n, rtype;
+       int eosaf = TRUE;
+       struct record_header record_hdr;
+
+       fprintf(stderr, _("Statistics: "));
+
+       do {
+               eosaf = sa_fread(fd, &record_hdr, RECORD_HEADER_SIZE, SOFT_SIZE);
+               rtype = record_hdr.record_type;
+
+               if (!eosaf) {
+
+                       if ((n = write(stdfd, &record_hdr, RECORD_HEADER_SIZE))
+                               != RECORD_HEADER_SIZE) {
+                               fprintf(stderr, "\nwrite: %s\n", strerror(errno));
+                               return -1;
+                       }
+
+                       if (rtype == R_COMMENT) {
+                               /* Upgrade the COMMENT record */
+                               if (upgrade_comment_record(fd, stdfd) < 0)
+                                       return -1;
+                       }
+
+                       else if (rtype == R_RESTART) {
+                               /* Upgrade the RESTART record */
+                               if (upgrade_restart_record(fd, stdfd, act, file_hdr,
+                                                          previous_format, vol_id_seq) < 0)
+                                       return -1;
+                       }
+
+                       else {
+                               /* Upgrade current statistics record */
+                               if (upgrade_common_record(fd, stdfd, act, file_hdr,
+                                                         file_actlst) < 0)
+                                       return -1;
+                       }
+               }
+       }
+       while (!eosaf);
+
+       return 0;
+}
+
+/*
+ ***************************************************************************
+ * Close file descriptors and exit.
+ *
+ * IN:
+ * @fd         File descriptor for sa datafile to convert.
+ * @stdfd      File descriptor for STDOUT.
+ * @exit_code  Exit code.
+ ***************************************************************************
+ */
+void upgrade_exit(int fd, int stdfd, int exit_code)
+{
+       if (fd) {
+               close(fd);
+       }
+       if (stdfd) {
+               close(stdfd);
+       }
+
+       exit(exit_code);
+}
+
+/*
+ ***************************************************************************
+ * Convert a sysstat activity data file from a previous version to the
+ * up-to-date format. Presently data files from sysstat version 9.1.6 and
+ * later are converted to current sysstat version format.
+ *
+ * IN:
+ * @dfile      System activity data file name.
+ * @act                Array of activities.
+ ***************************************************************************
+ */
+void convert_file(char dfile[], struct activity *act[])
+{
+       int fd = 0, stdfd = 0;
+       int previous_format = FALSE;
+       struct file_magic file_magic;
+       struct file_header file_hdr;
+       struct file_activity *file_actlst = NULL;
+       unsigned int vol_id_seq[NR_ACT];
+
+       /* Open stdout */
+       if ((stdfd = dup(STDOUT_FILENO)) < 0) {
+               perror("dup");
+               upgrade_exit(0, 0, 2);
+       }
+
+       /* Upgrade file's magic section */
+       if (upgrade_magic_section(dfile, &fd, stdfd, &file_magic,
+                                 &previous_format) < 0) {
+               upgrade_exit(fd, stdfd, 2);
+       }
+
+       /* Upgrade file's header section */
+       if (upgrade_header_section(dfile, fd, stdfd, act,
+                                  &file_magic, &file_hdr,
+                                  previous_format, &file_actlst,
+                                  vol_id_seq) < 0) {
+               upgrade_exit(fd, stdfd, 2);
+       }
+
+       /* Upgrade file's activity list section */
+       if (upgrade_activity_section(stdfd, act, &file_hdr,
+                                    file_actlst) < 0) {
+               upgrade_exit(fd, stdfd, 2);
+       }
+
+       /* Perform required allocations */
+       allocate_structures(act);
+
+       /* Upgrade statistics records */
+       if (upgrade_stat_records(fd, stdfd, act, &file_hdr,
+                                previous_format, file_actlst,
+                                vol_id_seq) <0) {
+               upgrade_exit(fd, stdfd, 2);
+       }
+
+       fprintf(stderr,
+               _("\nFile successfully converted to sysstat format version %s\n"),
+               VERSION);
+
+       free(file_actlst);
+       free_structures(act);
+       close(fd);
+       close(stdfd);
+}
diff --git a/sa_conv.h b/sa_conv.h
new file mode 100644 (file)
index 0000000..85416f9
--- /dev/null
+++ b/sa_conv.h
@@ -0,0 +1,148 @@
+/*
+ * sa_conv.h: Include file for "sadf -c" command.
+ * (C) 1999-2014 by Sebastien Godard (sysstat <at> orange.fr)
+ */
+
+#ifndef _SA_CONV_H
+#define _SA_CONV_H
+
+/*
+ * Header structure for previous system activity data file format
+ * (v9.1.6 up to v10.2.1).
+ */
+struct file_header_2171 {
+       unsigned long sa_ust_time       __attribute__ ((aligned (8)));
+       unsigned int sa_act_nr          __attribute__ ((aligned (8)));
+       unsigned char sa_day;
+       unsigned char sa_month;
+       unsigned char sa_year;
+       char sa_sizeof_long;
+       char sa_sysname[UTSNAME_LEN];
+       char sa_nodename[UTSNAME_LEN];
+       char sa_release[UTSNAME_LEN];
+       char sa_machine[UTSNAME_LEN];
+};
+
+/* Structure stats_io for ACTIVITY_MAGIC_BASE format */
+struct stats_io_8a {
+       unsigned int  dk_drive          __attribute__ ((aligned (4)));
+       unsigned int  dk_drive_rio      __attribute__ ((packed));
+       unsigned int  dk_drive_wio      __attribute__ ((packed));
+       unsigned int  dk_drive_rblk     __attribute__ ((packed));
+       unsigned int  dk_drive_wblk     __attribute__ ((packed));
+};
+
+/* Structure stats_queue for ACTIVITY_MAGIC_BASE format */
+struct stats_queue_8a {
+       unsigned long nr_running        __attribute__ ((aligned (8)));
+       unsigned int  load_avg_1        __attribute__ ((aligned (8)));
+       unsigned int  load_avg_5        __attribute__ ((packed));
+       unsigned int  load_avg_15       __attribute__ ((packed));
+       unsigned int  nr_threads        __attribute__ ((packed));
+};
+
+/* Structure stats_disk for ACTIVITY_MAGIC_BASE format */
+struct stats_disk_8a {
+       unsigned long long rd_sect      __attribute__ ((aligned (16)));
+       unsigned long long wr_sect      __attribute__ ((aligned (16)));
+       unsigned long rd_ticks          __attribute__ ((aligned (16)));
+       unsigned long wr_ticks          __attribute__ ((aligned (8)));
+       unsigned long tot_ticks         __attribute__ ((aligned (8)));
+       unsigned long rq_ticks          __attribute__ ((aligned (8)));
+       unsigned long nr_ios            __attribute__ ((aligned (8)));
+       unsigned int  major             __attribute__ ((aligned (8)));
+       unsigned int  minor             __attribute__ ((packed));
+};
+
+/* Structure stats_net_dev for ACTIVITY_MAGIC_BASE format */
+struct stats_net_dev_8a {
+       unsigned long rx_packets                __attribute__ ((aligned (8)));
+       unsigned long tx_packets                __attribute__ ((aligned (8)));
+       unsigned long rx_bytes                  __attribute__ ((aligned (8)));
+       unsigned long tx_bytes                  __attribute__ ((aligned (8)));
+       unsigned long rx_compressed             __attribute__ ((aligned (8)));
+       unsigned long tx_compressed             __attribute__ ((aligned (8)));
+       unsigned long multicast                 __attribute__ ((aligned (8)));
+       char          interface[MAX_IFACE_LEN]  __attribute__ ((aligned (8)));
+};
+
+/* Structure stats_net_dev for ACTIVITY_MAGIC_BASE + 1 format */
+struct stats_net_dev_8b {
+       unsigned long long rx_packets           __attribute__ ((aligned (16)));
+       unsigned long long tx_packets           __attribute__ ((aligned (16)));
+       unsigned long long rx_bytes             __attribute__ ((aligned (16)));
+       unsigned long long tx_bytes             __attribute__ ((aligned (16)));
+       unsigned long long rx_compressed        __attribute__ ((aligned (16)));
+       unsigned long long tx_compressed        __attribute__ ((aligned (16)));
+       unsigned long long multicast            __attribute__ ((aligned (16)));
+       char          interface[MAX_IFACE_LEN]  __attribute__ ((aligned (16)));
+};
+
+/* Structure stats_net_edev for ACTIVITY_MAGIC_BASE format */
+struct stats_net_edev_8a {
+       unsigned long collisions                __attribute__ ((aligned (8)));
+       unsigned long rx_errors                 __attribute__ ((aligned (8)));
+       unsigned long tx_errors                 __attribute__ ((aligned (8)));
+       unsigned long rx_dropped                __attribute__ ((aligned (8)));
+       unsigned long tx_dropped                __attribute__ ((aligned (8)));
+       unsigned long rx_fifo_errors            __attribute__ ((aligned (8)));
+       unsigned long tx_fifo_errors            __attribute__ ((aligned (8)));
+       unsigned long rx_frame_errors           __attribute__ ((aligned (8)));
+       unsigned long tx_carrier_errors         __attribute__ ((aligned (8)));
+       char          interface[MAX_IFACE_LEN]  __attribute__ ((aligned (8)));
+};
+
+/* Structure stats_net_ip for ACTIVITY_MAGIC_BASE format */
+struct stats_net_ip_8a {
+       unsigned long InReceives        __attribute__ ((aligned (8)));
+       unsigned long ForwDatagrams     __attribute__ ((aligned (8)));
+       unsigned long InDelivers        __attribute__ ((aligned (8)));
+       unsigned long OutRequests       __attribute__ ((aligned (8)));
+       unsigned long ReasmReqds        __attribute__ ((aligned (8)));
+       unsigned long ReasmOKs          __attribute__ ((aligned (8)));
+       unsigned long FragOKs           __attribute__ ((aligned (8)));
+       unsigned long FragCreates       __attribute__ ((aligned (8)));
+};
+
+/* Structure stats_net_eip for ACTIVITY_MAGIC_BASE format */
+struct stats_net_eip_8a {
+       unsigned long InHdrErrors       __attribute__ ((aligned (8)));
+       unsigned long InAddrErrors      __attribute__ ((aligned (8)));
+       unsigned long InUnknownProtos   __attribute__ ((aligned (8)));
+       unsigned long InDiscards        __attribute__ ((aligned (8)));
+       unsigned long OutDiscards       __attribute__ ((aligned (8)));
+       unsigned long OutNoRoutes       __attribute__ ((aligned (8)));
+       unsigned long ReasmFails        __attribute__ ((aligned (8)));
+       unsigned long FragFails         __attribute__ ((aligned (8)));
+};
+
+/* Structure stats_net_ip6 for ACTIVITY_MAGIC_BASE format */
+struct stats_net_ip6_8a {
+       unsigned long InReceives6       __attribute__ ((aligned (8)));
+       unsigned long OutForwDatagrams6 __attribute__ ((aligned (8)));
+       unsigned long InDelivers6       __attribute__ ((aligned (8)));
+       unsigned long OutRequests6      __attribute__ ((aligned (8)));
+       unsigned long ReasmReqds6       __attribute__ ((aligned (8)));
+       unsigned long ReasmOKs6         __attribute__ ((aligned (8)));
+       unsigned long InMcastPkts6      __attribute__ ((aligned (8)));
+       unsigned long OutMcastPkts6     __attribute__ ((aligned (8)));
+       unsigned long FragOKs6          __attribute__ ((aligned (8)));
+       unsigned long FragCreates6      __attribute__ ((aligned (8)));
+};
+
+/* Structure stats_net_eip6 for ACTIVITY_MAGIC_BASE format */
+struct stats_net_eip6_8a {
+        unsigned long InHdrErrors6      __attribute__ ((aligned (8)));
+        unsigned long InAddrErrors6     __attribute__ ((aligned (8)));
+        unsigned long InUnknownProtos6  __attribute__ ((aligned (8)));
+        unsigned long InTooBigErrors6   __attribute__ ((aligned (8)));
+        unsigned long InDiscards6       __attribute__ ((aligned (8)));
+        unsigned long OutDiscards6      __attribute__ ((aligned (8)));
+        unsigned long InNoRoutes6       __attribute__ ((aligned (8)));
+        unsigned long OutNoRoutes6      __attribute__ ((aligned (8)));
+        unsigned long ReasmFails6       __attribute__ ((aligned (8)));
+        unsigned long FragFails6        __attribute__ ((aligned (8)));
+        unsigned long InTruncatedPkts6  __attribute__ ((aligned (8)));
+};
+
+#endif  /* _SA_CONV_H */
diff --git a/sadc.c b/sadc.c
index 3cd3b6a6206e2490a9780097605feff3bce86f3b..567233afb51df3702536fd792ed3caf03dd53d11 100644 (file)
--- a/sadc.c
+++ b/sadc.c
@@ -434,38 +434,14 @@ int ask_for_flock(int fd, int fatal)
  */
 void fill_magic_header(struct file_magic *file_magic)
 {
-       char *v;
-       char version[16];
-
        memset(file_magic, 0, FILE_MAGIC_SIZE);
 
        file_magic->header_size = FILE_HEADER_SIZE;
 
        file_magic->sysstat_magic = SYSSTAT_MAGIC;
        file_magic->format_magic  = FORMAT_MAGIC;
-       file_magic->sysstat_extraversion = 0;
-
-       strcpy(version, VERSION);
 
-       /* Get version number */
-       if ((v = strtok(version, ".")) == NULL)
-               return;
-       file_magic->sysstat_version = atoi(v) & 0xff;
-
-       /* Get patchlevel number */
-       if ((v = strtok(NULL, ".")) == NULL)
-               return;
-       file_magic->sysstat_patchlevel = atoi(v) & 0xff;
-
-       /* Get sublevel number */
-       if ((v = strtok(NULL, ".")) == NULL)
-               return;
-       file_magic->sysstat_sublevel = atoi(v) & 0xff;
-
-       /* Get extraversion number. Don't necessarily exist */
-       if ((v = strtok(NULL, ".")) == NULL)
-               return;
-       file_magic->sysstat_extraversion = atoi(v) & 0xff;
+       enum_version_nr(file_magic);
 }
 
 /*
diff --git a/sadf.c b/sadf.c
index cdbddfe2ce675f7a230374b8e316dbc1074e49fc..690f73ef74dcf6e729dbf6fbe4da3f8e709380db 100644 (file)
--- a/sadf.c
+++ b/sadf.c
@@ -87,7 +87,7 @@ void usage(char *progname)
                progname);
 
        fprintf(stderr, _("Options are:\n"
-                         "[ -C ] [ -d | -j | -p | -x ] [ -H ] [ -h ] [ -T | -t | -U ] [ -V ]\n"
+                         "[ -C ] [ -c | -d | -j | -p | -x ] [ -H ] [ -h ] [ -T | -t | -U ] [ -V ]\n"
                          "[ -P { <cpu> [,...] | ALL } ] [ -s [ <hh:mm:ss> ] ] [ -e [ <hh:mm:ss> ] ]\n"
                          "[ -- <sar_options> ]\n"));
        exit(1);
@@ -1593,6 +1593,13 @@ int main(int argc, char **argv)
                                                flags |= S_F_COMMENT;
                                                break;
 
+                                       case 'c':
+                                               if (format) {
+                                                       usage(argv[0]);
+                                               }
+                                               format = F_CONV_OUTPUT;
+                                               break;
+
                                        case 'd':
                                                if (format) {
                                                        usage(argv[0]);
@@ -1744,8 +1751,14 @@ int main(int argc, char **argv)
                interval = 1;
        }
 
-       /* Read stats from file */
-       read_stats_from_file(dfile);
+       if (format == F_CONV_OUTPUT) {
+               /* Convert file to current format */
+               convert_file(dfile, act);
+       }
+       else {
+               /* Read stats from file */
+               read_stats_from_file(dfile);
+       }
 
        /* Free bitmaps */
        free_bitmaps(act);
diff --git a/sadf.h b/sadf.h
index df7537a111521de7dd4c513f7a2d83ded310d914..10114ab2a4fd5f6ac99e3341c682a184087e76af 100644 (file)
--- a/sadf.h
+++ b/sadf.h
@@ -27,7 +27,7 @@
  */
 
 /* Number of output formats */
-#define NR_FMT 5
+#define NR_FMT 6
 
 /* Output formats */
 #define F_DB_OUTPUT    1
@@ -35,6 +35,7 @@
 #define F_PPC_OUTPUT   3
 #define F_XML_OUTPUT   4
 #define F_JSON_OUTPUT  5
+#define F_CONV_OUTPUT  6
 
 /*
  ***************************************************************************
@@ -181,6 +182,8 @@ struct report_format {
  ***************************************************************************
  */
 
+extern void
+       convert_file(char [], struct activity *[]);
 extern void
        xprintf(int, const char *, ...);
 extern void