]> granicus.if.org Git - sysstat/blob - sadf_misc.c
Starting sysstat-12.5.4
[sysstat] / sadf_misc.c
1 /*
2  * sadf_misc.c: Funtions used by sadf to display special records
3  * (C) 2011-2021 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 <time.h>
25
26 #include "sadf.h"
27 #include "pcp_def_metrics.h"
28
29 #ifdef USE_NLS
30 #include <locale.h>
31 #include <libintl.h>
32 #define _(string) gettext(string)
33 #else
34 #define _(string) (string)
35 #endif
36
37 #ifdef HAVE_PCP
38 #include <pcp/pmapi.h>
39 #include <pcp/import.h>
40 #endif
41
42 extern char *tzname[2];
43
44 extern uint64_t flags;
45 extern char *seps[];
46
47 extern int palette;
48 extern unsigned int svg_colors[][SVG_COL_PALETTE_SIZE];
49
50 /*
51  ***************************************************************************
52  * Flush data to PCP archive.
53  *
54  * IN:
55  * @record_hdr  Record header for current sample.
56  * @flags       Flags for common options.
57  ***************************************************************************
58  */
59 void pcp_write_data(struct record_header *record_hdr, unsigned int flags)
60 {
61 #ifdef HAVE_PCP
62         int rc;
63         struct tm lrectime;
64         unsigned long long utc_sec = record_hdr->ust_time;
65         static long long delta_utc = LONG_MAX;
66
67         if (!PRINT_LOCAL_TIME(flags)) {
68                 if (delta_utc == LONG_MAX) {
69                         /* Convert a time_t value from local time to UTC */
70                         if (gmtime_r((const time_t *) &(record_hdr->ust_time), &lrectime)) {
71                                 utc_sec = mktime(&lrectime);
72                                 delta_utc = utc_sec - record_hdr->ust_time;
73                         }
74                 }
75                 else {
76                         /*
77                          * Once pmiWrite() has been called (after the first stats sample),
78                          * subsequent mktime() calls will not give the same result with
79                          * the same input data. So compute a time shift that will be used
80                          * for the next samples.
81                          * We should (really) be careful if pmiWrite() was to be used sooner
82                          * than for the first stats sample (e.g. if we want to save a
83                          * LINUX RESTART record heading the file).
84                          */
85                         utc_sec += delta_utc;
86                 }
87         }
88
89         /* Write data to PCP archive */
90         if ((rc = pmiWrite(utc_sec, 0)) < 0) {
91                 fprintf(stderr, "PCP: pmiWrite: %s\n", pmiErrStr(rc));
92                 exit(4);
93         }
94 #endif
95 }
96
97 /*
98  ***************************************************************************
99  * Display restart messages (database and ppc formats).
100  *
101  * IN:
102  * @cur_date    Date string of current restart message.
103  * @cur_time    Time string of current restart message.
104  * @utc         True if @cur_time is expressed in UTC.
105  * @sep         Character used as separator.
106  * @file_hdr    System activity file standard header.
107  ***************************************************************************
108  */
109 void print_dbppc_restart(char *cur_date, char *cur_time, int utc, char sep,
110                          struct file_header *file_hdr)
111 {
112         printf("%s%c-1%c", file_hdr->sa_nodename, sep, sep);
113         if (strlen(cur_date)) {
114                 printf("%s ", cur_date);
115         }
116         printf("%s", cur_time);
117         if (strlen(cur_date) && utc) {
118                 printf(" UTC");
119         }
120         printf("%cLINUX-RESTART\t(%d CPU)\n",
121                sep, file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
122 }
123
124 /*
125  ***************************************************************************
126  * Display restart messages (ppc format).
127  *
128  * IN:
129  * @tab         Number of tabulations (unused here).
130  * @action      Action expected from current function.
131  * @cur_date    Date string of current restart message.
132  * @cur_time    Time string of current restart message.
133  * @utc         True if @cur_time is expressed in UTC.
134  * @file_hdr    System activity file standard header.
135  * @record_hdr  Current record header (unused here).
136  ***************************************************************************
137  */
138 __printf_funct_t print_db_restart(int *tab, int action, char *cur_date,
139                                   char *cur_time, int utc, struct file_header *file_hdr,
140                                   struct record_header *record_hdr)
141 {
142         /* Actions F_BEGIN and F_END ignored */
143         if (action == F_MAIN) {
144                 print_dbppc_restart(cur_date, cur_time, utc, ';', file_hdr);
145         }
146 }
147
148 /*
149  ***************************************************************************
150  * Display restart messages (database format).
151  *
152  * IN:
153  * @tab         Number of tabulations (unused here).
154  * @action      Action expected from current function.
155  * @cur_date    Date string of current restart message.
156  * @cur_time    Time string of current restart message.
157  * @utc         True if @cur_time is expressed in UTC.
158  * @file_hdr    System activity file standard header.
159  * @record_hdr  Current record header (unused here).
160  ***************************************************************************
161  */
162 __printf_funct_t print_ppc_restart(int *tab, int action, char *cur_date,
163                                    char *cur_time, int utc, struct file_header *file_hdr,
164                                    struct record_header *record_hdr)
165 {
166         /* Actions F_BEGIN and F_END ignored */
167         if (action == F_MAIN) {
168                 print_dbppc_restart(cur_date, cur_time, utc, '\t', file_hdr);
169         }
170 }
171
172 /*
173  ***************************************************************************
174  * Display restart messages (XML format).
175  *
176  * IN:
177  * @tab         Number of tabulations.
178  * @action      Action expected from current function.
179  * @cur_date    Date string of current restart message.
180  * @cur_time    Time string of current restart message.
181  * @utc         True if @cur_time is expressed in UTC.
182  * @file_hdr    System activity file standard header.
183  * @record_hdr  Current record header (unused here).
184  *
185  * OUT:
186  * @tab         Number of tabulations.
187  ***************************************************************************
188  */
189 __printf_funct_t print_xml_restart(int *tab, int action, char *cur_date,
190                                    char *cur_time, int utc, struct file_header *file_hdr,
191                                    struct record_header *record_hdr)
192 {
193         if (action & F_BEGIN) {
194                 xprintf((*tab)++, "<restarts>");
195         }
196         if (action & F_MAIN) {
197                 xprintf(*tab, "<boot date=\"%s\" time=\"%s\" utc=\"%d\" cpu_count=\"%d\"/>",
198                         cur_date, cur_time, utc ? 1 : 0,
199                         file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
200         }
201         if (action & F_END) {
202                 xprintf(--(*tab), "</restarts>");
203         }
204 }
205
206 /*
207  ***************************************************************************
208  * Display restart messages (JSON format).
209  *
210  * IN:
211  * @tab         Number of tabulations.
212  * @action      Action expected from current function.
213  * @cur_date    Date string of current restart message.
214  * @cur_time    Time string of current restart message.
215  * @utc         True if @cur_time is expressed in UTC.
216  * @file_hdr    System activity file standard header.
217  * @record_hdr  Current record header (unused here).
218  *
219  * OUT:
220  * @tab         Number of tabulations.
221  ***************************************************************************
222  */
223 __printf_funct_t print_json_restart(int *tab, int action, char *cur_date,
224                                     char *cur_time, int utc, struct file_header *file_hdr,
225                                     struct record_header *record_hdr)
226 {
227         static int sep = FALSE;
228
229         if (action & F_BEGIN) {
230                 printf(",\n");
231                 xprintf((*tab)++, "\"restarts\": [");
232         }
233         if (action & F_MAIN) {
234                 if (sep) {
235                         printf(",\n");
236                 }
237                 xprintf((*tab)++, "{");
238                 xprintf(*tab, "\"boot\": {\"date\": \"%s\", \"time\": \"%s\", \"utc\": %d, \"cpu_count\": %d}",
239                         cur_date, cur_time, utc ? 1 : 0,
240                         file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
241                 xprintf0(--(*tab), "}");
242                 sep = TRUE;
243         }
244         if (action & F_END) {
245                 if (sep) {
246                         printf("\n");
247                         sep = FALSE;
248                 }
249                 xprintf0(--(*tab), "]");
250         }
251 }
252
253 /*
254  ***************************************************************************
255  * Display restart messages (raw format).
256  *
257  * IN:
258  * @tab         Number of tabulations (unused here).
259  * @action      Action expected from current function.
260  * @cur_date    Date string of current restart message.
261  * @cur_time    Time string of current restart message.
262  * @utc         True if @cur_time is expressed in UTC.
263  * @file_hdr    System activity file standard header.
264  * @record_hdr  Current record header (unused here).
265  ***************************************************************************
266  */
267 __printf_funct_t print_raw_restart(int *tab, int action, char *cur_date,
268                                    char *cur_time, int utc, struct file_header *file_hdr,
269                                    struct record_header *record_hdr)
270 {
271         /* Actions F_BEGIN and F_END ignored */
272         if (action == F_MAIN) {
273                 printf("%s", cur_time);
274                 if (strlen(cur_date) && utc) {
275                         printf(" UTC");
276                 }
277                 printf("; LINUX-RESTART (%d CPU)\n",
278                        file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
279         }
280 }
281
282 /*
283  ***************************************************************************
284  * Display restart messages (PCP format).
285  *
286  * IN:
287  * @tab         Number of tabulations (unused here).
288  * @action      Action expected from current function.
289  * @cur_date    Date string of current restart message (unused here).
290  * @cur_time    Time string of current restart message (unused here).
291  * @utc         True if @cur_time is expressed in UTC (unused here).
292  * @file_hdr    System activity file standard header.
293  * @record_hdr  Current record header.
294  ***************************************************************************
295  */
296 __printf_funct_t print_pcp_restart(int *tab, int action, char *cur_date, char *cur_time,
297                                    int utc, struct file_header *file_hdr,
298                                    struct record_header *record_hdr)
299 {
300 #ifdef HAVE_PCP
301         static int def_metrics = FALSE;
302         char buf[64];
303
304         if (action & F_BEGIN) {
305                 if (!def_metrics) {
306                         pmiAddMetric("system.restart.count",
307                                      PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
308                                      pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
309
310                         pmiAddMetric("system.restart.ncpu",
311                                      PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
312                                      pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
313
314                         def_metrics = TRUE;
315                 }
316         }
317         if (action & F_MAIN) {
318                 pmiPutValue("system.restart.count", NULL, "1");
319
320                 snprintf(buf, sizeof(buf), "%u",
321                          file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
322                 pmiPutValue("system.restart.ncpu", NULL, buf);
323
324                 /* Write data to PCP archive */
325                 pcp_write_data(record_hdr, flags);
326         }
327 #endif /* HAVE_PCP */
328 }
329
330 /*
331  ***************************************************************************
332  * Display comments (database and ppc formats).
333  *
334  * IN:
335  * @cur_date    Date string of current restart message.
336  * @cur_time    Time string of current restart message.
337  * @utc         True if @cur_time is expressed in UTC.
338  * @comment     Comment to display.
339  * @sep         Character used as separator.
340  * @file_hdr    System activity file standard header.
341  ***************************************************************************
342  */
343 void print_dbppc_comment(char *cur_date, char *cur_time, int utc,
344                          char *comment, char sep, struct file_header *file_hdr)
345 {
346         printf("%s%c-1%c", file_hdr->sa_nodename, sep, sep);
347         if (strlen(cur_date)) {
348                 printf("%s ", cur_date);
349         }
350         printf("%s", cur_time);
351         if (strlen(cur_date) && utc) {
352                 printf(" UTC");
353         }
354         printf("%cCOM %s\n", sep, comment);
355 }
356
357 /*
358  ***************************************************************************
359  * Display comments (database format).
360  *
361  * IN:
362  * @tab         Number of tabulations (unused here).
363  * @action      Action expected from current function.
364  * @cur_date    Date string of current restart message.
365  * @cur_time    Time string of current restart message.
366  * @utc         True if @cur_time is expressed in UTC.
367  * @comment     Comment to display.
368  * @file_hdr    System activity file standard header.
369  * @record_hdr  Current record header (unused here).
370  ***************************************************************************
371  */
372 __printf_funct_t print_db_comment(int *tab, int action, char *cur_date, char *cur_time,
373                                   int utc, char *comment, struct file_header *file_hdr,
374                                   struct record_header *record_hdr)
375 {
376         /* Actions F_BEGIN and F_END ignored */
377         if (action & F_MAIN) {
378                 print_dbppc_comment(cur_date, cur_time, utc, comment,
379                                     ';', file_hdr);
380         }
381 }
382
383 /*
384  ***************************************************************************
385  * Display comments (ppc format).
386  *
387  * IN:
388  * @tab         Number of tabulations (unused here).
389  * @action      Action expected from current function.
390  * @cur_date    Date string of current restart message.
391  * @cur_time    Time string of current restart message.
392  * @utc         True if @cur_time is expressed in UTC.
393  * @comment     Comment to display.
394  * @file_hdr    System activity file standard header.
395  * @record_hdr  Current record header (unused here).
396  ***************************************************************************
397  */
398 __printf_funct_t print_ppc_comment(int *tab, int action, char *cur_date, char *cur_time,
399                                    int utc, char *comment, struct file_header *file_hdr,
400                                    struct record_header *record_hdr)
401 {
402         /* Actions F_BEGIN and F_END ignored */
403         if (action & F_MAIN) {
404                 print_dbppc_comment(cur_date, cur_time, utc, comment,
405                                     '\t', file_hdr);
406         }
407 }
408
409 /*
410  ***************************************************************************
411  * Display comments (XML format).
412  *
413  * IN:
414  * @tab         Number of tabulations.
415  * @action      Action expected from current function.
416  * @cur_date    Date string of current comment.
417  * @cur_time    Time string of current comment.
418  * @utc         True if @cur_time is expressed in UTC.
419  * @comment     Comment to display.
420  * @file_hdr    System activity file standard header (unused here).
421  * @record_hdr  Current record header (unused here).
422  *
423  * OUT:
424  * @tab         Number of tabulations.
425  ***************************************************************************
426  */
427 __printf_funct_t print_xml_comment(int *tab, int action, char *cur_date, char *cur_time,
428                                    int utc, char *comment, struct file_header *file_hdr,
429                                    struct record_header *record_hdr)
430 {
431         if (action & F_BEGIN) {
432                 xprintf((*tab)++, "<comments>");
433         }
434         if (action & F_MAIN) {
435                 xprintf(*tab, "<comment date=\"%s\" time=\"%s\" utc=\"%d\" com=\"%s\"/>",
436                         cur_date, cur_time, utc ? 1 : 0, comment);
437         }
438         if (action & F_END) {
439                 xprintf(--(*tab), "</comments>");
440         }
441 }
442
443 /*
444  ***************************************************************************
445  * Display comments (JSON format).
446  *
447  * IN:
448  * @tab         Number of tabulations.
449  * @action      Action expected from current function.
450  * @cur_date    Date string of current comment.
451  * @cur_time    Time string of current comment.
452  * @utc         True if @cur_time is expressed in UTC.
453  * @comment     Comment to display.
454  * @file_hdr    System activity file standard header (unused here).
455  * @record_hdr  Current record header (unused here).
456  *
457  * OUT:
458  * @tab         Number of tabulations.
459  ***************************************************************************
460  */
461 __printf_funct_t print_json_comment(int *tab, int action, char *cur_date, char *cur_time,
462                                     int utc, char *comment, struct file_header *file_hdr,
463                                     struct record_header *record_hdr)
464 {
465         static int sep = FALSE;
466
467         if (action & F_BEGIN) {
468                 printf(",\n");
469                 xprintf((*tab)++, "\"comments\": [");
470         }
471         if (action & F_MAIN) {
472                 if (sep) {
473                         printf(",\n");
474                 }
475                 xprintf((*tab)++, "{");
476                 xprintf(*tab,
477                         "\"comment\": {\"date\": \"%s\", \"time\": \"%s\", "
478                         "\"utc\": %d, \"com\": \"%s\"}",
479                         cur_date, cur_time, utc ? 1 : 0, comment);
480                 xprintf0(--(*tab), "}");
481                 sep = TRUE;
482         }
483         if (action & F_END) {
484                 if (sep) {
485                         printf("\n");
486                         sep = FALSE;
487                 }
488                 xprintf0(--(*tab), "]");
489         }
490 }
491
492 /*
493  ***************************************************************************
494  * Display comments (raw format).
495  *
496  * IN:
497  * @tab         Number of tabulations (unused here).
498  * @action      Action expected from current function.
499  * @cur_date    Date string of current restart message.
500  * @cur_time    Time string of current restart message.
501  * @utc         True if @cur_time is expressed in UTC.
502  * @comment     Comment to display.
503  * @file_hdr    System activity file standard header (unused here).
504  * @record_hdr  Current record header (unused here).
505  ***************************************************************************
506  */
507 __printf_funct_t print_raw_comment(int *tab, int action, char *cur_date, char *cur_time,
508                                    int utc, char *comment, struct file_header *file_hdr,
509                                    struct record_header *record_hdr)
510 {
511         /* Actions F_BEGIN and F_END ignored */
512         if (action & F_MAIN) {
513                 printf("%s", cur_time);
514                 if (strlen(cur_date) && utc) {
515                         printf(" UTC");
516                 }
517                 printf("; COM %s\n", comment);
518         }
519 }
520
521 /*
522  ***************************************************************************
523  * Display comments (PCP format).
524  *
525  * IN:
526  * @tab         Number of tabulations (unused here).
527  * @action      Action expected from current function.
528  * @cur_date    Date string of current restart message (unused here).
529  * @cur_time    Time string of current restart message (unused here).
530  * @utc         True if @cur_time is expressed in UTC (unused here).
531  * @comment     Comment to display.
532  * @file_hdr    System activity file standard header (unused here).
533  * @record_hdr  Current record header.
534  ***************************************************************************
535  */
536 __printf_funct_t print_pcp_comment(int *tab, int action, char *cur_date, char *cur_time,
537                                    int utc, char *comment, struct file_header *file_hdr,
538                                    struct record_header *record_hdr)
539 {
540 #ifdef HAVE_PCP
541         static int def_metrics = FALSE;
542
543         if (action & F_BEGIN) {
544                 if (!def_metrics) {
545                         pmiAddMetric("system.comment.value",
546                                      PM_IN_NULL, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE,
547                                      pmiUnits(0, 0, 0, 0, 0, 0));
548
549                         def_metrics = TRUE;
550                 }
551         }
552         if (action & F_MAIN) {
553                 pmiPutValue("system.comment.value", NULL, comment);
554
555                 /* Write data to PCP archive */
556                 pcp_write_data(record_hdr, flags);
557         }
558 #endif /* HAVE_PCP */
559 }
560
561 /*
562  ***************************************************************************
563  * Display the "statistics" part of the report (XML format).
564  *
565  * IN:
566  * @tab         Number of tabulations.
567  * @action      Action expected from current function.
568  * @act         Array of activities (unused here).
569  * @id_seq      Activity sequence (unused here).
570  *
571  * OUT:
572  * @tab         Number of tabulations.
573  ***************************************************************************
574  */
575 __printf_funct_t print_xml_statistics(int *tab, int action, struct activity *act[],
576                                       unsigned int id_seq[])
577 {
578         if (action & F_BEGIN) {
579                 xprintf((*tab)++, "<statistics>");
580         }
581         if (action & F_END) {
582                 xprintf(--(*tab), "</statistics>");
583         }
584 }
585
586 /*
587  ***************************************************************************
588  * Display the "statistics" part of the report (JSON format).
589  *
590  * IN:
591  * @tab         Number of tabulations.
592  * @action      Action expected from current function.
593  * @act         Array of activities (unused here).
594  * @id_seq      Activity sequence (unused here).
595  *
596  * OUT:
597  * @tab         Number of tabulations.
598  ***************************************************************************
599  */
600 __printf_funct_t print_json_statistics(int *tab, int action, struct activity *act[],
601                                        unsigned int id_seq[])
602 {
603         static int sep = FALSE;
604
605         if (action & F_BEGIN) {
606                 printf(",\n");
607                 xprintf((*tab)++, "\"statistics\": [");
608         }
609         if (action & F_MAIN) {
610                 if (sep) {
611                         xprintf(--(*tab), "},");
612                 }
613                 xprintf((*tab)++, "{");
614                 sep = TRUE;
615         }
616         if (action & F_END) {
617                 if (sep) {
618                         xprintf(--(*tab), "}");
619                         sep = FALSE;
620                 }
621                 xprintf0(--(*tab), "]");
622         }
623 }
624
625 /*
626  ***************************************************************************
627  * Display the "statistics" part of the report (PCP format).
628  *
629  * IN:
630  * @tab         Number of tabulations (unused here).
631  * @action      Action expected from current function.
632  * @act         Array of activities.
633  * @id_seq      Activity sequence.
634  ***************************************************************************
635  */
636 __printf_funct_t print_pcp_statistics(int *tab, int action, struct activity *act[],
637                                       unsigned int id_seq[])
638 {
639 #ifdef HAVE_PCP
640         int i, p;
641
642         if (action & F_BEGIN) {
643                 for (i = 0; i < NR_ACT; i++) {
644                         if (!id_seq[i])
645                                 continue;       /* Activity not in file */
646
647                         p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
648                         if (!IS_SELECTED(act[p]->options))
649                                 continue;       /* Activity not selected */
650
651                         switch (act[p]->id) {
652
653                                 case A_CPU:
654                                 case A_PWR_CPU:
655                                 case A_NET_SOFT:
656                                         pcp_def_cpu_metrics(act[p]);
657                                         break;
658
659                                 case A_PCSW:
660                                         pcp_def_pcsw_metrics();
661                                         break;
662
663                                 case A_IRQ:
664                                         pcp_def_irq_metrics(act[p]);
665                                         break;
666
667                                 case A_SWAP:
668                                         pcp_def_swap_metrics();
669                                         break;
670
671                                 case A_PAGE:
672                                         pcp_def_paging_metrics();
673                                         break;
674
675                                 case A_IO:
676                                         pcp_def_io_metrics();
677                                         break;
678
679                                 case A_MEMORY:
680                                         pcp_def_memory_metrics(act[p]);
681                                         break;
682
683                                 case A_KTABLES:
684                                         pcp_def_ktables_metrics();
685                                         break;
686
687                                 case A_QUEUE:
688                                         pcp_def_queue_metrics();
689                                         break;
690
691                                 case A_SERIAL:
692                                         pcp_def_serial_metrics(act[p]);
693                                         break;
694
695                                 case A_DISK:
696                                         pcp_def_disk_metrics(act[p]);
697                                         break;
698
699                                 case A_NET_DEV:
700                                 case A_NET_EDEV:
701                                         pcp_def_net_dev_metrics(act[p]);
702                                         break;
703
704                                 case A_NET_NFS:
705                                         pcp_def_net_nfs_metrics();
706                                         break;
707
708                                 case A_NET_NFSD:
709                                         pcp_def_net_nfsd_metrics();
710                                         break;
711
712                                 case A_NET_SOCK:
713                                         pcp_def_net_sock_metrics();
714                                         break;
715
716                                 case A_NET_IP:
717                                         pcp_def_net_ip_metrics();
718                                         break;
719
720                                 case A_NET_EIP:
721                                         pcp_def_net_eip_metrics();
722                                         break;
723
724                                 case A_NET_ICMP:
725                                         pcp_def_net_icmp_metrics();
726                                         break;
727
728                                 case A_NET_EICMP:
729                                         pcp_def_net_eicmp_metrics();
730                                         break;
731
732                                 case A_NET_TCP:
733                                         pcp_def_net_tcp_metrics();
734                                         break;
735
736                                 case A_NET_ETCP:
737                                         pcp_def_net_etcp_metrics();
738                                         break;
739
740                                 case A_NET_UDP:
741                                         pcp_def_net_udp_metrics();
742                                         break;
743
744                                 case A_NET_SOCK6:
745                                         pcp_def_net_sock6_metrics();
746                                         break;
747
748                                 case A_NET_IP6:
749                                         pcp_def_net_ip6_metrics();
750                                         break;
751
752                                 case A_NET_EIP6:
753                                         pcp_def_net_eip6_metrics();
754                                         break;
755
756                                 case A_NET_ICMP6:
757                                         pcp_def_net_icmp6_metrics();
758                                         break;
759
760                                 case A_NET_EICMP6:
761                                         pcp_def_net_eicmp6_metrics();
762                                         break;
763
764                                 case A_NET_UDP6:
765                                         pcp_def_net_udp6_metrics();
766                                         break;
767
768                                 case A_HUGE:
769                                         pcp_def_huge_metrics();
770                                         break;
771
772                                 case A_PWR_FAN:
773                                         pcp_def_pwr_fan_metrics(act[p]);
774                                         break;
775
776                                 case A_PWR_TEMP:
777                                         pcp_def_pwr_temp_metrics(act[p]);
778                                         break;
779
780                                 case A_PWR_IN:
781                                         pcp_def_pwr_in_metrics(act[p]);
782                                         break;
783
784                                 case A_PWR_USB:
785                                         pcp_def_pwr_usb_metrics(act[p]);
786                                         break;
787
788                                 case A_FS:
789                                         pcp_def_filesystem_metrics(act[p]);
790                                         break;
791
792                                 case A_NET_FC:
793                                         pcp_def_fchost_metrics(act[p]);
794                                         break;
795
796                                 case A_PSI_CPU:
797                                 case A_PSI_IO:
798                                 case A_PSI_MEM:
799                                         pcp_def_psi_metrics(act[p]);
800                                         break;
801                         }
802                 }
803         }
804 #endif /* HAVE_PCP */
805 }
806
807 /*
808  ***************************************************************************
809  * Display the "timestamp" part of the report (db and ppc format).
810  *
811  * IN:
812  * @fmt         Output format (F_DB_OUTPUT or F_PPC_OUTPUT).
813  * @file_hdr    System activity file standard header.
814  * @cur_date    Date string of current record.
815  * @cur_time    Time string of current record.
816  * @utc         True if @cur_time is expressed in UTC.
817  * @itv         Interval of time with preceding record.
818  *
819  * RETURNS:
820  * Pointer on the "timestamp" string.
821  ***************************************************************************
822  */
823 char *print_dbppc_timestamp(int fmt, struct file_header *file_hdr, char *cur_date,
824                             char *cur_time, int utc, unsigned long long itv)
825 {
826         int isdb = (fmt == F_DB_OUTPUT);
827         static char pre[512];
828         char temp1[128], temp2[256];
829
830         /* This substring appears on every output line, preformat it here */
831         snprintf(temp1, sizeof(temp1), "%s%s%lld%s",
832                  file_hdr->sa_nodename, seps[isdb], itv, seps[isdb]);
833         if (strlen(cur_date)) {
834                 snprintf(temp2, sizeof(temp2), "%s%s ", temp1, cur_date);
835         }
836         else {
837                 strcpy(temp2, temp1);
838         }
839         snprintf(pre, sizeof(pre), "%s%s%s", temp2, cur_time,
840                  strlen(cur_date) && utc ? " UTC" : "");
841         pre[sizeof(pre) - 1] = '\0';
842
843         if (DISPLAY_HORIZONTALLY(flags)) {
844                 printf("%s", pre);
845         }
846
847         return pre;
848 }
849
850 /*
851  ***************************************************************************
852  * Display the "timestamp" part of the report (ppc format).
853  *
854  * IN:
855  * @parm        Pointer on specific parameters (unused here).
856  * @action      Action expected from current function.
857  * @cur_date    Date string of current record.
858  * @cur_time    Time string of current record.
859  * @itv         Interval of time with preceding record.
860  * @record_hdr  Record header for current sample (unused here).
861  * @file_hdr    System activity file standard header.
862  * @flags       Flags for common options.
863  *
864  * RETURNS:
865  * Pointer on the "timestamp" string.
866  ***************************************************************************
867  */
868 __tm_funct_t print_ppc_timestamp(void *parm, int action, char *cur_date,
869                                  char *cur_time, unsigned long long itv,
870                                  struct record_header *record_hdr,
871                                  struct file_header *file_hdr, unsigned int flags)
872 {
873         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
874
875         if (action & F_BEGIN) {
876                 return print_dbppc_timestamp(F_PPC_OUTPUT, file_hdr, cur_date, cur_time, utc, itv);
877         }
878
879         return NULL;
880 }
881
882 /*
883  ***************************************************************************
884  * Display the "timestamp" part of the report (db format).
885  *
886  * IN:
887  * @parm        Pointer on specific parameters (unused here).
888  * @action      Action expected from current function.
889  * @cur_date    Date string of current record.
890  * @cur_time    Time string of current record.
891  * @itv         Interval of time with preceding record.
892  * @record_hdr  Record header for current sample (unused here).
893  * @file_hdr    System activity file standard header.
894  * @flags       Flags for common options.
895  *
896  * RETURNS:
897  * Pointer on the "timestamp" string.
898  ***************************************************************************
899  */
900 __tm_funct_t print_db_timestamp(void *parm, int action, char *cur_date,
901                                 char *cur_time, unsigned long long itv,
902                                 struct record_header *record_hdr,
903                                 struct file_header *file_hdr, unsigned int flags)
904 {
905         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
906
907         if (action & F_BEGIN) {
908                 return print_dbppc_timestamp(F_DB_OUTPUT, file_hdr, cur_date, cur_time, utc, itv);
909         }
910         if (action & F_END) {
911                 if (DISPLAY_HORIZONTALLY(flags)) {
912                         printf("\n");
913                 }
914         }
915
916         return NULL;
917 }
918
919 /*
920  ***************************************************************************
921  * Display the "timestamp" part of the report (XML format).
922  *
923  * IN:
924  * @parm        Specific parameter. Here: number of tabulations.
925  * @action      Action expected from current function.
926  * @cur_date    Date string of current comment.
927  * @cur_time    Time string of current comment.
928  * @itv         Interval of time with preceding record.
929  * @record_hdr  Record header for current sample (unused here).
930  * @file_hdr    System activity file standard header (unused here).
931  * @flags       Flags for common options.
932  ***************************************************************************
933  */
934 __tm_funct_t print_xml_timestamp(void *parm, int action, char *cur_date,
935                                  char *cur_time, unsigned long long itv,
936                                  struct record_header *record_hdr,
937                                  struct file_header *file_hdr, unsigned int flags)
938 {
939         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
940         int *tab = (int *) parm;
941
942         if (action & F_BEGIN) {
943                 xprintf((*tab)++, "<timestamp date=\"%s\" time=\"%s\" utc=\"%d\" interval=\"%llu\">",
944                         cur_date, cur_time, utc ? 1 : 0, itv);
945         }
946         if (action & F_END) {
947                 xprintf(--(*tab), "</timestamp>");
948         }
949
950         return NULL;
951 }
952
953 /*
954  ***************************************************************************
955  * Display the "timestamp" part of the report (JSON format).
956  *
957  * IN:
958  * @parm        Specific parameter. Here: number of tabulations.
959  * @action      Action expected from current function.
960  * @cur_date    Date string of current comment.
961  * @cur_time    Time string of current comment.
962  * @itv         Interval of time with preceding record.
963  * @record_hdr  Record header for current sample (unused here).
964  * @file_hdr    System activity file standard header (unused here).
965  * @flags       Flags for common options.
966  ***************************************************************************
967  */
968 __tm_funct_t print_json_timestamp(void *parm, int action, char *cur_date,
969                                   char *cur_time, unsigned long long itv,
970                                   struct record_header *record_hdr,
971                                   struct file_header *file_hdr, unsigned int flags)
972 {
973         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
974         int *tab = (int *) parm;
975
976         if (action & F_BEGIN) {
977                 xprintf0(*tab,
978                          "\"timestamp\": {\"date\": \"%s\", \"time\": \"%s\", "
979                          "\"utc\": %d, \"interval\": %llu}",
980                          cur_date, cur_time, utc ? 1 : 0, itv);
981         }
982         if (action & F_MAIN) {
983                 printf(",\n");
984         }
985         if (action & F_END) {
986                 printf("\n");
987         }
988
989         return NULL;
990 }
991
992 /*
993  ***************************************************************************
994  * Display the "timestamp" part of the report (raw format).
995  *
996  * IN:
997  * @parm        Pointer on specific parameters (unused here).
998  * @action      Action expected from current function.
999  * @cur_date    Date string of current record.
1000  * @cur_time    Time string of current record.
1001  * @itv         Interval of time with preceding record (unused here).
1002  * @record_hdr  Record header for current sample (unused here).
1003  * @file_hdr    System activity file standard header (unused here).
1004  * @flags       Flags for common options.
1005  *
1006  * RETURNS:
1007  * Pointer on the "timestamp" string.
1008  ***************************************************************************
1009  */
1010 __tm_funct_t print_raw_timestamp(void *parm, int action, char *cur_date,
1011                                  char *cur_time, unsigned long long itv,
1012                                  struct record_header *record_hdr,
1013                                  struct file_header *file_hdr, unsigned int flags)
1014 {
1015         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
1016         static char pre[80];
1017
1018         if (action & F_BEGIN) {
1019                 snprintf(pre, 80, "%s%s", cur_time, strlen(cur_date) && utc ? " UTC" : "");
1020                 pre[79] = '\0';
1021                 return pre;
1022         }
1023
1024         return NULL;
1025 }
1026
1027 /*
1028  ***************************************************************************
1029  * Display the "timestamp" part of the report (PCP format).
1030  *
1031  * IN:
1032  * @parm        Pointer on specific parameters (unused here).
1033  * @action      Action expected from current function.
1034  * @cur_date    Date string of current record (unused here).
1035  * @cur_time    Time string of current record (unused here).
1036  * @itv         Interval of time with preceding record (unused here).
1037  * @record_hdr  Record header for current sample.
1038  * @file_hdr    System activity file standard header (unused here).
1039  * @flags       Flags for common options.
1040  *
1041  * RETURNS:
1042  * Pointer on the "timestamp" string.
1043  ***************************************************************************
1044  */
1045 __tm_funct_t print_pcp_timestamp(void *parm, int action, char *cur_date,
1046                                  char *cur_time, unsigned long long itv,
1047                                  struct record_header *record_hdr,
1048                                  struct file_header *file_hdr, unsigned int flags)
1049 {
1050         if (action & F_END) {
1051                 pcp_write_data(record_hdr, flags);
1052         }
1053
1054         return NULL;
1055 }
1056
1057 /*
1058  ***************************************************************************
1059  * Display the header of the report (XML format).
1060  *
1061  * IN:
1062  * @parm        Specific parameter. Here: number of tabulations.
1063  * @action      Action expected from current function.
1064  * @dfile       Unused here (PCP archive file).
1065  * @file_magic  System activity file magic header.
1066  * @file_hdr    System activity file standard header.
1067  * @act         Array of activities (unused here).
1068  * @id_seq      Activity sequence (unused here).
1069  * @file_actlst List of (known or unknown) activities in file (unused here).
1070  *
1071  * OUT:
1072  * @parm        Number of tabulations.
1073  ***************************************************************************
1074  */
1075 __printf_funct_t print_xml_header(void *parm, int action, char *dfile,
1076                                   struct file_magic *file_magic,
1077                                   struct file_header *file_hdr,
1078                                   struct activity *act[], unsigned int id_seq[],
1079                                   struct file_activity *file_actlst)
1080 {
1081         struct tm rectime, loc_t;
1082         char cur_time[TIMESTAMP_LEN];
1083         int *tab = (int *) parm;
1084
1085         if (action & F_BEGIN) {
1086                 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1087                 printf("<!DOCTYPE sysstat PUBLIC \"DTD v%s sysstat //EN\"\n",
1088                        XML_DTD_VERSION);
1089                 printf("\"http://pagesperso-orange.fr/sebastien.godard/sysstat-%s.dtd\">\n",
1090                        XML_DTD_VERSION);
1091
1092                 xprintf(*tab, "<sysstat\n"
1093                               "xmlns=\"http://pagesperso-orange.fr/sebastien.godard/sysstat\"\n"
1094                               "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
1095                               "xsi:schemaLocation=\"http://pagesperso-orange.fr/sebastien.godard sysstat.xsd\">");
1096
1097                 xprintf(++(*tab), "<sysdata-version>%s</sysdata-version>",
1098                         XML_DTD_VERSION);
1099
1100                 xprintf(*tab, "<host nodename=\"%s\">", file_hdr->sa_nodename);
1101                 xprintf(++(*tab), "<sysname>%s</sysname>", file_hdr->sa_sysname);
1102                 xprintf(*tab, "<release>%s</release>", file_hdr->sa_release);
1103
1104                 xprintf(*tab, "<machine>%s</machine>", file_hdr->sa_machine);
1105                 xprintf(*tab, "<number-of-cpus>%d</number-of-cpus>",
1106                         file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1107
1108                 /* Fill file timestmap structure (rectime) */
1109                 get_file_timestamp_struct(flags, &rectime, file_hdr);
1110                 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1111                 xprintf(*tab, "<file-date>%s</file-date>", cur_time);
1112
1113                 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1114                         strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1115                         xprintf(*tab, "<file-utc-time>%s</file-utc-time>", cur_time);
1116                 }
1117
1118                 xprintf(*tab, "<timezone>%s</timezone>", file_hdr->sa_tzname);
1119         }
1120         if (action & F_END) {
1121                 xprintf(--(*tab), "</host>");
1122                 xprintf(--(*tab), "</sysstat>");
1123         }
1124 }
1125
1126 /*
1127  ***************************************************************************
1128  * Display the header of the report (JSON format).
1129  *
1130  * IN:
1131  * @parm        Specific parameter. Here: number of tabulations.
1132  * @action      Action expected from current function.
1133  * @dfile       Unused here (PCP archive file).
1134  * @file_magic  System activity file magic header.
1135  * @file_hdr    System activity file standard header.
1136  * @act         Array of activities (unused here).
1137  * @id_seq      Activity sequence (unused here).
1138  * @file_actlst List of (known or unknown) activities in file (unused here).
1139  *
1140  * OUT:
1141  * @parm        Number of tabulations.
1142  ***************************************************************************
1143  */
1144 __printf_funct_t print_json_header(void *parm, int action, char *dfile,
1145                                    struct file_magic *file_magic,
1146                                    struct file_header *file_hdr,
1147                                    struct activity *act[], unsigned int id_seq[],
1148                                    struct file_activity *file_actlst)
1149 {
1150         struct tm rectime, loc_t;
1151         char cur_time[TIMESTAMP_LEN];
1152         int *tab = (int *) parm;
1153
1154         if (action & F_BEGIN) {
1155                 xprintf(*tab, "{\"sysstat\": {");
1156
1157                 xprintf(++(*tab), "\"hosts\": [");
1158                 xprintf(++(*tab), "{");
1159                 xprintf(++(*tab), "\"nodename\": \"%s\",", file_hdr->sa_nodename);
1160                 xprintf(*tab, "\"sysname\": \"%s\",", file_hdr->sa_sysname);
1161                 xprintf(*tab, "\"release\": \"%s\",", file_hdr->sa_release);
1162
1163                 xprintf(*tab, "\"machine\": \"%s\",", file_hdr->sa_machine);
1164                 xprintf(*tab, "\"number-of-cpus\": %d,",
1165                         file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1166
1167                 /* Fill file timestmap structure (rectime) */
1168                 get_file_timestamp_struct(flags, &rectime, file_hdr);
1169                 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1170                 xprintf(*tab, "\"file-date\": \"%s\",", cur_time);
1171
1172                 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1173                         strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1174                         xprintf(*tab, "\"file-utc-time\": \"%s\",", cur_time);
1175                 }
1176
1177                 xprintf0(*tab, "\"timezone\": \"%s\"", file_hdr->sa_tzname);
1178         }
1179         if (action & F_END) {
1180                 printf("\n");
1181                 xprintf(--(*tab), "}");
1182                 xprintf(--(*tab), "]");
1183                 xprintf(--(*tab), "}}");
1184         }
1185 }
1186
1187 /*
1188  ***************************************************************************
1189  * Display data file header.
1190  *
1191  * IN:
1192  * @parm        Specific parameter (unused here).
1193  * @action      Action expected from current function.
1194  * @dfile       Name of system activity data file (unused here).
1195  * @file_magic  System activity file magic header.
1196  * @file_hdr    System activity file standard header.
1197  * @act         Array of activities.
1198  * @id_seq      Activity sequence.
1199  * @file_actlst List of (known or unknown) activities in file.
1200  ***************************************************************************
1201  */
1202 __printf_funct_t print_hdr_header(void *parm, int action, char *dfile,
1203                                   struct file_magic *file_magic,
1204                                   struct file_header *file_hdr,
1205                                   struct activity *act[], unsigned int id_seq[],
1206                                   struct file_activity *file_actlst)
1207 {
1208         int i, p;
1209         struct tm rectime, loc_t;
1210         struct file_activity *fal;
1211         char cur_time[TIMESTAMP_LEN];
1212
1213         /* Actions F_MAIN and F_END ignored */
1214         if (action & F_BEGIN) {
1215                 printf(_("System activity data file: %s (%#x)\n"),
1216                        dfile, file_magic->format_magic);
1217
1218                 display_sa_file_version(stdout, file_magic);
1219
1220                 if (file_magic->format_magic != FORMAT_MAGIC) {
1221                         return;
1222                 }
1223
1224                 printf(_("Genuine sa datafile: %s (%x)\n"),
1225                        file_magic->upgraded ? _("no") : _("yes"),
1226                        file_magic->upgraded);
1227
1228                 printf(_("Host: "));
1229                 print_gal_header(localtime_r((const time_t *) &(file_hdr->sa_ust_time), &rectime),
1230                                  file_hdr->sa_sysname, file_hdr->sa_release,
1231                                  file_hdr->sa_nodename, file_hdr->sa_machine,
1232                                  file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
1233                                  PLAIN_OUTPUT);
1234
1235                 /* Fill file timestamp structure (rectime) */
1236                 get_file_timestamp_struct(flags, &rectime, file_hdr);
1237                 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1238                 printf(_("File date: %s\n"), cur_time);
1239
1240                 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1241                         printf(_("File time: "));
1242                         strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1243                         printf("%s UTC (%lld)\n", cur_time, file_hdr->sa_ust_time);
1244                 }
1245
1246                 printf(_("Timezone: %s\n"), file_hdr->sa_tzname);
1247
1248                 /* File composition: file_header, file_activity, record_header */
1249                 printf(_("File composition: (%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n"),
1250                        file_magic->hdr_types_nr[0], file_magic->hdr_types_nr[1], file_magic->hdr_types_nr[2],
1251                        file_hdr->act_types_nr[0], file_hdr->act_types_nr[1], file_hdr->act_types_nr[2],
1252                        file_hdr->rec_types_nr[0], file_hdr->rec_types_nr[1], file_hdr->rec_types_nr[2]);
1253
1254                 printf(_("Size of a long int: %d\n"), file_hdr->sa_sizeof_long);
1255                 printf("HZ = %lu\n", file_hdr->sa_hz);
1256                 printf(_("Number of activities in file: %u\n"),
1257                        file_hdr->sa_act_nr);
1258                 printf(_("Extra structures available: %c\n"),
1259                        file_hdr->extra_next ? 'Y' : 'N');
1260
1261                 printf(_("List of activities:\n"));
1262                 fal = file_actlst;
1263                 for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1264
1265                         p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND);
1266
1267                         printf("%02d: [%02x] ", fal->id, fal->magic);
1268                         if (p >= 0) {
1269                                 printf("%-20s", act[p]->name);
1270                         }
1271                         else {
1272                                 printf("%-20s", _("Unknown activity"));
1273                         }
1274                         printf(" %c:%4d", fal->has_nr ? 'Y' : 'N', fal->nr);
1275                         if (fal->nr2 > 1) {
1276                                 printf("x%d", fal->nr2);
1277                         }
1278                         printf("\t(%d,%d,%d)", fal->types_nr[0], fal->types_nr[1], fal->types_nr[2]);
1279                         if ((p >= 0) && (act[p]->magic == ACTIVITY_MAGIC_UNKNOWN)) {
1280                                 printf(_(" \t[Unknown format]"));
1281                         }
1282                         printf("\n");
1283                 }
1284         }
1285 }
1286
1287 /*
1288  ***************************************************************************
1289  * Display the header of the report (SVG format).
1290  *
1291  * IN:
1292  * @parm        Specific parameters. Here: number of rows of views to display
1293  *              or canvas height entered on the command line (@graph_nr), and
1294  *              max number of views on a single row (@views_per_row).
1295  * @action      Action expected from current function.
1296  * @dfile       Name of system activity data file (unused here).
1297  * @file_magic  System activity file magic header (unused here).
1298  * @file_hdr    System activity file standard header.
1299  * @act         Array of activities (unused here).
1300  * @id_seq      Activity sequence (unused here).
1301  * @file_actlst List of (known or unknown) activities in file (unused here).
1302  ***************************************************************************
1303  */
1304 __printf_funct_t print_svg_header(void *parm, int action, char *dfile,
1305                                   struct file_magic *file_magic,
1306                                   struct file_header *file_hdr,
1307                                   struct activity *act[], unsigned int id_seq[],
1308                                   struct file_activity *file_actlst)
1309 {
1310         struct svg_hdr_parm *hdr_parm = (struct svg_hdr_parm *) parm;
1311         struct tm rectime;
1312         unsigned int height = 0, ht = 0;
1313         int i, p;
1314
1315         if (action & F_BEGIN) {
1316                 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1317                 printf("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
1318                 printf("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
1319                 printf("<svg xmlns=\"http://www.w3.org/2000/svg\"");
1320                 if (DISPLAY_TOC(flags)) {
1321                         printf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
1322                 }
1323                 if (action & F_END) {
1324                         printf(">\n");
1325                 }
1326         }
1327
1328         if (action & F_MAIN) {
1329                 if (SET_CANVAS_HEIGHT(flags)) {
1330                         /*
1331                          * Option "-O height=..." used: @graph_nr is
1332                          * the SVG canvas height set on the command line.
1333                          */
1334                         height = hdr_parm->graph_nr;
1335                 }
1336                 else {
1337                         height = SVG_H_YSIZE +
1338                                  SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0) +
1339                                  SVG_T_YSIZE * hdr_parm->graph_nr;
1340                 }
1341                 if (height < 100) {
1342                         /* Min canvas height is 100 (at least to display "No data") */
1343                         height = 100;
1344                 }
1345                 printf(" width=\"%d\" height=\"%d\""
1346                        " fill=\"black\" stroke=\"#%06x\" stroke-width=\"1\">\n",
1347                        SVG_T_XSIZE * (hdr_parm->views_per_row), height,
1348                        svg_colors[palette][SVG_COL_DEFAULT_IDX]);
1349                 printf("<text x=\"0\" y=\"30\" text-anchor=\"start\" stroke=\"#%06x\">",
1350                        svg_colors[palette][SVG_COL_HEADER_IDX]);
1351                 print_gal_header(localtime_r((const time_t *) &(file_hdr->sa_ust_time), &rectime),
1352                                  file_hdr->sa_sysname, file_hdr->sa_release,
1353                                  file_hdr->sa_nodename, file_hdr->sa_machine,
1354                                  file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
1355                                  PLAIN_OUTPUT);
1356                 printf("</text>\n");
1357                 if (DISPLAY_TOC(flags)) {
1358                         for (i = 0; i < NR_ACT; i++) {
1359                                 if (!id_seq[i])
1360                                         continue;       /* Activity not in file */
1361
1362                                 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1363                                 if (!IS_SELECTED(act[p]->options) || !act[p]->g_nr)
1364                                         continue;       /* Activity not selected or no graph available */
1365
1366                                 printf("<a xlink:href=\"#g%d-0\" xlink:title=\"%s\">\n",
1367                                        act[p]->id, act[p]->name);
1368                                 printf("<text x=\"10\" y=\"%d\">%s</text></a>\n",
1369                                        SVG_H_YSIZE + ht, act[p]->desc);
1370                                 ht += SVG_C_YSIZE;
1371                         }
1372                 }
1373         }
1374
1375         if (action & F_END) {
1376                 if (!(action & F_BEGIN)) {
1377                         if (!hdr_parm->graph_nr) {
1378                                 /* No views displayed */
1379                                 printf("<text x= \"0\" y=\"%d\" text-anchor=\"start\" stroke=\"#%06x\">",
1380                                        SVG_H_YSIZE +
1381                                        SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0),
1382                                        svg_colors[palette][SVG_COL_ERROR_IDX]);
1383                                 printf("No data!</text>\n");
1384                         }
1385                         /* Give actual SVG height */
1386                         printf("<!-- Actual canvas height: %d -->\n",
1387                                SVG_H_YSIZE +
1388                                SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0) +
1389                                SVG_T_YSIZE * hdr_parm->graph_nr);
1390                 }
1391                 printf("</svg>\n");
1392         }
1393 }
1394
1395 /*
1396  ***************************************************************************
1397  * PCP header function.
1398  *
1399  * IN:
1400  * @parm        Specific parameter (unused here).
1401  * @action      Action expected from current function.
1402  * @dfile       Name of PCP archive file.
1403  * @file_magic  System activity file magic header (unused here).
1404  * @file_hdr    System activity file standard header (unused here).
1405  * @act         Array of activities (unused here).
1406  * @id_seq      Activity sequence (unused here).
1407  * @file_actlst List of (known or unknown) activities in file (unused here).
1408  ***************************************************************************
1409  */
1410 __printf_funct_t print_pcp_header(void *parm, int action, char *dfile,
1411                                   struct file_magic *file_magic,
1412                                   struct file_header *file_hdr,
1413                                   struct activity *act[], unsigned int id_seq[],
1414                                   struct file_activity *file_actlst)
1415 {
1416 #ifdef HAVE_PCP
1417         char buf[64];
1418         struct tm lrectime;
1419         unsigned long long utc_sec = file_hdr->sa_ust_time;
1420
1421         if (action & F_BEGIN) {
1422                 /* Create new PCP context */
1423                 pmiStart(dfile, FALSE);
1424
1425                 if (PRINT_LOCAL_TIME(flags)) {
1426                         pmiSetTimezone(file_hdr->sa_tzname);
1427                 }
1428                 else {
1429                         pmiSetTimezone("UTC");
1430                 }
1431
1432                 /* Save hostname */
1433                 pmiSetHostname(file_hdr->sa_nodename);
1434
1435                 /* Save number of CPU in PCP archive */
1436                 pmiAddMetric("hinv.ncpu",
1437                              PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
1438                              pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
1439                 snprintf(buf, sizeof(buf), "%u",
1440                          file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1441                 pmiPutValue("hinv.ncpu", NULL, buf);
1442         }
1443
1444         if (action & F_END) {
1445                 if (action & F_BEGIN) {
1446                         /* Only the header data will be written to PCP archive */
1447                         if (!PRINT_LOCAL_TIME(flags)) {
1448                                 /* Convert a time_t value from local time to UTC */
1449                                 if (gmtime_r((const time_t *) &(file_hdr->sa_ust_time), &lrectime)) {
1450                                         utc_sec = mktime(&lrectime);
1451                                 }
1452                         }
1453                         pmiWrite(utc_sec, 0);
1454                 }
1455                 pmiEnd();
1456         }
1457 #endif
1458 }
1459
1460 /*
1461  ***************************************************************************
1462  * Count the number of new network interfaces in current sample. If a new
1463  * interface is found then add it to the linked list starting at
1464  * @a->item_list.
1465  *
1466  * IN:
1467  * @a           Activity structure with statistics.
1468  * @curr        Index in array for current sample statistics.
1469  *
1470  * RETURNS:
1471  * Number of new interfaces identified in current sample that were not
1472  * previously in the list.
1473  ***************************************************************************
1474  */
1475 __nr_t count_new_net_dev(struct activity *a, int curr)
1476 {
1477         int i, nr = 0;
1478         struct stats_net_dev *sndc;
1479
1480         for (i = 0; i < a->nr[curr]; i++) {
1481                 sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
1482
1483                 nr += add_list_item(&(a->item_list), sndc->interface, MAX_IFACE_LEN);
1484         }
1485
1486         return nr;
1487 }
1488
1489 /*
1490  ***************************************************************************
1491  * Count the number of new network interfaces in current sample. If a new
1492  * interface is found then add it to the linked list starting at
1493  * @a->item_list.
1494  *
1495  * IN:
1496  * @a           Activity structure with statistics.
1497  * @curr        Index in array for current sample statistics.
1498  *
1499  * RETURNS:
1500  * Number of new interfaces identified in current sample that were not
1501  * previously in the list.
1502  ***************************************************************************
1503  */
1504 __nr_t count_new_net_edev(struct activity *a, int curr)
1505 {
1506         int i, nr = 0;
1507         struct stats_net_edev *snedc;
1508
1509         for (i = 0; i < a->nr[curr]; i++) {
1510                 snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + i * a->msize);
1511
1512                 nr += add_list_item(&(a->item_list), snedc->interface, MAX_IFACE_LEN);
1513         }
1514
1515         return nr;
1516 }
1517
1518 /*
1519  ***************************************************************************
1520  * Count the number of new filesystems in current sample. If a new
1521  * filesystem is found then add it to the linked list starting at
1522  * @a->item_list.
1523  *
1524  * IN:
1525  * @a           Activity structure with statistics.
1526  * @curr        Index in array for current sample statistics.
1527  *
1528  * RETURNS:
1529  * Number of new filesystems identified in current sample that were not
1530  * previously in the list.
1531  ***************************************************************************
1532  */
1533 __nr_t count_new_filesystem(struct activity *a, int curr)
1534 {
1535         int i, nr = 0;
1536         struct stats_filesystem *sfc;
1537
1538         for (i = 0; i < a->nr[curr]; i++) {
1539                 sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize);
1540
1541                 nr += add_list_item(&(a->item_list),
1542                                     get_fs_name_to_display(a, flags, sfc),
1543                                     MAX_FS_LEN);
1544         }
1545
1546         return nr;
1547 }
1548
1549 /*
1550  ***************************************************************************
1551  * Count the number of new fchosts in current sample. If a new
1552  * fchost is found then add it to the linked list starting at
1553  * @a->item_list.
1554  *
1555  * IN:
1556  * @a           Activity structure with statistics.
1557  * @curr        Index in array for current sample statistics.
1558  *
1559  * RETURNS:
1560  * Number of new fchosts identified in current sample that were not
1561  * previously in the list.
1562  ***************************************************************************
1563  */
1564 __nr_t count_new_fchost(struct activity *a, int curr)
1565 {
1566         int i, nr = 0;
1567         struct stats_fchost *sfcc;
1568
1569         for (i = 0; i < a->nr[curr]; i++) {
1570                 sfcc = (struct stats_fchost *) ((char *) a->buf[curr] + i * a->msize);
1571
1572                 nr += add_list_item(&(a->item_list), sfcc->fchost_name, MAX_FCH_LEN);
1573         }
1574
1575         return nr;
1576 }
1577
1578 /*
1579  ***************************************************************************
1580  * Count the number of new block devices in current sample. If a new
1581  * block device is found then add it to the linked list starting at
1582  * @a->item_list.
1583  *
1584  * IN:
1585  * @a           Activity structure with statistics.
1586  * @curr        Index in array for current sample statistics.
1587  *
1588  * RETURNS:
1589  * Number of new block devices identified in current sample that were not
1590  * previously in the list.
1591  ***************************************************************************
1592  */
1593 __nr_t count_new_disk(struct activity *a, int curr)
1594 {
1595         int i, nr = 0;
1596         struct stats_disk *sdc;
1597
1598         for (i = 0; i < a->nr[curr]; i++) {
1599                 sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
1600
1601                 nr += add_list_item(&(a->item_list),
1602                                     get_device_name(sdc->major, sdc->minor, sdc->wwn, sdc->part_nr,
1603                                                     DISPLAY_PRETTY(flags), DISPLAY_PERSIST_NAME_S(flags),
1604                                                     USE_STABLE_ID(flags), NULL),
1605                                     MAX_DEV_LEN);
1606         }
1607
1608         return nr;
1609 }
1610
1611 /*
1612  ***************************************************************************
1613  * Init custom color palette used to draw graphs (sadf -g).
1614  ***************************************************************************
1615  */
1616 void init_custom_color_palette()
1617 {
1618         char *e, *p;
1619         int len;
1620         unsigned int val;
1621
1622         /* Read S_COLORS_PALETTE environment variable */
1623         if ((e = __getenv(ENV_COLORS_PALETTE)) == NULL)
1624                 /* Environment variable not set */
1625                 return;
1626
1627         for (p = strtok(e, ":"); p; p =strtok(NULL, ":")) {
1628
1629                 len = strlen(p);
1630                 if ((len > 8) || (len < 3) || (*(p + 1) != '=') ||
1631                     (strspn(p + 2, "0123456789ABCDEFabcdef") != (len - 2)))
1632                         /* Ignore malformed codes */
1633                         continue;
1634
1635                 sscanf(p + 2, "%x", &val);
1636
1637                 if ((*p >= '0') && (*p <= '9')) {
1638                         svg_colors[SVG_CUSTOM_COL_PALETTE][*p & 0xf] = val;
1639                         continue;
1640                 }
1641                 else if (((*p >= 'A') && (*p <= 'F')) ||
1642                          ((*p >= 'a') && (*p <= 'f'))) {
1643                         svg_colors[SVG_CUSTOM_COL_PALETTE][9 + (*p & 0xf)] = val;
1644                         continue;
1645                 }
1646
1647                 switch (*p) {
1648                         case 'G':
1649                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_GRID_IDX] = val;
1650                                 break;
1651                         case 'H':
1652                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_HEADER_IDX] = val;
1653                                 break;
1654                         case 'I':
1655                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_INFO_IDX] = val;
1656                                 break;
1657                         case 'K':
1658                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_BCKGRD_IDX] = val;
1659                                 break;
1660                         case 'L':
1661                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_DEFAULT_IDX] = val;
1662                                 break;
1663                         case 'T':
1664                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_TITLE_IDX] = val;
1665                                 break;
1666                         case 'W':
1667                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_ERROR_IDX] = val;
1668                                 break;
1669                         case 'X':
1670                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_AXIS_IDX] = val;
1671                                 break;
1672                 }
1673         }
1674 }