2 * sar: report system activity
3 * (C) 1999-2017 by Sebastien GODARD (sysstat <at> orange.fr)
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. *
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 *
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 ***************************************************************************
40 #define _(string) gettext(string)
42 #define _(string) (string)
46 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
47 char *sccsid(void) { return (SCCSID); }
50 /* Interval and count parameters */
51 long interval = -1, count = 0;
53 /* TRUE if a header line must be printed */
55 /* TRUE if data read from file don't match current machine's endianness */
56 int endian_mismatch = FALSE;
57 /* TRUE if file's data come from a 64 bit machine */
60 unsigned int flags = 0;
61 unsigned int dm_major; /* Device-mapper major number */
63 char timestamp[2][TIMESTAMP_LEN];
64 extern unsigned int rec_types_nr[];
66 unsigned long avg_count = 0;
69 struct file_header file_hdr;
71 /* Current record header */
72 struct record_header record_hdr[3];
76 * This array must always be entirely filled (even with trailing zeros).
78 unsigned int id_seq[NR_ACT];
82 /* Contain the date specified by -s and -e options */
83 struct tstamp tm_start, tm_end;
85 char *args[MAX_ARGV_NR];
87 extern struct activity *act[];
88 extern struct report_format sar_fmt;
90 struct sigaction int_act;
91 int sigint_caught = 0;
94 ***************************************************************************
95 * Print usage title message.
98 * @progname Name of sysstat command
99 ***************************************************************************
101 void print_usage_title(FILE *fp, char *progname)
103 fprintf(fp, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
108 ***************************************************************************
109 * Print usage and exit.
112 * @progname Name of sysstat command
113 ***************************************************************************
115 void usage(char *progname)
117 print_usage_title(stderr, progname);
118 fprintf(stderr, _("Options are:\n"
119 "[ -A ] [ -B ] [ -b ] [ -C ] [ -D ] [ -d ] [ -F [ MOUNT ] ] [ -H ] [ -h ]\n"
120 "[ -p ] [ -q ] [ -r [ ALL ] ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ]\n"
121 "[ -v ] [ -W ] [ -w ] [ -y ] [ --human ] [ --sadc ]\n"
122 "[ -I { <int_list> | SUM | ALL } ] [ -P { <cpu_list> | ALL } ]\n"
123 "[ -m { <keyword> [,...] | ALL } ] [ -n { <keyword> [,...] | ALL } ]\n"
124 "[ -j { ID | LABEL | PATH | UUID | ... } ]\n"
125 "[ -f [ <filename> ] | -o [ <filename> ] | -[0-9]+ ]\n"
126 "[ -i <interval> ] [ -s [ <hh:mm[:ss]> ] ] [ -e [ <hh:mm[:ss]> ] ]\n"));
131 ***************************************************************************
132 * Display a short help message and exit.
135 * @progname Name of sysstat command
136 ***************************************************************************
138 void display_help(char *progname)
140 print_usage_title(stdout, progname);
141 printf(_("Main options and reports:\n"));
142 printf(_("\t-B\tPaging statistics\n"));
143 printf(_("\t-b\tI/O and transfer rate statistics\n"));
144 printf(_("\t-d\tBlock devices statistics\n"));
145 printf(_("\t-F [ MOUNT ]\n"));
146 printf(_("\t\tFilesystems statistics\n"));
147 printf(_("\t-H\tHugepages utilization statistics\n"));
148 printf(_("\t-I { <int_list> | SUM | ALL }\n"
149 "\t\tInterrupts statistics\n"));
150 printf(_("\t-m { <keyword> [,...] | ALL }\n"
151 "\t\tPower management statistics\n"
152 "\t\tKeywords are:\n"
153 "\t\tCPU\tCPU instantaneous clock frequency\n"
154 "\t\tFAN\tFans speed\n"
155 "\t\tFREQ\tCPU average clock frequency\n"
156 "\t\tIN\tVoltage inputs\n"
157 "\t\tTEMP\tDevices temperature\n"
158 "\t\tUSB\tUSB devices plugged into the system\n"));
159 printf(_("\t-n { <keyword> [,...] | ALL }\n"
160 "\t\tNetwork statistics\n"
161 "\t\tKeywords are:\n"
162 "\t\tDEV\tNetwork interfaces\n"
163 "\t\tEDEV\tNetwork interfaces (errors)\n"
164 "\t\tNFS\tNFS client\n"
165 "\t\tNFSD\tNFS server\n"
166 "\t\tSOCK\tSockets\t(v4)\n"
167 "\t\tIP\tIP traffic\t(v4)\n"
168 "\t\tEIP\tIP traffic\t(v4) (errors)\n"
169 "\t\tICMP\tICMP traffic\t(v4)\n"
170 "\t\tEICMP\tICMP traffic\t(v4) (errors)\n"
171 "\t\tTCP\tTCP traffic\t(v4)\n"
172 "\t\tETCP\tTCP traffic\t(v4) (errors)\n"
173 "\t\tUDP\tUDP traffic\t(v4)\n"
174 "\t\tSOCK6\tSockets\t(v6)\n"
175 "\t\tIP6\tIP traffic\t(v6)\n"
176 "\t\tEIP6\tIP traffic\t(v6) (errors)\n"
177 "\t\tICMP6\tICMP traffic\t(v6)\n"
178 "\t\tEICMP6\tICMP traffic\t(v6) (errors)\n"
179 "\t\tUDP6\tUDP traffic\t(v6)\n"
180 "\t\tFC\tFibre channel HBAs\n"
181 "\t\tSOFT\tSoftware-based network processing\n"));
182 printf(_("\t-q\tQueue length and load average statistics\n"));
183 printf(_("\t-r [ ALL ]\n"
184 "\t\tMemory utilization statistics\n"));
185 printf(_("\t-S\tSwap space utilization statistics\n"));
186 printf(_("\t-u [ ALL ]\n"
187 "\t\tCPU utilization statistics\n"));
188 printf(_("\t-v\tKernel tables statistics\n"));
189 printf(_("\t-W\tSwapping statistics\n"));
190 printf(_("\t-w\tTask creation and system switching statistics\n"));
191 printf(_("\t-y\tTTY devices statistics\n"));
196 ***************************************************************************
197 * Give a hint to the user about where is located the data collector.
198 ***************************************************************************
200 void which_sadc(void)
204 if (stat(SADC_PATH, &buf) < 0) {
205 printf(_("Data collector will be sought in PATH\n"));
208 printf(_("Data collector found: %s\n"), SADC_PATH);
214 ***************************************************************************
215 * SIGINT signal handler.
218 * @sig Signal number.
219 ***************************************************************************
221 void int_handler(int sig)
224 printf("\n"); /* Skip "^C" displayed on screen */
229 ***************************************************************************
230 * Init some structures.
231 ***************************************************************************
233 void init_structures(void)
237 for (i = 0; i < 3; i++)
238 memset(&record_hdr[i], 0, RECORD_HEADER_SIZE);
242 ***************************************************************************
243 * Allocate memory for sadc args.
246 * @i Argument number.
247 * @ltemp Argument value.
248 ***************************************************************************
250 void salloc(int i, char *ltemp)
252 if ((args[i] = (char *) malloc(strlen(ltemp) + 1)) == NULL) {
256 strcpy(args[i], ltemp);
260 ***************************************************************************
261 * Display an error message.
264 * @error_code Code of error message to display.
265 ***************************************************************************
267 void print_read_error(int error_code)
269 switch (error_code) {
271 case END_OF_DATA_UNEXPECTED:
272 /* Happens when the data collector doesn't send enough data */
273 fprintf(stderr, _("End of data collecting unexpected\n"));
277 /* Strange data sent by sadc...! */
278 fprintf(stderr, _("Inconsistent input data\n"));
285 ***************************************************************************
286 * Check that every selected activity actually belongs to the sequence list.
287 * If not, then the activity should be unselected since it will not be sent
288 * by sadc. An activity can be not sent if its number of items is zero.
291 * @act_nr Size of sequence list.
292 ***************************************************************************
294 void reverse_check_act(unsigned int act_nr)
298 for (i = 0; i < NR_ACT; i++) {
300 if (IS_SELECTED(act[i]->options)) {
302 for (j = 0; j < act_nr; j++) {
303 if (id_seq[j] == act[i]->id)
307 act[i]->options &= ~AO_SELECTED;
313 ***************************************************************************
314 * Determine if a stat header line has to be displayed.
317 * TRUE if a header line has to be displayed.
318 ***************************************************************************
320 int check_line_hdr(void)
324 /* Get number of options entered on the command line */
325 if (get_activity_nr(act, AO_SELECTED, COUNT_OUTPUTS) > 1)
328 for (i = 0; i < NR_ACT; i++) {
329 if (IS_SELECTED(act[i]->options)) {
330 /* Special processing for activities using a bitmap */
331 if (act[i]->bitmap) {
332 if (count_bits(act[i]->bitmap->b_array,
333 BITMAP_SIZE(act[i]->bitmap->b_size)) > 1) {
337 else if (act[i]->nr_ini > 1) {
340 /* Stop now since we have only one selected activity */
349 ***************************************************************************
350 * Print statistics average.
353 * @curr Index in array for current sample statistics.
354 * @read_from_file Set to TRUE if stats are read from a system activity
356 * @act_id Activity that can be displayed, or ~0 for all.
357 * Remember that when reading stats from a file, only
358 * one activity can be displayed at a time.
359 ***************************************************************************
361 void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
364 unsigned long long itv;
366 /* Interval value in 1/100th of a second */
367 itv = get_interval(record_hdr[2].uptime_cs, record_hdr[curr].uptime_cs);
369 strncpy(timestamp[curr], _("Average:"), TIMESTAMP_LEN);
370 timestamp[curr][TIMESTAMP_LEN - 1] = '\0';
371 strcpy(timestamp[!curr], timestamp[curr]);
374 TEST_STDOUT(STDOUT_FILENO);
376 for (i = 0; i < NR_ACT; i++) {
378 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
381 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
382 /* Display current average activity statistics */
383 (*act[i]->f_print_avg)(act[i], 2, curr, itv);
387 if (read_from_file) {
389 * Reset number of lines printed only if we read stats
390 * from a system activity file.
397 ***************************************************************************
398 * Print system statistics.
399 * This is called when we read stats either from a file or from sadc.
402 * @curr Index in array for current sample statistics.
403 * @read_from_file Set to TRUE if stats are read from a system activity
405 * @use_tm_start Set to TRUE if option -s has been used.
406 * @use_tm_end Set to TRUE if option -e has been used.
407 * @reset Set to TRUE if last_uptime variable should be
408 * reinitialized (used in next_slice() function).
409 * @act_id Activity that can be displayed or ~0 for all.
410 * Remember that when reading stats from a file, only
411 * one activity can be displayed at a time.
412 * @reset_cd TRUE if static cross_day variable should be reset
416 * @cnt Number of remaining lines to display.
419 * 1 if stats have been successfully displayed, and 0 otherwise.
420 ***************************************************************************
422 int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start,
423 int use_tm_end, int reset, unsigned int act_id, int reset_cd)
426 unsigned long long itv;
427 static int cross_day = 0;
431 * cross_day is a static variable that is set to 1 when the first
432 * record of stats from a new day is read from a unique data file
433 * (in the case where the file contains data from two consecutive
434 * days). When set to 1, every following records timestamp will
435 * have its hour value increased by 24.
436 * Yet when a new activity (being read from the file) is going to
437 * be displayed, we start reading the file from the beginning
438 * again, and so cross_day should be reset in this case.
444 if (read_from_file) {
445 if (!next_slice(record_hdr[2].uptime_cs, record_hdr[curr].uptime_cs,
447 /* Not close enough to desired interval */
451 if (!is_iso_time_fmt())
452 flags |= S_F_PREFD_TIME_OUTPUT;
454 /* Get then set previous timestamp */
455 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[!curr],
458 set_record_timestamp_string(flags, &record_hdr[!curr],
459 NULL, timestamp[!curr], TIMESTAMP_LEN, &rectime);
461 /* Get then set current timestamp */
462 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[curr],
465 set_record_timestamp_string(flags, &record_hdr[curr],
466 NULL, timestamp[curr], TIMESTAMP_LEN, &rectime);
468 /* Check if we are beginning a new day */
469 if (use_tm_start && record_hdr[!curr].ust_time &&
470 (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
471 (record_hdr[curr].hour < record_hdr[!curr].hour)) {
477 * This is necessary if we want to properly handle something like:
478 * sar -s time_start -e time_end with
479 * time_start(day D) > time_end(day D+1)
481 rectime.tm_hour +=24;
485 if (use_tm_start && (datecmp(&rectime, &tm_start) < 0))
486 /* it's too soon... */
489 /* Get interval value in 1/100th of a second */
490 get_itv_value(&record_hdr[curr], &record_hdr[!curr], &itv);
493 if (use_tm_end && (datecmp(&rectime, &tm_end) > 0)) {
494 /* It's too late... */
502 TEST_STDOUT(STDOUT_FILENO);
504 for (i = 0; i < NR_ACT; i++) {
506 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
509 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
510 /* Display current activity statistics */
511 (*act[i]->f_print)(act[i], !curr, curr, itv);
519 ***************************************************************************
520 * Display stats since system startup.
523 * @curr Index in array for current sample statistics.
524 ***************************************************************************
526 void write_stats_startup(int curr)
530 /* Set to 0 previous structures corresponding to boot time */
531 memset(&record_hdr[!curr], 0, RECORD_HEADER_SIZE);
532 record_hdr[!curr].record_type = R_STATS;
533 record_hdr[!curr].hour = record_hdr[curr].hour;
534 record_hdr[!curr].minute = record_hdr[curr].minute;
535 record_hdr[!curr].second = record_hdr[curr].second;
536 record_hdr[!curr].ust_time = record_hdr[curr].ust_time;
538 for (i = 0; i < NR_ACT; i++) {
539 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
541 * Using nr[curr] and not nr[!curr] below because we initialize
542 * reference structures for each structure that has been
543 * currently read in memory.
544 * No problem with buffers allocation since they all have the
547 memset(act[i]->buf[!curr], 0,
548 (size_t) act[i]->msize * (size_t) act[i]->nr[curr] * (size_t) act[i]->nr2);
552 flags |= S_F_SINCE_BOOT;
555 write_stats(curr, USE_SADC, &count, NO_TM_START, NO_TM_END, NO_RESET,
556 ALL_ACTIVITIES, TRUE);
562 ***************************************************************************
563 * Read data sent by the data collector.
566 * @size Number of bytes of data to read.
569 * @buffer Buffer where data will be saved.
572 * 1 if end of file has been reached, 0 otherwise.
573 ***************************************************************************
575 int sa_read(void *buffer, int size)
581 if ((n = read(STDIN_FILENO, buffer, size)) < 0) {
590 buffer = (char *) buffer + n;
597 ***************************************************************************
598 * Display a restart message (contents of a R_RESTART record).
601 * @tab Number of tabulations (unused here).
602 * @action Action expected from current function (unused here).
603 * @cur_date Date string of current restart message (unused here).
604 * @cur_time Time string of current restart message.
605 * @utc True if @cur_time is expressed in UTC (unused here).
606 * @file_hdr System activity file standard header (unused here).
607 ***************************************************************************
609 __printf_funct_t print_sar_restart(int *tab, int action, char *cur_date, char *cur_time,
610 int utc, struct file_header *file_hdr)
614 printf("\n%-11s", cur_time);
615 sprintf(restart, " LINUX RESTART\t(%d CPU)\n",
616 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
617 cprintf_s(IS_RESTART, "%s", restart);
622 ***************************************************************************
623 * Display a comment (contents of R_COMMENT record).
626 * @tab Number of tabulations (unused here).
627 * @action Action expected from current function (unused here).
628 * @cur_date Date string of current comment (unused here).
629 * @cur_time Time string of current comment.
630 * @utc True if @cur_time is expressed in UTC (unused here).
631 * @comment Comment to display.
632 * @file_hdr System activity file standard header (unused here).
633 ***************************************************************************
635 __print_funct_t print_sar_comment(int *tab, int action, char *cur_date, char *cur_time, int utc,
636 char *comment, struct file_header *file_hdr)
638 printf("%-11s", cur_time);
639 cprintf_s(IS_COMMENT, " COM %s\n", comment);
643 ***************************************************************************
644 * Read the various statistics sent by the data collector (sadc).
647 * @curr Index in array for current sample statistics.
648 ***************************************************************************
650 void read_sadc_stat_bunch(int curr)
654 /* Read record header (type is always R_STATS since it is read from sadc) */
655 if (sa_read(&record_hdr[curr], RECORD_HEADER_SIZE)) {
657 * SIGINT (sent by sadc) is likely to be received
658 * while we are stuck in sa_read().
659 * If this happens then no data have to be read.
664 print_read_error(END_OF_DATA_UNEXPECTED);
667 for (i = 0; i < NR_ACT; i++) {
671 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
673 if (HAS_COUNT_FUNCTION(act[p]->options)) {
674 if (sa_read(&(act[p]->nr[curr]), sizeof(__nr_t))) {
675 print_read_error(END_OF_DATA_UNEXPECTED);
677 if (act[p]->nr[curr] > act[p]->nr_max) {
678 print_read_error(INCONSISTENT_INPUT_DATA);
680 if (act[p]->nr[curr] > act[p]->nr_allocated) {
681 reallocate_all_buffers(act[p]);
686 * For persistent activities, we must make sure that no statistics
687 * from a previous iteration remain, especially if the number
688 * of structures read is smaller than @nr_ini.
690 if (HAS_PERSISTENT_VALUES(act[p]->options)) {
691 memset(act[p]->buf[curr], 0,
692 (size_t) act[p]->fsize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
695 if (sa_read(act[p]->buf[curr], act[p]->fsize * act[p]->nr[curr] * act[p]->nr2)) {
696 print_read_error(END_OF_DATA_UNEXPECTED);
702 ***************************************************************************
703 * Read stats for current activity from file and display them.
706 * @ifd Input file descriptor.
707 * @fpos Position in file where reading must start.
708 * @curr Index in array for current sample statistics.
709 * @rows Number of rows of screen.
710 * @act_id Activity to display.
711 * @file_actlst List of activities in file.
712 * @file Name of file being read.
713 * @file_magic file_magic structure filled with file magic header data.
714 * @rec_hdr_tmp Temporary buffer where current record header will be saved.
716 * TRUE if file's data don't match current machine's endianness.
717 * @arch_64 TRUE if file's data come from a 64 bit machine.
720 * @curr Index in array for next sample statistics.
721 * @cnt Number of remaining lines of stats to write.
722 * @eosaf Set to TRUE if EOF (end of file) has been reached.
723 * @reset Set to TRUE if last_uptime variable should be reinitialized
724 * (used in next_slice() function).
725 ***************************************************************************
727 void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
728 int rows, unsigned int act_id, int *reset,
729 struct file_activity *file_actlst, char *file,
730 struct file_magic *file_magic, void *rec_hdr_tmp,
731 int endian_mismatch, int arch_64)
734 unsigned long lines = 0;
736 int davg = 0, next, inc;
738 if (lseek(ifd, fpos, SEEK_SET) < fpos) {
744 * Restore the first stats collected.
745 * Used to compute the rate displayed on the first line.
747 copy_structures(act, id_seq, record_hdr, !*curr, 2);
751 /* Assess number of lines printed */
752 p = get_activity_position(act, act_id, EXIT_IF_NOT_FOUND);
753 if (act[p]->bitmap) {
754 inc = count_bits(act[p]->bitmap->b_array,
755 BITMAP_SIZE(act[p]->bitmap->b_size));
758 inc = act[p]->nr[*curr];
765 * Display <count> lines of stats.
766 * Start with reading current sample's record header.
768 *eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[*curr],
769 &file_hdr, arch_64, endian_mismatch);
770 rtype = record_hdr[*curr].record_type;
772 if (!*eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
773 /* Read the extra fields since it's not a special record */
774 read_file_stat_bunch(act, *curr, ifd, file_hdr.sa_act_nr, file_actlst,
775 endian_mismatch, arch_64, file, file_magic);
778 if ((lines >= rows) || !lines) {
785 if (!*eosaf && (rtype != R_RESTART)) {
787 if (rtype == R_COMMENT) {
788 /* Display comment */
789 next = print_special_record(&record_hdr[*curr], flags + S_F_LOCAL_TIME,
790 &tm_start, &tm_end, R_COMMENT, ifd,
791 &rectime, NULL, file, 0,
792 file_magic, &file_hdr, act, &sar_fmt,
793 endian_mismatch, arch_64);
795 /* A line of comment was actually displayed */
801 /* next is set to 1 when we were close enough to desired interval */
802 next = write_stats(*curr, USE_SA_FILE, cnt, tm_start.use, tm_end.use,
803 *reset, act_id, reset_cd);
805 if (next && (*cnt > 0)) {
816 while (*cnt && !*eosaf && (rtype != R_RESTART));
819 write_stats_avg(!*curr, USE_SA_FILE, act_id);
826 ***************************************************************************
827 * Read header data sent by sadc.
828 ***************************************************************************
830 void read_header_data(void)
832 struct file_magic file_magic;
833 struct file_activity file_act;
837 /* Read magic header */
838 rc = sa_read(&file_magic, FILE_MAGIC_SIZE);
840 sprintf(version, "%d.%d.%d.%d",
841 file_magic.sysstat_version,
842 file_magic.sysstat_patchlevel,
843 file_magic.sysstat_sublevel,
844 file_magic.sysstat_extraversion);
845 if (!file_magic.sysstat_extraversion) {
846 version[strlen(version) - 2] = '\0';
849 if (rc || (file_magic.sysstat_magic != SYSSTAT_MAGIC) ||
850 (file_magic.format_magic != FORMAT_MAGIC) ||
851 strcmp(version, VERSION)) {
853 /* sar and sadc commands are not consistent */
854 if (!rc && (file_magic.sysstat_magic == SYSSTAT_MAGIC)) {
856 _("Using a wrong data collector from a different sysstat version\n"));
859 print_read_error(INCONSISTENT_INPUT_DATA);
864 * No need to take into account file_magic.header_size. We are sure that
865 * sadc and sar are from the same version (we have checked FORMAT_MAGIC
866 * but also VERSION above) and thus the size of file_header is FILE_HEADER_SIZE.
868 if (sa_read(&file_hdr, FILE_HEADER_SIZE)) {
869 print_read_error(END_OF_DATA_UNEXPECTED);
872 /* All activities are not necessarily selected, but NR_ACT is a max */
873 if (file_hdr.sa_act_nr > NR_ACT) {
874 print_read_error(INCONSISTENT_INPUT_DATA);
877 if ((file_hdr.act_size != FILE_ACTIVITY_SIZE) ||
878 (file_hdr.rec_size != RECORD_HEADER_SIZE)) {
879 print_read_error(INCONSISTENT_INPUT_DATA);
882 /* Read activity list */
883 for (i = 0; i < file_hdr.sa_act_nr; i++) {
885 if (sa_read(&file_act, FILE_ACTIVITY_SIZE)) {
886 print_read_error(END_OF_DATA_UNEXPECTED);
889 p = get_activity_position(act, file_act.id, RESUME_IF_NOT_FOUND);
891 if ((p < 0) || (act[p]->fsize != file_act.size)
892 || (act[p]->gtypes_nr[0] != file_act.types_nr[0])
893 || (act[p]->gtypes_nr[1] != file_act.types_nr[1])
894 || (act[p]->gtypes_nr[2] != file_act.types_nr[2])
895 || (file_act.nr <= 0)
896 || (file_act.nr2 <= 0)
897 || (act[p]->magic != file_act.magic)) {
898 /* Remember that we are reading data from sadc and not from a file... */
899 print_read_error(INCONSISTENT_INPUT_DATA);
902 id_seq[i] = file_act.id; /* We necessarily have "i < NR_ACT" */
903 act[p]->nr_ini = file_act.nr;
904 act[p]->nr2 = file_act.nr2;
911 /* Check that all selected activties are actually sent by sadc */
912 reverse_check_act(file_hdr.sa_act_nr);
918 ***************************************************************************
919 * Read statistics from a system activity data file.
922 * @from_file Input file name.
923 ***************************************************************************
925 void read_stats_from_file(char from_file[])
927 struct file_magic file_magic;
928 struct file_activity *file_actlst = NULL;
929 char rec_hdr_tmp[MAX_RECORD_HEADER_SIZE];
932 int rows, eosaf = TRUE, reset = FALSE;
936 /* Get window size */
937 rows = get_win_height();
939 /* Read file headers and activity list */
940 check_file_actlst(&ifd, from_file, act, &file_magic, &file_hdr,
941 &file_actlst, id_seq, FALSE, &endian_mismatch, &arch_64);
943 /* Perform required allocations */
944 allocate_structures(act);
946 /* Print report header */
947 print_report_hdr(flags, &rectime, &file_hdr);
949 /* Read system statistics from file */
952 * If this record is a special (RESTART or COMMENT) one, print it and
953 * (try to) get another one.
956 if (read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[0], &file_hdr,
957 arch_64, endian_mismatch)) {
958 /* End of sa data file */
962 rtype = record_hdr[0].record_type;
963 if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
964 print_special_record(&record_hdr[0], flags + S_F_LOCAL_TIME,
965 &tm_start, &tm_end, rtype, ifd,
966 &rectime, NULL, from_file, 0, &file_magic,
967 &file_hdr, act, &sar_fmt, endian_mismatch, arch_64);
971 * OK: Previous record was not a special one.
972 * So read now the extra fields.
974 read_file_stat_bunch(act, 0, ifd, file_hdr.sa_act_nr,
975 file_actlst, endian_mismatch, arch_64,
976 from_file, &file_magic);
977 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME,
981 * An error was detected.
982 * The timestamp hasn't been updated.
987 while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
988 (tm_start.use && (datecmp(&rectime, &tm_start) < 0)) ||
989 (tm_end.use && (datecmp(&rectime, &tm_end) >=0)));
991 /* Save the first stats collected. Will be used to compute the average */
992 copy_structures(act, id_seq, record_hdr, 2, 0);
994 reset = TRUE; /* Set flag to reset last_uptime variable */
996 /* Save current file position */
997 if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
1003 * Read and write stats located between two possible Linux restarts.
1004 * Activities that should be displayed are saved in id_seq[] array.
1005 * Since we are reading from a file, we print all the stats for an
1006 * activity before displaying the next activity.
1007 * id_seq[] has been created in check_file_actlst(), retaining only
1008 * activities known by current sysstat version.
1010 for (i = 0; i < NR_ACT; i++) {
1015 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1016 if (!IS_SELECTED(act[p]->options))
1019 if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
1020 handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
1021 act[p]->id, &reset, file_actlst,
1022 from_file, &file_magic, rec_hdr_tmp,
1023 endian_mismatch, arch_64);
1026 unsigned int optf, msk;
1028 optf = act[p]->opt_flags;
1030 for (msk = 1; msk < 0x100; msk <<= 1) {
1031 if ((act[p]->opt_flags & 0xff) & msk) {
1032 act[p]->opt_flags &= (0xffffff00 + msk);
1034 handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
1035 rows, act[p]->id, &reset, file_actlst,
1036 from_file, &file_magic, rec_hdr_tmp,
1037 endian_mismatch, arch_64);
1038 act[p]->opt_flags = optf;
1045 /* Go to next Linux restart, if possible */
1047 /* Read next record header */
1048 eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[curr],
1049 &file_hdr, arch_64, endian_mismatch);
1050 rtype = record_hdr[curr].record_type;
1052 if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
1053 read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
1054 file_actlst, endian_mismatch, arch_64,
1055 from_file, &file_magic);
1057 else if (!eosaf && (rtype == R_COMMENT)) {
1058 /* This was a COMMENT record: print it */
1059 print_special_record(&record_hdr[curr], flags + S_F_LOCAL_TIME,
1060 &tm_start, &tm_end, R_COMMENT, ifd,
1061 &rectime, NULL, from_file, 0,
1062 &file_magic, &file_hdr, act, &sar_fmt,
1063 endian_mismatch, arch_64);
1066 while (!eosaf && (rtype != R_RESTART));
1069 /* The last record we read was a RESTART one: Print it */
1070 if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
1071 print_special_record(&record_hdr[curr], flags + S_F_LOCAL_TIME,
1072 &tm_start, &tm_end, R_RESTART, ifd,
1073 &rectime, NULL, from_file, 0,
1074 &file_magic, &file_hdr, act, &sar_fmt,
1075 endian_mismatch, arch_64);
1086 ***************************************************************************
1087 * Read statistics sent by sadc, the data collector.
1088 ***************************************************************************
1090 void read_stats(void)
1093 unsigned long lines;
1097 /* Don't buffer data if redirected to a pipe... */
1098 setbuf(stdout, NULL);
1100 /* Read stats header */
1103 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1104 fprintf(stderr, _("Requested activities not available\n"));
1108 /* Determine if a stat line header has to be displayed */
1109 dis_hdr = check_line_hdr();
1111 lines = rows = get_win_height();
1113 /* Perform required allocations */
1114 allocate_structures(act);
1116 /* Print report header */
1117 print_report_hdr(flags, &rectime, &file_hdr);
1119 /* Read system statistics sent by the data collector */
1120 read_sadc_stat_bunch(0);
1123 /* Display stats since boot time and exit */
1124 write_stats_startup(0);
1127 /* Save the first stats collected. Will be used to compute the average */
1128 copy_structures(act, id_seq, record_hdr, 2, 0);
1130 /* Set a handler for SIGINT */
1131 memset(&int_act, 0, sizeof(int_act));
1132 int_act.sa_handler = int_handler;
1133 int_act.sa_flags = SA_RESTART;
1134 sigaction(SIGINT, &int_act, NULL);
1140 read_sadc_stat_bunch(curr);
1141 if (sigint_caught) {
1143 * SIGINT signal caught (it is sent by sadc).
1144 * => Display average stats.
1146 curr ^= 1; /* No data retrieved from last read */
1158 write_stats(curr, USE_SADC, &count, NO_TM_START, tm_end.use,
1159 NO_RESET, ALL_ACTIVITIES, TRUE);
1161 if (record_hdr[curr].record_type == R_LAST_STATS) {
1162 /* File rotation is happening: Re-read header data sent by sadc */
1164 allocate_structures(act);
1177 * Print statistics average.
1178 * At least one line of stats must have been displayed for this.
1179 * (There may be no lines at all if we press Ctrl/C immediately).
1183 write_stats_avg(curr, USE_SADC, ALL_ACTIVITIES);
1188 ***************************************************************************
1189 * Main entry to the sar program.
1190 ***************************************************************************
1192 int main(int argc, char **argv)
1194 int i, rc, opt = 1, args_idx = 2;
1197 char from_file[MAX_FILE_LEN], to_file[MAX_FILE_LEN];
1200 /* Compute page shift in kB */
1203 from_file[0] = to_file[0] = '\0';
1206 /* Init National Language Support */
1210 /* Init color strings */
1213 tm_start.use = tm_end.use = FALSE;
1215 /* Allocate and init activity bitmaps */
1216 allocate_bitmaps(act);
1220 /* Process options */
1221 while (opt < argc) {
1223 if (!strcmp(argv[opt], "--sadc")) {
1228 else if (!strcmp(argv[opt], "--human")) {
1229 /* Display sizes in a human readable format */
1234 else if (!strcmp(argv[opt], "-I")) {
1235 /* Parse -I option */
1236 if (parse_sar_I_opt(argv, &opt, act)) {
1241 else if (!strcmp(argv[opt], "-D")) {
1242 /* Option to tell sar to write to saYYYYMMDD data files */
1243 flags |= S_F_SA_YYYYMMDD;
1247 else if (!strcmp(argv[opt], "-P")) {
1248 /* Parse -P option */
1249 if (parse_sa_P_opt(argv, &opt, &flags, act)) {
1254 else if (!strcmp(argv[opt], "-o")) {
1256 /* Output file already specified */
1259 /* Save stats to a file */
1260 if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
1261 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1262 strncpy(to_file, argv[opt++], MAX_FILE_LEN);
1263 to_file[MAX_FILE_LEN - 1] = '\0';
1266 strcpy(to_file, "-");
1270 else if (!strcmp(argv[opt], "-f")) {
1271 if (from_file[0] || day_offset) {
1272 /* Input file already specified */
1275 /* Read stats from a file */
1276 if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
1277 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1278 strncpy(from_file, argv[opt++], MAX_FILE_LEN);
1279 from_file[MAX_FILE_LEN - 1] = '\0';
1280 /* Check if this is an alternate directory for sa files */
1281 check_alt_sa_dir(from_file, day_offset, -1);
1284 set_default_file(from_file, day_offset, -1);
1288 else if (!strcmp(argv[opt], "-s")) {
1289 /* Get time start */
1290 if (parse_timestamp(argv, &opt, &tm_start, DEF_TMSTART)) {
1295 else if (!strcmp(argv[opt], "-e")) {
1297 if (parse_timestamp(argv, &opt, &tm_end, DEF_TMEND)) {
1302 else if (!strcmp(argv[opt], "-h")) {
1303 /* Display help message */
1304 display_help(argv[0]);
1307 else if (!strcmp(argv[opt], "-i")) {
1308 if (!argv[++opt] || (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1311 interval = atol(argv[opt++]);
1315 flags |= S_F_INTERVAL_SET;
1318 else if (!strcmp(argv[opt], "-m")) {
1322 /* Parse option -m */
1323 if (parse_sar_m_opt(argv, &opt, act)) {
1328 else if (!strcmp(argv[opt], "-n")) {
1332 /* Parse option -n */
1333 if (parse_sar_n_opt(argv, &opt, act)) {
1338 else if ((strlen(argv[opt]) > 1) &&
1339 (strlen(argv[opt]) < 4) &&
1340 !strncmp(argv[opt], "-", 1) &&
1341 (strspn(argv[opt] + 1, DIGITS) == (strlen(argv[opt]) - 1))) {
1342 if (from_file[0] || day_offset) {
1343 /* Input file already specified */
1346 day_offset = atoi(argv[opt++] + 1);
1349 else if (!strncmp(argv[opt], "-", 1)) {
1350 /* Other options not previously tested */
1351 if ((rc = parse_sar_opt(argv, &opt, act, &flags, C_SAR)) != 0) {
1360 else if (interval < 0) {
1362 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
1365 interval = atol(argv[opt++]);
1372 /* Get count value */
1373 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
1378 /* Count parameter already set */
1381 count = atol(argv[opt++]);
1388 /* 'sar' is equivalent to 'sar -f' */
1390 ((interval < 0) && !from_file[0] && !to_file[0])) {
1391 set_default_file(from_file, day_offset, -1);
1394 if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) {
1395 tm_end.tm_hour += 24;
1399 * Check option dependencies.
1401 /* You read from a file OR you write to it... */
1402 if (from_file[0] && to_file[0]) {
1403 fprintf(stderr, _("-f and -o options are mutually exclusive\n"));
1406 /* Use time start or option -i only when reading stats from a file */
1407 if ((tm_start.use || INTERVAL_SET(flags)) && !from_file[0]) {
1409 _("Not reading from a system activity file (use -f option)\n"));
1412 /* Don't print stats since boot time if -o or -f options are used */
1413 if (!interval && (from_file[0] || to_file[0])) {
1417 /* Cannot enter a day shift with -o option */
1418 if (to_file[0] && day_offset) {
1422 if (USE_PRETTY_OPTION(flags)) {
1423 dm_major = get_devmap_major();
1428 * count parameter not set: Display all the contents of the file
1429 * or generate a report continuously.
1434 /* Default is CPU activity... */
1435 select_default_activity(act);
1437 /* Reading stats from file: */
1443 /* Read stats from file */
1444 read_stats_from_file(from_file);
1446 /* Free stuctures and activity bitmaps */
1448 free_structures(act);
1453 /* Reading stats from sadc: */
1455 /* Create anonymous pipe */
1456 if (pipe(fd) == -1) {
1469 if (dup2(fd[1], STDOUT_FILENO) < 0) {
1476 * Prepare options for sadc.
1481 /* Interval value */
1485 else if (!interval) {
1489 sprintf(ltemp, "%ld", interval);
1495 sprintf(ltemp, "%ld", count + 1);
1496 salloc(args_idx++, ltemp);
1499 /* Flags to be passed to sadc */
1500 salloc(args_idx++, "-z");
1502 /* Writing data to a file (option -o) */
1504 /* Set option -D if entered */
1505 if (USE_SA_YYYYMMDD(flags)) {
1506 salloc(args_idx++, "-D");
1508 /* Collect all possible activities (option -S XALL for sadc) */
1509 salloc(args_idx++, "-S");
1510 salloc(args_idx++, K_XALL);
1512 salloc(args_idx++, to_file);
1516 * If option -o hasn't been used, then tell sadc
1517 * to collect only activities that will be displayed.
1521 for (i = 0; i < NR_ACT; i++) {
1522 if (IS_SELECTED(act[i]->options)) {
1523 act_id |= act[i]->group;
1528 snprintf(ltemp, 19, "%d", act_id);
1530 salloc(args_idx++, "-S");
1531 salloc(args_idx++, ltemp);
1535 /* Last arg is NULL */
1536 args[args_idx] = NULL;
1538 /* Call now the data collector */
1539 execv(SADC_PATH, args);
1542 * Note: Don't use execl/execlp since we don't have a fixed number of
1543 * args to give to sadc.
1545 fprintf(stderr, _("Cannot find the data collector (%s)\n"), SADC);
1550 default: /* Parent */
1551 if (dup2(fd[0], STDIN_FILENO) < 0) {
1557 /* Get now the statistics */
1563 /* Free structures and activity bitmaps */
1565 free_structures(act);