1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/timerfd.h>
24 #include <sys/timex.h>
26 #include "alloc-util.h"
30 #include "parse-util.h"
31 #include "path-util.h"
32 #include "string-util.h"
34 #include "time-util.h"
37 usec_t now(clockid_t clock_id) {
40 assert_se(clock_gettime(clock_id, &ts) == 0);
42 return timespec_load(&ts);
45 #if 0 /// UNNEEDED by elogind
46 nsec_t now_nsec(clockid_t clock_id) {
49 assert_se(clock_gettime(clock_id, &ts) == 0);
51 return timespec_load_nsec(&ts);
55 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
58 ts->realtime = now(CLOCK_REALTIME);
59 ts->monotonic = now(CLOCK_MONOTONIC);
64 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
68 if (u == USEC_INFINITY || u <= 0) {
69 ts->realtime = ts->monotonic = u;
75 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
76 ts->monotonic = now(CLOCK_MONOTONIC);
78 if ((int64_t) ts->monotonic > delta)
79 ts->monotonic -= delta;
86 #if 0 /// UNNEEDED by elogind
87 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
91 if (u == USEC_INFINITY) {
92 ts->realtime = ts->monotonic = USEC_INFINITY;
97 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
99 ts->realtime = now(CLOCK_REALTIME);
100 if ((int64_t) ts->realtime > delta)
101 ts->realtime -= delta;
108 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
111 if (u == USEC_INFINITY) {
112 ts->realtime = ts->monotonic = USEC_INFINITY;
115 ts->realtime = now(CLOCK_REALTIME);
116 ts->monotonic = now(CLOCK_MONOTONIC);
118 delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
120 if ((int64_t) ts->realtime > delta)
121 ts->realtime -= delta;
125 if ((int64_t) ts->monotonic > delta)
126 ts->monotonic -= delta;
134 usec_t timespec_load(const struct timespec *ts) {
137 if (ts->tv_sec == (time_t) -1 &&
138 ts->tv_nsec == (long) -1)
139 return USEC_INFINITY;
141 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
142 return USEC_INFINITY;
145 (usec_t) ts->tv_sec * USEC_PER_SEC +
146 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
149 nsec_t timespec_load_nsec(const struct timespec *ts) {
152 if (ts->tv_sec == (time_t) -1 &&
153 ts->tv_nsec == (long) -1)
154 return NSEC_INFINITY;
157 (nsec_t) ts->tv_sec * NSEC_PER_SEC +
158 (nsec_t) ts->tv_nsec;
161 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
164 if (u == USEC_INFINITY) {
165 ts->tv_sec = (time_t) -1;
166 ts->tv_nsec = (long) -1;
170 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
171 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
176 usec_t timeval_load(const struct timeval *tv) {
179 if (tv->tv_sec == (time_t) -1 &&
180 tv->tv_usec == (suseconds_t) -1)
181 return USEC_INFINITY;
183 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
184 return USEC_INFINITY;
187 (usec_t) tv->tv_sec * USEC_PER_SEC +
188 (usec_t) tv->tv_usec;
191 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
194 if (u == USEC_INFINITY) {
195 tv->tv_sec = (time_t) -1;
196 tv->tv_usec = (suseconds_t) -1;
198 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
199 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
205 static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
212 if (t <= 0 || t == USEC_INFINITY)
215 sec = (time_t) (t / USEC_PER_SEC);
216 localtime_or_gmtime_r(&sec, &tm, utc);
218 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
224 char *format_timestamp(char *buf, size_t l, usec_t t) {
225 return format_timestamp_internal(buf, l, t, false);
228 #if 0 /// UNNEEDED by elogind
229 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
230 return format_timestamp_internal(buf, l, t, true);
234 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
241 if (t <= 0 || t == USEC_INFINITY)
244 sec = (time_t) (t / USEC_PER_SEC);
245 localtime_or_gmtime_r(&sec, &tm, utc);
247 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
249 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
250 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
256 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
257 return format_timestamp_internal_us(buf, l, t, false);
260 #if 0 /// UNNEEDED by elogind
261 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
262 return format_timestamp_internal_us(buf, l, t, true);
266 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
270 if (t <= 0 || t == USEC_INFINITY)
273 n = now(CLOCK_REALTIME);
282 if (d >= USEC_PER_YEAR)
283 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
285 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
286 else if (d >= USEC_PER_MONTH)
287 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
289 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
290 else if (d >= USEC_PER_WEEK)
291 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
293 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
294 else if (d >= 2*USEC_PER_DAY)
295 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
296 else if (d >= 25*USEC_PER_HOUR)
297 snprintf(buf, l, "1 day " USEC_FMT "h %s",
298 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
299 else if (d >= 6*USEC_PER_HOUR)
300 snprintf(buf, l, USEC_FMT "h %s",
301 d / USEC_PER_HOUR, s);
302 else if (d >= USEC_PER_HOUR)
303 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
305 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
306 else if (d >= 5*USEC_PER_MINUTE)
307 snprintf(buf, l, USEC_FMT "min %s",
308 d / USEC_PER_MINUTE, s);
309 else if (d >= USEC_PER_MINUTE)
310 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
312 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
313 else if (d >= USEC_PER_SEC)
314 snprintf(buf, l, USEC_FMT "s %s",
315 d / USEC_PER_SEC, s);
316 else if (d >= USEC_PER_MSEC)
317 snprintf(buf, l, USEC_FMT "ms %s",
318 d / USEC_PER_MSEC, s);
320 snprintf(buf, l, USEC_FMT"us %s",
323 snprintf(buf, l, "now");
329 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
330 static const struct {
334 { "y", USEC_PER_YEAR },
335 { "month", USEC_PER_MONTH },
336 { "w", USEC_PER_WEEK },
337 { "d", USEC_PER_DAY },
338 { "h", USEC_PER_HOUR },
339 { "min", USEC_PER_MINUTE },
340 { "s", USEC_PER_SEC },
341 { "ms", USEC_PER_MSEC },
347 bool something = false;
352 if (t == USEC_INFINITY) {
353 strncpy(p, "infinity", l-1);
359 strncpy(p, "0", l-1);
364 /* The result of this function can be parsed with parse_sec */
366 for (i = 0; i < ELEMENTSOF(table); i++) {
375 if (t < accuracy && something)
378 if (t < table[i].usec)
384 a = t / table[i].usec;
385 b = t % table[i].usec;
387 /* Let's see if we should shows this in dot notation */
388 if (t < USEC_PER_MINUTE && b > 0) {
393 for (cc = table[i].usec; cc > 1; cc /= 10)
396 for (cc = accuracy; cc > 1; cc /= 10) {
403 "%s"USEC_FMT".%0*llu%s",
407 (unsigned long long) b,
415 /* No? Then let's show it normally */
426 n = MIN((size_t) k, l);
439 #if 0 /// UNNEEDED by elogind
440 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
446 if (!dual_timestamp_is_set(t))
449 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
455 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
456 unsigned long long a, b;
461 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
462 log_debug("Failed to parse finish timestamp value %s.", value);
472 int parse_timestamp(const char *t, usec_t *usec) {
473 static const struct {
497 usec_t x_usec, plus = 0, minus = 0, ret;
504 * 2012-09-22 16:34:22
505 * 2012-09-22 16:34 (seconds will be set to 0)
506 * 2012-09-22 (time will be set to 00:00:00)
507 * 16:34:22 (date will be set to today)
508 * 16:34 (date will be set to today, seconds to 0)
510 * yesterday (time is set to 00:00:00)
511 * today (time is set to 00:00:00)
512 * tomorrow (time is set to 00:00:00)
515 * @2147483647 (seconds since epoch)
523 return parse_sec(t + 1, usec);
525 ret = now(CLOCK_REALTIME);
530 else if (t[0] == '+') {
531 r = parse_sec(t+1, &plus);
537 } else if (t[0] == '-') {
538 r = parse_sec(t+1, &minus);
544 } else if ((k = endswith(t, " ago"))) {
545 t = strndupa(t, k - t);
547 r = parse_sec(t, &minus);
553 } else if ((k = endswith(t, " left"))) {
554 t = strndupa(t, k - t);
556 r = parse_sec(t, &plus);
563 utc = endswith_no_case(t, " UTC");
565 t = strndupa(t, utc - t);
567 x = ret / USEC_PER_SEC;
570 assert_se(localtime_or_gmtime_r(&x, &tm, utc));
573 if (streq(t, "today")) {
574 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
577 } else if (streq(t, "yesterday")) {
579 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
582 } else if (streq(t, "tomorrow")) {
584 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
589 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
592 if (!startswith_no_case(t, day_nr[i].name))
595 skip = strlen(day_nr[i].name);
599 weekday = day_nr[i].nr;
605 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
614 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
623 k = strptime(t, "%y-%m-%d %H:%M", &tm);
630 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
637 k = strptime(t, "%y-%m-%d", &tm);
639 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
644 k = strptime(t, "%Y-%m-%d", &tm);
646 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
651 k = strptime(t, "%H:%M:%S", &tm);
660 k = strptime(t, "%H:%M", &tm);
673 r = parse_fractional_part_u(&k, 6, &add);
685 x = mktime_or_timegm(&tm, utc);
686 if (x == (time_t) -1)
689 if (weekday >= 0 && tm.tm_wday != weekday)
692 ret = (usec_t) x * USEC_PER_SEC + x_usec;
707 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
709 static const struct {
713 { "seconds", USEC_PER_SEC },
714 { "second", USEC_PER_SEC },
715 { "sec", USEC_PER_SEC },
716 { "s", USEC_PER_SEC },
717 { "minutes", USEC_PER_MINUTE },
718 { "minute", USEC_PER_MINUTE },
719 { "min", USEC_PER_MINUTE },
720 { "months", USEC_PER_MONTH },
721 { "month", USEC_PER_MONTH },
722 { "M", USEC_PER_MONTH },
723 { "msec", USEC_PER_MSEC },
724 { "ms", USEC_PER_MSEC },
725 { "m", USEC_PER_MINUTE },
726 { "hours", USEC_PER_HOUR },
727 { "hour", USEC_PER_HOUR },
728 { "hr", USEC_PER_HOUR },
729 { "h", USEC_PER_HOUR },
730 { "days", USEC_PER_DAY },
731 { "day", USEC_PER_DAY },
732 { "d", USEC_PER_DAY },
733 { "weeks", USEC_PER_WEEK },
734 { "week", USEC_PER_WEEK },
735 { "w", USEC_PER_WEEK },
736 { "years", USEC_PER_YEAR },
737 { "year", USEC_PER_YEAR },
738 { "y", USEC_PER_YEAR },
745 bool something = false;
749 assert(default_unit > 0);
753 p += strspn(p, WHITESPACE);
754 s = startswith(p, "infinity");
756 s += strspn(s, WHITESPACE);
760 *usec = USEC_INFINITY;
768 usec_t multiplier, k;
770 p += strspn(p, WHITESPACE);
780 l = strtoll(p, &e, 10);
792 z = strtoll(b, &e, 10);
807 e += strspn(e, WHITESPACE);
809 for (i = 0; i < ELEMENTSOF(table); i++)
810 if (startswith(e, table[i].suffix)) {
811 multiplier = table[i].usec;
812 p = e + strlen(table[i].suffix);
816 if (i >= ELEMENTSOF(table)) {
817 multiplier = default_unit;
823 k = (usec_t) z * multiplier;
828 r += (usec_t) l * multiplier + k;
836 int parse_sec(const char *t, usec_t *usec) {
837 return parse_time(t, usec, USEC_PER_SEC);
840 #if 0 /// UNNEEDED by elogind
841 int parse_nsec(const char *t, nsec_t *nsec) {
842 static const struct {
846 { "seconds", NSEC_PER_SEC },
847 { "second", NSEC_PER_SEC },
848 { "sec", NSEC_PER_SEC },
849 { "s", NSEC_PER_SEC },
850 { "minutes", NSEC_PER_MINUTE },
851 { "minute", NSEC_PER_MINUTE },
852 { "min", NSEC_PER_MINUTE },
853 { "months", NSEC_PER_MONTH },
854 { "month", NSEC_PER_MONTH },
855 { "msec", NSEC_PER_MSEC },
856 { "ms", NSEC_PER_MSEC },
857 { "m", NSEC_PER_MINUTE },
858 { "hours", NSEC_PER_HOUR },
859 { "hour", NSEC_PER_HOUR },
860 { "hr", NSEC_PER_HOUR },
861 { "h", NSEC_PER_HOUR },
862 { "days", NSEC_PER_DAY },
863 { "day", NSEC_PER_DAY },
864 { "d", NSEC_PER_DAY },
865 { "weeks", NSEC_PER_WEEK },
866 { "week", NSEC_PER_WEEK },
867 { "w", NSEC_PER_WEEK },
868 { "years", NSEC_PER_YEAR },
869 { "year", NSEC_PER_YEAR },
870 { "y", NSEC_PER_YEAR },
871 { "usec", NSEC_PER_USEC },
872 { "us", NSEC_PER_USEC },
875 { "", 1ULL }, /* default is nsec */
880 bool something = false;
887 p += strspn(p, WHITESPACE);
888 s = startswith(p, "infinity");
890 s += strspn(s, WHITESPACE);
894 *nsec = NSEC_INFINITY;
903 p += strspn(p, WHITESPACE);
913 l = strtoll(p, &e, 10);
925 z = strtoll(b, &e, 10);
940 e += strspn(e, WHITESPACE);
942 for (i = 0; i < ELEMENTSOF(table); i++)
943 if (startswith(e, table[i].suffix)) {
944 nsec_t k = (nsec_t) z * table[i].nsec;
949 r += (nsec_t) l * table[i].nsec + k;
950 p = e + strlen(table[i].suffix);
956 if (i >= ELEMENTSOF(table))
966 bool ntp_synced(void) {
967 struct timex txc = {};
969 if (adjtimex(&txc) < 0)
972 if (txc.status & STA_UNSYNC)
978 int get_timezones(char ***ret) {
979 _cleanup_fclose_ FILE *f = NULL;
980 _cleanup_strv_free_ char **zones = NULL;
981 size_t n_zones = 0, n_allocated = 0;
985 zones = strv_new("UTC", NULL);
992 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
996 FOREACH_LINE(l, f, return -errno) {
1002 if (isempty(p) || *p == '#')
1005 /* Skip over country code */
1006 p += strcspn(p, WHITESPACE);
1007 p += strspn(p, WHITESPACE);
1009 /* Skip over coordinates */
1010 p += strcspn(p, WHITESPACE);
1011 p += strspn(p, WHITESPACE);
1013 /* Found timezone name */
1014 k = strcspn(p, WHITESPACE);
1022 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1027 zones[n_zones++] = w;
1028 zones[n_zones] = NULL;
1033 } else if (errno != ENOENT)
1042 bool timezone_is_valid(const char *name) {
1053 for (p = name; *p; p++) {
1054 if (!(*p >= '0' && *p <= '9') &&
1055 !(*p >= 'a' && *p <= 'z') &&
1056 !(*p >= 'A' && *p <= 'Z') &&
1057 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1073 t = strjoina("/usr/share/zoneinfo/", name);
1074 if (stat(t, &st) < 0)
1077 if (!S_ISREG(st.st_mode))
1083 clockid_t clock_boottime_or_monotonic(void) {
1084 static clockid_t clock = -1;
1090 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1092 clock = CLOCK_MONOTONIC;
1095 clock = CLOCK_BOOTTIME;
1101 int get_timezone(char **tz) {
1102 _cleanup_free_ char *t = NULL;
1107 r = readlink_malloc("/etc/localtime", &t);
1109 return r; /* returns EINVAL if not a symlink */
1111 e = path_startswith(t, "/usr/share/zoneinfo/");
1113 e = path_startswith(t, "../usr/share/zoneinfo/");
1117 if (!timezone_is_valid(e))
1128 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1129 return utc ? timegm(tm) : mktime(tm);
1133 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1134 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1137 #if 0 /// UNNEEDED by elogind
1138 unsigned long usec_to_jiffies(usec_t u) {
1139 static thread_local unsigned long hz = 0;
1143 r = sysconf(_SC_CLK_TCK);
1146 hz = (unsigned long) r;
1149 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);