#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"
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. */
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 */
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;
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;
+}
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)
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);
#endif
int time_change_fd(void);
+
+const char* timestamp_style_to_string(TimestampStyle t) _const_;
+TimestampStyle timestamp_style_from_string(const char *s) _pure_;
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);
}
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)
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)
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);
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
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);
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);
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);
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);
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);
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));
}
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);
/* 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;
}
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;
}
/* 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;
}
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;
}
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;
}
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[]) {
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);