From: Sebastien GODARD Date: Sun, 22 Jan 2023 10:41:03 +0000 (+0100) Subject: sar/sadf: Rework code related to options -s/-e X-Git-Tag: v12.7.2~5 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9f07e0971cca03e13d11cca3c3fa3b28227498da;p=sysstat sar/sadf: Rework code related to options -s/-e Timestamps entered as a number of seconds since the Epoch are now used as they are and no longer converted to a broken time representation, so that even month and year are taken into account when current record time is compared to those timestamps. The record which is exactly at the ending time is now displayed. Signed-off-by: Sebastien GODARD --- diff --git a/common.c b/common.c index ed144d9..89a0805 100644 --- a/common.c +++ b/common.c @@ -564,7 +564,7 @@ void xprintf(int nr_tab, const char *fmtf, ...) * Get report date as a string of characters. * * IN: - * @rectime Date to display (don't use time fields). + * @tm_time Date to display (don't use time fields). * @cur_date String where date will be saved. * @sz Max size of cur_date string. * @@ -575,18 +575,18 @@ void xprintf(int nr_tab, const char *fmtf, ...) * TRUE if S_TIME_FORMAT is set to ISO, or FALSE otherwise. *************************************************************************** */ -int set_report_date(struct tm *rectime, char cur_date[], int sz) +int set_report_date(struct tm *tm_time, char cur_date[], int sz) { - if (rectime == NULL) { + if (tm_time == NULL) { strncpy(cur_date, "?/?/?", sz); cur_date[sz - 1] = '\0'; } else if (is_iso_time_fmt()) { - strftime(cur_date, sz, "%Y-%m-%d", rectime); + strftime(cur_date, sz, "%Y-%m-%d", tm_time); return 1; } else { - strftime(cur_date, sz, "%x", rectime); + strftime(cur_date, sz, "%x", tm_time); } return 0; @@ -597,7 +597,7 @@ int set_report_date(struct tm *rectime, char cur_date[], int sz) * Print banner. * * IN: - * @rectime Date to display (don't use time fields). + * @tm_time Date to display (don't use time fields). * @sysname System name to display. * @release System release number to display. * @nodename Hostname to display. @@ -610,13 +610,13 @@ int set_report_date(struct tm *rectime, char cur_date[], int sz) * TRUE if S_TIME_FORMAT is set to ISO, or FALSE otherwise. *************************************************************************** */ -int print_gal_header(struct tm *rectime, char *sysname, char *release, +int print_gal_header(struct tm *tm_time, char *sysname, char *release, char *nodename, char *machine, int cpu_nr, int format) { char cur_date[TIMESTAMP_LEN]; int rc = 0; - rc = set_report_date(rectime, cur_date, sizeof(cur_date)); + rc = set_report_date(tm_time, cur_date, sizeof(cur_date)); if (format == PLAIN_OUTPUT) { /* Plain output */ diff --git a/sa.h b/sa.h index 7cc435d..3d13b08 100644 --- a/sa.h +++ b/sa.h @@ -300,8 +300,6 @@ enum { /* Miscellaneous constants */ #define USE_SADC 0 #define USE_SA_FILE 1 -#define NO_TM_START 0 -#define NO_TM_END 0 #define NO_RESET 0 #define NO_RANGE 0 #define NON_FATAL 0 @@ -352,9 +350,40 @@ enum count_mode { /* Type for all functions displaying statistics */ #define __print_funct_t void +/* + * ************************************************************************** + * Various structure definitions. + *************************************************************************** + */ + +enum time_mode { + NO_TIME = 0, + USE_HHMMSS_T = 1, + USE_EPOCH_T = 2 +}; + +/* + * Structure for timestamps. + * @tm_time has the GMT or local broken time representation of @epoch_time. + * Exception is when the structure is used to save the timestamp given by the + * user on the command line with options -s/-e. In this case, it includes either + * the number of seconds since the epoch *or* the broken time entered by the user. + */ +struct tstamp_ext { + unsigned long long epoch_time; + struct tm tm_time; + enum time_mode use; +}; + +/* Structure for items in list */ +struct sa_item { + char *item_name; + struct sa_item *next; +}; + /* *************************************************************************** - * Output formats for sadfsize_mode + * Output formats for sadf *************************************************************************** */ @@ -1221,7 +1250,7 @@ struct report_format { * This is the main function used to display all the statistics for current format. */ void (*f_display) (int, char *, struct file_activity *, struct file_magic *, - struct tm *, void *); + struct tstamp_ext *, void *); }; @@ -1345,28 +1374,6 @@ enum { #define CLOSE(_fd_) if (_fd_ >= 0) \ close(_fd_) - -/* - *************************************************************************** - * Various structure definitions. - *************************************************************************** - */ - -/* Structure for timestamps */ -struct tstamp { - int tm_sec; - int tm_min; - int tm_hour; - int use; -}; - -/* Structure for items in list */ -struct sa_item { - char *item_name; - struct sa_item *next; -}; - - /* *************************************************************************** * Functions prototypes. @@ -1545,12 +1552,14 @@ int check_net_dev_reg (struct activity *, int, int, int); int check_net_edev_reg (struct activity *, int, int, int); +int check_time_limits + (struct tstamp_ext *, struct tstamp_ext *); double compute_ifutil (struct stats_net_dev *, double, double); void copy_structures (struct activity * [], unsigned int [], struct record_header [], int, int); int datecmp - (struct tm *, struct tstamp *, int); + (struct tstamp_ext *, struct tstamp_ext *, int); void display_sa_file_version (FILE *, struct file_magic *); void free_bitmaps @@ -1590,7 +1599,7 @@ int parse_sar_n_opt int parse_sar_q_opt (char * [], int *, struct activity * []); int parse_timestamp - (char * [], int *, struct tstamp *, const char *, uint64_t); + (char * [], int *, struct tstamp_ext *, const char *, uint64_t); void print_report_hdr (uint64_t, struct tm *, struct file_header *); void print_sar_comment @@ -1599,8 +1608,8 @@ void print_sar_comment __printf_funct_t print_sar_restart (int *, int, char *, char *, char *, struct file_header *, struct record_header *); int print_special_record - (struct record_header *, uint64_t, struct tstamp *, struct tstamp *, - int, int, struct tm *, char *, int, char *, struct file_magic *, + (struct record_header *, uint64_t, struct tstamp_ext *, struct tstamp_ext *, + int, int, struct tstamp_ext *, char *, int, char *, struct file_magic *, struct file_header *, struct activity * [], struct report_format *, int, int); int read_file_stat_bunch (struct activity * [], int, int, int, struct file_activity *, int, int, @@ -1617,7 +1626,7 @@ void replace_nonprintable_char int sa_fread (int, void *, size_t, enum size_mode, enum on_eof); int sa_get_record_timestamp_struct - (uint64_t, struct record_header *, struct tm *); + (uint64_t, struct record_header *, struct tstamp_ext *); int sa_open_read_magic (int *, char *, struct file_magic *, int, int *, int); int search_list_item @@ -1631,7 +1640,7 @@ void set_bitmaps void set_hdr_rectime (unsigned int, struct tm *, struct file_header *); void set_record_timestamp_string - (uint64_t, struct record_header *, char *, char *, int, struct tm *); + (uint64_t, char *, char *, int, struct tstamp_ext *); void swap_struct (unsigned int [], void *, int); #endif /* SOURCE_SADC undefined */ diff --git a/sa_common.c b/sa_common.c index b6f3d6c..d96a1b9 100644 --- a/sa_common.c +++ b/sa_common.c @@ -614,7 +614,7 @@ int next_slice(unsigned long long uptime_ref, unsigned long long uptime, /* *************************************************************************** - * Use time stamp to fill tstamp structure. + * Use time stamp to fill tstamp_ext structure. * * IN: * @timestamp Timestamp to decode (format: HH:MM:SS). @@ -626,7 +626,7 @@ int next_slice(unsigned long long uptime_ref, unsigned long long uptime, * 0 if the timestamp has been successfully decoded, 1 otherwise. *************************************************************************** */ -int decode_timestamp(char timestamp[], struct tstamp *tse) +int decode_timestamp(char timestamp[], struct tstamp_ext *tse) { timestamp[2] = timestamp[5] = '\0'; @@ -635,25 +635,25 @@ int decode_timestamp(char timestamp[], struct tstamp *tse) (strspn(×tamp[6], DIGITS) != 2)) return 1; - tse->tm_sec = atoi(×tamp[6]); - tse->tm_min = atoi(×tamp[3]); - tse->tm_hour = atoi(timestamp); + tse->tm_time.tm_sec = atoi(×tamp[6]); + tse->tm_time.tm_min = atoi(×tamp[3]); + tse->tm_time.tm_hour = atoi(timestamp); - if ((tse->tm_sec < 0) || (tse->tm_sec > 59) || - (tse->tm_min < 0) || (tse->tm_min > 59) || - (tse->tm_hour < 0) || (tse->tm_hour > 23)) { - tse->use = FALSE; + if ((tse->tm_time.tm_sec < 0) || (tse->tm_time.tm_sec > 59) || + (tse->tm_time.tm_min < 0) || (tse->tm_time.tm_min > 59) || + (tse->tm_time.tm_hour < 0) || (tse->tm_time.tm_hour > 23)) { + tse->use = NO_TIME; return 1; } - tse->use = TRUE; + tse->use = USE_HHMMSS_T; return 0; } /* *************************************************************************** - * Use time stamp to fill tstamp structure. + * Use time stamp to fill tstamp_ext structure. * * IN: * @timestamp Epoch time to decode (format: number of seconds since @@ -667,29 +667,16 @@ int decode_timestamp(char timestamp[], struct tstamp *tse) * 0 if the epoch time has been successfully decoded, 1 otherwise. *************************************************************************** */ -int decode_epoch(char timestamp[], struct tstamp *tse, uint64_t flags) +int decode_epoch(char timestamp[], struct tstamp_ext *tse, uint64_t flags) { - time_t epoch = atol(timestamp); - struct tm given_time; + tse->epoch_time = atol(timestamp); - if (epoch <= 0) { - tse->use = FALSE; + if (tse->epoch_time <= 0) { + tse->use = NO_TIME; return 1; } - if (PRINT_LOCAL_TIME(flags)) { - /* This is for sar or sadf -T */ - localtime_r(&epoch, &given_time); - } - else { - /* This is for sadf */ - gmtime_r(&epoch, &given_time); - } - tse->tm_sec = given_time.tm_sec; - tse->tm_min = given_time.tm_min; - tse->tm_hour = given_time.tm_hour; - - tse->use = TRUE; + tse->use = USE_EPOCH_T; return 0; } @@ -706,29 +693,38 @@ int decode_epoch(char timestamp[], struct tstamp *tse, uint64_t flags) * RETURNS: * A positive value if @rectime is greater than @tse, * a negative one otherwise. + * Also returns 0 if no valid time is saved in @tse. *************************************************************************** */ -int datecmp(struct tm *rectime, struct tstamp *tse, int cross_day) +int datecmp(struct tstamp_ext *rectime, struct tstamp_ext *tse, int cross_day) { - int tm_hour = rectime->tm_hour; + int tm_hour; - if (cross_day) { - /* - * This is necessary if we want to properly handle something like: - * sar -s time_start -e time_end with - * time_start(day D) > time_end(day D+1) - */ - tm_hour += 24; - } + switch (tse->use) { - if (tm_hour == tse->tm_hour) { - if (rectime->tm_min == tse->tm_min) - return (rectime->tm_sec - tse->tm_sec); - else - return (rectime->tm_min - tse->tm_min); + case USE_HHMMSS_T: + /* + * This is necessary if we want to properly handle something like: + * sar -s time_start -e time_end with + * time_start(day D) > time_end(day D+1) + */ + tm_hour = rectime->tm_time.tm_hour + (24 * (cross_day != 0)); + + if (tm_hour == tse->tm_time.tm_hour) { + if (rectime->tm_time.tm_min == tse->tm_time.tm_min) + return (rectime->tm_time.tm_sec - tse->tm_time.tm_sec); + else + return (rectime->tm_time.tm_min - tse->tm_time.tm_min); + } + else + return (tm_hour - tse->tm_time.tm_hour); + + case USE_EPOCH_T: + return (rectime->epoch_time - tse->epoch_time); + + default: /* NO_TIME */ + return 0; } - else - return (tm_hour - tse->tm_hour); } /* @@ -749,7 +745,7 @@ int datecmp(struct tm *rectime, struct tstamp *tse, int cross_day) * 0 if the timestamp has been successfully decoded, 1 otherwise. *************************************************************************** */ -int parse_timestamp(char *argv[], int *opt, struct tstamp *tse, +int parse_timestamp(char *argv[], int *opt, struct tstamp_ext *tse, const char *def_timestamp, uint64_t flags) { char timestamp[11]; @@ -817,7 +813,7 @@ void get_itv_value(struct record_header *record_hdr_curr, /* *************************************************************************** - * Fill the rectime structure with the file's creation date, based on file's + * Fill the tm_time structure with the file's creation date, based on file's * time data saved in file header. * The resulting timestamp is expressed in the locale of the file creator or * in the user's own locale, depending on whether option -t has been used @@ -828,31 +824,31 @@ void get_itv_value(struct record_header *record_hdr_curr, * @file_hdr System activity file standard header. * * OUT: - * @rectime Date (and possibly time) from file header. Only the date, + * @tm_time Date (and possibly time) from file header. Only the date, * not the time, should be used by the caller. *************************************************************************** */ -void get_file_timestamp_struct(uint64_t flags, struct tm *rectime, +void get_file_timestamp_struct(uint64_t flags, struct tm *tm_time, struct file_header *file_hdr) { time_t t = file_hdr->sa_ust_time; if (PRINT_TRUE_TIME(flags)) { /* Get local time. This is just to fill fields with a default value. */ - get_time(rectime, 0); + get_time(tm_time, 0); - rectime->tm_mday = file_hdr->sa_day; - rectime->tm_mon = file_hdr->sa_month; - rectime->tm_year = file_hdr->sa_year; + tm_time->tm_mday = file_hdr->sa_day; + tm_time->tm_mon = file_hdr->sa_month; + tm_time->tm_year = file_hdr->sa_year; /* * Call mktime() to set DST (Daylight Saving Time) flag. * Has anyone a better way to do it? */ - rectime->tm_hour = rectime->tm_min = rectime->tm_sec = 0; - mktime(rectime); + tm_time->tm_hour = tm_time->tm_min = tm_time->tm_sec = 0; + mktime(tm_time); } else { - localtime_r(&t, rectime); + localtime_r(&t, tm_time); } } @@ -865,15 +861,15 @@ void get_file_timestamp_struct(uint64_t flags, struct tm *rectime, * @file_hdr System activity file standard header. * * OUT: - * @rectime Date and time from file header. + * @tm_time Date and time from file header. *************************************************************************** */ -void print_report_hdr(uint64_t flags, struct tm *rectime, +void print_report_hdr(uint64_t flags, struct tm *tm_time, struct file_header *file_hdr) { /* Get date of file creation */ - get_file_timestamp_struct(flags, rectime, file_hdr); + get_file_timestamp_struct(flags, tm_time, file_hdr); /* * Display the header. @@ -881,7 +877,7 @@ void print_report_hdr(uint64_t flags, struct tm *rectime, * 1 means that there is only one proc and non SMP kernel. * 2 means one proc and SMP kernel. Etc. */ - print_gal_header(rectime, file_hdr->sa_sysname, file_hdr->sa_release, + print_gal_header(tm_time, file_hdr->sa_sysname, file_hdr->sa_release, file_hdr->sa_nodename, file_hdr->sa_machine, file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1, PLAIN_OUTPUT); @@ -2924,26 +2920,28 @@ void replace_nonprintable_char(int ifd, char *comment) *************************************************************************** */ int sa_get_record_timestamp_struct(uint64_t l_flags, struct record_header *record_hdr, - struct tm *rectime) + struct tstamp_ext *rectime) { struct tm *ltm; - time_t t = record_hdr->ust_time; + time_t t = (time_t) record_hdr->ust_time; int rc = 0; + rectime->epoch_time = record_hdr->ust_time; + if (!PRINT_LOCAL_TIME(l_flags) && !PRINT_TRUE_TIME(l_flags)) { /* * Get time in UTC * (the user doesn't want local time nor time of file's creator). */ - ltm = gmtime_r(&t, rectime); + ltm = gmtime_r(&t, &(rectime->tm_time)); } else { /* * Fill generic rectime structure in local time. * Done so that we have some default values. */ - ltm = localtime_r(&t, rectime); - rectime->tm_gmtoff = TRUE; + ltm = localtime_r(&t, &(rectime->tm_time)); + rectime->tm_time.tm_gmtoff = TRUE; } if (!ltm) { @@ -2952,9 +2950,9 @@ int sa_get_record_timestamp_struct(uint64_t l_flags, struct record_header *recor if (PRINT_TRUE_TIME(l_flags)) { /* Time of file's creator */ - rectime->tm_hour = record_hdr->hour; - rectime->tm_min = record_hdr->minute; - rectime->tm_sec = record_hdr->second; + rectime->tm_time.tm_hour = record_hdr->hour; + rectime->tm_time.tm_min = record_hdr->minute; + rectime->tm_time.tm_sec = record_hdr->second; } return rc; @@ -2970,8 +2968,6 @@ int sa_get_record_timestamp_struct(uint64_t l_flags, struct record_header *recor * @l_flags Flags indicating the type of time expected by the user. * S_F_SEC_EPOCH means the time should be expressed in seconds * since the epoch (01/01/1970). - * @record_hdr Record header containing the number of seconds since the - * epoch. * @cur_date String where timestamp's date will be saved. May be NULL. * @cur_time String where timestamp's time will be saved. * @len Maximum length of timestamp strings. @@ -2986,12 +2982,12 @@ int sa_get_record_timestamp_struct(uint64_t l_flags, struct record_header *recor * been used. *************************************************************************** */ -void set_record_timestamp_string(uint64_t l_flags, struct record_header *record_hdr, - char *cur_date, char *cur_time, int len, struct tm *rectime) +void set_record_timestamp_string(uint64_t l_flags, char *cur_date, char *cur_time, int len, + struct tstamp_ext *rectime) { /* Set cur_time date value */ if (PRINT_SEC_EPOCH(l_flags) && cur_date) { - sprintf(cur_time, "%llu", record_hdr->ust_time); + sprintf(cur_time, "%llu", rectime->epoch_time); strcpy(cur_date, ""); } else { @@ -3000,13 +2996,13 @@ void set_record_timestamp_string(uint64_t l_flags, struct record_header *record_ * expressed in local time. Else it is expressed in UTC. */ if (cur_date) { - strftime(cur_date, len, "%Y-%m-%d", rectime); + strftime(cur_date, len, "%Y-%m-%d", &(rectime->tm_time)); } if (USE_PREFD_TIME_OUTPUT(l_flags)) { - strftime(cur_time, len, "%X", rectime); + strftime(cur_time, len, "%X", &(rectime->tm_time)); } else { - strftime(cur_time, len, "%H:%M:%S", rectime); + strftime(cur_time, len, "%H:%M:%S", &(rectime->tm_time)); } } } @@ -3046,8 +3042,8 @@ void set_record_timestamp_string(uint64_t l_flags, struct record_header *record_ *************************************************************************** */ int print_special_record(struct record_header *record_hdr, uint64_t l_flags, - struct tstamp *tm_start, struct tstamp *tm_end, int rtype, int ifd, - struct tm *rectime, char *file, int tab, char *my_tz, + struct tstamp_ext *tm_start, struct tstamp_ext *tm_end, int rtype, + int ifd, struct tstamp_ext *rectime, char *file, int tab, char *my_tz, struct file_magic *file_magic, struct file_header *file_hdr, struct activity *act[], struct report_format *ofmt, int endian_mismatch, int arch_64) @@ -3061,15 +3057,15 @@ int print_special_record(struct record_header *record_hdr, uint64_t l_flags, return 0; /* The record must be in the interval specified by -s/-e options */ - if ((tm_start->use && (datecmp(rectime, tm_start, FALSE) < 0)) || - (tm_end->use && (datecmp(rectime, tm_end, FALSE) > 0))) { + if ((datecmp(rectime, tm_start, FALSE) < 0) || + (datecmp(rectime, tm_end, FALSE) > 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(l_flags, record_hdr, - cur_date, cur_time, TIMESTAMP_LEN, rectime); + set_record_timestamp_string(l_flags, cur_date, cur_time, TIMESTAMP_LEN, + rectime); } if (rtype == R_RESTART) { @@ -3453,4 +3449,31 @@ char *get_fs_name_to_display(struct activity *a, uint64_t flags, struct stats_fi } return pname; } + +/* + * ************************************************************************** + * Make a few checks on timestamps entered with options -s/-e. + * + * IN: + * @tm_start Timestamp entered with option -s. + * @tm_end Timestamp entered with option -e. + * + * RETURNS: + * 1 if an error has been detected. + *************************************************************************** + */ +int check_time_limits(struct tstamp_ext *tm_start, struct tstamp_ext *tm_end) +{ + if ((tm_start->use == USE_HHMMSS_T) && (tm_end->use == USE_HHMMSS_T) && + (tm_end->tm_time.tm_hour < tm_start->tm_time.tm_hour)) { + tm_end->tm_time.tm_hour += 24; + } + + if ((tm_start->use == USE_EPOCH_T) && (tm_end->use == USE_EPOCH_T) && + (tm_end->epoch_time < tm_start->epoch_time)) + return 1; + + return 0; +} + #endif /* SOURCE_SADC undefined */ diff --git a/sadf.c b/sadf.c index 8f201ba..f65be74 100644 --- a/sadf.c +++ b/sadf.c @@ -87,7 +87,7 @@ unsigned int id_seq[NR_ACT]; struct record_header record_hdr[3]; /* Contain the date specified by -s and -e options */ -struct tstamp tm_start, tm_end; +struct tstamp_ext tm_start, tm_end; char *args[MAX_ARGV_NR]; /* Current timezone */ @@ -250,7 +250,7 @@ void check_format_options(void) */ int read_next_sample(int ifd, int action, int curr, char *file, int *rtype, int tab, struct file_magic *file_magic, struct file_activity *file_actlst, - struct tm *rectime, enum on_eof oneof) + struct tstamp_ext *rectime, enum on_eof oneof) { int rc; char rec_hdr_tmp[MAX_RECORD_HEADER_SIZE]; @@ -485,7 +485,7 @@ void seek_file_position(int ifd, int action) *************************************************************************** */ int count_file_items(int ifd, char *file, struct file_magic *file_magic, - struct file_activity *file_actlst, struct tm *rectime) + struct file_activity *file_actlst, struct tstamp_ext *rectime) { int i, eosaf, rtype; @@ -508,8 +508,8 @@ int count_file_items(int ifd, char *file, struct file_magic *file_magic, /* No record to display */ return 0; } - while ((tm_start.use && (datecmp(rectime, &tm_start, FALSE) < 0)) || - (tm_end.use && (datecmp(rectime, &tm_end, FALSE) >= 0))); + while ((datecmp(rectime, &tm_start, FALSE) < 0) || + (datecmp(rectime, &tm_end, FALSE) > 0)); /* * Read all the file and determine the maximum number @@ -531,14 +531,13 @@ int count_file_items(int ifd, char *file, struct file_magic *file_magic, eosaf = read_next_sample(ifd, IGNORE_RESTART | IGNORE_COMMENT | SET_TIMESTAMPS, 0, file, &rtype, 0, file_magic, file_actlst, rectime, UEOF_CONT); - if (eosaf || - (tm_end.use && (datecmp(rectime, &tm_end, FALSE) >= 0))) + if (eosaf || (datecmp(rectime, &tm_end, FALSE) > 0)) /* End of data file or end time exceeded */ break; } while ((rtype == R_RESTART) || (rtype == R_COMMENT)); } - while (!eosaf && !(tm_end.use && (datecmp(rectime, &tm_end, FALSE) >= 0))); + while (!eosaf && !(datecmp(rectime, &tm_end, FALSE) > 0)); /* Rewind file */ seek_file_position(ifd, DO_RESTORE); @@ -578,7 +577,7 @@ int count_file_items(int ifd, char *file, struct file_magic *file_magic, *************************************************************************** */ int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic, - struct file_activity *file_actlst, struct tm *rectime, + struct file_activity *file_actlst, struct tstamp_ext *rectime, int *views_per_row, int *nr_act_dispd) { int i, n, p, tot_g_nr = 0; @@ -644,8 +643,8 @@ int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic, * * 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. + * @use_tm_start Set to non-zero if option -s has been used. + * @use_tm_end Set to non-zero if option -e has been used. * @reset Set to TRUE if last_uptime should be reinitialized * (used in next_slice() function). * @parm Pointer on parameters depending on output format @@ -666,8 +665,8 @@ int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic, * 1 if stats have been successfully displayed. *************************************************************************** */ -int generic_write_stats(int curr, int use_tm_start, int use_tm_end, int reset, - long *cnt, void *parm, struct tm *rectime, +int generic_write_stats(int curr, enum time_mode use_tm_start, enum time_mode use_tm_end, + int reset, long *cnt, void *parm, struct tstamp_ext *rectime, int reset_cd, unsigned int act_id) { int i; @@ -720,8 +719,7 @@ int generic_write_stats(int curr, int use_tm_start, int use_tm_end, int reset, } /* Set date and time strings for current record */ - set_record_timestamp_string(flags, &record_hdr[curr], - cur_date, cur_time, TIMESTAMP_LEN, rectime); + set_record_timestamp_string(flags, cur_date, cur_time, TIMESTAMP_LEN, rectime); if (*fmt[f_position]->f_timestamp) { pre = (char *) (*fmt[f_position]->f_timestamp)(parm, F_BEGIN, cur_date, cur_time, @@ -834,7 +832,7 @@ int generic_write_stats(int curr, int use_tm_start, int use_tm_end, int reset, */ void rw_curr_act_stats(int ifd, int *curr, long *cnt, int *eosaf, unsigned int act_id, int *reset, struct file_activity *file_actlst, - struct tm *rectime, char *file, + struct tstamp_ext *rectime, char *file, struct file_magic *file_magic) { int rtype; @@ -919,8 +917,8 @@ void rw_curr_act_stats(int ifd, int *curr, long *cnt, int *eosaf, */ void display_curr_act_graphs(int ifd, int *curr, long *cnt, int *eosaf, int p, int *reset, struct file_activity *file_actlst, - struct tm *rectime, char *file, struct file_magic *file_magic, - int *g_nr, int nr_act_dispd) + struct tstamp_ext *rectime, char *file, + struct file_magic *file_magic, int *g_nr, int nr_act_dispd) { struct svg_parm parm; int rtype; @@ -1037,7 +1035,7 @@ void display_curr_act_graphs(int ifd, int *curr, long *cnt, int *eosaf, *************************************************************************** */ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, - struct file_magic *file_magic, struct tm *rectime, void *dparm) + struct file_magic *file_magic, struct tstamp_ext *rectime, void *dparm) { int curr, rtype, tab = 0; int eosaf, next, reset = FALSE; @@ -1090,8 +1088,8 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, rectime, UEOF_STOP); } while (!eosaf && ((rtype == R_RESTART) || (rtype == R_COMMENT) || - (tm_start.use && (datecmp(rectime, &tm_start, FALSE) < 0)) || - (tm_end.use && (datecmp(rectime, &tm_end, FALSE) >= 0)))); + (datecmp(rectime, &tm_start, FALSE) < 0) || + (datecmp(rectime, &tm_end, FALSE) > 0))); curr = 1; cnt = count; @@ -1238,7 +1236,7 @@ terminate: *************************************************************************** */ void logic2_display_loop(int ifd, char *file, struct file_activity *file_actlst, - struct file_magic *file_magic, struct tm *rectime, void *dparm) + struct file_magic *file_magic, struct tstamp_ext *rectime, void *dparm) { int i, p; int curr = 1, rtype; @@ -1259,8 +1257,8 @@ void logic2_display_loop(int ifd, char *file, struct file_activity *file_actlst, return; } while ((rtype == R_RESTART) || (rtype == R_COMMENT) || - (tm_start.use && (datecmp(rectime, &tm_start, FALSE) < 0)) || - (tm_end.use && (datecmp(rectime, &tm_end, FALSE) >= 0))); + (datecmp(rectime, &tm_start, FALSE) < 0) || + (datecmp(rectime, &tm_end, FALSE) > 0)); /* Save the first stats collected. Used for example in next_slice() function */ copy_structures(act, id_seq, record_hdr, 2, 0); @@ -1359,7 +1357,7 @@ void logic2_display_loop(int ifd, char *file, struct file_activity *file_actlst, *************************************************************************** */ void svg_display_loop(int ifd, char *file, struct file_activity *file_actlst, - struct file_magic *file_magic, struct tm *rectime, void *dparm) + struct file_magic *file_magic, struct tstamp_ext *rectime, void *dparm) { struct svg_hdr_parm parm; int i, p; @@ -1412,8 +1410,8 @@ void svg_display_loop(int ifd, char *file, struct file_activity *file_actlst, } } while ((rtype == R_RESTART) || (rtype == R_COMMENT) || - (tm_start.use && (datecmp(rectime, &tm_start, FALSE) < 0)) || - (tm_end.use && (datecmp(rectime, &tm_end, FALSE) >= 0))); + (datecmp(rectime, &tm_start, FALSE) < 0) || + (datecmp(rectime, &tm_end, FALSE) > 0)); /* Save the first stats collected. Used for example in next_slice() function */ copy_structures(act, id_seq, record_hdr, 2, 0); @@ -1481,7 +1479,7 @@ void read_stats_from_file(char dfile[], char pcparchive[]) { struct file_magic file_magic; struct file_activity *file_actlst = NULL; - struct tm rectime; + struct tstamp_ext rectime; int ifd, tab = 0; /* Prepare file for reading and read its headers */ @@ -1544,7 +1542,7 @@ int main(int argc, char **argv) init_nls(); #endif - tm_start.use = tm_end.use = FALSE; + tm_start.use = tm_end.use = NO_TIME; /* Allocate and init activity bitmaps */ allocate_bitmaps(act); @@ -1898,8 +1896,8 @@ int main(int argc, char **argv) } #endif - if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) { - tm_end.tm_hour += 24; + if (check_time_limits(&tm_start, &tm_end)) { + usage(argv[0]); } if (DISPLAY_PRETTY(flags)) { diff --git a/sadf.h b/sadf.h index b0a8910..b4fed5b 100644 --- a/sadf.h +++ b/sadf.h @@ -200,12 +200,12 @@ __printf_funct_t print_pcp_header */ void logic1_display_loop (int, char *, struct file_activity *, struct file_magic *, - struct tm *, void *); + struct tstamp_ext *, void *); void logic2_display_loop (int, char *, struct file_activity *, struct file_magic *, - struct tm *, void *); + struct tstamp_ext *, void *); void svg_display_loop (int, char *, struct file_activity *, struct file_magic *, - struct tm *, void *); + struct tstamp_ext *, void *); #endif /* _SADF_H */ diff --git a/sar.c b/sar.c index e92c542..6ecb244 100644 --- a/sar.c +++ b/sar.c @@ -82,10 +82,10 @@ struct record_header record_hdr[3]; */ unsigned int id_seq[NR_ACT]; -struct tm rectime; +struct tstamp_ext rectime; /* Contain the date specified by -s and -e options */ -struct tstamp tm_start, tm_end; +struct tstamp_ext tm_start, tm_end; char *args[MAX_ARGV_NR]; @@ -418,8 +418,10 @@ void write_stats_avg(int curr, int read_from_file, unsigned int act_id) * @curr Index in array for current sample statistics. * @read_from_file Set to TRUE if stats are read from a system activity * data file. - * @use_tm_start Set to TRUE if option -s has been used. - * @use_tm_end Set to TRUE if option -e has been used. + * @use_tm_start Set to non-zero (USE_HHMMSS_T or USE_EPOCH_T) if + * option -s has been used. + * @use_tm_end Set to non-zero (USE_HHMMSS_T or USE_EPOCH_T) if + * option -e has been used. * @reset Set to TRUE if last_uptime variable should be * reinitialized (used in next_slice() function). * @act_id Activity that can be displayed or ~0 for all. @@ -435,8 +437,8 @@ void write_stats_avg(int curr, int read_from_file, unsigned int act_id) * 1 if stats have been successfully displayed, and 0 otherwise. *************************************************************************** */ -int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start, - int use_tm_end, int reset, unsigned int act_id, int reset_cd) +int write_stats(int curr, int read_from_file, long *cnt, enum time_mode use_tm_start, + enum time_mode use_tm_end, int reset, unsigned int act_id, int reset_cd) { int i, prev_hour, rc = 0; unsigned long long itv; @@ -465,15 +467,13 @@ int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start, /* Get then set previous timestamp */ if (sa_get_record_timestamp_struct(flags, &record_hdr[!curr], &rectime)) return 0; - prev_hour = rectime.tm_hour; - set_record_timestamp_string(flags, &record_hdr[!curr], - NULL, timestamp[!curr], TIMESTAMP_LEN, &rectime); + prev_hour = rectime.tm_time.tm_hour; + set_record_timestamp_string(flags, NULL, timestamp[!curr], TIMESTAMP_LEN, &rectime); /* Get then set current timestamp */ if (sa_get_record_timestamp_struct(flags, &record_hdr[curr], &rectime)) return 0; - set_record_timestamp_string(flags, &record_hdr[curr], - NULL, timestamp[curr], TIMESTAMP_LEN, &rectime); + set_record_timestamp_string(flags, NULL, timestamp[curr], TIMESTAMP_LEN, &rectime); /* * Check if we are beginning a new day. @@ -481,14 +481,14 @@ int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start, * to take into account the current timezone (hours displayed will depend on the * TZ variable value). */ - if (use_tm_start && record_hdr[!curr].ust_time && + if ((use_tm_start == USE_HHMMSS_T) && record_hdr[!curr].ust_time && (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) && - (rectime.tm_hour < prev_hour)) { + (rectime.tm_time.tm_hour < prev_hour)) { cross_day = TRUE; } /* Check time (2) */ - if (use_tm_end && (datecmp(&rectime, &tm_end, cross_day) > 0)) { + if ((use_tm_end != NO_TIME) && datecmp(&rectime, &tm_end, cross_day) > 0) { /* End time exceeded */ *cnt = 0; return 0; @@ -554,7 +554,7 @@ void write_stats_startup(int curr) flags |= S_F_SINCE_BOOT; dish = TRUE; - write_stats(curr, USE_SADC, &count, NO_TM_START, NO_TM_END, NO_RESET, + write_stats(curr, USE_SADC, &count, NO_TIME, NO_TIME, NO_RESET, ALL_ACTIVITIES, TRUE); exit(0); @@ -1021,7 +1021,7 @@ void read_stats_from_file(char from_file[]) allocate_structures(act); /* Print report header */ - print_report_hdr(flags, &rectime, &file_hdr); + print_report_hdr(flags, &(rectime.tm_time), &file_hdr); /* Read system statistics from file */ do { @@ -1064,8 +1064,8 @@ void read_stats_from_file(char from_file[]) } } while ((rtype == R_RESTART) || (rtype == R_COMMENT) || - (tm_start.use && (datecmp(&rectime, &tm_start, FALSE) < 0)) || - (tm_end.use && (datecmp(&rectime, &tm_end, FALSE) >= 0))); + (datecmp(&rectime, &tm_start, FALSE) < 0) || + (datecmp(&rectime, &tm_end, FALSE) > 0)); /* Save the first stats collected. Will be used to compute the average */ copy_structures(act, id_seq, record_hdr, 2, 0); @@ -1205,7 +1205,7 @@ void read_stats(void) allocate_structures(act); /* Print report header */ - print_report_hdr(flags, &rectime, &file_hdr); + print_report_hdr(flags, &(rectime.tm_time), &file_hdr); /* Read system statistics sent by the data collector */ read_sadc_stat_bunch(0); @@ -1246,9 +1246,22 @@ void read_stats(void) } lines++; } - write_stats(curr, USE_SADC, &count, NO_TM_START, tm_end.use, + write_stats(curr, USE_SADC, &count, NO_TIME, tm_end.use, NO_RESET, ALL_ACTIVITIES, TRUE); + if ((tm_end.use != NO_TIME) && (datecmp(&rectime, &tm_end, FALSE) == 0)) { + /* + * The last record displayed has reached ending time. + * Set @count to 0 to keep sadc from saving an additional + * record on next loop and stop now. + * This is not perfect anyway: If the last displayed record hasn't + * reached ending time, but the next one exceeds it, it will not be + * displayed but will still have been saved in datafile by sadc since + * the test is made later at display time. + */ + count = 0; + } + if (record_hdr[curr].record_type == R_LAST_STATS) { /* File rotation is happening: Re-read header data sent by sadc */ read_header_data(); @@ -1298,7 +1311,7 @@ int main(int argc, char **argv) init_nls(); #endif - tm_start.use = tm_end.use = FALSE; + tm_start.use = tm_end.use = NO_TIME; /* Allocate and init activity bitmaps */ allocate_bitmaps(act); @@ -1541,8 +1554,8 @@ int main(int argc, char **argv) set_default_file(from_file, day_offset, -1); } - if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) { - tm_end.tm_hour += 24; + if (check_time_limits(&tm_start, &tm_end)) { + usage(argv[0]); } /* @@ -1558,7 +1571,7 @@ int main(int argc, char **argv) set_bitmaps(act, &flags); } /* Use time start or option -i only when reading stats from a file */ - if ((tm_start.use || INTERVAL_SET(flags)) && !from_file[0]) { + if (((tm_start.use != NO_TIME) || INTERVAL_SET(flags)) && !from_file[0]) { fprintf(stderr, _("Not reading from a system activity file (use -f option)\n")); exit(1); diff --git a/svg_stats.c b/svg_stats.c index 5cb99aa..d6bf5a4 100644 --- a/svg_stats.c +++ b/svg_stats.c @@ -683,7 +683,7 @@ void display_hgrid(double ypos, double yfactor, double lmax, int dp) void display_vgrid(long int xpos, double xfactor, int v_gridnr, struct svg_parm *svg_p) { struct record_header stamp; - struct tm rectime; + struct tstamp_ext rectime; char cur_time[TIMESTAMP_LEN]; int j; @@ -712,7 +712,7 @@ void display_vgrid(long int xpos, double xfactor, int v_gridnr, struct svg_parm #endif exit(1); } - set_record_timestamp_string(flags, &stamp, NULL, cur_time, TIMESTAMP_LEN, &rectime); + set_record_timestamp_string(flags, NULL, cur_time, TIMESTAMP_LEN, &rectime); printf("\n", xpos * j, xpos * j, -SVG_G_YSIZE, @@ -723,12 +723,12 @@ void display_vgrid(long int xpos, double xfactor, int v_gridnr, struct svg_parm * NB: We may have tm_min != 0 if we have more than 24H worth of data in one datafile. * In this case, we should rather display the exact time instead of only the hour. */ - if (DISPLAY_ONE_DAY(flags) && (rectime.tm_min == 0)) { + if (DISPLAY_ONE_DAY(flags) && (rectime.tm_time.tm_min == 0)) { printf("%2d:00\n", (long) (xpos * j * xfactor) - 15, svg_colors[palette][SVG_COL_AXIS_IDX], - rectime.tm_hour); + rectime.tm_time.tm_hour); } else { printf("