2 * sar: report system activity
3 * (C) 1999-2014 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 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
19 ***************************************************************************
39 #define _(string) gettext(string)
41 #define _(string) (string)
44 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
45 char *sccsid(void) { return (SCCSID); }
47 /* Interval and count parameters */
48 long interval = -1, count = 0;
50 /* TRUE if a header line must be printed */
53 unsigned int flags = 0;
54 unsigned int dm_major; /* Device-mapper major number */
56 char timestamp[2][TIMESTAMP_LEN];
58 unsigned long avg_count = 0;
61 struct file_header file_hdr;
63 /* Current record header */
64 struct record_header record_hdr[3];
68 * This array must always be entirely filled (even with trailing zeros).
70 unsigned int id_seq[NR_ACT];
74 /* Contain the date specified by -s and -e options */
75 struct tstamp tm_start, tm_end;
77 char *args[MAX_ARGV_NR];
79 extern struct activity *act[];
81 struct sigaction int_act;
82 int sigint_caught = 0;
85 ***************************************************************************
86 * Print usage title message.
89 * @progname Name of sysstat command
90 ***************************************************************************
92 void print_usage_title(FILE *fp, char *progname)
94 fprintf(fp, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
99 ***************************************************************************
100 * Print usage and exit.
103 * @progname Name of sysstat command
104 ***************************************************************************
106 void usage(char *progname)
108 print_usage_title(stderr, progname);
109 fprintf(stderr, _("Options are:\n"
110 "[ -A ] [ -B ] [ -b ] [ -C ] [ -D ] [ -d ] [ -F [ MOUNTS ] ] [ -H ] [ -h ]\n"
111 "[ -p ] [ -q ] [ -R ] [ -r [ ALL ] ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ]\n"
112 "[ -v ] [ -W ] [ -w ] [ -y ]\n"
113 "[ -I { <int> [,...] | SUM | ALL | XALL } ] [ -P { <cpu> [,...] | ALL } ]\n"
114 "[ -m { <keyword> [,...] | ALL } ] [ -n { <keyword> [,...] | ALL } ]\n"
115 "[ -j { ID | LABEL | PATH | UUID | ... } ]\n"
116 "[ -f [ <filename> ] | -o [ <filename> ] | -[0-9]+ ]\n"
117 "[ -i <interval> ] [ -s [ <hh:mm[:ss]> ] ] [ -e [ <hh:mm[:ss]> ] ]\n"));
122 ***************************************************************************
123 * Display a short help message and exit.
126 * @progname Name of sysstat command
127 ***************************************************************************
129 void display_help(char *progname)
131 print_usage_title(stdout, progname);
132 printf(_("Main options and reports:\n"));
133 printf(_("\t-B\tPaging statistics\n"));
134 printf(_("\t-b\tI/O and transfer rate statistics\n"));
135 printf(_("\t-d\tBlock devices statistics\n"));
136 printf(_("\t-F [ MOUNTS ]\n"));
137 printf(_("\t\tFilesystems statistics\n"));
138 printf(_("\t-H\tHugepages utilization statistics\n"));
139 printf(_("\t-I { <int> | SUM | ALL | XALL }\n"
140 "\t\tInterrupts statistics\n"));
141 printf(_("\t-m { <keyword> [,...] | ALL }\n"
142 "\t\tPower management statistics\n"
143 "\t\tKeywords are:\n"
144 "\t\tCPU\tCPU instantaneous clock frequency\n"
145 "\t\tFAN\tFans speed\n"
146 "\t\tFREQ\tCPU average clock frequency\n"
147 "\t\tIN\tVoltage inputs\n"
148 "\t\tTEMP\tDevices temperature\n"
149 "\t\tUSB\tUSB devices plugged into the system\n"));
150 printf(_("\t-n { <keyword> [,...] | ALL }\n"
151 "\t\tNetwork statistics\n"
152 "\t\tKeywords are:\n"
153 "\t\tDEV\tNetwork interfaces\n"
154 "\t\tEDEV\tNetwork interfaces (errors)\n"
155 "\t\tNFS\tNFS client\n"
156 "\t\tNFSD\tNFS server\n"
157 "\t\tSOCK\tSockets\t(v4)\n"
158 "\t\tIP\tIP traffic\t(v4)\n"
159 "\t\tEIP\tIP traffic\t(v4) (errors)\n"
160 "\t\tICMP\tICMP traffic\t(v4)\n"
161 "\t\tEICMP\tICMP traffic\t(v4) (errors)\n"
162 "\t\tTCP\tTCP traffic\t(v4)\n"
163 "\t\tETCP\tTCP traffic\t(v4) (errors)\n"
164 "\t\tUDP\tUDP traffic\t(v4)\n"
165 "\t\tSOCK6\tSockets\t(v6)\n"
166 "\t\tIP6\tIP traffic\t(v6)\n"
167 "\t\tEIP6\tIP traffic\t(v6) (errors)\n"
168 "\t\tICMP6\tICMP traffic\t(v6)\n"
169 "\t\tEICMP6\tICMP traffic\t(v6) (errors)\n"
170 "\t\tUDP6\tUDP traffic\t(v6)\n"));
171 printf(_("\t-q\tQueue length and load average statistics\n"));
172 printf(_("\t-R\tMemory statistics\n"));
173 printf(_("\t-r [ ALL ]\n"
174 "\t\tMemory utilization statistics\n"));
175 printf(_("\t-S\tSwap space utilization statistics\n"));
176 printf(_("\t-u [ ALL ]\n"
177 "\t\tCPU utilization statistics\n"));
178 printf(_("\t-v\tKernel tables statistics\n"));
179 printf(_("\t-W\tSwapping statistics\n"));
180 printf(_("\t-w\tTask creation and system switching statistics\n"));
181 printf(_("\t-y\tTTY devices statistics\n"));
186 ***************************************************************************
187 * SIGINT signal handler.
190 * @sig Signal number.
191 ***************************************************************************
193 void int_handler(int sig)
196 printf("\n"); /* Skip "^C" displayed on screen */
201 ***************************************************************************
202 * Init some structures.
203 ***************************************************************************
205 void init_structures(void)
209 for (i = 0; i < 3; i++)
210 memset(&record_hdr[i], 0, RECORD_HEADER_SIZE);
214 ***************************************************************************
215 * Allocate memory for sadc args.
218 * @i Argument number.
219 * @ltemp Argument value.
220 ***************************************************************************
222 void salloc(int i, char *ltemp)
224 if ((args[i] = (char *) malloc(strlen(ltemp) + 1)) == NULL) {
228 strcpy(args[i], ltemp);
232 ***************************************************************************
233 * Display an error message. Happens when the data collector doesn't send
235 ***************************************************************************
237 void print_read_error(void)
239 fprintf(stderr, _("End of data collecting unexpected\n"));
244 ***************************************************************************
245 * Check that every selected activity actually belongs to the sequence list.
246 * If not, then the activity should be unselected since it will not be sent
247 * by sadc. An activity can be not sent if its number of items is null.
250 * @act_nr Size of sequence list.
251 ***************************************************************************
253 void reverse_check_act(unsigned int act_nr)
257 for (i = 0; i < NR_ACT; i++) {
259 if (IS_SELECTED(act[i]->options)) {
261 for (j = 0; j < act_nr; j++) {
262 if (id_seq[j] == act[i]->id)
266 act[i]->options &= ~AO_SELECTED;
272 ***************************************************************************
273 * Fill the (struct tm) rectime structure with current record's time,
274 * based on current record's time data saved in file.
275 * The resulting timestamp is expressed in the locale of the file creator
276 * or in the user's own locale depending on whether option -t has been used
280 * @curr Index in array for current sample statistics.
283 * 1 if an error was detected, or 0 otherwise.
284 ***************************************************************************
286 int sar_get_record_timestamp_struct(int curr)
290 /* Check if option -t was specified on the command line */
291 if (PRINT_TRUE_TIME(flags)) {
293 rectime.tm_hour = record_hdr[curr].hour;
294 rectime.tm_min = record_hdr[curr].minute;
295 rectime.tm_sec = record_hdr[curr].second;
298 if ((ltm = localtime((const time_t *) &record_hdr[curr].ust_time)) == NULL)
300 * An error was detected.
301 * The rectime structure has NOT been updated.
312 ***************************************************************************
313 * Determine if a stat header line has to be displayed.
316 * TRUE if a header line has to be displayed.
317 ***************************************************************************
319 int check_line_hdr(void)
323 /* Get number of options entered on the command line */
324 if (get_activity_nr(act, AO_SELECTED, COUNT_OUTPUTS) > 1)
327 for (i = 0; i < NR_ACT; i++) {
328 if (IS_SELECTED(act[i]->options)) {
329 /* Special processing for activities using a bitmap */
330 if (act[i]->bitmap) {
331 if (count_bits(act[i]->bitmap->b_array,
332 BITMAP_SIZE(act[i]->bitmap->b_size)) > 1) {
336 else if (act[i]->nr > 1) {
339 /* Stop now since we have only one selected activity */
348 ***************************************************************************
349 * Set current record's timestamp string.
352 * @curr Index in array for current sample statistics.
353 * @len Maximum length of timestamp string.
356 * @cur_time Timestamp string.
359 * 1 if an error was detected, or 0 otherwise.
360 ***************************************************************************
362 int set_record_timestamp_string(int curr, char *cur_time, int len)
364 /* Fill timestamp structure */
365 if (sar_get_record_timestamp_struct(curr))
369 /* Set cur_time date value */
370 strftime(cur_time, len, "%X", &rectime);
376 ***************************************************************************
377 * Print statistics average.
380 * @curr Index in array for current sample statistics.
381 * @read_from_file Set to TRUE if stats are read from a system activity
383 * @act_id Activity that can be displayed, or ~0 for all.
384 * Remember that when reading stats from a file, only
385 * one activity can be displayed at a time.
386 ***************************************************************************
388 void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
391 unsigned long long itv, g_itv;
392 static __nr_t cpu_nr = -1;
395 cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr;
397 /* Interval value in jiffies */
398 g_itv = get_interval(record_hdr[2].uptime, record_hdr[curr].uptime);
401 itv = get_interval(record_hdr[2].uptime0, record_hdr[curr].uptime0);
405 strncpy(timestamp[curr], _("Average:"), TIMESTAMP_LEN);
406 timestamp[curr][TIMESTAMP_LEN - 1] = '\0';
407 strcpy(timestamp[!curr], timestamp[curr]);
410 TEST_STDOUT(STDOUT_FILENO);
412 for (i = 0; i < NR_ACT; i++) {
414 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
417 if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
418 /* Display current average activity statistics */
419 (*act[i]->f_print_avg)(act[i], 2, curr,
420 NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
424 if (read_from_file) {
426 * Reset number of lines printed only if we read stats
427 * from a system activity file.
434 ***************************************************************************
435 * Print system statistics.
438 * @curr Index in array for current sample statistics.
439 * @read_from_file Set to TRUE if stats are read from a system activity
441 * @use_tm_start Set to TRUE if option -s has been used.
442 * @use_tm_end Set to TRUE if option -e has been used.
443 * @reset Set to TRUE if last_uptime variable should be
444 * reinitialized (used in next_slice() function).
445 * @act_id Activity that can be displayed or ~0 for all.
446 * Remember that when reading stats from a file, only
447 * one activity can be displayed at a time.
448 * @reset_cd TRUE if static cross_day variable should be reset
452 * @cnt Number of remaining lines to display.
455 * 1 if stats have been successfully displayed, and 0 otherwise.
456 ***************************************************************************
458 int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start,
459 int use_tm_end, int reset, unsigned int act_id, int reset_cd)
462 unsigned long long itv, g_itv;
463 static int cross_day = 0;
464 static __nr_t cpu_nr = -1;
467 cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr;
471 * cross_day is a static variable that is set to 1 when the first
472 * record of stats from a new day is read from a unique data file
473 * (in the case where the file contains data from two consecutive
474 * days). When set to 1, every following records timestamp will
475 * have its hour value increased by 24.
476 * Yet when a new activity (being read from the file) is going to
477 * be displayed, we start reading the file from the beginning
478 * again, and so cross_day should be reset in this case.
484 if (read_from_file) {
485 if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0,
487 /* Not close enough to desired interval */
491 /* Set previous timestamp */
492 if (set_record_timestamp_string(!curr, timestamp[!curr], 16))
494 /* Set current timestamp */
495 if (set_record_timestamp_string(curr, timestamp[curr], 16))
498 /* Check if we are beginning a new day */
499 if (use_tm_start && record_hdr[!curr].ust_time &&
500 (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
501 (record_hdr[curr].hour < record_hdr[!curr].hour)) {
507 * This is necessary if we want to properly handle something like:
508 * sar -s time_start -e time_end with
509 * time_start(day D) > time_end(day D+1)
511 rectime.tm_hour +=24;
515 if (use_tm_start && (datecmp(&rectime, &tm_start) < 0))
516 /* it's too soon... */
519 /* Get interval values */
520 get_itv_value(&record_hdr[curr], &record_hdr[!curr],
521 cpu_nr, &itv, &g_itv);
524 if (use_tm_end && (datecmp(&rectime, &tm_end) > 0)) {
525 /* It's too late... */
533 TEST_STDOUT(STDOUT_FILENO);
535 for (i = 0; i < NR_ACT; i++) {
537 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
540 if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
541 /* Display current activity statistics */
542 (*act[i]->f_print)(act[i], !curr, curr,
543 NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
551 ***************************************************************************
552 * Display stats since system startup.
555 * @curr Index in array for current sample statistics.
556 ***************************************************************************
558 void write_stats_startup(int curr)
562 /* Set to 0 previous structures corresponding to boot time */
563 memset(&record_hdr[!curr], 0, RECORD_HEADER_SIZE);
564 record_hdr[!curr].record_type = R_STATS;
565 record_hdr[!curr].hour = record_hdr[curr].hour;
566 record_hdr[!curr].minute = record_hdr[curr].minute;
567 record_hdr[!curr].second = record_hdr[curr].second;
568 record_hdr[!curr].ust_time = record_hdr[curr].ust_time;
570 for (i = 0; i < NR_ACT; i++) {
571 if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
572 memset(act[i]->buf[!curr], 0,
573 (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
577 flags |= S_F_SINCE_BOOT;
580 write_stats(curr, USE_SADC, &count, NO_TM_START, NO_TM_END, NO_RESET,
581 ALL_ACTIVITIES, TRUE);
587 ***************************************************************************
588 * Read data sent by the data collector.
591 * @size Number of bytes of data to read.
594 * @buffer Buffer where data will be saved.
597 * 1 if end of file has been reached, 0 otherwise.
598 ***************************************************************************
600 int sa_read(void *buffer, int size)
606 if ((n = read(STDIN_FILENO, buffer, size)) < 0) {
615 buffer = (char *) buffer + n;
622 ***************************************************************************
623 * Print a Linux restart message (contents of a RESTART record) or a
624 * comment (contents of a COMMENT record).
627 * @curr Index in array for current sample statistics.
628 * @use_tm_start Set to TRUE if option -s has been used.
629 * @use_tm_end Set to TRUE if option -e has been used.
630 * @rtype Record type to display.
631 * @ifd Input file descriptor.
632 * @file Name of file being read.
633 * @file_magic file_magic structure filled with file magic header
637 * 1 if the record has been successfully displayed, and 0 otherwise.
638 ***************************************************************************
640 int sar_print_special(int curr, int use_tm_start, int use_tm_end, int rtype,
641 int ifd, char *file, struct file_magic *file_magic)
645 unsigned int new_cpu_nr;
647 if (set_record_timestamp_string(curr, cur_time, 26))
650 /* The record must be in the interval specified by -s/-e options */
651 if ((use_tm_start && (datecmp(&rectime, &tm_start) < 0)) ||
652 (use_tm_end && (datecmp(&rectime, &tm_end) > 0))) {
656 if (rtype == R_RESTART) {
657 /* Don't forget to read the volatile activities structures */
658 new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic,
659 file_hdr.sa_vol_act_nr);
662 printf("\n%-11s LINUX RESTART\t(%d CPU)\n",
663 cur_time, new_cpu_nr > 1 ? new_cpu_nr - 1 : 1);
667 else if (rtype == R_COMMENT) {
668 char file_comment[MAX_COMMENT_LEN];
670 /* Don't forget to read comment record even if it won't be displayed... */
671 sa_fread(ifd, file_comment, MAX_COMMENT_LEN, HARD_SIZE);
672 file_comment[MAX_COMMENT_LEN - 1] = '\0';
674 if (dp && DISPLAY_COMMENT(flags)) {
675 printf("%-11s COM %s\n", cur_time, file_comment);
684 ***************************************************************************
685 * Read the various statistics sent by the data collector (sadc).
688 * @curr Index in array for current sample statistics.
689 ***************************************************************************
691 void read_sadc_stat_bunch(int curr)
695 /* Read record header (type is always R_STATS since it is read from sadc) */
696 if (sa_read(&record_hdr[curr], RECORD_HEADER_SIZE)) {
700 for (i = 0; i < NR_ACT; i++) {
704 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
706 if (sa_read(act[p]->buf[curr], act[p]->fsize * act[p]->nr * act[p]->nr2)) {
713 ***************************************************************************
714 * Read stats for current activity from file and display them.
717 * @ifd Input file descriptor.
718 * @fpos Position in file where reading must start.
719 * @curr Index in array for current sample statistics.
720 * @rows Number of rows of screen.
721 * @act_id Activity to display.
722 * @file_actlst List of activities in file.
723 * @file Name of file being read.
724 * @file_magic file_magic structure filled with file magic header data.
727 * @curr Index in array for next sample statistics.
728 * @cnt Number of remaining lines of stats to write.
729 * @eosaf Set to TRUE if EOF (end of file) has been reached.
730 * @reset Set to TRUE if last_uptime variable should be
731 * reinitialized (used in next_slice() function).
732 ***************************************************************************
734 void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
735 int rows, unsigned int act_id, int *reset,
736 struct file_activity *file_actlst, char *file,
737 struct file_magic *file_magic)
740 unsigned long lines = 0;
742 int davg = 0, next, inc;
744 if (lseek(ifd, fpos, SEEK_SET) < fpos) {
750 * Restore the first stats collected.
751 * Used to compute the rate displayed on the first line.
753 copy_structures(act, id_seq, record_hdr, !*curr, 2);
757 /* Assess number of lines printed */
758 p = get_activity_position(act, act_id, EXIT_IF_NOT_FOUND);
759 if (act[p]->bitmap) {
760 inc = count_bits(act[p]->bitmap->b_array,
761 BITMAP_SIZE(act[p]->bitmap->b_size));
770 /* Display count lines of stats */
771 *eosaf = sa_fread(ifd, &record_hdr[*curr],
772 RECORD_HEADER_SIZE, SOFT_SIZE);
773 rtype = record_hdr[*curr].record_type;
775 if (!*eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
776 /* Read the extra fields since it's not a special record */
777 read_file_stat_bunch(act, *curr, ifd, file_hdr.sa_act_nr, file_actlst);
780 if ((lines >= rows) || !lines) {
787 if (!*eosaf && (rtype != R_RESTART)) {
789 if (rtype == R_COMMENT) {
790 /* Display comment */
791 next = sar_print_special(*curr, tm_start.use, tm_end.use,
792 R_COMMENT, ifd, file, file_magic);
794 /* A line of comment was actually displayed */
800 /* next is set to 1 when we were close enough to desired interval */
801 next = write_stats(*curr, USE_SA_FILE, cnt, tm_start.use, tm_end.use,
802 *reset, act_id, reset_cd);
804 if (next && (*cnt > 0)) {
815 while (*cnt && !*eosaf && (rtype != R_RESTART));
818 write_stats_avg(!*curr, USE_SA_FILE, act_id);
825 ***************************************************************************
826 * Read header data sent by sadc.
827 ***************************************************************************
829 void read_header_data(void)
831 struct file_magic file_magic;
832 struct file_activity file_act;
836 /* Read magic header */
837 rc = sa_read(&file_magic, FILE_MAGIC_SIZE);
839 sprintf(version, "%d.%d.%d.%d",
840 file_magic.sysstat_version,
841 file_magic.sysstat_patchlevel,
842 file_magic.sysstat_sublevel,
843 file_magic.sysstat_extraversion);
844 if (!file_magic.sysstat_extraversion) {
845 version[strlen(version) - 2] = '\0';
848 if (rc || (file_magic.sysstat_magic != SYSSTAT_MAGIC) ||
849 (file_magic.format_magic != FORMAT_MAGIC) ||
850 strcmp(version, VERSION)) {
852 /* sar and sadc commands are not consistent */
853 fprintf(stderr, _("Invalid data format\n"));
855 if (!rc && (file_magic.sysstat_magic == SYSSTAT_MAGIC)) {
857 _("Using a wrong data collector from a different sysstat version\n"));
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)) {
872 /* Read activity list */
873 for (i = 0; i < file_hdr.sa_act_nr; i++) {
875 if (sa_read(&file_act, FILE_ACTIVITY_SIZE)) {
879 p = get_activity_position(act, file_act.id, RESUME_IF_NOT_FOUND);
881 if ((p < 0) || (act[p]->fsize != file_act.size)
884 || (act[p]->magic != file_act.magic)) {
885 /* Remember that we are reading data from sadc and not from a file... */
886 fprintf(stderr, _("Inconsistent input data\n"));
890 id_seq[i] = file_act.id; /* We necessarily have "i < NR_ACT" */
891 act[p]->nr = file_act.nr;
892 act[p]->nr2 = file_act.nr2;
899 /* Check that all selected activties are actually sent by sadc */
900 reverse_check_act(file_hdr.sa_act_nr);
904 ***************************************************************************
905 * Read statistics from a system activity data file.
908 * @from_file Input file name.
909 ***************************************************************************
911 void read_stats_from_file(char from_file[])
913 struct file_magic file_magic;
914 struct file_activity *file_actlst = NULL;
917 int rows, eosaf = TRUE, reset = FALSE;
921 /* Get window size */
922 rows = get_win_height();
924 /* Read file headers and activity list */
925 check_file_actlst(&ifd, from_file, act, &file_magic, &file_hdr,
926 &file_actlst, id_seq, FALSE);
928 /* Perform required allocations */
929 allocate_structures(act);
931 /* Print report header */
932 print_report_hdr(flags, &rectime, &file_hdr,
933 act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr);
935 /* Read system statistics from file */
938 * If this record is a special (RESTART or COMMENT) one, print it and
939 * (try to) get another one.
942 if (sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE))
943 /* End of sa data file */
946 rtype = record_hdr[0].record_type;
947 if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
948 sar_print_special(0, tm_start.use, tm_end.use, rtype,
949 ifd, from_file, &file_magic);
953 * OK: Previous record was not a special one.
954 * So read now the extra fields.
956 read_file_stat_bunch(act, 0, ifd, file_hdr.sa_act_nr,
958 if (sar_get_record_timestamp_struct(0))
960 * An error was detected.
961 * The timestamp hasn't been updated.
966 while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
967 (tm_start.use && (datecmp(&rectime, &tm_start) < 0)) ||
968 (tm_end.use && (datecmp(&rectime, &tm_end) >=0)));
970 /* Save the first stats collected. Will be used to compute the average */
971 copy_structures(act, id_seq, record_hdr, 2, 0);
973 reset = TRUE; /* Set flag to reset last_uptime variable */
975 /* Save current file position */
976 if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
982 * Read and write stats located between two possible Linux restarts.
983 * Activities that should be displayed are saved in id_seq[] array.
985 for (i = 0; i < NR_ACT; i++) {
990 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
991 if (!IS_SELECTED(act[p]->options))
994 if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
995 handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
996 act[p]->id, &reset, file_actlst,
997 from_file, &file_magic);
1000 unsigned int optf, msk;
1002 optf = act[p]->opt_flags;
1004 for (msk = 1; msk < 0x100; msk <<= 1) {
1005 if ((act[p]->opt_flags & 0xff) & msk) {
1006 act[p]->opt_flags &= (0xffffff00 + msk);
1008 handle_curr_act_stats(ifd, fpos, &curr, &cnt,
1009 &eosaf, rows, act[p]->id,
1010 &reset, file_actlst,
1011 from_file, &file_magic);
1012 act[p]->opt_flags = optf;
1019 /* Go to next Linux restart, if possible */
1021 eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE,
1023 rtype = record_hdr[curr].record_type;
1024 if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
1025 read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
1028 else if (!eosaf && (rtype == R_COMMENT)) {
1029 /* This was a COMMENT record: print it */
1030 sar_print_special(curr, tm_start.use, tm_end.use, R_COMMENT,
1031 ifd, from_file, &file_magic);
1034 while (!eosaf && (rtype != R_RESTART));
1037 /* The last record we read was a RESTART one: Print it */
1038 if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
1039 sar_print_special(curr, tm_start.use, tm_end.use, R_RESTART,
1040 ifd, from_file, &file_magic);
1051 ***************************************************************************
1052 * Read statistics sent by sadc, the data collector.
1053 ***************************************************************************
1055 void read_stats(void)
1058 unsigned long lines;
1062 /* Don't buffer data if redirected to a pipe... */
1063 setbuf(stdout, NULL);
1065 /* Read stats header */
1068 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1069 fprintf(stderr, _("Requested activities not available\n"));
1073 /* Determine if a stat line header has to be displayed */
1074 dis_hdr = check_line_hdr();
1076 lines = rows = get_win_height();
1078 /* Perform required allocations */
1079 allocate_structures(act);
1081 /* Print report header */
1082 print_report_hdr(flags, &rectime, &file_hdr,
1083 act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr);
1085 /* Read system statistics sent by the data collector */
1086 read_sadc_stat_bunch(0);
1089 /* Display stats since boot time and exit */
1090 write_stats_startup(0);
1093 /* Save the first stats collected. Will be used to compute the average */
1094 copy_structures(act, id_seq, record_hdr, 2, 0);
1096 /* Set a handler for SIGINT */
1097 memset(&int_act, 0, sizeof(int_act));
1098 int_act.sa_handler = int_handler;
1099 int_act.sa_flags = SA_RESTART;
1100 sigaction(SIGINT, &int_act, NULL);
1106 read_sadc_stat_bunch(curr);
1116 write_stats(curr, USE_SADC, &count, NO_TM_START, tm_end.use,
1117 NO_RESET, ALL_ACTIVITIES, TRUE);
1119 if (record_hdr[curr].record_type == R_LAST_STATS) {
1120 /* File rotation is happening: Re-read header data sent by sadc */
1122 allocate_structures(act);
1129 if (sigint_caught) {
1130 /* SIGINT signal caught => Display average stats */
1140 /* Print statistics average */
1142 write_stats_avg(curr, USE_SADC, ALL_ACTIVITIES);
1146 ***************************************************************************
1147 * Main entry to the sar program.
1148 ***************************************************************************
1150 int main(int argc, char **argv)
1152 int i, rc, opt = 1, args_idx = 2;
1155 char from_file[MAX_FILE_LEN], to_file[MAX_FILE_LEN];
1161 /* Compute page shift in kB */
1164 from_file[0] = to_file[0] = '\0';
1167 /* Init National Language Support */
1171 tm_start.use = tm_end.use = FALSE;
1173 /* Allocate and init activity bitmaps */
1174 allocate_bitmaps(act);
1178 /* Process options */
1179 while (opt < argc) {
1181 if (!strcmp(argv[opt], "-I")) {
1183 /* Parse -I option */
1184 if (parse_sar_I_opt(argv, &opt, act)) {
1193 else if (!strcmp(argv[opt], "-D")) {
1194 /* Option to tell sar to write to saYYYYMMDD data files */
1195 flags |= S_F_SA_YYYYMMDD;
1199 else if (!strcmp(argv[opt], "-P")) {
1200 /* Parse -P option */
1201 if (parse_sa_P_opt(argv, &opt, &flags, act)) {
1206 else if (!strcmp(argv[opt], "-o")) {
1208 /* Output file already specified */
1211 /* Save stats to a file */
1212 if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
1213 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1214 strncpy(to_file, argv[opt++], MAX_FILE_LEN);
1215 to_file[MAX_FILE_LEN - 1] = '\0';
1218 strcpy(to_file, "-");
1222 else if (!strcmp(argv[opt], "-f")) {
1223 if (from_file[0] || day_offset) {
1224 /* Input file already specified */
1227 /* Read stats from a file */
1228 if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
1229 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1230 strncpy(from_file, argv[opt++], MAX_FILE_LEN);
1231 from_file[MAX_FILE_LEN - 1] = '\0';
1232 /* Check if this is an alternate directory for sa files */
1233 check_alt_sa_dir(from_file, day_offset, -1);
1236 set_default_file(from_file, day_offset, -1);
1240 else if (!strcmp(argv[opt], "-s")) {
1241 /* Get time start */
1242 if (parse_timestamp(argv, &opt, &tm_start, DEF_TMSTART)) {
1247 else if (!strcmp(argv[opt], "-e")) {
1249 if (parse_timestamp(argv, &opt, &tm_end, DEF_TMEND)) {
1254 else if (!strcmp(argv[opt], "-h")) {
1255 /* Display help message */
1256 display_help(argv[0]);
1259 else if (!strcmp(argv[opt], "-i")) {
1260 if (!argv[++opt] || (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1263 interval = atol(argv[opt++]);
1267 flags |= S_F_INTERVAL_SET;
1270 else if (!strcmp(argv[opt], "-m")) {
1272 /* Parse option -m */
1273 if (parse_sar_m_opt(argv, &opt, act)) {
1282 else if (!strcmp(argv[opt], "-n")) {
1284 /* Parse option -n */
1285 if (parse_sar_n_opt(argv, &opt, act)) {
1294 else if ((strlen(argv[opt]) > 1) &&
1295 (strlen(argv[opt]) < 4) &&
1296 !strncmp(argv[opt], "-", 1) &&
1297 (strspn(argv[opt] + 1, DIGITS) == (strlen(argv[opt]) - 1))) {
1298 if (from_file[0] || day_offset) {
1299 /* Input file already specified */
1302 day_offset = atoi(argv[opt++] + 1);
1305 else if (!strncmp(argv[opt], "-", 1)) {
1306 /* Other options not previously tested */
1307 if ((rc = parse_sar_opt(argv, &opt, act, &flags, C_SAR)) != 0) {
1316 else if (interval < 0) {
1318 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
1321 interval = atol(argv[opt++]);
1328 /* Get count value */
1329 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
1334 /* Count parameter already set */
1337 count = atol(argv[opt++]);
1344 /* 'sar' is equivalent to 'sar -f' */
1346 ((interval < 0) && !from_file[0] && !to_file[0])) {
1347 set_default_file(from_file, day_offset, -1);
1350 if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) {
1351 tm_end.tm_hour += 24;
1355 * Check option dependencies.
1357 /* You read from a file OR you write to it... */
1358 if (from_file[0] && to_file[0]) {
1359 fprintf(stderr, _("-f and -o options are mutually exclusive\n"));
1362 /* Use time start or option -i only when reading stats from a file */
1363 if ((tm_start.use || INTERVAL_SET(flags)) && !from_file[0]) {
1365 _("Not reading from a system activity file (use -f option)\n"));
1368 /* Don't print stats since boot time if -o or -f options are used */
1369 if (!interval && (from_file[0] || to_file[0])) {
1373 /* Cannot enter a day shift with -o option */
1374 if (to_file[0] && day_offset) {
1378 if (USE_PRETTY_OPTION(flags)) {
1379 dm_major = get_devmap_major();
1384 * count parameter not set: Display all the contents of the file
1385 * or generate a report continuously.
1390 /* Default is CPU activity... */
1391 select_default_activity(act);
1393 /* Reading stats from file: */
1399 /* Read stats from file */
1400 read_stats_from_file(from_file);
1402 /* Free stuctures and activity bitmaps */
1404 free_structures(act);
1409 /* Reading stats from sadc: */
1411 /* Create anonymous pipe */
1412 if (pipe(fd) == -1) {
1425 if (dup2(fd[1], STDOUT_FILENO) < 0) {
1432 * Prepare options for sadc.
1437 /* Interval value */
1441 else if (!interval) {
1445 sprintf(ltemp, "%ld", interval);
1451 sprintf(ltemp, "%ld", count + 1);
1452 salloc(args_idx++, ltemp);
1455 /* Flags to be passed to sadc */
1456 salloc(args_idx++, "-z");
1458 /* Writing data to a file (option -o) */
1460 /* Set option -D if entered */
1461 if (USE_SA_YYYYMMDD(flags)) {
1462 salloc(args_idx++, "-D");
1464 /* Collect all possible activities (option -S XALL for sadc) */
1465 salloc(args_idx++, "-S");
1466 salloc(args_idx++, K_XALL);
1468 salloc(args_idx++, to_file);
1472 * If option -o hasn't been used, then tell sadc
1473 * to collect only activities that will be displayed.
1477 for (i = 0; i < NR_ACT; i++) {
1478 if (IS_SELECTED(act[i]->options)) {
1479 act_id |= act[i]->group;
1484 snprintf(ltemp, 19, "%d", act_id);
1486 salloc(args_idx++, "-S");
1487 salloc(args_idx++, ltemp);
1491 /* Last arg is NULL */
1492 args[args_idx] = NULL;
1494 /* Call now the data collector */
1495 execv(SADC_PATH, args);
1498 * Note: Don't use execl/execlp since we don't have a fixed number of
1499 * args to give to sadc.
1501 fprintf(stderr, _("Cannot find the data collector (%s)\n"), SADC);
1506 default: /* Parent */
1507 if (dup2(fd[0], STDIN_FILENO) < 0) {
1513 /* Get now the statistics */
1519 /* Free structures and activity bitmaps */
1521 free_structures(act);