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