X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Ftime-util.c;h=12f1b193be550aa7b3962891c99ea7fe75943b7e;hp=fc79c569f4bceb52450a4a7be17ea09d6b8c817b;hb=86e97d599f8b1ca379dce64fadac9b8f6b002ac5;hpb=7568345034f2890af745747783c5abfbf6eccf0f diff --git a/src/shared/time-util.c b/src/shared/time-util.c index fc79c569f..12f1b193b 100644 --- a/src/shared/time-util.c +++ b/src/shared/time-util.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "util.h" #include "time-util.h" @@ -48,25 +49,20 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { int64_t delta; assert(ts); - if (u == (usec_t) -1) { - ts->realtime = ts->monotonic = (usec_t) -1; + if (u == USEC_INFINITY || u <= 0) { + ts->realtime = ts->monotonic = u; return ts; } ts->realtime = u; - if (u == 0) - ts->monotonic = 0; - else { - delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - - ts->monotonic = now(CLOCK_MONOTONIC); + delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; + ts->monotonic = now(CLOCK_MONOTONIC); - if ((int64_t) ts->monotonic > delta) - ts->monotonic -= delta; - else - ts->monotonic = 0; - } + if ((int64_t) ts->monotonic > delta) + ts->monotonic -= delta; + else + ts->monotonic = 0; return ts; } @@ -75,8 +71,8 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { int64_t delta; assert(ts); - if (u == (usec_t) -1) { - ts->realtime = ts->monotonic = (usec_t) -1; + if (u == USEC_INFINITY) { + ts->realtime = ts->monotonic = USEC_INFINITY; return ts; } @@ -97,10 +93,10 @@ usec_t timespec_load(const struct timespec *ts) { if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) - return (usec_t) -1; + return USEC_INFINITY; if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) - return (usec_t) -1; + return USEC_INFINITY; return (usec_t) ts->tv_sec * USEC_PER_SEC + @@ -110,7 +106,7 @@ usec_t timespec_load(const struct timespec *ts) { struct timespec *timespec_store(struct timespec *ts, usec_t u) { assert(ts); - if (u == (usec_t) -1) { + if (u == USEC_INFINITY) { ts->tv_sec = (time_t) -1; ts->tv_nsec = (long) -1; return ts; @@ -127,10 +123,10 @@ usec_t timeval_load(const struct timeval *tv) { if (tv->tv_sec == (time_t) -1 && tv->tv_usec == (suseconds_t) -1) - return (usec_t) -1; + return USEC_INFINITY; if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC) - return (usec_t) -1; + return USEC_INFINITY; return (usec_t) tv->tv_sec * USEC_PER_SEC + @@ -140,7 +136,7 @@ usec_t timeval_load(const struct timeval *tv) { struct timeval *timeval_store(struct timeval *tv, usec_t u) { assert(tv); - if (u == (usec_t) -1) { + if (u == USEC_INFINITY) { tv->tv_sec = (time_t) -1; tv->tv_usec = (suseconds_t) -1; } else { @@ -151,36 +147,51 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) { return tv; } -char *format_timestamp(char *buf, size_t l, usec_t t) { +static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) { struct tm tm; time_t sec; assert(buf); assert(l > 0); - if (t <= 0 || t == (usec_t) -1) + if (t <= 0 || t == USEC_INFINITY) return NULL; sec = (time_t) (t / USEC_PER_SEC); - if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0) + if (utc) + gmtime_r(&sec, &tm); + else + localtime_r(&sec, &tm); + if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0) return NULL; return buf; } -char *format_timestamp_us(char *buf, size_t l, usec_t t) { +char *format_timestamp(char *buf, size_t l, usec_t t) { + return format_timestamp_internal(buf, l, t, false); +} + +char *format_timestamp_utc(char *buf, size_t l, usec_t t) { + return format_timestamp_internal(buf, l, t, true); +} + +static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) { struct tm tm; time_t sec; assert(buf); assert(l > 0); - if (t <= 0 || t == (usec_t) -1) + if (t <= 0 || t == USEC_INFINITY) return NULL; sec = (time_t) (t / USEC_PER_SEC); - localtime_r(&sec, &tm); + if (utc) + gmtime_r(&sec, &tm); + else + localtime_r(&sec, &tm); if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) return NULL; @@ -191,15 +202,22 @@ char *format_timestamp_us(char *buf, size_t l, usec_t t) { return buf; } +char *format_timestamp_us(char *buf, size_t l, usec_t t) { + return format_timestamp_internal_us(buf, l, t, false); +} + +char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) { + return format_timestamp_internal_us(buf, l, t, true); +} + char *format_timestamp_relative(char *buf, size_t l, usec_t t) { const char *s; usec_t n, d; - n = now(CLOCK_REALTIME); - - if (t <= 0 || (t == (usec_t) -1)) + if (t <= 0 || t == USEC_INFINITY) return NULL; + n = now(CLOCK_REALTIME); if (n > t) { d = n - t; s = "ago"; @@ -278,11 +296,14 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { assert(buf); assert(l > 0); - if (t == (usec_t) -1) - return NULL; + if (t == USEC_INFINITY) { + strncpy(p, "infinity", l-1); + p[l-1] = 0; + return p; + } if (t <= 0) { - snprintf(p, l, "0"); + strncpy(p, "0", l-1); p[l-1] = 0; return p; } @@ -377,18 +398,21 @@ void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { t->monotonic); } -void dual_timestamp_deserialize(const char *value, dual_timestamp *t) { +int dual_timestamp_deserialize(const char *value, dual_timestamp *t) { unsigned long long a, b; assert(value); assert(t); - if (sscanf(value, "%llu %llu", &a, &b) != 2) - log_debug("Failed to parse finish timestamp value %s", value); - else { - t->realtime = a; - t->monotonic = b; + if (sscanf(value, "%llu %llu", &a, &b) != 2) { + log_debug("Failed to parse finish timestamp value %s.", value); + return -EINVAL; } + + t->realtime = a; + t->monotonic = b; + + return 0; } int parse_timestamp(const char *t, usec_t *usec) { @@ -627,7 +651,7 @@ int parse_sec(const char *t, usec_t *usec) { { "", USEC_PER_SEC }, /* default is sec */ }; - const char *p; + const char *p, *s; usec_t r = 0; bool something = false; @@ -635,6 +659,18 @@ int parse_sec(const char *t, usec_t *usec) { assert(usec); p = t; + + p += strspn(p, WHITESPACE); + s = startswith(p, "infinity"); + if (s) { + s += strspn(s, WHITESPACE); + if (*s != 0) + return -EINVAL; + + *usec = USEC_INFINITY; + return 0; + } + for (;;) { long long l, z = 0; char *e; @@ -740,7 +776,7 @@ int parse_nsec(const char *t, nsec_t *nsec) { { "", 1ULL }, /* default is nsec */ }; - const char *p; + const char *p, *s; nsec_t r = 0; bool something = false; @@ -748,6 +784,18 @@ int parse_nsec(const char *t, nsec_t *nsec) { assert(nsec); p = t; + + p += strspn(p, WHITESPACE); + s = startswith(p, "infinity"); + if (s) { + s += strspn(s, WHITESPACE); + if (*s != 0) + return -EINVAL; + + *nsec = NSEC_INFINITY; + return 0; + } + for (;;) { long long l, z = 0; char *e; @@ -920,7 +968,7 @@ bool timezone_is_valid(const char *name) { if (slash) return false; - t = strappenda("/usr/share/zoneinfo/", name); + t = strjoina("/usr/share/zoneinfo/", name); if (stat(t, &st) < 0) return false; @@ -929,3 +977,21 @@ bool timezone_is_valid(const char *name) { return true; } + +clockid_t clock_boottime_or_monotonic(void) { + static clockid_t clock = -1; + int fd; + + if (clock != -1) + return clock; + + fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (fd < 0) + clock = CLOCK_MONOTONIC; + else { + safe_close(fd); + clock = CLOCK_BOOTTIME; + } + + return clock; +}