]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/time-util: add function to format timestamps with different styles
authorLuca Boccassi <luca.boccassi@microsoft.com>
Fri, 19 Jun 2020 10:24:09 +0000 (11:24 +0100)
committerLuca Boccassi <luca.boccassi@microsoft.com>
Wed, 19 Aug 2020 14:30:13 +0000 (15:30 +0100)
Instead of a multiple fixed format helper functions, add an enum and
a single helper, so that it's easier to extend in the future.

src/basic/time-util.c
src/basic/time-util.h
src/journal/journalctl.c
src/shared/format-table.c
src/shared/logs-show.c
src/test/test-calendarspec.c
src/test/test-date.c
src/test/test-time-util.c
src/time-wait-sync/time-wait-sync.c
src/tmpfiles/tmpfiles.c

index 15cc1b885121b0c78a57c11f85bf070183648842..0958f251eaf3f46b7750e5b0ce60cc8f1524700b 100644 (file)
@@ -23,6 +23,7 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "stat-util.h"
+#include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
@@ -282,12 +283,11 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
         return tv;
 }
 
-static char *format_timestamp_internal(
+char *format_timestamp_style(
                 char *buf,
                 size_t l,
                 usec_t t,
-                bool utc,
-                bool us) {
+                TimestampStyle style) {
 
         /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
          * generated timestamps may be parsed with parse_timestamp(), and always read the same. */
@@ -304,9 +304,27 @@ static char *format_timestamp_internal(
         struct tm tm;
         time_t sec;
         size_t n;
+        bool utc = false, us = false;
 
         assert(buf);
 
+        switch (style) {
+                case TIMESTAMP_PRETTY:
+                        break;
+                case TIMESTAMP_US:
+                        us = true;
+                        break;
+                case TIMESTAMP_UTC:
+                        utc = true;
+                        break;
+                case TIMESTAMP_US_UTC:
+                        us = true;
+                        utc = true;
+                        break;
+                default:
+                        return NULL;
+        }
+
         if (l < (size_t) (3 +                  /* week day */
                           1 + 10 +             /* space and date */
                           1 + 8 +              /* space and time */
@@ -380,22 +398,6 @@ static char *format_timestamp_internal(
         return buf;
 }
 
-char *format_timestamp(char *buf, size_t l, usec_t t) {
-        return format_timestamp_internal(buf, l, t, false, false);
-}
-
-char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
-        return format_timestamp_internal(buf, l, t, true, false);
-}
-
-char *format_timestamp_us(char *buf, size_t l, usec_t t) {
-        return format_timestamp_internal(buf, l, t, false, true);
-}
-
-char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
-        return format_timestamp_internal(buf, l, t, true, true);
-}
-
 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
         const char *s;
         usec_t n, d;
@@ -1568,3 +1570,27 @@ int time_change_fd(void) {
 
         return -errno;
 }
+
+static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
+        [TIMESTAMP_PRETTY] = "pretty",
+        [TIMESTAMP_US] = "us",
+        [TIMESTAMP_UTC] = "utc",
+        [TIMESTAMP_US_UTC] = "us+utc",
+};
+
+/* Use the macro for enum → string to allow for aliases */
+_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(timestamp_style, TimestampStyle,);
+
+/* For the string → enum mapping we use the generic implementation, but also support two aliases */
+TimestampStyle timestamp_style_from_string(const char *s) {
+        TimestampStyle t;
+
+        t = (TimestampStyle) string_table_lookup(timestamp_style_table, ELEMENTSOF(timestamp_style_table), s);
+        if (t >= 0)
+                return t;
+        if (streq_ptr(s, "µs"))
+                return TIMESTAMP_US;
+        if (streq_ptr(s, "µs+uts"))
+                return TIMESTAMP_US_UTC;
+        return t;
+}
index 9bbe9863062cae405984748365b60ebb7ca8cae9..b181a6b3b4586ce2f7dd0f5191119ac8fc0d5777 100644 (file)
@@ -29,6 +29,15 @@ typedef struct triple_timestamp {
         usec_t boottime;
 } triple_timestamp;
 
+typedef enum TimestampStyle {
+        TIMESTAMP_PRETTY,
+        TIMESTAMP_US,
+        TIMESTAMP_UTC,
+        TIMESTAMP_US_UTC,
+        _TIMESTAMP_STYLE_MAX,
+        _TIMESTAMP_STYLE_INVALID = -1,
+} TimestampStyle;
+
 #define USEC_INFINITY ((usec_t) UINT64_MAX)
 #define NSEC_INFINITY ((nsec_t) UINT64_MAX)
 
@@ -107,13 +116,14 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u);
 usec_t timeval_load(const struct timeval *tv) _pure_;
 struct timeval *timeval_store(struct timeval *tv, usec_t u);
 
-char *format_timestamp(char *buf, size_t l, usec_t t);
-char *format_timestamp_utc(char *buf, size_t l, usec_t t);
-char *format_timestamp_us(char *buf, size_t l, usec_t t);
-char *format_timestamp_us_utc(char *buf, size_t l, usec_t t);
+char *format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style);
 char *format_timestamp_relative(char *buf, size_t l, usec_t t);
 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
 
+static inline char *format_timestamp(char *buf, size_t l, usec_t t) {
+        return format_timestamp_style(buf, l, t, TIMESTAMP_PRETTY);
+}
+
 int parse_timestamp(const char *t, usec_t *usec);
 
 int parse_sec(const char *t, usec_t *usec);
@@ -185,3 +195,6 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
 #endif
 
 int time_change_fd(void);
+
+const char* timestamp_style_to_string(TimestampStyle t) _const_;
+TimestampStyle timestamp_style_from_string(const char *s) _pure_;
index 094499f47b1257a00c9b0d38031a387861cdd4ec..9d0048b8bc6ee6f83c5381a9b2d79ab770ce8cc5 100644 (file)
@@ -265,7 +265,7 @@ get_parent:
 static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
 
         if (arg_utc)
-                return format_timestamp_utc(buf, l, t);
+                return format_timestamp_style(buf, l, t, TIMESTAMP_UTC);
 
         return format_timestamp(buf, l, t);
 }
index 87ef5c3f00c98172ea7d85ab3e4a3d4c086aaab3..7e876295ff16d296908b9c85ade9d2e73039adcf 100644 (file)
@@ -1335,7 +1335,7 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
                 if (d->type == TABLE_TIMESTAMP)
                         ret = format_timestamp(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
                 else if (d->type == TABLE_TIMESTAMP_UTC)
-                        ret = format_timestamp_utc(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
+                        ret = format_timestamp_style(p, FORMAT_TIMESTAMP_MAX, d->timestamp, TIMESTAMP_UTC);
                 else
                         ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
                 if (!ret)
index 780ac508ced3300a9a1c5199dfbe05d014e6d632..979c9b3f290fb82a8f570ce7793622bd540d9399 100644 (file)
@@ -368,7 +368,7 @@ static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, Ou
                 const char *k;
 
                 if (flags & OUTPUT_UTC)
-                        k = format_timestamp_utc(buf, sizeof(buf), x);
+                        k = format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC);
                 else
                         k = format_timestamp(buf, sizeof(buf), x);
                 if (!k)
@@ -685,8 +685,8 @@ static int output_verbose(
         if (r < 0)
                 return log_error_errno(r, "Failed to get cursor: %m");
 
-        timestamp = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
-                                       : format_timestamp_us(ts, sizeof ts, realtime);
+        timestamp = format_timestamp_style(ts, sizeof ts, realtime,
+                                           flags & OUTPUT_UTC ? TIMESTAMP_US_UTC : TIMESTAMP_US);
         fprintf(f, "%s [%s]\n",
                 timestamp ?: "(no timestamp)",
                 cursor);
index 9e2ae55ab60c8f9d9f9aff904184f5d151f752f7..d566638d5d46b29b73beee373d4ebbdbcc1214be 100644 (file)
@@ -58,7 +58,7 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_
 
         u = after;
         r = calendar_spec_next_usec(c, after, &u);
-        printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_us(buf, sizeof buf, u));
+        printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US));
         if (expect != (usec_t)-1)
                 assert_se(r >= 0 && u == expect);
         else
@@ -83,7 +83,7 @@ static void test_timestamp(void) {
 
         x = now(CLOCK_REALTIME);
 
-        assert_se(format_timestamp_us(buf, sizeof(buf), x));
+        assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
         printf("%s\n", buf);
         assert_se(calendar_spec_from_string(buf, &c) >= 0);
         assert_se(calendar_spec_to_string(c, &t) >= 0);
@@ -104,11 +104,11 @@ static void test_hourly_bug_4031(void) {
         n = now(CLOCK_REALTIME);
         assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0);
 
-        printf("Now: %s (%"PRIu64")\n", format_timestamp_us(buf, sizeof buf, n), n);
-        printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(buf, sizeof buf, u), u);
+        printf("Now: %s (%"PRIu64")\n", format_timestamp_style(buf, sizeof buf, n, TIMESTAMP_US), n);
+        printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US), u);
 
         assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0);
-        printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(zaf, sizeof zaf, w), w);
+        printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w);
 
         assert_se(n < u);
         assert_se(u <= n + USEC_PER_HOUR);
index 7d27cfa703d4311653327d383750fb2e50cc2fed..f39eca61763ead0741631a2e945d99c2f429b356 100644 (file)
@@ -11,7 +11,7 @@ static void test_should_pass(const char *p) {
 
         log_info("Test: %s", p);
         assert_se(parse_timestamp(p, &t) >= 0);
-        assert_se(format_timestamp_us(buf, sizeof(buf), t));
+        assert_se(format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US));
         log_info("\"%s\" → \"%s\"", p, buf);
 
         assert_se(parse_timestamp(buf, &q) >= 0);
@@ -19,7 +19,7 @@ static void test_should_pass(const char *p) {
                 char tmp[FORMAT_TIMESTAMP_MAX];
 
                 log_error("round-trip failed: \"%s\" → \"%s\"",
-                          buf, format_timestamp_us(tmp, sizeof(tmp), q));
+                          buf, format_timestamp_style(tmp, sizeof(tmp), q, TIMESTAMP_US));
         }
         assert_se(q == t);
 
index 8826956d10f7774371087f7e6180b9263e6faad6..64242951acac11740545fea29788b071b03151af 100644 (file)
@@ -333,17 +333,17 @@ static void test_format_timestamp(void) {
                 assert_se(parse_timestamp(buf, &y) >= 0);
                 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
 
-                assert_se(format_timestamp_utc(buf, sizeof(buf), x));
+                assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
                 log_info("%s", buf);
                 assert_se(parse_timestamp(buf, &y) >= 0);
                 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
 
-                assert_se(format_timestamp_us(buf, sizeof(buf), x));
+                assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
                 log_info("%s", buf);
                 assert_se(parse_timestamp(buf, &y) >= 0);
                 assert_se(x == y);
 
-                assert_se(format_timestamp_us_utc(buf, sizeof(buf), x));
+                assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
                 log_info("%s", buf);
                 assert_se(parse_timestamp(buf, &y) >= 0);
                 assert_se(x == y);
@@ -364,7 +364,7 @@ static void test_format_timestamp_utc_one(usec_t val, const char *result) {
         char buf[FORMAT_TIMESTAMP_MAX];
         const char *t;
 
-        t = format_timestamp_utc(buf, sizeof(buf), val);
+        t = format_timestamp_style(buf, sizeof(buf), val, TIMESTAMP_UTC);
         assert_se(streq_ptr(t, result));
 }
 
index e880f9e6b67d33bf50fa3d0fb34e9fd5defcdcfa..96072445f6efe4b9eac9250cf6a3d94e4dc52e47 100644 (file)
@@ -155,7 +155,7 @@ static int clock_state_update(
         if (tx.status & STA_NANO)
                 tx.time.tv_usec /= 1000;
         t = timeval_load(&tx.time);
-        ts = format_timestamp_us_utc(buf, sizeof(buf), t);
+        ts = format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US_UTC);
         if (!ts)
                 strcpy(buf, "unrepresentable");
         log_info("adjtime state %d status %x time %s", sp->adjtime_state, tx.status, ts);
index 616a54b3c31c20f392d4a8e19bdcc40a6f89cea8..437b8bb4498a3df8fd2eb1d86b1a5b60249ed64e 100644 (file)
@@ -611,7 +611,7 @@ static int dir_cleanup(
                                 /* Follows spelling in stat(1). */
                                 log_debug("Directory \"%s\": modify time %s is too new.",
                                           sub_path,
-                                          format_timestamp_us(a, sizeof(a), age));
+                                          format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
                                 continue;
                         }
 
@@ -620,7 +620,7 @@ static int dir_cleanup(
                                 char a[FORMAT_TIMESTAMP_MAX];
                                 log_debug("Directory \"%s\": access time %s is too new.",
                                           sub_path,
-                                          format_timestamp_us(a, sizeof(a), age));
+                                          format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
                                 continue;
                         }
 
@@ -672,7 +672,7 @@ static int dir_cleanup(
                                 /* Follows spelling in stat(1). */
                                 log_debug("File \"%s\": modify time %s is too new.",
                                           sub_path,
-                                          format_timestamp_us(a, sizeof(a), age));
+                                          format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
                                 continue;
                         }
 
@@ -681,7 +681,7 @@ static int dir_cleanup(
                                 char a[FORMAT_TIMESTAMP_MAX];
                                 log_debug("File \"%s\": access time %s is too new.",
                                           sub_path,
-                                          format_timestamp_us(a, sizeof(a), age));
+                                          format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
                                 continue;
                         }
 
@@ -690,7 +690,7 @@ static int dir_cleanup(
                                 char a[FORMAT_TIMESTAMP_MAX];
                                 log_debug("File \"%s\": change time %s is too new.",
                                           sub_path,
-                                          format_timestamp_us(a, sizeof(a), age));
+                                          format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
                                 continue;
                         }
 
@@ -713,8 +713,8 @@ finish:
 
                 log_debug("Restoring access and modification time on \"%s\": %s, %s",
                           p,
-                          format_timestamp_us(a, sizeof(a), age1),
-                          format_timestamp_us(b, sizeof(b), age2));
+                          format_timestamp_style(a, sizeof(a), age1, TIMESTAMP_US),
+                          format_timestamp_style(b, sizeof(b), age2, TIMESTAMP_US));
 
                 /* Restore original directory timestamps */
                 if (futimens(dirfd(d), (struct timespec[]) {
@@ -2228,7 +2228,7 @@ static int clean_item_instance(Item *i, const char* instance) {
         log_debug("Cleanup threshold for %s \"%s\" is %s",
                   mountpoint ? "mount point" : "directory",
                   instance,
-                  format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
+                  format_timestamp_style(timestamp, sizeof(timestamp), cutoff, TIMESTAMP_US));
 
         return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
                            MAX_DEPTH, i->keep_first_level);