]> granicus.if.org Git - sysstat/commitdiff
sar/sadf: Rework code related to options -s/-e
authorSebastien GODARD <sysstat@users.noreply.github.com>
Sun, 22 Jan 2023 10:41:03 +0000 (11:41 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Sun, 22 Jan 2023 10:41:03 +0000 (11:41 +0100)
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 <sysstat@users.noreply.github.com>
common.c
sa.h
sa_common.c
sadf.c
sadf.h
sar.c
svg_stats.c

index ed144d950dcce00282d0905a385911213c018658..89a080528c09b084a73c86097ddc1725497f56e2 100644 (file)
--- 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 7cc435de95a78b0cd62026f8f40c4b470e6117fe..3d13b0874e5b85e96355b52ba7ebd6fe06c1de49 100644 (file)
--- 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 */
index b6f3d6ce79f0859fa43b9120f9bf219a0db0c834..d96a1b99d954e6cada5c585ab89317d389d49d80 100644 (file)
@@ -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(&timestamp[6], DIGITS) != 2))
                return 1;
 
-       tse->tm_sec  = atoi(&timestamp[6]);
-       tse->tm_min  = atoi(&timestamp[3]);
-       tse->tm_hour = atoi(timestamp);
+       tse->tm_time.tm_sec  = atoi(&timestamp[6]);
+       tse->tm_time.tm_min  = atoi(&timestamp[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 8f201bafa4aa5a633887481389e36c2e87274c7d..f65be7469b87bc66759c0832cd93087b0d56a50e 100644 (file)
--- 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 b0a891069f4f9445344241a067326bd8fe69d24e..b4fed5b9d7dadd2c096ec012ccf8bd87a230fe38 100644 (file)
--- 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 e92c54284562162972b37f941bdedb361a82188e..6ecb24401764f5cff687b2ae04e04d8ae5c64e3b 100644 (file)
--- 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);
index 5cb99aa8946923e9922454a2bb308a1a0403748b..d6bf5a4512b1c319b90a4b4bc49d6c4b9779b671 100644 (file)
@@ -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("<polyline points=\"%ld,0 %ld,%d\" style=\"vector-effect: non-scaling-stroke; "
                       "stroke: #%06x\" transform=\"scale(%f,1)\"/>\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("<text x=\"%ld\" y=\"15\" style=\"fill: #%06x; stroke: none; font-size: 14px; "
                               "text-anchor: start\">%2d:00</text>\n",
                               (long) (xpos * j * xfactor) - 15,
                               svg_colors[palette][SVG_COL_AXIS_IDX],
-                              rectime.tm_hour);
+                              rectime.tm_time.tm_hour);
                }
                else {
                        printf("<text x=\"%ld\" y=\"10\" style=\"fill: #%06x; stroke: none; font-size: 12px; "