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