]> granicus.if.org Git - sysstat/blob - sadf_misc.c
868963700a55268e6eaee33215ea0980e7d4d589
[sysstat] / sadf_misc.c
1 /*
2  * sadf_misc.c: Funtions used by sadf to display special records
3  * (C) 2011-2019 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 unsigned int 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_USB:
777                                         pcp_def_pwr_usb_metrics(act[p]);
778                                         break;
779
780                                 case A_FS:
781                                         pcp_def_filesystem_metrics(act[p]);
782                                         break;
783
784                                 case A_NET_FC:
785                                         pcp_def_fchost_metrics(act[p]);
786                                         break;
787                         }
788                 }
789         }
790 #endif /* HAVE_PCP */
791 }
792
793 /*
794  ***************************************************************************
795  * Display the "timestamp" part of the report (db and ppc format).
796  *
797  * IN:
798  * @fmt         Output format (F_DB_OUTPUT or F_PPC_OUTPUT).
799  * @file_hdr    System activity file standard header.
800  * @cur_date    Date string of current record.
801  * @cur_time    Time string of current record.
802  * @utc         True if @cur_time is expressed in UTC.
803  * @itv         Interval of time with preceding record.
804  *
805  * RETURNS:
806  * Pointer on the "timestamp" string.
807  ***************************************************************************
808  */
809 char *print_dbppc_timestamp(int fmt, struct file_header *file_hdr, char *cur_date,
810                             char *cur_time, int utc, unsigned long long itv)
811 {
812         int isdb = (fmt == F_DB_OUTPUT);
813         static char pre[512];
814         char temp1[128], temp2[256];
815
816         /* This substring appears on every output line, preformat it here */
817         snprintf(temp1, sizeof(temp1), "%s%s%lld%s",
818                  file_hdr->sa_nodename, seps[isdb], itv, seps[isdb]);
819         if (strlen(cur_date)) {
820                 snprintf(temp2, sizeof(temp2), "%s%s ", temp1, cur_date);
821         }
822         else {
823                 strcpy(temp2, temp1);
824         }
825         snprintf(pre, sizeof(pre), "%s%s%s", temp2, cur_time,
826                  strlen(cur_date) && utc ? " UTC" : "");
827         pre[sizeof(pre) - 1] = '\0';
828
829         if (DISPLAY_HORIZONTALLY(flags)) {
830                 printf("%s", pre);
831         }
832
833         return pre;
834 }
835
836 /*
837  ***************************************************************************
838  * Display the "timestamp" part of the report (ppc format).
839  *
840  * IN:
841  * @parm        Pointer on specific parameters (unused here).
842  * @action      Action expected from current function.
843  * @cur_date    Date string of current record.
844  * @cur_time    Time string of current record.
845  * @itv         Interval of time with preceding record.
846  * @record_hdr  Record header for current sample (unused here).
847  * @file_hdr    System activity file standard header.
848  * @flags       Flags for common options.
849  *
850  * RETURNS:
851  * Pointer on the "timestamp" string.
852  ***************************************************************************
853  */
854 __tm_funct_t print_ppc_timestamp(void *parm, int action, char *cur_date,
855                                  char *cur_time, unsigned long long itv,
856                                  struct record_header *record_hdr,
857                                  struct file_header *file_hdr, unsigned int flags)
858 {
859         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
860
861         if (action & F_BEGIN) {
862                 return print_dbppc_timestamp(F_PPC_OUTPUT, file_hdr, cur_date, cur_time, utc, itv);
863         }
864         if (action & F_END) {
865                 if (DISPLAY_HORIZONTALLY(flags)) {
866                         printf("\n");
867                 }
868         }
869
870         return NULL;
871 }
872
873 /*
874  ***************************************************************************
875  * Display the "timestamp" part of the report (db format).
876  *
877  * IN:
878  * @parm        Pointer on specific parameters (unused here).
879  * @action      Action expected from current function.
880  * @cur_date    Date string of current record.
881  * @cur_time    Time string of current record.
882  * @itv         Interval of time with preceding record.
883  * @record_hdr  Record header for current sample (unused here).
884  * @file_hdr    System activity file standard header.
885  * @flags       Flags for common options.
886  *
887  * RETURNS:
888  * Pointer on the "timestamp" string.
889  ***************************************************************************
890  */
891 __tm_funct_t print_db_timestamp(void *parm, int action, char *cur_date,
892                                 char *cur_time, unsigned long long itv,
893                                 struct record_header *record_hdr,
894                                 struct file_header *file_hdr, unsigned int flags)
895 {
896         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
897
898         if (action & F_BEGIN) {
899                 return print_dbppc_timestamp(F_DB_OUTPUT, file_hdr, cur_date, cur_time, utc, itv);
900         }
901         if (action & F_END) {
902                 if (DISPLAY_HORIZONTALLY(flags)) {
903                         printf("\n");
904                 }
905         }
906
907         return NULL;
908 }
909
910 /*
911  ***************************************************************************
912  * Display the "timestamp" part of the report (XML format).
913  *
914  * IN:
915  * @parm        Specific parameter. Here: number of tabulations.
916  * @action      Action expected from current function.
917  * @cur_date    Date string of current comment.
918  * @cur_time    Time string of current comment.
919  * @itv         Interval of time with preceding record.
920  * @record_hdr  Record header for current sample (unused here).
921  * @file_hdr    System activity file standard header (unused here).
922  * @flags       Flags for common options.
923  ***************************************************************************
924  */
925 __tm_funct_t print_xml_timestamp(void *parm, int action, char *cur_date,
926                                  char *cur_time, unsigned long long itv,
927                                  struct record_header *record_hdr,
928                                  struct file_header *file_hdr, unsigned int flags)
929 {
930         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
931         int *tab = (int *) parm;
932
933         if (action & F_BEGIN) {
934                 xprintf((*tab)++, "<timestamp date=\"%s\" time=\"%s\" utc=\"%d\" interval=\"%llu\">",
935                         cur_date, cur_time, utc ? 1 : 0, itv);
936         }
937         if (action & F_END) {
938                 xprintf(--(*tab), "</timestamp>");
939         }
940
941         return NULL;
942 }
943
944 /*
945  ***************************************************************************
946  * Display the "timestamp" part of the report (JSON format).
947  *
948  * IN:
949  * @parm        Specific parameter. Here: number of tabulations.
950  * @action      Action expected from current function.
951  * @cur_date    Date string of current comment.
952  * @cur_time    Time string of current comment.
953  * @itv         Interval of time with preceding record.
954  * @record_hdr  Record header for current sample (unused here).
955  * @file_hdr    System activity file standard header (unused here).
956  * @flags       Flags for common options.
957  ***************************************************************************
958  */
959 __tm_funct_t print_json_timestamp(void *parm, int action, char *cur_date,
960                                   char *cur_time, unsigned long long itv,
961                                   struct record_header *record_hdr,
962                                   struct file_header *file_hdr, unsigned int flags)
963 {
964         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
965         int *tab = (int *) parm;
966
967         if (action & F_BEGIN) {
968                 xprintf0(*tab,
969                          "\"timestamp\": {\"date\": \"%s\", \"time\": \"%s\", "
970                          "\"utc\": %d, \"interval\": %llu}",
971                          cur_date, cur_time, utc ? 1 : 0, itv);
972         }
973         if (action & F_MAIN) {
974                 printf(",\n");
975         }
976         if (action & F_END) {
977                 printf("\n");
978         }
979
980         return NULL;
981 }
982
983 /*
984  ***************************************************************************
985  * Display the "timestamp" part of the report (raw format).
986  *
987  * IN:
988  * @parm        Pointer on specific parameters (unused here).
989  * @action      Action expected from current function.
990  * @cur_date    Date string of current record.
991  * @cur_time    Time string of current record.
992  * @itv         Interval of time with preceding record (unused here).
993  * @record_hdr  Record header for current sample (unused here).
994  * @file_hdr    System activity file standard header (unused here).
995  * @flags       Flags for common options.
996  *
997  * RETURNS:
998  * Pointer on the "timestamp" string.
999  ***************************************************************************
1000  */
1001 __tm_funct_t print_raw_timestamp(void *parm, int action, char *cur_date,
1002                                  char *cur_time, unsigned long long itv,
1003                                  struct record_header *record_hdr,
1004                                  struct file_header *file_hdr, unsigned int flags)
1005 {
1006         int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
1007         static char pre[80];
1008
1009         if (action & F_BEGIN) {
1010                 snprintf(pre, 80, "%s%s", cur_time, strlen(cur_date) && utc ? " UTC" : "");
1011                 pre[79] = '\0';
1012                 return pre;
1013         }
1014
1015         return NULL;
1016 }
1017
1018 /*
1019  ***************************************************************************
1020  * Display the "timestamp" part of the report (PCP format).
1021  *
1022  * IN:
1023  * @parm        Pointer on specific parameters (unused here).
1024  * @action      Action expected from current function.
1025  * @cur_date    Date string of current record (unused here).
1026  * @cur_time    Time string of current record (unused here).
1027  * @itv         Interval of time with preceding record (unused here).
1028  * @record_hdr  Record header for current sample.
1029  * @file_hdr    System activity file standard header (unused here).
1030  * @flags       Flags for common options.
1031  *
1032  * RETURNS:
1033  * Pointer on the "timestamp" string.
1034  ***************************************************************************
1035  */
1036 __tm_funct_t print_pcp_timestamp(void *parm, int action, char *cur_date,
1037                                  char *cur_time, unsigned long long itv,
1038                                  struct record_header *record_hdr,
1039                                  struct file_header *file_hdr, unsigned int flags)
1040 {
1041         if (action & F_END) {
1042                 pcp_write_data(record_hdr, flags);
1043         }
1044
1045         return NULL;
1046 }
1047
1048 /*
1049  ***************************************************************************
1050  * Display the header of the report (XML format).
1051  *
1052  * IN:
1053  * @parm        Specific parameter. Here: number of tabulations.
1054  * @action      Action expected from current function.
1055  * @dfile       Unused here (PCP archive file).
1056  * @file_magic  System activity file magic header.
1057  * @file_hdr    System activity file standard header.
1058  * @act         Array of activities (unused here).
1059  * @id_seq      Activity sequence (unused here).
1060  * @file_actlst List of (known or unknown) activities in file (unused here).
1061  *
1062  * OUT:
1063  * @parm        Number of tabulations.
1064  ***************************************************************************
1065  */
1066 __printf_funct_t print_xml_header(void *parm, int action, char *dfile,
1067                                   struct file_magic *file_magic,
1068                                   struct file_header *file_hdr,
1069                                   struct activity *act[], unsigned int id_seq[],
1070                                   struct file_activity *file_actlst)
1071 {
1072         struct tm rectime, loc_t;
1073         char cur_time[TIMESTAMP_LEN];
1074         int *tab = (int *) parm;
1075
1076         if (action & F_BEGIN) {
1077                 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1078                 printf("<!DOCTYPE sysstat PUBLIC \"DTD v%s sysstat //EN\"\n",
1079                        XML_DTD_VERSION);
1080                 printf("\"http://pagesperso-orange.fr/sebastien.godard/sysstat-%s.dtd\">\n",
1081                        XML_DTD_VERSION);
1082
1083                 xprintf(*tab, "<sysstat\n"
1084                               "xmlns=\"http://pagesperso-orange.fr/sebastien.godard/sysstat\"\n"
1085                               "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
1086                               "xsi:schemaLocation=\"http://pagesperso-orange.fr/sebastien.godard sysstat.xsd\">");
1087
1088                 xprintf(++(*tab), "<sysdata-version>%s</sysdata-version>",
1089                         XML_DTD_VERSION);
1090
1091                 xprintf(*tab, "<host nodename=\"%s\">", file_hdr->sa_nodename);
1092                 xprintf(++(*tab), "<sysname>%s</sysname>", file_hdr->sa_sysname);
1093                 xprintf(*tab, "<release>%s</release>", file_hdr->sa_release);
1094
1095                 xprintf(*tab, "<machine>%s</machine>", file_hdr->sa_machine);
1096                 xprintf(*tab, "<number-of-cpus>%d</number-of-cpus>",
1097                         file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1098
1099                 /* Fill file timestmap structure (rectime) */
1100                 get_file_timestamp_struct(flags, &rectime, file_hdr);
1101                 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1102                 xprintf(*tab, "<file-date>%s</file-date>", cur_time);
1103
1104                 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1105                         strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1106                         xprintf(*tab, "<file-utc-time>%s</file-utc-time>", cur_time);
1107                 }
1108
1109         }
1110         if (action & F_END) {
1111                 xprintf(--(*tab), "</host>");
1112                 xprintf(--(*tab), "</sysstat>");
1113         }
1114 }
1115
1116 /*
1117  ***************************************************************************
1118  * Display the header of the report (JSON format).
1119  *
1120  * IN:
1121  * @parm        Specific parameter. Here: number of tabulations.
1122  * @action      Action expected from current function.
1123  * @dfile       Unused here (PCP archive file).
1124  * @file_magic  System activity file magic header.
1125  * @file_hdr    System activity file standard header.
1126  * @act         Array of activities (unused here).
1127  * @id_seq      Activity sequence (unused here).
1128  * @file_actlst List of (known or unknown) activities in file (unused here).
1129  *
1130  * OUT:
1131  * @parm        Number of tabulations.
1132  ***************************************************************************
1133  */
1134 __printf_funct_t print_json_header(void *parm, int action, char *dfile,
1135                                    struct file_magic *file_magic,
1136                                    struct file_header *file_hdr,
1137                                    struct activity *act[], unsigned int id_seq[],
1138                                    struct file_activity *file_actlst)
1139 {
1140         struct tm rectime, loc_t;
1141         char cur_time[TIMESTAMP_LEN];
1142         int *tab = (int *) parm;
1143
1144         if (action & F_BEGIN) {
1145                 xprintf(*tab, "{\"sysstat\": {");
1146
1147                 xprintf(++(*tab), "\"hosts\": [");
1148                 xprintf(++(*tab), "{");
1149                 xprintf(++(*tab), "\"nodename\": \"%s\",", file_hdr->sa_nodename);
1150                 xprintf(*tab, "\"sysname\": \"%s\",", file_hdr->sa_sysname);
1151                 xprintf(*tab, "\"release\": \"%s\",", file_hdr->sa_release);
1152
1153                 xprintf(*tab, "\"machine\": \"%s\",", file_hdr->sa_machine);
1154                 xprintf(*tab, "\"number-of-cpus\": %d,",
1155                         file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1156
1157                 /* Fill file timestmap structure (rectime) */
1158                 get_file_timestamp_struct(flags, &rectime, file_hdr);
1159                 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1160                 xprintf0(*tab, "\"file-date\": \"%s\"", cur_time);
1161
1162                 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1163                         strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1164                         printf(",\n");
1165                         xprintf0(*tab, "\"file-utc-time\": \"%s\"", cur_time);
1166                 }
1167
1168         }
1169         if (action & F_END) {
1170                 printf("\n");
1171                 xprintf(--(*tab), "}");
1172                 xprintf(--(*tab), "]");
1173                 xprintf(--(*tab), "}}");
1174         }
1175 }
1176
1177 /*
1178  ***************************************************************************
1179  * Display data file header.
1180  *
1181  * IN:
1182  * @parm        Specific parameter (unused here).
1183  * @action      Action expected from current function.
1184  * @dfile       Name of system activity data file (unused here).
1185  * @file_magic  System activity file magic header.
1186  * @file_hdr    System activity file standard header.
1187  * @act         Array of activities.
1188  * @id_seq      Activity sequence.
1189  * @file_actlst List of (known or unknown) activities in file.
1190  ***************************************************************************
1191  */
1192 __printf_funct_t print_hdr_header(void *parm, int action, char *dfile,
1193                                   struct file_magic *file_magic,
1194                                   struct file_header *file_hdr,
1195                                   struct activity *act[], unsigned int id_seq[],
1196                                   struct file_activity *file_actlst)
1197 {
1198         int i, p;
1199         struct tm rectime, loc_t;
1200         struct file_activity *fal;
1201         char cur_time[TIMESTAMP_LEN];
1202
1203         /* Actions F_MAIN and F_END ignored */
1204         if (action & F_BEGIN) {
1205                 printf(_("System activity data file: %s (%#x)\n"),
1206                        dfile, file_magic->format_magic);
1207
1208                 display_sa_file_version(stdout, file_magic);
1209
1210                 if (file_magic->format_magic != FORMAT_MAGIC) {
1211                         return;
1212                 }
1213
1214                 printf(_("Genuine sa datafile: %s (%x)\n"),
1215                        file_magic->upgraded ? _("no") : _("yes"),
1216                        file_magic->upgraded);
1217
1218                 printf(_("Host: "));
1219                 print_gal_header(localtime_r((const time_t *) &(file_hdr->sa_ust_time), &rectime),
1220                                  file_hdr->sa_sysname, file_hdr->sa_release,
1221                                  file_hdr->sa_nodename, file_hdr->sa_machine,
1222                                  file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
1223                                  PLAIN_OUTPUT);
1224
1225                 /* Fill file timestmap structure (rectime) */
1226                 get_file_timestamp_struct(flags, &rectime, file_hdr);
1227                 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1228                 printf(_("File date: %s\n"), cur_time);
1229
1230                 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1231                         printf(_("File time: "));
1232                         strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1233                         printf("%s UTC\n", cur_time);
1234                 }
1235
1236                 /* File composition: file_header, file_activity, record_header */
1237                 printf(_("File composition: (%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n"),
1238                        file_magic->hdr_types_nr[0], file_magic->hdr_types_nr[1], file_magic->hdr_types_nr[2],
1239                        file_hdr->act_types_nr[0], file_hdr->act_types_nr[1], file_hdr->act_types_nr[2],
1240                        file_hdr->rec_types_nr[0], file_hdr->rec_types_nr[1], file_hdr->rec_types_nr[2]);
1241
1242                 printf(_("Size of a long int: %d\n"), file_hdr->sa_sizeof_long);
1243                 printf("HZ = %lu\n", file_hdr->sa_hz);
1244                 printf(_("Number of activities in file: %u\n"),
1245                        file_hdr->sa_act_nr);
1246
1247                 printf(_("List of activities:\n"));
1248                 fal = file_actlst;
1249                 for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1250
1251                         p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND);
1252
1253                         printf("%02d: [%02x] ", fal->id, fal->magic);
1254                         if (p >= 0) {
1255                                 printf("%-20s", act[p]->name);
1256                         }
1257                         else {
1258                                 printf("%-20s", _("Unknown activity"));
1259                         }
1260                         printf(" %c:%4d", fal->has_nr ? 'Y' : 'N', fal->nr);
1261                         if (fal->nr2 > 1) {
1262                                 printf("x%d", fal->nr2);
1263                         }
1264                         printf("\t(%d,%d,%d)", fal->types_nr[0], fal->types_nr[1], fal->types_nr[2]);
1265                         if ((p >= 0) && (act[p]->magic == ACTIVITY_MAGIC_UNKNOWN)) {
1266                                 printf(_(" \t[Unknown format]"));
1267                         }
1268                         printf("\n");
1269                 }
1270         }
1271 }
1272
1273 /*
1274  ***************************************************************************
1275  * Display the header of the report (SVG format).
1276  *
1277  * IN:
1278  * @parm        Specific parameters. Here: number of rows of views to display
1279  *              or canvas height entered on the command line (@graph_nr), and
1280  *              max number of views on a single row (@views_per_row).
1281  * @action      Action expected from current function.
1282  * @dfile       Name of system activity data file (unused here).
1283  * @file_magic  System activity file magic header (unused here).
1284  * @file_hdr    System activity file standard header.
1285  * @act         Array of activities (unused here).
1286  * @id_seq      Activity sequence (unused here).
1287  * @file_actlst List of (known or unknown) activities in file (unused here).
1288  ***************************************************************************
1289  */
1290 __printf_funct_t print_svg_header(void *parm, int action, char *dfile,
1291                                   struct file_magic *file_magic,
1292                                   struct file_header *file_hdr,
1293                                   struct activity *act[], unsigned int id_seq[],
1294                                   struct file_activity *file_actlst)
1295 {
1296         struct svg_hdr_parm *hdr_parm = (struct svg_hdr_parm *) parm;
1297         struct tm rectime;
1298         unsigned int height = 0, ht = 0;
1299         int i, p;
1300
1301         if (action & F_BEGIN) {
1302                 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1303                 printf("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
1304                 printf("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
1305                 printf("<svg xmlns=\"http://www.w3.org/2000/svg\"");
1306                 if (DISPLAY_TOC(flags)) {
1307                         printf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
1308                 }
1309                 if (action & F_END) {
1310                         printf(">\n");
1311                 }
1312         }
1313
1314         if (action & F_MAIN) {
1315                 if (SET_CANVAS_HEIGHT(flags)) {
1316                         /*
1317                          * Option "-O height=..." used: @graph_nr is
1318                          * the SVG canvas height set on the command line.
1319                          */
1320                         height = hdr_parm->graph_nr;
1321                 }
1322                 else {
1323                         height = SVG_H_YSIZE +
1324                                  SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0) +
1325                                  SVG_T_YSIZE * hdr_parm->graph_nr;
1326                 }
1327                 if (height < 100) {
1328                         /* Min canvas height is 100 (at least to display "No data") */
1329                         height = 100;
1330                 }
1331                 printf(" width=\"%d\" height=\"%d\""
1332                        " fill=\"black\" stroke=\"#%06x\" stroke-width=\"1\">\n",
1333                        SVG_T_XSIZE * (hdr_parm->views_per_row), height,
1334                        svg_colors[palette][SVG_COL_DEFAULT_IDX]);
1335                 printf("<text x=\"0\" y=\"30\" text-anchor=\"start\" stroke=\"#%06x\">",
1336                        svg_colors[palette][SVG_COL_HEADER_IDX]);
1337                 print_gal_header(localtime_r((const time_t *) &(file_hdr->sa_ust_time), &rectime),
1338                                  file_hdr->sa_sysname, file_hdr->sa_release,
1339                                  file_hdr->sa_nodename, file_hdr->sa_machine,
1340                                  file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
1341                                  PLAIN_OUTPUT);
1342                 printf("</text>\n");
1343                 if (DISPLAY_TOC(flags)) {
1344                         for (i = 0; i < NR_ACT; i++) {
1345                                 if (!id_seq[i])
1346                                         continue;       /* Activity not in file */
1347
1348                                 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1349                                 if (!IS_SELECTED(act[p]->options) || !act[p]->g_nr)
1350                                         continue;       /* Activity not selected or no graph available */
1351
1352                                 printf("<a xlink:href=\"#g%d-0\" xlink:title=\"%s\">\n",
1353                                        act[p]->id, act[p]->name);
1354                                 printf("<text x=\"10\" y=\"%d\">%s</text></a>\n",
1355                                        SVG_H_YSIZE + ht, act[p]->desc);
1356                                 ht += SVG_C_YSIZE;
1357                         }
1358                 }
1359         }
1360
1361         if (action & F_END) {
1362                 if (!(action & F_BEGIN)) {
1363                         if (!hdr_parm->graph_nr) {
1364                                 /* No views displayed */
1365                                 printf("<text x= \"0\" y=\"%d\" text-anchor=\"start\" stroke=\"#%06x\">",
1366                                        SVG_H_YSIZE +
1367                                        SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0),
1368                                        svg_colors[palette][SVG_COL_ERROR_IDX]);
1369                                 printf("No data!</text>\n");
1370                         }
1371                         /* Give actual SVG height */
1372                         printf("<!-- Actual canvas height: %d -->\n",
1373                                SVG_H_YSIZE +
1374                                SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0) +
1375                                SVG_T_YSIZE * hdr_parm->graph_nr);
1376                 }
1377                 printf("</svg>\n");
1378         }
1379 }
1380
1381 /*
1382  ***************************************************************************
1383  * PCP header function.
1384  *
1385  * IN:
1386  * @parm        Specific parameter (unused here).
1387  * @action      Action expected from current function.
1388  * @dfile       Name of PCP archive file.
1389  * @file_magic  System activity file magic header (unused here).
1390  * @file_hdr    System activity file standard header (unused here).
1391  * @act         Array of activities (unused here).
1392  * @id_seq      Activity sequence (unused here).
1393  * @file_actlst List of (known or unknown) activities in file (unused here).
1394  ***************************************************************************
1395  */
1396 __printf_funct_t print_pcp_header(void *parm, int action, char *dfile,
1397                                   struct file_magic *file_magic,
1398                                   struct file_header *file_hdr,
1399                                   struct activity *act[], unsigned int id_seq[],
1400                                   struct file_activity *file_actlst)
1401 {
1402 #ifdef HAVE_PCP
1403         char buf[64];
1404         struct tm lrectime;
1405         unsigned long long utc_sec = file_hdr->sa_ust_time;
1406
1407         if (action & F_BEGIN) {
1408                 /* Create new PCP context */
1409                 pmiStart(dfile, FALSE);
1410
1411                 if (PRINT_LOCAL_TIME(flags)) {
1412                         tzset();        /* Set timezone value in tzname */
1413                         pmiSetTimezone(tzname[0]);
1414                 }
1415                 else {
1416                         pmiSetTimezone("UTC");
1417                 }
1418
1419                 /* Save hostname */
1420                 pmiSetHostname(file_hdr->sa_nodename);
1421
1422                 /* Save number of CPU in PCP archive */
1423                 pmiAddMetric("hinv.ncpu",
1424                              PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
1425                              pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
1426                 snprintf(buf, sizeof(buf), "%u",
1427                          file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1428                 pmiPutValue("hinv.ncpu", NULL, buf);
1429         }
1430
1431         if (action & F_END) {
1432                 if (action & F_BEGIN) {
1433                         /* Only the header data will be written to PCP archive */
1434                         if (!PRINT_LOCAL_TIME(flags)) {
1435                                 /* Convert a time_t value from local time to UTC */
1436                                 if (gmtime_r((const time_t *) &(file_hdr->sa_ust_time), &lrectime)) {
1437                                         utc_sec = mktime(&lrectime);
1438                                 }
1439                         }
1440                         pmiWrite(utc_sec, 0);
1441                 }
1442                 pmiEnd();
1443         }
1444 #endif
1445 }
1446
1447 /*
1448  ***************************************************************************
1449  * Count the number of new network interfaces in current sample. If a new
1450  * interface is found then add it to the linked list starting at
1451  * @a->item_list.
1452  *
1453  * IN:
1454  * @a           Activity structure with statistics.
1455  * @curr        Index in array for current sample statistics.
1456  *
1457  * RETURNS:
1458  * Number of new interfaces identified in current sample that were not
1459  * previously in the list.
1460  ***************************************************************************
1461  */
1462 __nr_t count_new_net_dev(struct activity *a, int curr)
1463 {
1464         int i, nr = 0;
1465         struct stats_net_dev *sndc;
1466
1467         for (i = 0; i < a->nr[curr]; i++) {
1468                 sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
1469
1470                 nr += add_list_item(&(a->item_list), sndc->interface, MAX_IFACE_LEN);
1471         }
1472
1473         return nr;
1474 }
1475
1476 /*
1477  ***************************************************************************
1478  * Count the number of new network interfaces in current sample. If a new
1479  * interface is found then add it to the linked list starting at
1480  * @a->item_list.
1481  *
1482  * IN:
1483  * @a           Activity structure with statistics.
1484  * @curr        Index in array for current sample statistics.
1485  *
1486  * RETURNS:
1487  * Number of new interfaces identified in current sample that were not
1488  * previously in the list.
1489  ***************************************************************************
1490  */
1491 __nr_t count_new_net_edev(struct activity *a, int curr)
1492 {
1493         int i, nr = 0;
1494         struct stats_net_edev *snedc;
1495
1496         for (i = 0; i < a->nr[curr]; i++) {
1497                 snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + i * a->msize);
1498
1499                 nr += add_list_item(&(a->item_list), snedc->interface, MAX_IFACE_LEN);
1500         }
1501
1502         return nr;
1503 }
1504
1505 /*
1506  ***************************************************************************
1507  * Count the number of new filesystems in current sample. If a new
1508  * filesystem is found then add it to the linked list starting at
1509  * @a->item_list.
1510  *
1511  * IN:
1512  * @a           Activity structure with statistics.
1513  * @curr        Index in array for current sample statistics.
1514  *
1515  * RETURNS:
1516  * Number of new filesystems identified in current sample that were not
1517  * previously in the list.
1518  ***************************************************************************
1519  */
1520 __nr_t count_new_filesystem(struct activity *a, int curr)
1521 {
1522         int i, nr = 0;
1523         struct stats_filesystem *sfc;
1524
1525         for (i = 0; i < a->nr[curr]; i++) {
1526                 sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize);
1527
1528                 nr += add_list_item(&(a->item_list),
1529                                     DISPLAY_MOUNT(a->opt_flags) ? sfc->mountp : sfc->fs_name,
1530                                     MAX_FS_LEN);
1531         }
1532
1533         return nr;
1534 }
1535
1536 /*
1537  ***************************************************************************
1538  * Count the number of new fchosts in current sample. If a new
1539  * fchost is found then add it to the linked list starting at
1540  * @a->item_list.
1541  *
1542  * IN:
1543  * @a           Activity structure with statistics.
1544  * @curr        Index in array for current sample statistics.
1545  *
1546  * RETURNS:
1547  * Number of new fchosts identified in current sample that were not
1548  * previously in the list.
1549  ***************************************************************************
1550  */
1551 __nr_t count_new_fchost(struct activity *a, int curr)
1552 {
1553         int i, nr = 0;
1554         struct stats_fchost *sfcc;
1555
1556         for (i = 0; i < a->nr[curr]; i++) {
1557                 sfcc = (struct stats_fchost *) ((char *) a->buf[curr] + i * a->msize);
1558
1559                 nr += add_list_item(&(a->item_list), sfcc->fchost_name, MAX_FCH_LEN);
1560         }
1561
1562         return nr;
1563 }
1564
1565 /*
1566  ***************************************************************************
1567  * Count the number of new block devices in current sample. If a new
1568  * block device is found then add it to the linked list starting at
1569  * @a->item_list.
1570  *
1571  * IN:
1572  * @a           Activity structure with statistics.
1573  * @curr        Index in array for current sample statistics.
1574  *
1575  * RETURNS:
1576  * Number of new block devices identified in current sample that were not
1577  * previously in the list.
1578  ***************************************************************************
1579  */
1580 __nr_t count_new_disk(struct activity *a, int curr)
1581 {
1582         int i, nr = 0;
1583         struct stats_disk *sdc;
1584
1585         for (i = 0; i < a->nr[curr]; i++) {
1586                 sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
1587
1588                 nr += add_list_item(&(a->item_list),
1589                                     get_sa_devname(sdc->major, sdc->minor, flags),
1590                                     MAX_DEV_LEN);
1591         }
1592
1593         return nr;
1594 }
1595
1596 /*
1597  ***************************************************************************
1598  * Init custom color palette used to draw graphs (sadf -g).
1599  ***************************************************************************
1600  */
1601 void init_custom_color_palette()
1602 {
1603         char *e, *p;
1604         int len;
1605         unsigned int val;
1606
1607         /* Read S_COLORS_PALETTE environment variable */
1608         if ((e = __getenv(ENV_COLORS_PALETTE)) == NULL)
1609                 /* Environment variable not set */
1610                 return;
1611
1612         for (p = strtok(e, ":"); p; p =strtok(NULL, ":")) {
1613
1614                 len = strlen(p);
1615                 if ((len > 8) || (len < 3) || (*(p + 1) != '=') ||
1616                     (strspn(p + 2, "0123456789ABCDEFabcdef") != (len - 2)))
1617                         /* Ignore malformed codes */
1618                         continue;
1619
1620                 sscanf(p + 2, "%x", &val);
1621
1622                 if ((*p >= '0') && (*p <= '9')) {
1623                         svg_colors[SVG_CUSTOM_COL_PALETTE][*p & 0xf] = val;
1624                         continue;
1625                 }
1626                 else if (((*p >= 'A') && (*p <= 'F')) ||
1627                          ((*p >= 'a') && (*p <= 'f'))) {
1628                         svg_colors[SVG_CUSTOM_COL_PALETTE][9 + (*p & 0xf)] = val;
1629                         continue;
1630                 }
1631
1632                 switch (*p) {
1633                         case 'G':
1634                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_GRID_IDX] = val;
1635                                 break;
1636                         case 'H':
1637                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_HEADER_IDX] = val;
1638                                 break;
1639                         case 'I':
1640                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_INFO_IDX] = val;
1641                                 break;
1642                         case 'K':
1643                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_BCKGRD_IDX] = val;
1644                                 break;
1645                         case 'L':
1646                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_DEFAULT_IDX] = val;
1647                                 break;
1648                         case 'T':
1649                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_TITLE_IDX] = val;
1650                                 break;
1651                         case 'W':
1652                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_ERROR_IDX] = val;
1653                                 break;
1654                         case 'X':
1655                                 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_AXIS_IDX] = val;
1656                                 break;
1657                 }
1658         }
1659 }