X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fbasic%2Ftime-util.c;h=97db1e2ccc659d4804acf991cbc204f10c316869;hb=9eaebafed6dec1c3b5d1307b37f1b03a19530527;hp=7fb3745d6c317f1dc0109f070d13c85d5388ed55;hpb=eaca07ccfdf5d7dabc50afc7e539c2413dd69d3e;p=elogind.git
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 7fb3745d6..97db1e2cc 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -19,34 +17,66 @@
along with systemd; If not, see .
***/
+#include
+#include
+#include
#include
+#include
+#include
#include
#include
+#include
+#include
#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "log.h"
+#include "macro.h"
+#include "parse-util.h"
#include "path-util.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
-#include "util.h"
+
+#if 0 /// UNNEEDED by elogind
+static nsec_t timespec_load_nsec(const struct timespec *ts);
+#endif // 0
+
+static clockid_t map_clock_id(clockid_t c) {
+
+ /* Some more exotic archs (s390, ppc, â¦) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
+ * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
+ * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
+ * those archs. */
+
+ switch (c) {
+
+ case CLOCK_BOOTTIME_ALARM:
+ return CLOCK_BOOTTIME;
+
+ case CLOCK_REALTIME_ALARM:
+ return CLOCK_REALTIME;
+
+ default:
+ return c;
+ }
+}
usec_t now(clockid_t clock_id) {
struct timespec ts;
- assert_se(clock_gettime(clock_id, &ts) == 0);
+ assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
return timespec_load(&ts);
}
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
nsec_t now_nsec(clockid_t clock_id) {
struct timespec ts;
- assert_se(clock_gettime(clock_id, &ts) == 0);
+ assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
return timespec_load_nsec(&ts);
}
@@ -73,18 +103,12 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
ts->realtime = u;
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;
+ ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
return ts;
}
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
int64_t delta;
assert(ts);
@@ -96,12 +120,7 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
ts->monotonic = u;
delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
-
- ts->realtime = now(CLOCK_REALTIME);
- if ((int64_t) ts->realtime > delta)
- ts->realtime -= delta;
- else
- ts->realtime = 0;
+ ts->realtime = usec_sub(now(CLOCK_REALTIME), delta);
return ts;
}
@@ -113,20 +132,11 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
ts->realtime = ts->monotonic = USEC_INFINITY;
return ts;
}
- ts->realtime = now(CLOCK_REALTIME);
- ts->monotonic = now(CLOCK_MONOTONIC);
+ dual_timestamp_get(ts);
delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
-
- if ((int64_t) ts->realtime > delta)
- ts->realtime -= delta;
- else
- ts->realtime = 0;
-
- if ((int64_t) ts->monotonic > delta)
- ts->monotonic -= delta;
- else
- ts->monotonic = 0;
+ ts->realtime = usec_sub(ts->realtime, delta);
+ ts->monotonic = usec_sub(ts->monotonic, delta);
return ts;
}
@@ -135,8 +145,7 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
usec_t timespec_load(const struct timespec *ts) {
assert(ts);
- if (ts->tv_sec == (time_t) -1 &&
- ts->tv_nsec == (long) -1)
+ if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1)
return USEC_INFINITY;
if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
@@ -147,17 +156,19 @@ usec_t timespec_load(const struct timespec *ts) {
(usec_t) ts->tv_nsec / NSEC_PER_USEC;
}
-nsec_t timespec_load_nsec(const struct timespec *ts) {
+#if 0 /// UNNEEDED by elogind
+static nsec_t timespec_load_nsec(const struct timespec *ts) {
assert(ts);
- if (ts->tv_sec == (time_t) -1 &&
- ts->tv_nsec == (long) -1)
+ if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1)
return NSEC_INFINITY;
- return
- (nsec_t) ts->tv_sec * NSEC_PER_SEC +
- (nsec_t) ts->tv_nsec;
+ if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC)
+ return NSEC_INFINITY;
+
+ return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec;
}
+#endif // 0
struct timespec *timespec_store(struct timespec *ts, usec_t u) {
assert(ts);
@@ -203,9 +214,11 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
return tv;
}
-static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
+static char *format_timestamp_internal(char *buf, size_t l, usec_t t,
+ bool utc, bool us) {
struct tm tm;
time_t sec;
+ int k;
assert(buf);
assert(l > 0);
@@ -216,53 +229,39 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc)
sec = (time_t) (t / USEC_PER_SEC);
localtime_or_gmtime_r(&sec, &tm, utc);
- if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
+ if (us)
+ k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm);
+ else
+ k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm);
+
+ if (k <= 0)
return NULL;
+ if (us) {
+ snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
+ if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
+ return NULL;
+ }
return buf;
}
char *format_timestamp(char *buf, size_t l, usec_t t) {
- return format_timestamp_internal(buf, l, t, false);
+ return format_timestamp_internal(buf, l, t, false, false);
}
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
- return format_timestamp_internal(buf, l, t, true);
+ return format_timestamp_internal(buf, l, t, true, false);
}
#endif // 0
-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_INFINITY)
- return NULL;
-
- sec = (time_t) (t / USEC_PER_SEC);
- localtime_or_gmtime_r(&sec, &tm, utc);
-
- if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
- return NULL;
- snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
- if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
- return NULL;
-
- return buf;
-}
-
char *format_timestamp_us(char *buf, size_t l, usec_t t) {
- return format_timestamp_internal_us(buf, l, t, false);
+ return format_timestamp_internal(buf, l, t, false, true);
}
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
- return format_timestamp_internal_us(buf, l, t, true);
+ return format_timestamp_internal(buf, l, t, true, true);
}
#endif // 0
@@ -334,15 +333,15 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
const char *suffix;
usec_t usec;
} table[] = {
- { "y", USEC_PER_YEAR },
- { "month", USEC_PER_MONTH },
- { "w", USEC_PER_WEEK },
- { "d", USEC_PER_DAY },
- { "h", USEC_PER_HOUR },
- { "min", USEC_PER_MINUTE },
- { "s", USEC_PER_SEC },
- { "ms", USEC_PER_MSEC },
- { "us", 1 },
+ { "y", USEC_PER_YEAR },
+ { "month", USEC_PER_MONTH },
+ { "w", USEC_PER_WEEK },
+ { "d", USEC_PER_DAY },
+ { "h", USEC_PER_HOUR },
+ { "min", USEC_PER_MINUTE },
+ { "s", USEC_PER_SEC },
+ { "ms", USEC_PER_MSEC },
+ { "us", 1 },
};
unsigned i;
@@ -439,8 +438,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
return buf;
}
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
assert(f);
@@ -463,7 +461,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
assert(t);
if (sscanf(value, "%llu %llu", &a, &b) != 2) {
- log_debug("Failed to parse finish timestamp value %s.", value);
+ log_debug("Failed to parse dual timestamp value \"%s\": %m", value);
return -EINVAL;
}
@@ -473,6 +471,20 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
return 0;
}
+#endif // 0
+int timestamp_deserialize(const char *value, usec_t *timestamp) {
+ int r;
+
+ assert(value);
+
+ r = safe_atou64(value, timestamp);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value);
+
+ return r;
+}
+
+#if 0 /// UNNEEDED by elogind
int parse_timestamp(const char *t, usec_t *usec) {
static const struct {
const char *name;
@@ -579,12 +591,12 @@ int parse_timestamp(const char *t, usec_t *usec) {
goto from_tm;
} else if (streq(t, "yesterday")) {
- tm.tm_mday --;
+ tm.tm_mday--;
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto from_tm;
} else if (streq(t, "tomorrow")) {
- tm.tm_mday ++;
+ tm.tm_mday++;
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto from_tm;
}
@@ -671,29 +683,18 @@ int parse_timestamp(const char *t, usec_t *usec) {
parse_usec:
{
- char *end;
- unsigned long long val;
- size_t l;
+ unsigned add;
k++;
- if (*k < '0' || *k > '9')
+ r = parse_fractional_part_u(&k, 6, &add);
+ if (r < 0)
return -EINVAL;
- /* base 10 instead of base 0, .09 is not base 8 */
- errno = 0;
- val = strtoull(k, &end, 10);
- if (*end || errno)
+ if (*k)
return -EINVAL;
- l = end-k;
+ x_usec = add;
- /* val has l digits, make them 6 */
- for (; l < 6; l++)
- val *= 10;
- for (; l > 6; l--)
- val /= 10;
-
- x_usec = val;
}
from_tm:
@@ -719,42 +720,56 @@ finish:
}
#endif // 0
-int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
-
+static char* extract_multiplier(char *p, usec_t *multiplier) {
static const struct {
const char *suffix;
usec_t usec;
} table[] = {
- { "seconds", USEC_PER_SEC },
- { "second", USEC_PER_SEC },
- { "sec", USEC_PER_SEC },
- { "s", USEC_PER_SEC },
+ { "seconds", USEC_PER_SEC },
+ { "second", USEC_PER_SEC },
+ { "sec", USEC_PER_SEC },
+ { "s", USEC_PER_SEC },
{ "minutes", USEC_PER_MINUTE },
- { "minute", USEC_PER_MINUTE },
- { "min", USEC_PER_MINUTE },
- { "months", USEC_PER_MONTH },
- { "month", USEC_PER_MONTH },
+ { "minute", USEC_PER_MINUTE },
+ { "min", USEC_PER_MINUTE },
+ { "months", USEC_PER_MONTH },
+ { "month", USEC_PER_MONTH },
{ "M", USEC_PER_MONTH },
- { "msec", USEC_PER_MSEC },
- { "ms", USEC_PER_MSEC },
- { "m", USEC_PER_MINUTE },
- { "hours", USEC_PER_HOUR },
- { "hour", USEC_PER_HOUR },
- { "hr", USEC_PER_HOUR },
- { "h", USEC_PER_HOUR },
- { "days", USEC_PER_DAY },
- { "day", USEC_PER_DAY },
- { "d", USEC_PER_DAY },
- { "weeks", USEC_PER_WEEK },
- { "week", USEC_PER_WEEK },
- { "w", USEC_PER_WEEK },
- { "years", USEC_PER_YEAR },
- { "year", USEC_PER_YEAR },
- { "y", USEC_PER_YEAR },
- { "usec", 1ULL },
- { "us", 1ULL },
+ { "msec", USEC_PER_MSEC },
+ { "ms", USEC_PER_MSEC },
+ { "m", USEC_PER_MINUTE },
+ { "hours", USEC_PER_HOUR },
+ { "hour", USEC_PER_HOUR },
+ { "hr", USEC_PER_HOUR },
+ { "h", USEC_PER_HOUR },
+ { "days", USEC_PER_DAY },
+ { "day", USEC_PER_DAY },
+ { "d", USEC_PER_DAY },
+ { "weeks", USEC_PER_WEEK },
+ { "week", USEC_PER_WEEK },
+ { "w", USEC_PER_WEEK },
+ { "years", USEC_PER_YEAR },
+ { "year", USEC_PER_YEAR },
+ { "y", USEC_PER_YEAR },
+ { "usec", 1ULL },
+ { "us", 1ULL },
};
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(table); i++) {
+ char *e;
+
+ e = startswith(p, table[i].suffix);
+ if (e) {
+ *multiplier = table[i].usec;
+ return e;
+ }
+ }
+
+ return p;
+}
+int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
const char *p, *s;
usec_t r = 0;
bool something = false;
@@ -779,8 +794,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
for (;;) {
long long l, z = 0;
char *e;
- unsigned i, n = 0;
- usec_t multiplier, k;
+ unsigned n = 0;
+ usec_t multiplier = default_unit, k;
p += strspn(p, WHITESPACE);
@@ -793,10 +808,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
errno = 0;
l = strtoll(p, &e, 10);
-
if (errno > 0)
return -errno;
-
if (l < 0)
return -ERANGE;
@@ -820,18 +833,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
return -EINVAL;
e += strspn(e, WHITESPACE);
-
- for (i = 0; i < ELEMENTSOF(table); i++)
- if (startswith(e, table[i].suffix)) {
- multiplier = table[i].usec;
- p = e + strlen(table[i].suffix);
- break;
- }
-
- if (i >= ELEMENTSOF(table)) {
- multiplier = default_unit;
- p = e;
- }
+ p = extract_multiplier(e, &multiplier);
something = true;
@@ -852,8 +854,7 @@ int parse_sec(const char *t, usec_t *usec) {
return parse_time(t, usec, USEC_PER_SEC);
}
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
int parse_nsec(const char *t, nsec_t *nsec) {
static const struct {
const char *suffix;
@@ -1096,22 +1097,33 @@ 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;
+#endif // 0
+bool clock_boottime_supported(void) {
+ static int supported = -1;
+
+ /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
+
+ if (supported < 0) {
+ int fd;
+
+ fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (fd < 0)
+ supported = false;
+ else {
+ safe_close(fd);
+ supported = true;
+ }
}
- return clock;
+ return supported;
+}
+
+#if 0 /// UNNEEDED by elogind
+clockid_t clock_boottime_or_monotonic(void) {
+ if (clock_boottime_supported())
+ return CLOCK_BOOTTIME;
+ else
+ return CLOCK_MONOTONIC;
}
int get_timezone(char **tz) {
@@ -1150,8 +1162,7 @@ struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
}
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
unsigned long usec_to_jiffies(usec_t u) {
static thread_local unsigned long hz = 0;
long r;