]> granicus.if.org Git - sysstat/blob - sa_conv.c
sar/sadf: On-the-fly endianness conversion
[sysstat] / sa_conv.c
1 /*
2  * sa_conv.c: Convert an old format sa file to the up-to-date format.
3  * (C) 1999-2017 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
5  ***************************************************************************
6  * This program is free software; you can redistribute it and/or modify it *
7  * under the terms of the GNU General Public License as published  by  the *
8  * Free Software Foundation; either version 2 of the License, or (at  your *
9  * option) any later version.                                              *
10  *                                                                         *
11  * This program is distributed in the hope that it  will  be  useful,  but *
12  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
14  * for more details.                                                       *
15  *                                                                         *
16  * You should have received a copy of the GNU General Public License along *
17  * with this program; if not, write to the Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
19  ***************************************************************************
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <errno.h>
27
28 #include "version.h"
29 #include "sadf.h"
30 #include "sa.h"
31 #include "sa_conv.h"
32
33 #ifdef USE_NLS
34 # include <locale.h>
35 # include <libintl.h>
36 # define _(string) gettext(string)
37 #else
38 # define _(string) (string)
39 #endif
40
41 extern int endian_mismatch;
42
43 /*
44  ***************************************************************************
45  * Read and upgrade file's magic data section.
46  *
47  * IN:
48  * @dfile               System activity data file name.
49  * @stdfd               File descriptor for STDOUT.
50  *
51  * OUT:
52  * @fd                  File descriptor for sa datafile to convert.
53  * @file_magic          Pointer on file_magic structure.
54  * @previous_format     TRUE is sa datafile has an old format which is no
55  *                      longer compatible with current one.
56  *
57  * RETURNS:
58  * -1 on error, 0 otherwise.
59  ***************************************************************************
60  */
61 int upgrade_magic_section(char dfile[], int *fd, int stdfd,
62                           struct file_magic *file_magic, int *previous_format)
63 {
64         struct file_magic fm;
65
66         /* Open and read sa magic structure */
67         sa_open_read_magic(fd, dfile, file_magic, TRUE, &endian_mismatch);
68
69         if ((file_magic->format_magic != FORMAT_MAGIC) &&
70             (file_magic->format_magic != PREVIOUS_FORMAT_MAGIC)) {
71                 fprintf(stderr, _("Cannot convert the format of this file\n"));
72                 return -1;
73         }
74
75         fprintf(stderr, "file_magic: ");
76         if (file_magic->format_magic == PREVIOUS_FORMAT_MAGIC) {
77                 /*
78                  * We have read too many bytes: file_magic structure
79                  * was smaller with previous sysstat versions.
80                  * Go back 4 (unsigned int header_size) + 64 (char pad[64]) bytes.
81                  */
82                 if (lseek(*fd, -68, SEEK_CUR) < 0) {
83                         fprintf(stderr, "\nlseek: %s\n", strerror(errno));
84                         return -1;
85                 }
86                 /* Set format magic number to that of current version */
87                 *previous_format = TRUE;
88                 file_magic->format_magic = FORMAT_MAGIC;
89
90                 /* Fill new structure members */
91                 file_magic->header_size = FILE_HEADER_SIZE;
92                 memset(file_magic->pad, 0, sizeof(unsigned char) * FILE_MAGIC_PADDING);
93         }
94
95         /* Indicate that file has been upgraded */
96         enum_version_nr(&fm);
97         file_magic->upgraded = (fm.sysstat_patchlevel << 4) +
98                                fm.sysstat_sublevel + 1;
99
100         /* Write file_magic structure */
101         if (write(stdfd, file_magic, FILE_MAGIC_SIZE) != FILE_MAGIC_SIZE) {
102                 fprintf(stderr, "\nwrite: %s\n", strerror(errno));
103                 return -1;
104         }
105         fprintf(stderr, "OK\n");
106
107         return 0;
108 }
109
110 /*
111  ***************************************************************************
112  * Upgrade file_header structure (from 0x2171 format to current format).
113  *
114  * IN:
115  * @buffer      Pointer on file's header structure (as read from file).
116  *
117  * OUT:
118  * @file_hdr    Pointer on file_header structure (up-to-date format).
119  ***************************************************************************
120  */
121 void upgrade_file_header(void *buffer, struct file_header *file_hdr)
122 {
123         struct file_header_2171 *f_hdr = (struct file_header_2171 *) buffer;
124
125         file_hdr->sa_ust_time = f_hdr->sa_ust_time;
126         file_hdr->sa_act_nr = f_hdr->sa_act_nr;
127         file_hdr->sa_day = f_hdr->sa_day;
128         file_hdr->sa_month = f_hdr->sa_month;
129         file_hdr->sa_year = f_hdr->sa_year;
130         file_hdr->sa_sizeof_long = f_hdr->sa_sizeof_long;
131         strncpy(file_hdr->sa_sysname, f_hdr->sa_sysname, UTSNAME_LEN);
132         file_hdr->sa_sysname[UTSNAME_LEN - 1] = '\0';
133         strncpy(file_hdr->sa_nodename, f_hdr->sa_nodename, UTSNAME_LEN);
134         file_hdr->sa_nodename[UTSNAME_LEN - 1] = '\0';
135         strncpy(file_hdr->sa_release, f_hdr->sa_release, UTSNAME_LEN);
136         file_hdr->sa_release[UTSNAME_LEN - 1] = '\0';
137         strncpy(file_hdr->sa_machine, f_hdr->sa_machine, UTSNAME_LEN);
138         file_hdr->sa_machine[UTSNAME_LEN - 1] = '\0';
139         /* The last two values below will be updated later */
140         file_hdr->sa_vol_act_nr = 0;
141         file_hdr->sa_last_cpu_nr = 0;
142 }
143
144 /*
145  ***************************************************************************
146  * Upgrade stats_io structure (from ACTIVITY_MAGIC_BASE format to
147  * ACTIVITY_MAGIC_BASE + 1 format).
148  *
149  * IN:
150  * @act         Array of activities.
151  * @p           Position of activity in array.
152  ***************************************************************************
153  */
154 void upgrade_stats_io(struct activity *act[], int p)
155 {
156         struct stats_io *sic = (struct stats_io *) act[p]->buf[1];
157         struct stats_io_8a *sip = (struct stats_io_8a *) act[p]->buf[0];
158
159         sic->dk_drive = (unsigned long long) sip->dk_drive;
160         sic->dk_drive_rio = (unsigned long long) sip->dk_drive_rio;
161         sic->dk_drive_wio = (unsigned long long) sip->dk_drive_wio;
162         sic->dk_drive_rblk = (unsigned long long) sip->dk_drive_rblk;
163         sic->dk_drive_wblk = (unsigned long long) sip->dk_drive_wblk;
164 }
165
166 /*
167  ***************************************************************************
168  * Upgrade stats_queue structure (from ACTIVITY_MAGIC_BASE format to
169  * ACTIVITY_MAGIC_BASE + 1 format).
170  *
171  * IN:
172  * @act         Array of activities.
173  * @p           Position of activity in array.
174  ***************************************************************************
175  */
176 void upgrade_stats_queue(struct activity *act[], int p)
177 {
178         struct stats_queue *sqc = (struct stats_queue *) act[p]->buf[1];
179         struct stats_queue_8a *sqp = (struct stats_queue_8a *) act[p]->buf[0];
180
181         sqc->nr_running = sqp->nr_running;
182         sqc->procs_blocked = 0; /* New field */
183         sqc->load_avg_1 = sqp->load_avg_1;
184         sqc->load_avg_5 = sqp->load_avg_5;
185         sqc->load_avg_15 = sqp->load_avg_15;
186         sqc->nr_threads = sqp->nr_threads;
187 }
188
189 /*
190  ***************************************************************************
191  * Upgrade stats_disk structure (from ACTIVITY_MAGIC_BASE format to
192  * ACTIVITY_MAGIC_BASE + 1 format).
193  *
194  * IN:
195  * @act         Array of activities.
196  * @p           Position of activity in array.
197  ***************************************************************************
198  */
199 void upgrade_stats_disk(struct activity *act[], int p)
200 {
201         int i;
202         struct stats_disk *sdc;
203         struct stats_disk_8a *sdp;
204
205         for (i = 0; i < act[p]->nr; i++) {
206                 sdp = (struct stats_disk_8a *) ((char *) act[p]->buf[0] + i * act[p]->msize);
207                 sdc = (struct stats_disk *)    ((char *) act[p]->buf[1] + i * act[p]->fsize);
208
209                 sdc->nr_ios = (unsigned long long) sdp->nr_ios;
210                 sdc->rd_sect = (unsigned long) sdp->rd_sect;
211                 sdc->wr_sect = (unsigned long) sdp->wr_sect;
212                 sdc->rd_ticks = (unsigned int) sdp->rd_ticks;
213                 sdc->wr_ticks = (unsigned int) sdp->wr_ticks;
214                 sdc->tot_ticks = (unsigned int) sdp->tot_ticks;
215                 sdc->rq_ticks = (unsigned int) sdp->rq_ticks;
216                 sdc->major = sdp->major;
217                 sdc->minor = sdp->minor;
218         }
219 }
220
221 /*
222  ***************************************************************************
223  * Upgrade stats_net_dev structure (from ACTIVITY_MAGIC_BASE or
224  * ACTIVITY_MAGIC_BASE + 1 format to ACTIVITY_MAGIC_BASE + 2 format).
225  *
226  * IN:
227  * @act         Array of activities.
228  * @p           Position of activity in array.
229  * @m_format    Structure format magic value.
230  ***************************************************************************
231  */
232 void upgrade_stats_net_dev(struct activity *act[], int p, unsigned int m_format)
233 {
234         int i;
235         struct stats_net_dev *sndc;
236
237         if (m_format == ACTIVITY_MAGIC_BASE) {
238                 struct stats_net_dev_8a *sndp_a;
239
240                 for (i = 0; i < act[p]->nr; i++) {
241                         sndp_a = (struct stats_net_dev_8a *) ((char *) act[p]->buf[0] + i * act[p]->msize);
242                         sndc = (struct stats_net_dev *) ((char *) act[p]->buf[1] + i * act[p]->fsize);
243
244                         sndc->rx_packets = (unsigned long long) sndp_a->rx_packets;
245                         sndc->tx_packets = (unsigned long long) sndp_a->tx_packets;
246                         sndc->rx_bytes = (unsigned long long) sndp_a->rx_bytes;
247                         sndc->tx_bytes = (unsigned long long) sndp_a->tx_bytes;
248                         sndc->rx_compressed = (unsigned long long) sndp_a->rx_compressed;
249                         sndc->tx_compressed = (unsigned long long) sndp_a->tx_compressed;
250                         sndc->multicast = (unsigned long long) sndp_a->multicast;
251                         sndc->speed = 0; /* New field */
252                         strncpy(sndc->interface, sndp_a->interface, MAX_IFACE_LEN);
253                         sndc->interface[MAX_IFACE_LEN - 1] = '\0';
254                         sndc->duplex = '\0'; /* New field */
255                 }
256         }
257         else {
258                 struct stats_net_dev_8b *sndp_b;
259
260                 for (i = 0; i < act[p]->nr; i++) {
261                         sndp_b = (struct stats_net_dev_8b *) ((char *) act[p]->buf[0] + i * act[p]->msize);
262                         sndc = (struct stats_net_dev *) ((char *) act[p]->buf[1] + i * act[p]->fsize);
263
264                         sndc->rx_packets = sndp_b->rx_packets;
265                         sndc->tx_packets = sndp_b->tx_packets;
266                         sndc->rx_bytes = sndp_b->rx_bytes;
267                         sndc->tx_bytes = sndp_b->tx_bytes;
268                         sndc->rx_compressed = sndp_b->rx_compressed;
269                         sndc->tx_compressed = sndp_b->tx_compressed;
270                         sndc->multicast = sndp_b->multicast;
271                         sndc->speed = 0; /* New field */
272                         strncpy(sndc->interface, sndp_b->interface, MAX_IFACE_LEN);
273                         sndc->interface[MAX_IFACE_LEN - 1] = '\0';
274                         sndc->duplex = '\0'; /* New field */
275                 }
276         }
277 }
278
279 /*
280  ***************************************************************************
281  * Upgrade stats_net_edev structure (from ACTIVITY_MAGIC_BASE format to
282  * ACTIVITY_MAGIC_BASE + 1 format).
283  *
284  * IN:
285  * @act         Array of activities.
286  * @p           Position of activity in array.
287  ***************************************************************************
288  */
289 void upgrade_stats_net_edev(struct activity *act[], int p)
290 {
291         int i;
292         struct stats_net_edev *snedc;
293         struct stats_net_edev_8a *snedp;
294
295         for (i = 0; i < act[p]->nr; i++) {
296                 snedp = (struct stats_net_edev_8a *) ((char *) act[p]->buf[0] + i * act[p]->msize);
297                 snedc = (struct stats_net_edev *) ((char *) act[p]->buf[1] + i * act[p]->fsize);
298
299                 snedc->collisions = (unsigned long long) snedp->collisions;
300                 snedc->rx_errors = (unsigned long long) snedp->rx_errors;
301                 snedc->tx_errors = (unsigned long long) snedp->tx_errors;
302                 snedc->rx_dropped = (unsigned long long) snedp->rx_dropped;
303                 snedc->tx_dropped = (unsigned long long) snedp->tx_dropped;
304                 snedc->rx_fifo_errors = (unsigned long long) snedp->rx_fifo_errors;
305                 snedc->tx_fifo_errors = (unsigned long long) snedp->tx_fifo_errors;
306                 snedc->rx_frame_errors = (unsigned long long) snedp->rx_frame_errors;
307                 snedc->tx_carrier_errors = (unsigned long long) snedp->tx_carrier_errors;
308                 strncpy(snedc->interface, snedp->interface, MAX_IFACE_LEN);
309                 snedc->interface[MAX_IFACE_LEN - 1] = '\0';
310         }
311 }
312
313 /*
314  ***************************************************************************
315  * Upgrade stats_net_ip structure (from ACTIVITY_MAGIC_BASE format to
316  * ACTIVITY_MAGIC_BASE + 1 format).
317  *
318  * IN:
319  * @act         Array of activities.
320  * @p           Position of activity in array.
321  ***************************************************************************
322  */
323 void upgrade_stats_net_ip(struct activity *act[], int p)
324 {
325         struct stats_net_ip *snic = (struct stats_net_ip *) act[p]->buf[1];
326         struct stats_net_ip_8a *snip = (struct stats_net_ip_8a *) act[p]->buf[0];
327
328         snic->InReceives = (unsigned long long) snip->InReceives;
329         snic->ForwDatagrams = (unsigned long long) snip->ForwDatagrams;
330         snic->InDelivers = (unsigned long long) snip->InDelivers;
331         snic->OutRequests = (unsigned long long) snip->OutRequests;
332         snic->ReasmReqds = (unsigned long long) snip->ReasmReqds;
333         snic->ReasmOKs = (unsigned long long) snip->ReasmOKs;
334         snic->FragOKs = (unsigned long long) snip->FragOKs;
335         snic->FragCreates = (unsigned long long) snip->FragCreates;
336 }
337
338 /*
339  ***************************************************************************
340  * Upgrade stats_net_eip structure (from ACTIVITY_MAGIC_BASE format to
341  * ACTIVITY_MAGIC_BASE + 1 format).
342  *
343  * IN:
344  * @act         Array of activities.
345  * @p           Position of activity in array.
346  ***************************************************************************
347  */
348 void upgrade_stats_net_eip(struct activity *act[], int p)
349 {
350         struct stats_net_eip *sneic = (struct stats_net_eip *) act[p]->buf[1];
351         struct stats_net_eip_8a *sneip = (struct stats_net_eip_8a *) act[p]->buf[0];
352
353         sneic->InHdrErrors = (unsigned long long) sneip->InHdrErrors;
354         sneic->InAddrErrors = (unsigned long long) sneip->InAddrErrors;
355         sneic->InUnknownProtos = (unsigned long long) sneip->InUnknownProtos;
356         sneic->InDiscards = (unsigned long long) sneip->InDiscards;
357         sneic->OutDiscards = (unsigned long long) sneip->OutDiscards;
358         sneic->OutNoRoutes = (unsigned long long) sneip->OutNoRoutes;
359         sneic->ReasmFails = (unsigned long long) sneip->ReasmFails;
360         sneic->FragFails = (unsigned long long) sneip->FragFails;
361 }
362
363 /*
364  ***************************************************************************
365  * Upgrade stats_net_ip6 structure (from ACTIVITY_MAGIC_BASE format to
366  * ACTIVITY_MAGIC_BASE + 1 format).
367  *
368  * IN:
369  * @act         Array of activities.
370  * @p           Position of activity in array.
371  ***************************************************************************
372  */
373 void upgrade_stats_net_ip6(struct activity *act[], int p)
374 {
375         struct stats_net_ip6 *snic6 = (struct stats_net_ip6 *) act[p]->buf[1];
376         struct stats_net_ip6_8a *snip6 = (struct stats_net_ip6_8a *) act[p]->buf[0];
377
378         snic6->InReceives6 = (unsigned long long) snip6->InReceives6;
379         snic6->OutForwDatagrams6 = (unsigned long long) snip6->OutForwDatagrams6;
380         snic6->InDelivers6 = (unsigned long long) snip6->InDelivers6;
381         snic6->OutRequests6 = (unsigned long long) snip6->OutRequests6;
382         snic6->ReasmReqds6 = (unsigned long long) snip6->ReasmReqds6;
383         snic6->ReasmOKs6 = (unsigned long long) snip6->ReasmOKs6;
384         snic6->InMcastPkts6 = (unsigned long long) snip6->InMcastPkts6;
385         snic6->OutMcastPkts6 = (unsigned long long) snip6->OutMcastPkts6;
386         snic6->FragOKs6 = (unsigned long long) snip6->FragOKs6;
387         snic6->FragCreates6 = (unsigned long long) snip6->FragCreates6;
388 }
389
390 /*
391  ***************************************************************************
392  * Upgrade stats_net_eip6 structure (from ACTIVITY_MAGIC_BASE format to
393  * ACTIVITY_MAGIC_BASE + 1 format).
394  *
395  * IN:
396  * @act         Array of activities.
397  * @p           Position of activity in array.
398  ***************************************************************************
399  */
400 void upgrade_stats_net_eip6(struct activity *act[], int p)
401 {
402         struct stats_net_eip6 *sneic6 = (struct stats_net_eip6 *) act[p]->buf[1];
403         struct stats_net_eip6_8a *sneip6 = (struct stats_net_eip6_8a *) act[p]->buf[0];
404
405         sneic6->InHdrErrors6 = (unsigned long long) sneip6->InHdrErrors6;
406         sneic6->InAddrErrors6 = (unsigned long long) sneip6->InAddrErrors6;
407         sneic6->InUnknownProtos6 = (unsigned long long) sneip6->InUnknownProtos6;
408         sneic6->InTooBigErrors6 = (unsigned long long) sneip6->InTooBigErrors6;
409         sneic6->InDiscards6 = (unsigned long long) sneip6->InDiscards6;
410         sneic6->OutDiscards6 = (unsigned long long) sneip6->OutDiscards6;
411         sneic6->InNoRoutes6 = (unsigned long long) sneip6->InNoRoutes6;
412         sneic6->OutNoRoutes6 = (unsigned long long) sneip6->OutNoRoutes6;
413         sneic6->ReasmFails6 = (unsigned long long) sneip6->ReasmFails6;
414         sneic6->FragFails6 = (unsigned long long) sneip6->FragFails6;
415         sneic6->InTruncatedPkts6 = (unsigned long long) sneip6->InTruncatedPkts6;
416 }
417
418 /*
419  ***************************************************************************
420  * Read and upgrade file's header section.
421  *
422  * IN:
423  * @dfile               System activity data file name.
424  * @fd                  File descriptor for sa datafile to convert.
425  * @stdfd               File descriptor for STDOUT.
426  * @act                 Array of activities.
427  * @file_magic          Pointer on file_magic structure.
428  * @previous_format     TRUE is sa datafile has an old format which is no
429  *                      longer compatible with current one.
430  *
431  * OUT:
432  * @file_hdr            Pointer on file_header structure.
433  * @file_actlst         Activity list in file.
434  * @vol_id_seq          Sequence of volatile activities.
435  *
436  * RETURNS:
437  * -1 on error, 0 otherwise.
438 ***************************************************************************
439  */
440 int upgrade_header_section(char dfile[], int fd, int stdfd,
441                            struct activity *act[], struct file_magic *file_magic,
442                            struct file_header *file_hdr, int previous_format,
443                            struct file_activity **file_actlst, unsigned int vol_id_seq[])
444 {
445         int i, j, n, p;
446         unsigned int a_cpu = FALSE;
447         void *buffer = NULL;
448         struct file_activity *fal;
449
450         /* Read file header structure */
451         fprintf(stderr, "file_header: ");
452
453         if (previous_format) {
454                 /* Previous format had 2 unsigned int less */
455                 n = FILE_HEADER_SIZE - 8;
456         }
457         else {
458                 n = file_magic->header_size;
459         }
460
461         SREALLOC(buffer, char, n);
462
463         sa_fread(fd, buffer, n, HARD_SIZE);
464
465         if (previous_format) {
466                 /* Upgrade file_header structure */
467                 upgrade_file_header(buffer, file_hdr);
468         }
469         else {
470                 memcpy(file_hdr, buffer, MINIMUM(n, FILE_HEADER_SIZE));
471         }
472
473         free(buffer);
474
475         /* Sanity check */
476         if (file_hdr->sa_act_nr > MAX_NR_ACT)
477                 goto invalid_header;
478
479         /* Read file activity list */
480         SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
481         fal = *file_actlst;
482
483         j = 0;
484         for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
485
486                 sa_fread(fd, fal, FILE_ACTIVITY_SIZE, HARD_SIZE);
487
488                 if ((fal->nr < 1) || (fal->nr2 < 1))
489                         /*
490                          * Every activity, known or unknown,
491                          * should have at least one item and sub-item.
492                          */
493                         goto invalid_header;
494
495                 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) >= 0) {
496                         /* This is a known activity, maybe with an unknown format */
497
498                         if (IS_VOLATILE(act[p]->options) && previous_format) {
499                                 /*
500                                  * Current activity is known by current version
501                                  * as a volatile one: So increment the number of
502                                  * volatile activities in file's header (but only
503                                  * for old format data files, since up-to-date
504                                  * format data files already have the right value here).
505                                  */
506                                 file_hdr->sa_vol_act_nr += 1;
507
508                                 /*
509                                  * Create the sequence of volatile activities.
510                                  * Used only for old format datafiles.
511                                  * For new format datafiles, this is not necessary
512                                  * since this sequence already exists following
513                                  * the RESTART record.
514                                  */
515                                 vol_id_seq[j++] = act[p]->id;
516                         }
517
518                         if (fal->id == A_CPU) {
519                                 /*
520                                  * Old format data files don't know volatile
521                                  * activities. The number of CPU is a constant
522                                  * all along the file.
523                                  */
524                                 if (previous_format) {
525                                         file_hdr->sa_last_cpu_nr = fal->nr;
526                                 }
527                                 a_cpu = TRUE;
528                         }
529
530                         /* Size of an activity cannot be zero */
531                         if (!fal->size)
532                                 goto invalid_header;
533
534                         /* Size of activity in file is larger than up-to-date activity size */
535                         if (fal->size > act[p]->msize) {
536                                 act[p]->msize = fal->size;
537                         }
538
539                         /*
540                          * When upgrading a file:
541                          * fal->size    : Size of an item for current activity, as
542                          *                read from the file.
543                          * act[p]->msize: Size of the buffer in memory where an item
544                          *                for current activity, as read from the file,
545                          *                will be saved. We have:
546                          *                act[p]->msize >= {fal->size ; act[p]->fsize}
547                          * act[p]->fsize: Size of an item for current activity with
548                          *                up-to-date format.
549                          */
550                         act[p]->nr    = fal->nr;
551                         act[p]->nr2   = fal->nr2;
552                         /*
553                          * Don't set act[p]->fsize! Should retain the size of an item
554                          * for up-to-date format!
555                          */
556                 }
557         }
558
559         if (!a_cpu) {
560                 /*
561                  * CPU activity should always be in file
562                  * and have a known format (expected magical number).
563                  */
564                 fprintf(stderr, _("\nCPU activity not found in file. Aborting...\n"));
565                 return -1;
566         }
567
568         /* Write file_header structure */
569         if ((n = write(stdfd, file_hdr, FILE_HEADER_SIZE)) != FILE_HEADER_SIZE) {
570                 fprintf(stderr, "\nwrite: %s\n", strerror(errno));
571                 return -1;
572         }
573
574         fprintf(stderr, "OK\n");
575
576         return 0;
577
578 invalid_header:
579
580         fprintf(stderr, _("\nInvalid data found. Aborting...\n"));
581
582         return -1;
583
584 }
585
586 /*
587  ***************************************************************************
588  * Upgrade file's activity list section.
589  *
590  * IN:
591  * @stdfd               File descriptor for STDOUT.
592  * @act                 Array of activities.
593  * @file_hdr            Pointer on file_header structure.
594  * @file_actlst         Activity list in file.
595  *
596  * RETURNS:
597  * -1 on error, 0 otherwise.
598 ***************************************************************************
599  */
600 int upgrade_activity_section(int stdfd, struct activity *act[],
601                              struct file_header *file_hdr,
602                              struct file_activity *file_actlst)
603 {
604         int i, p;
605         struct file_activity file_act;
606         struct file_activity *fal;
607
608         fprintf(stderr, "file_activity: ");
609
610         fal = file_actlst;
611
612         for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
613
614                 file_act = *fal;
615                 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) >= 0) {
616                         /* Update activity magic number */
617                         file_act.magic = act[p]->magic;
618                         /* Also update its size, which may have changed with recent versions */
619                         file_act.size = act[p]->fsize;
620                 }
621
622                 /*
623                  * Even unknown activities must be written
624                  * (they are counted in sa_act_nr).
625                  */
626                 if (write(stdfd, &file_act, FILE_ACTIVITY_SIZE) != FILE_ACTIVITY_SIZE) {
627                         fprintf(stderr, "\nwrite: %s\n", strerror(errno));
628                         return -1;
629                 }
630
631                 fprintf(stderr, "%s ", act[p]->name);
632         }
633
634         fprintf(stderr, "OK\n");
635
636         return 0;
637 }
638
639 /*
640  ***************************************************************************
641  * Upgrade a COMMENT record.
642  *
643  * IN:
644  * @fd          File descriptor for sa datafile to convert.
645  * @stdfd       File descriptor for STDOUT.
646  *
647  * RETURNS:
648  * -1 on error, 0 otherwise.
649 ***************************************************************************
650  */
651 int upgrade_comment_record(int fd, int stdfd)
652 {
653         char file_comment[MAX_COMMENT_LEN];
654
655         /* Read the COMMENT record */
656         sa_fread(fd, file_comment, MAX_COMMENT_LEN, HARD_SIZE);
657         file_comment[MAX_COMMENT_LEN - 1] = '\0';
658
659         /* Then write it. No changes at this time */
660         if (write(stdfd, file_comment, MAX_COMMENT_LEN) != MAX_COMMENT_LEN) {
661                 fprintf(stderr, "\nwrite: %s\n", strerror(errno));
662                 return -1;
663         }
664
665         fprintf(stderr, "C");
666
667         return 0;
668 }
669
670 /*
671  ***************************************************************************
672  * Upgrade a RESTART record.
673  *
674  * IN:
675  * @fd                  File descriptor for sa datafile to convert.
676  * @stdfd               File descriptor for STDOUT.
677  * @act                 Array of activities.
678  * @file_hdr            Pointer on file_header structure.
679  * @previous_format     TRUE is sa datafile has an old format which is no
680  *                      longer compatible with current one.
681  * @vol_id_seq          Sequence of volatile activities.
682  *
683  * RETURNS:
684  * -1 on error, 0 otherwise.
685 ***************************************************************************
686  */
687 int upgrade_restart_record(int fd, int stdfd, struct activity *act[],
688                            struct file_header *file_hdr, int previous_format,
689                            unsigned int vol_id_seq[])
690 {
691         int i, p;
692         struct file_activity file_act;
693
694         /*
695          * This is a RESTART record.
696          * Only new format data file have additional structures
697          * to read here for volatile activities.
698          */
699         for (i = 0; i < file_hdr->sa_vol_act_nr; i++) {
700
701                 if (!previous_format) {
702                         sa_fread(fd, &file_act, FILE_ACTIVITY_SIZE, HARD_SIZE);
703                         if (file_act.id) {
704                                 reallocate_vol_act_structures(act, file_act.nr, file_act.id);
705                         }
706                 }
707                 else {
708                         memset(&file_act, 0, FILE_ACTIVITY_SIZE);
709
710                         /* Old format: Sequence of volatile activities is in vol_id_seq */
711                         p = get_activity_position(act, vol_id_seq[i], EXIT_IF_NOT_FOUND);
712
713                         /* Set only the necessary fields */
714                         file_act.id = act[p]->id;
715                         file_act.nr = act[p]->nr;
716                 }
717
718                 if (write(stdfd, &file_act, FILE_ACTIVITY_SIZE) != FILE_ACTIVITY_SIZE) {
719                         fprintf(stderr, "\nwrite: %s\n", strerror(errno));
720                         return -1;
721                 }
722         }
723
724         fprintf(stderr, "R");
725
726         return 0;
727 }
728
729 /*
730  ***************************************************************************
731  * Upgrade a record which is not a COMMENT or a RESTART one.
732  *
733  * IN:
734  * @fd                  File descriptor for sa datafile to convert.
735  * @stdfd               File descriptor for STDOUT.
736  * @act                 Array of activities.
737  * @file_hdr            Pointer on file_header structure.
738  * @file_actlst         Activity list in file.
739  *
740  * RETURNS:
741  * -1 on error, 0 otherwise.
742 ***************************************************************************
743  */
744 int upgrade_common_record(int fd, int stdfd, struct activity *act[],
745                            struct file_header *file_hdr,
746                            struct file_activity *file_actlst)
747 {
748         int i, j, k, p;
749         struct file_activity *fal;
750         void *buffer = NULL;
751         size_t size;
752
753         /*
754          * This is not a special record, so read the extra fields,
755          * even if the format of the activity is unknown.
756          */
757         fal = file_actlst;
758         for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
759
760                 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) {
761                         /* An unknown activity should still be read and written */
762                         size = (size_t) fal->size * (size_t) fal->nr * (size_t) fal->nr2;
763                         if (!size) {
764                                 /* Buffer may have been allocated from a previous iteration in the loop */
765                                 if (buffer) {
766                                         free (buffer);
767                                 }
768                                 return -1;
769                         }
770                         SREALLOC(buffer, void, size);
771                         sa_fread(fd, buffer, fal->size * fal->nr * fal->nr2, HARD_SIZE);
772                         if (write(stdfd, (char *) buffer, size) != size) {
773                                 fprintf(stderr, "\nwrite: %s\n", strerror(errno));
774                                 free(buffer);
775                                 return -1;
776                         }
777                         continue;
778                 }
779
780                 if ((act[p]->nr > 0) &&
781                     ((act[p]->nr > 1) || (act[p]->nr2 > 1)) &&
782                     (act[p]->msize > fal->size)) {
783
784                         for (j = 0; j < act[p]->nr; j++) {
785                                 for (k = 0; k < act[p]->nr2; k++) {
786                                         sa_fread(fd,
787                                                  (char *) act[p]->buf[0] + (j * act[p]->nr2 + k) * act[p]->msize,
788                                                  fal->size, HARD_SIZE);
789                                 }
790                         }
791                 }
792
793                 else if (act[p]->nr > 0) {
794                         sa_fread(fd, act[p]->buf[0], fal->size * act[p]->nr * act[p]->nr2, HARD_SIZE);
795                 }
796
797                 if (act[p]->magic != fal->magic) {
798
799                         /* Known activity but old format */
800                         switch (fal->id) {
801
802                                 case A_IO:
803                                         upgrade_stats_io(act, p);
804                                         break;
805
806                                 case A_QUEUE:
807                                         upgrade_stats_queue(act, p);
808                                         break;
809
810                                 case A_DISK:
811                                         upgrade_stats_disk(act, p);
812                                         break;
813
814                                 case A_NET_DEV:
815                                         upgrade_stats_net_dev(act, p, fal->magic);
816                                         break;
817
818                                 case A_NET_EDEV:
819                                         upgrade_stats_net_edev(act, p);
820                                         break;
821
822                                 case A_NET_IP:
823                                         upgrade_stats_net_ip(act, p);
824                                         break;
825
826                                 case A_NET_EIP:
827                                         upgrade_stats_net_eip(act, p);
828                                         break;
829
830                                 case A_NET_IP6:
831                                         upgrade_stats_net_ip6(act, p);
832                                         break;
833
834                                 case A_NET_EIP6:
835                                         upgrade_stats_net_eip6(act, p);
836                                         break;
837                                 }
838                 }
839                 else {
840                         /* Known activity with current up-to-date format */
841                         for (j = 0; j < act[p]->nr; j++) {
842                                 for (k = 0; k < act[p]->nr2; k++) {
843                                         memcpy((char *) act[p]->buf[1] + (j * act[p]->nr2 + k) * act[p]->msize,
844                                                (char *) act[p]->buf[0] + (j * act[p]->nr2 + k) * act[p]->msize,
845                                                fal->size);
846                                 }
847                         }
848                 }
849
850                 for (j = 0; j < act[p]->nr; j++) {
851                         for (k = 0; k < act[p]->nr2; k++) {
852                                 if (write(stdfd,
853                                                (char *) act[p]->buf[1] + (j * act[p]->nr2 + k) * act[p]->msize,
854                                                act[p]->fsize) !=
855                                                act[p]->fsize) {
856                                         fprintf(stderr, "\nwrite: %s\n", strerror(errno));
857                                         free(buffer);
858                                         return -1;
859                                 }
860                         }
861                 }
862         }
863
864         fprintf(stderr, ".");
865
866         if (buffer) {
867                 free(buffer);
868         }
869
870         return 0;
871 }
872
873 /*
874  ***************************************************************************
875  * Upgrade statistics records.
876  *
877  * IN:
878  * @fd                  File descriptor for sa datafile to convert.
879  * @stdfd               File descriptor for STDOUT.
880  * @act                 Array of activities.
881  * @file_hdr            Pointer on file_header structure.
882  * @previous_format     TRUE is sa datafile has an old format which is no
883  *                      longer compatible with current one.
884  * @file_actlst         Activity list in file.
885  * @vol_id_seq          Sequence of volatile activities.
886  *
887  * RETURNS:
888  * -1 on error, 0 otherwise.
889 ***************************************************************************
890  */
891 int upgrade_stat_records(int fd, int stdfd, struct activity *act[],
892                          struct file_header *file_hdr, int previous_format,
893                          struct file_activity *file_actlst, unsigned int vol_id_seq[])
894 {
895         int rtype;
896         int eosaf;
897         struct record_header record_hdr;
898
899         fprintf(stderr, _("Statistics: "));
900
901         do {
902                 eosaf = sa_fread(fd, &record_hdr, RECORD_HEADER_SIZE, SOFT_SIZE);
903                 rtype = record_hdr.record_type;
904
905                 if (!eosaf) {
906
907                         if (write(stdfd, &record_hdr, RECORD_HEADER_SIZE)
908                                 != RECORD_HEADER_SIZE) {
909                                 fprintf(stderr, "\nwrite: %s\n", strerror(errno));
910                                 return -1;
911                         }
912
913                         if (rtype == R_COMMENT) {
914                                 /* Upgrade the COMMENT record */
915                                 if (upgrade_comment_record(fd, stdfd) < 0)
916                                         return -1;
917                         }
918
919                         else if (rtype == R_RESTART) {
920                                 /* Upgrade the RESTART record */
921                                 if (upgrade_restart_record(fd, stdfd, act, file_hdr,
922                                                            previous_format, vol_id_seq) < 0)
923                                         return -1;
924                         }
925
926                         else {
927                                 /* Upgrade current statistics record */
928                                 if (upgrade_common_record(fd, stdfd, act, file_hdr,
929                                                           file_actlst) < 0)
930                                         return -1;
931                         }
932                 }
933         }
934         while (!eosaf);
935
936         return 0;
937 }
938
939 /*
940  ***************************************************************************
941  * Close file descriptors and exit.
942  *
943  * IN:
944  * @fd          File descriptor for sa datafile to convert.
945  * @stdfd       File descriptor for STDOUT.
946  * @exit_code   Exit code.
947  ***************************************************************************
948  */
949 void upgrade_exit(int fd, int stdfd, int exit_code)
950 {
951         if (fd) {
952                 close(fd);
953         }
954         if (stdfd) {
955                 close(stdfd);
956         }
957
958         exit(exit_code);
959 }
960
961 /*
962  ***************************************************************************
963  * Convert a sysstat activity data file from a previous version to the
964  * up-to-date format. Presently data files from sysstat version 9.1.6 and
965  * later are converted to current sysstat version format.
966  *
967  * IN:
968  * @dfile       System activity data file name.
969  * @act         Array of activities.
970  ***************************************************************************
971  */
972 void convert_file(char dfile[], struct activity *act[])
973 {
974         int fd = 0, stdfd = 0;
975         int previous_format = FALSE;
976         struct file_magic file_magic;
977         struct file_header file_hdr;
978         struct file_activity *file_actlst = NULL;
979         unsigned int vol_id_seq[NR_ACT];
980
981         /* Open stdout */
982         if ((stdfd = dup(STDOUT_FILENO)) < 0) {
983                 perror("dup");
984                 upgrade_exit(0, 0, 2);
985         }
986
987         /* Upgrade file's magic section */
988         if (upgrade_magic_section(dfile, &fd, stdfd, &file_magic,
989                                   &previous_format) < 0) {
990                 upgrade_exit(fd, stdfd, 2);
991         }
992
993         /* Upgrade file's header section */
994         if (upgrade_header_section(dfile, fd, stdfd, act,
995                                    &file_magic, &file_hdr,
996                                    previous_format, &file_actlst,
997                                    vol_id_seq) < 0) {
998                 upgrade_exit(fd, stdfd, 2);
999         }
1000
1001         /* Upgrade file's activity list section */
1002         if (upgrade_activity_section(stdfd, act, &file_hdr,
1003                                      file_actlst) < 0) {
1004                 upgrade_exit(fd, stdfd, 2);
1005         }
1006
1007         /* Perform required allocations */
1008         allocate_structures(act);
1009
1010         /* Upgrade statistics records */
1011         if (upgrade_stat_records(fd, stdfd, act, &file_hdr,
1012                                  previous_format, file_actlst,
1013                                  vol_id_seq) <0) {
1014                 upgrade_exit(fd, stdfd, 2);
1015         }
1016
1017         fprintf(stderr,
1018                 _("\nFile successfully converted to sysstat format version %s\n"),
1019                 VERSION);
1020
1021         free(file_actlst);
1022         free_structures(act);
1023         close(fd);
1024         close(stdfd);
1025 }