/* *************************************************************************** * Print a Linux restart message (contents of a RESTART record) or a * comment (contents of a COMMENT record). * * IN: * @curr Index in array for current sample statistics. * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @rtype Record type to display. * @ifd Input file descriptor. * * RETURNS: * 1 if the record has been successfully displayed. *************************************************************************** */ int sar_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, int ifd) { char cur_time[26]; int dp = 1; set_timestamp(curr, cur_time, 26); /* The record must be in the interval specified by -s/-e options */ if ((use_tm_start && (datecmp(&rectime, &tm_start) < 0)) || (use_tm_end && (datecmp(&rectime, &tm_end) > 0))) { dp = 0; } if (rtype == R_RESTART) { if (dp) { printf("\n%-11s LINUX RESTART\n", cur_time); return 1; } } else if (rtype == R_COMMENT) { char file_comment[MAX_COMMENT_LEN]; /* Don't forget to read comment record even if it won't be displayed... */ sa_fread(ifd, file_comment, MAX_COMMENT_LEN, HARD_SIZE); file_comment[MAX_COMMENT_LEN - 1] = '\0'; if (dp && DISPLAY_COMMENT(flags)) { printf("%-11s COM %s\n", cur_time, file_comment); return 1; } } return 0; }
/* *************************************************************************** * Print contents of a special (RESTART or COMMENT) record. * * IN: * @curr Index in array for current sample statistics. * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @rtype Record type (RESTART or COMMENT). * @ifd Input file descriptor. * @rectime Structure where timestamp (expressed in local time * or in UTC depending on whether options -T/-t have * been used or not) can be saved for current record. * @loctime Structure where timestamp (expressed in local time) * can be saved for current record. * @file Name of file being read. * @tab Number of tabulations to print. * @file_magic file_magic structure filled with file magic header * data. *************************************************************************** */ void print_special_record(int curr, int use_tm_start, int use_tm_end, int rtype, int ifd, struct tm *rectime, struct tm *loctime, char *file, int tab, struct file_magic *file_magic) { char cur_date[32], cur_time[32]; int dp = 1; unsigned int new_cpu_nr; /* Fill timestamp structure (rectime) for current record */ sa_get_record_timestamp_struct(flags, &record_hdr[curr], rectime, loctime); /* The record must be in the interval specified by -s/-e options */ if ((use_tm_start && (datecmp(loctime, &tm_start) < 0)) || (use_tm_end && (datecmp(loctime, &tm_end) > 0))) { /* Will not display the special record */ dp = 0; } else { /* Set date and time strings to be displayed for current record */ set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime); } if (rtype == R_RESTART) { /* Don't forget to read the volatile activities structures */ new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic, file_hdr.sa_vol_act_nr); if (!dp) return; if (*fmt[f_position]->f_restart) { (*fmt[f_position]->f_restart)(&tab, F_MAIN, cur_date, cur_time, !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags), &file_hdr, new_cpu_nr); } } else if (rtype == R_COMMENT) { char file_comment[MAX_COMMENT_LEN]; /* Read and replace non printable chars in comment */ replace_nonprintable_char(ifd, file_comment); if (!dp || !DISPLAY_COMMENT(flags)) return; if (*fmt[f_position]->f_comment) { (*fmt[f_position]->f_comment)(&tab, F_MAIN, cur_date, cur_time, !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags), file_comment, &file_hdr); } } }
/* *************************************************************************** * Print a Linux restart message (contents of a RESTART record) or a * comment (contents of a COMMENT record). * * IN: * @curr Index in array for current sample statistics. * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @rtype Record type to display. * @ifd Input file descriptor. * @file Name of file being read. * @file_magic file_magic structure filled with file magic header * data. * * RETURNS: * 1 if the record has been successfully displayed, and 0 otherwise. *************************************************************************** */ int sar_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, int ifd, char *file, struct file_magic *file_magic) { char cur_time[26], restart[64]; int dp = 1; unsigned int new_cpu_nr; if (set_record_timestamp_string(curr, cur_time, 26)) return 0; /* The record must be in the interval specified by -s/-e options */ if ((use_tm_start && (datecmp(&rectime, &tm_start) < 0)) || (use_tm_end && (datecmp(&rectime, &tm_end) > 0))) { dp = 0; } if (rtype == R_RESTART) { /* Don't forget to read the volatile activities structures */ new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic, file_hdr.sa_vol_act_nr); if (dp) { printf("\n%-11s", cur_time); sprintf(restart, " LINUX RESTART\t(%d CPU)\n", new_cpu_nr > 1 ? new_cpu_nr - 1 : 1); cprintf_s(IS_RESTART, "%s", restart); return 1; } } else if (rtype == R_COMMENT) { char file_comment[MAX_COMMENT_LEN]; /* Don't forget to read comment record even if it won't be displayed... */ replace_nonprintable_char(ifd, file_comment); if (dp && DISPLAY_COMMENT(flags)) { printf("%-11s", cur_time); cprintf_s(IS_COMMENT, " COM %s\n", file_comment); return 1; } } return 0; }
/* *************************************************************************** * Print contents of a special (RESTART or COMMENT) record. * * IN: * @curr Index in array for current sample statistics. * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @rtype Record type (RESTART or COMMENT). * @ifd Input file descriptor. * @rectime Structure where timestamp (expressed in local time * or in UTC depending on whether option -t has been * used or not) can be saved for current record. * @loctime Structure where timestamp (expressed in local time) * can be saved for current record. *************************************************************************** */ void sadf_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, int ifd, struct tm *rectime, struct tm *loctime) { char cur_date[32], cur_time[32]; int dp = 1; /* Fill timestamp structure (rectime) for current record */ sadf_get_record_timestamp_struct(curr, rectime, loctime); /* Set date and time strings for current record */ set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime); /* The record must be in the interval specified by -s/-e options */ if ((use_tm_start && (datecmp(loctime, &tm_start) < 0)) || (use_tm_end && (datecmp(loctime, &tm_end) > 0))) { dp = 0; } if (rtype == R_RESTART) { if (!dp) return; if (*fmt[f_position]->f_restart) { (*fmt[f_position]->f_restart)(NULL, F_MAIN, cur_date, cur_time, !PRINT_TRUE_TIME(flags), &file_hdr); } } else if (rtype == R_COMMENT) { char file_comment[MAX_COMMENT_LEN]; sa_fread(ifd, file_comment, MAX_COMMENT_LEN, HARD_SIZE); file_comment[MAX_COMMENT_LEN - 1] = '\0'; if (!dp || !DISPLAY_COMMENT(flags)) return; if (*fmt[f_position]->f_comment) { (*fmt[f_position]->f_comment)(NULL, F_MAIN, cur_date, cur_time, !PRINT_TRUE_TIME(flags), file_comment, &file_hdr); } } }
/* *************************************************************************** * Display activities for textual (XML-like) formats. * * IN: * @ifd File descriptor of input file. * @file_actlst List of (known or unknown) activities in file. * @dfile System activity data file name. * @file_magic System activity file magic header. * @cpu_nr Number of processors for current activity data file. * @rectime Structure where timestamp (expressed in local time or in UTC * depending on whether option -t has been used or not) can be * saved for current record. * @loctime Structure where timestamp (expressed in local time) can be * saved for current record. *************************************************************************** */ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfile, struct file_magic *file_magic, __nr_t cpu_nr, struct tm *rectime, struct tm *loctime) { int curr, tab = 0, rtype; int eosaf = TRUE, next, reset = FALSE; long cnt = 1; off_t fpos; /* Save current file position */ if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) { perror("lseek"); exit(2); } /* Print header (eg. XML file header) */ if (*fmt[f_position]->f_header) { (*fmt[f_position]->f_header)(&tab, F_BEGIN, dfile, file_magic, &file_hdr, cpu_nr, act, id_seq); } /* Process activities */ if (*fmt[f_position]->f_statistics) { (*fmt[f_position]->f_statistics)(&tab, F_BEGIN); } do { /* * If this record is a special (RESTART or COMMENT) one, * skip it and try to read the next record in file. */ do { eosaf = sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE); rtype = record_hdr[0].record_type; if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) { /* * OK: Previous record was not a special one. * So read now the extra fields. */ read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act, file_actlst); sadf_get_record_timestamp_struct(0, rectime, loctime); } if (!eosaf && (rtype == R_COMMENT)) { /* * Ignore COMMENT record. * (Unlike RESTART records, COMMENT records have an additional * comment field). */ if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) { perror("lseek"); } } } while (!eosaf && ((rtype == R_RESTART) || (rtype == R_COMMENT) || (tm_start.use && (datecmp(loctime, &tm_start) < 0)) || (tm_end.use && (datecmp(loctime, &tm_end) >=0)))); /* Save the first stats collected. Used for example in next_slice() function */ copy_structures(act, id_seq, record_hdr, 2, 0); curr = 1; cnt = count; reset = TRUE; if (!eosaf) { do { eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE, SOFT_SIZE); rtype = record_hdr[curr].record_type; if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) { /* Read the extra fields since it's not a special record */ read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act, file_actlst); if (*fmt[f_position]->f_statistics) { (*fmt[f_position]->f_statistics)(&tab, F_MAIN); } /* next is set to 1 when we were close enough to desired interval */ next = write_textual_stats(curr, tm_start.use, tm_end.use, reset, &cnt, tab, cpu_nr, rectime, loctime); if (next) { curr ^= 1; if (cnt > 0) { cnt--; } } reset = FALSE; } if (!eosaf && (rtype == R_COMMENT)) { /* Ignore COMMENT record */ if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) { perror("lseek"); } } } while (cnt && !eosaf && (rtype != R_RESTART)); if (!cnt) { /* Go to next Linux restart, if possible */ do { eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE, SOFT_SIZE); rtype = record_hdr[curr].record_type; if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) { read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act, file_actlst); } else if (!eosaf && (rtype == R_COMMENT)) { /* Ignore COMMENT record */ if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) { perror("lseek"); } } } while (!eosaf && (rtype != R_RESTART)); } reset = TRUE; } } while (!eosaf); if (*fmt[f_position]->f_statistics) { (*fmt[f_position]->f_statistics)(&tab, F_END); } /* Rewind file */ if (lseek(ifd, fpos, SEEK_SET) < fpos) { perror("lseek"); exit(2); } /* Process now RESTART entries to display restart messages */ if (*fmt[f_position]->f_restart) { (*fmt[f_position]->f_restart)(&tab, F_BEGIN, NULL, NULL, FALSE, &file_hdr); } do { if ((eosaf = sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE)) == 0) { rtype = record_hdr[0].record_type; if ((rtype != R_RESTART) && (rtype != R_COMMENT)) { read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act, file_actlst); } if (rtype == R_RESTART) { write_textual_restarts(0, tm_start.use, tm_end.use, tab, rectime, loctime); } else if (rtype == R_COMMENT) { /* Ignore COMMENT record */ if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) { perror("lseek"); } } } } while (!eosaf); if (*fmt[f_position]->f_restart) { (*fmt[f_position]->f_restart)(&tab, F_END, NULL, NULL, FALSE, &file_hdr); } /* Rewind file */ if (lseek(ifd, fpos, SEEK_SET) < fpos) { perror("lseek"); exit(2); } /* Last, process COMMENT entries to display comments */ if (DISPLAY_COMMENT(flags)) { if (*fmt[f_position]->f_comment) { (*fmt[f_position]->f_comment)(&tab, F_BEGIN, NULL, NULL, 0, NULL, &file_hdr); } do { if ((eosaf = sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE)) == 0) { rtype = record_hdr[0].record_type; if ((rtype != R_RESTART) && (rtype != R_COMMENT)) { read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act, file_actlst); } if (rtype == R_COMMENT) { write_textual_comments(0, tm_start.use, tm_end.use, tab, ifd, rectime, loctime); } } } while (!eosaf); if (*fmt[f_position]->f_comment) { (*fmt[f_position]->f_comment)(&tab, F_END, NULL, NULL, 0, NULL, &file_hdr); } } /* Print header trailer */ if (*fmt[f_position]->f_header) { (*fmt[f_position]->f_header)(&tab, F_END, dfile, file_magic, &file_hdr, cpu_nr, act, id_seq); } }
/* *************************************************************************** * Display file contents in selected format (logic #1). * Logic #1: Grouped by record type. Sorted by timestamp. * Formats: XML, JSON * * IN: * @ifd File descriptor of input file. * @file_actlst List of (known or unknown) activities in file. * @file System activity data file name (name of file being read). * @file_magic System activity file magic header. * @cpu_nr Number of processors for current activity data file. * @rectime Structure where timestamp (expressed in local time or in UTC * depending on whether options -T/-t have been used or not) can * be saved for current record. * @loctime Structure where timestamp (expressed in local time) can be * saved for current record. *************************************************************************** */ void logic1_display_loop(int ifd, struct file_activity *file_actlst, char *file, struct file_magic *file_magic, __nr_t cpu_nr, struct tm *rectime, struct tm *loctime) { int curr, tab = 0, rtype; int eosaf, next, reset = FALSE; __nr_t save_act_nr[NR_ACT] = {0}; long cnt = 1; off_t fpos; /* Save current file position */ if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) { perror("lseek"); exit(2); } /* Save number of activities items for current file position */ sr_act_nr(save_act_nr, DO_SAVE); /* Print header (eg. XML file header) */ if (*fmt[f_position]->f_header) { (*fmt[f_position]->f_header)(&tab, F_BEGIN, file, file_magic, &file_hdr, cpu_nr, act, id_seq); } /* Process activities */ if (*fmt[f_position]->f_statistics) { (*fmt[f_position]->f_statistics)(&tab, F_BEGIN); } do { /* * If this record is a special (RESTART or COMMENT) one, * skip it and try to read the next record in file. */ do { eosaf = read_next_sample(ifd, IGNORE_COMMENT | IGNORE_RESTART, 0, file, &rtype, tab, file_magic, file_actlst, rectime, loctime); } while (!eosaf && ((rtype == R_RESTART) || (rtype == R_COMMENT) || (tm_start.use && (datecmp(loctime, &tm_start) < 0)) || (tm_end.use && (datecmp(loctime, &tm_end) >= 0)))); /* Save the first stats collected. Used for example in next_slice() function */ copy_structures(act, id_seq, record_hdr, 2, 0); curr = 1; cnt = count; reset = TRUE; if (!eosaf) { do { eosaf = read_next_sample(ifd, IGNORE_COMMENT | IGNORE_RESTART, curr, file, &rtype, tab, file_magic, file_actlst, rectime, loctime); if (!eosaf && (rtype != R_COMMENT) && (rtype != R_RESTART)) { if (*fmt[f_position]->f_statistics) { (*fmt[f_position]->f_statistics)(&tab, F_MAIN); } /* next is set to 1 when we were close enough to desired interval */ next = generic_write_stats(curr, tm_start.use, tm_end.use, reset, &cnt, &tab, cpu_nr, rectime, loctime, FALSE, ALL_ACTIVITIES); if (next) { curr ^= 1; if (cnt > 0) { cnt--; } } reset = FALSE; } } while (cnt && !eosaf && (rtype != R_RESTART)); if (!cnt) { /* Go to next Linux restart, if possible */ do { eosaf = read_next_sample(ifd, IGNORE_COMMENT | IGNORE_RESTART, curr, file, &rtype, tab, file_magic, file_actlst, rectime, loctime); } while (!eosaf && (rtype != R_RESTART)); } reset = TRUE; } } while (!eosaf); if (*fmt[f_position]->f_statistics) { (*fmt[f_position]->f_statistics)(&tab, F_END); } /* Rewind file... */ if (lseek(ifd, fpos, SEEK_SET) < fpos) { perror("lseek"); exit(2); } /* * ... and restore number of items for volatile activities * for this position in file. */ sr_act_nr(save_act_nr, DO_RESTORE); /* Process now RESTART entries to display restart messages */ if (*fmt[f_position]->f_restart) { (*fmt[f_position]->f_restart)(&tab, F_BEGIN, NULL, NULL, FALSE, &file_hdr, 0); } do { eosaf = read_next_sample(ifd, IGNORE_COMMENT, 0, file, &rtype, tab, file_magic, file_actlst, rectime, loctime); } while (!eosaf); if (*fmt[f_position]->f_restart) { (*fmt[f_position]->f_restart)(&tab, F_END, NULL, NULL, FALSE, &file_hdr, 0); } /* Rewind file... */ if (lseek(ifd, fpos, SEEK_SET) < fpos) { perror("lseek"); exit(2); } /* * ... and restore number of items for volatile activities * for this position in file. */ sr_act_nr(save_act_nr, DO_RESTORE); /* Last, process COMMENT entries to display comments */ if (DISPLAY_COMMENT(flags)) { if (*fmt[f_position]->f_comment) { (*fmt[f_position]->f_comment)(&tab, F_BEGIN, NULL, NULL, 0, NULL, &file_hdr); } do { eosaf = read_next_sample(ifd, IGNORE_RESTART, 0, file, &rtype, tab, file_magic, file_actlst, rectime, loctime); } while (!eosaf); if (*fmt[f_position]->f_comment) { (*fmt[f_position]->f_comment)(&tab, F_END, NULL, NULL, 0, NULL, &file_hdr); } } /* Print header trailer */ if (*fmt[f_position]->f_header) { (*fmt[f_position]->f_header)(&tab, F_END, file, file_magic, &file_hdr, cpu_nr, act, id_seq); } }