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;
116 dual_timestamp_get(ts);
117 delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
119 if ((int64_t) ts->realtime > delta)
120 ts->realtime -= delta;
124 if ((int64_t) ts->monotonic > delta)
125 ts->monotonic -= delta;
133 usec_t timespec_load(const struct timespec *ts) {
136 if (ts->tv_sec == (time_t) -1 &&
137 ts->tv_nsec == (long) -1)
138 return USEC_INFINITY;
140 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
141 return USEC_INFINITY;
144 (usec_t) ts->tv_sec * USEC_PER_SEC +
145 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
148 nsec_t timespec_load_nsec(const struct timespec *ts) {
151 if (ts->tv_sec == (time_t) -1 &&
152 ts->tv_nsec == (long) -1)
153 return NSEC_INFINITY;
156 (nsec_t) ts->tv_sec * NSEC_PER_SEC +
157 (nsec_t) ts->tv_nsec;
160 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
163 if (u == USEC_INFINITY) {
164 ts->tv_sec = (time_t) -1;
165 ts->tv_nsec = (long) -1;
169 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
170 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
175 usec_t timeval_load(const struct timeval *tv) {
178 if (tv->tv_sec == (time_t) -1 &&
179 tv->tv_usec == (suseconds_t) -1)
180 return USEC_INFINITY;
182 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
183 return USEC_INFINITY;
186 (usec_t) tv->tv_sec * USEC_PER_SEC +
187 (usec_t) tv->tv_usec;
190 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
193 if (u == USEC_INFINITY) {
194 tv->tv_sec = (time_t) -1;
195 tv->tv_usec = (suseconds_t) -1;
197 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
198 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
204 static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
211 if (t <= 0 || t == USEC_INFINITY)
214 sec = (time_t) (t / USEC_PER_SEC);
215 localtime_or_gmtime_r(&sec, &tm, utc);
217 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
223 char *format_timestamp(char *buf, size_t l, usec_t t) {
224 return format_timestamp_internal(buf, l, t, false);
227 #if 0 /// UNNEEDED by elogind
228 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
229 return format_timestamp_internal(buf, l, t, true);
233 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
240 if (t <= 0 || t == USEC_INFINITY)
243 sec = (time_t) (t / USEC_PER_SEC);
244 localtime_or_gmtime_r(&sec, &tm, utc);
246 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
248 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
249 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
255 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
256 return format_timestamp_internal_us(buf, l, t, false);
259 #if 0 /// UNNEEDED by elogind
260 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
261 return format_timestamp_internal_us(buf, l, t, true);
265 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
269 if (t <= 0 || t == USEC_INFINITY)
272 n = now(CLOCK_REALTIME);
281 if (d >= USEC_PER_YEAR)
282 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
284 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
285 else if (d >= USEC_PER_MONTH)
286 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
288 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
289 else if (d >= USEC_PER_WEEK)
290 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
292 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
293 else if (d >= 2*USEC_PER_DAY)
294 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
295 else if (d >= 25*USEC_PER_HOUR)
296 snprintf(buf, l, "1 day " USEC_FMT "h %s",
297 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
298 else if (d >= 6*USEC_PER_HOUR)
299 snprintf(buf, l, USEC_FMT "h %s",
300 d / USEC_PER_HOUR, s);
301 else if (d >= USEC_PER_HOUR)
302 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
304 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
305 else if (d >= 5*USEC_PER_MINUTE)
306 snprintf(buf, l, USEC_FMT "min %s",
307 d / USEC_PER_MINUTE, s);
308 else if (d >= USEC_PER_MINUTE)
309 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
311 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
312 else if (d >= USEC_PER_SEC)
313 snprintf(buf, l, USEC_FMT "s %s",
314 d / USEC_PER_SEC, s);
315 else if (d >= USEC_PER_MSEC)
316 snprintf(buf, l, USEC_FMT "ms %s",
317 d / USEC_PER_MSEC, s);
319 snprintf(buf, l, USEC_FMT"us %s",
322 snprintf(buf, l, "now");
328 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
329 static const struct {
333 { "y", USEC_PER_YEAR },
334 { "month", USEC_PER_MONTH },
335 { "w", USEC_PER_WEEK },
336 { "d", USEC_PER_DAY },
337 { "h", USEC_PER_HOUR },
338 { "min", USEC_PER_MINUTE },
339 { "s", USEC_PER_SEC },
340 { "ms", USEC_PER_MSEC },
346 bool something = false;
351 if (t == USEC_INFINITY) {
352 strncpy(p, "infinity", l-1);
358 strncpy(p, "0", l-1);
363 /* The result of this function can be parsed with parse_sec */
365 for (i = 0; i < ELEMENTSOF(table); i++) {
374 if (t < accuracy && something)
377 if (t < table[i].usec)
383 a = t / table[i].usec;
384 b = t % table[i].usec;
386 /* Let's see if we should shows this in dot notation */
387 if (t < USEC_PER_MINUTE && b > 0) {
392 for (cc = table[i].usec; cc > 1; cc /= 10)
395 for (cc = accuracy; cc > 1; cc /= 10) {
402 "%s"USEC_FMT".%0*llu%s",
406 (unsigned long long) b,
414 /* No? Then let's show it normally */
425 n = MIN((size_t) k, l);
438 #if 0 /// UNNEEDED by elogind
439 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
445 if (!dual_timestamp_is_set(t))
448 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
454 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
455 unsigned long long a, b;
460 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
461 log_debug("Failed to parse finish timestamp value %s.", value);
471 int parse_timestamp(const char *t, usec_t *usec) {
472 static const struct {
496 usec_t x_usec, plus = 0, minus = 0, ret;
503 * 2012-09-22 16:34:22
504 * 2012-09-22 16:34 (seconds will be set to 0)
505 * 2012-09-22 (time will be set to 00:00:00)
506 * 16:34:22 (date will be set to today)
507 * 16:34 (date will be set to today, seconds to 0)
509 * yesterday (time is set to 00:00:00)
510 * today (time is set to 00:00:00)
511 * tomorrow (time is set to 00:00:00)
514 * @2147483647 (seconds since epoch)
522 return parse_sec(t + 1, usec);
524 ret = now(CLOCK_REALTIME);
529 else if (t[0] == '+') {
530 r = parse_sec(t+1, &plus);
536 } else if (t[0] == '-') {
537 r = parse_sec(t+1, &minus);
543 } else if ((k = endswith(t, " ago"))) {
544 t = strndupa(t, k - t);
546 r = parse_sec(t, &minus);
552 } else if ((k = endswith(t, " left"))) {
553 t = strndupa(t, k - t);
555 r = parse_sec(t, &plus);
562 utc = endswith_no_case(t, " UTC");
564 t = strndupa(t, utc - t);
566 x = ret / USEC_PER_SEC;
569 assert_se(localtime_or_gmtime_r(&x, &tm, utc));
572 if (streq(t, "today")) {
573 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
576 } else if (streq(t, "yesterday")) {
578 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
581 } else if (streq(t, "tomorrow")) {
583 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
588 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
591 if (!startswith_no_case(t, day_nr[i].name))
594 skip = strlen(day_nr[i].name);
598 weekday = day_nr[i].nr;
604 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
613 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
622 k = strptime(t, "%y-%m-%d %H:%M", &tm);
629 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
636 k = strptime(t, "%y-%m-%d", &tm);
638 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
643 k = strptime(t, "%Y-%m-%d", &tm);
645 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
650 k = strptime(t, "%H:%M:%S", &tm);
659 k = strptime(t, "%H:%M", &tm);
672 r = parse_fractional_part_u(&k, 6, &add);
684 x = mktime_or_timegm(&tm, utc);
685 if (x == (time_t) -1)
688 if (weekday >= 0 && tm.tm_wday != weekday)
691 ret = (usec_t) x * USEC_PER_SEC + x_usec;
706 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
708 static const struct {
712 { "seconds", USEC_PER_SEC },
713 { "second", USEC_PER_SEC },
714 { "sec", USEC_PER_SEC },
715 { "s", USEC_PER_SEC },
716 { "minutes", USEC_PER_MINUTE },
717 { "minute", USEC_PER_MINUTE },
718 { "min", USEC_PER_MINUTE },
719 { "months", USEC_PER_MONTH },
720 { "month", USEC_PER_MONTH },
721 { "M", USEC_PER_MONTH },
722 { "msec", USEC_PER_MSEC },
723 { "ms", USEC_PER_MSEC },
724 { "m", USEC_PER_MINUTE },
725 { "hours", USEC_PER_HOUR },
726 { "hour", USEC_PER_HOUR },
727 { "hr", USEC_PER_HOUR },
728 { "h", USEC_PER_HOUR },
729 { "days", USEC_PER_DAY },
730 { "day", USEC_PER_DAY },
731 { "d", USEC_PER_DAY },
732 { "weeks", USEC_PER_WEEK },
733 { "week", USEC_PER_WEEK },
734 { "w", USEC_PER_WEEK },
735 { "years", USEC_PER_YEAR },
736 { "year", USEC_PER_YEAR },
737 { "y", USEC_PER_YEAR },
744 bool something = false;
748 assert(default_unit > 0);
752 p += strspn(p, WHITESPACE);
753 s = startswith(p, "infinity");
755 s += strspn(s, WHITESPACE);
759 *usec = USEC_INFINITY;
767 usec_t multiplier, k;
769 p += strspn(p, WHITESPACE);
779 l = strtoll(p, &e, 10);
791 z = strtoll(b, &e, 10);
806 e += strspn(e, WHITESPACE);
808 for (i = 0; i < ELEMENTSOF(table); i++)
809 if (startswith(e, table[i].suffix)) {
810 multiplier = table[i].usec;
811 p = e + strlen(table[i].suffix);
815 if (i >= ELEMENTSOF(table)) {
816 multiplier = default_unit;
822 k = (usec_t) z * multiplier;
827 r += (usec_t) l * multiplier + k;
835 int parse_sec(const char *t, usec_t *usec) {
836 return parse_time(t, usec, USEC_PER_SEC);
839 #if 0 /// UNNEEDED by elogind
840 int parse_nsec(const char *t, nsec_t *nsec) {
841 static const struct {
845 { "seconds", NSEC_PER_SEC },
846 { "second", NSEC_PER_SEC },
847 { "sec", NSEC_PER_SEC },
848 { "s", NSEC_PER_SEC },
849 { "minutes", NSEC_PER_MINUTE },
850 { "minute", NSEC_PER_MINUTE },
851 { "min", NSEC_PER_MINUTE },
852 { "months", NSEC_PER_MONTH },
853 { "month", NSEC_PER_MONTH },
854 { "msec", NSEC_PER_MSEC },
855 { "ms", NSEC_PER_MSEC },
856 { "m", NSEC_PER_MINUTE },
857 { "hours", NSEC_PER_HOUR },
858 { "hour", NSEC_PER_HOUR },
859 { "hr", NSEC_PER_HOUR },
860 { "h", NSEC_PER_HOUR },
861 { "days", NSEC_PER_DAY },
862 { "day", NSEC_PER_DAY },
863 { "d", NSEC_PER_DAY },
864 { "weeks", NSEC_PER_WEEK },
865 { "week", NSEC_PER_WEEK },
866 { "w", NSEC_PER_WEEK },
867 { "years", NSEC_PER_YEAR },
868 { "year", NSEC_PER_YEAR },
869 { "y", NSEC_PER_YEAR },
870 { "usec", NSEC_PER_USEC },
871 { "us", NSEC_PER_USEC },
874 { "", 1ULL }, /* default is nsec */
879 bool something = false;
886 p += strspn(p, WHITESPACE);
887 s = startswith(p, "infinity");
889 s += strspn(s, WHITESPACE);
893 *nsec = NSEC_INFINITY;
902 p += strspn(p, WHITESPACE);
912 l = strtoll(p, &e, 10);
924 z = strtoll(b, &e, 10);
939 e += strspn(e, WHITESPACE);
941 for (i = 0; i < ELEMENTSOF(table); i++)
942 if (startswith(e, table[i].suffix)) {
943 nsec_t k = (nsec_t) z * table[i].nsec;
948 r += (nsec_t) l * table[i].nsec + k;
949 p = e + strlen(table[i].suffix);
955 if (i >= ELEMENTSOF(table))
965 bool ntp_synced(void) {
966 struct timex txc = {};
968 if (adjtimex(&txc) < 0)
971 if (txc.status & STA_UNSYNC)
977 int get_timezones(char ***ret) {
978 _cleanup_fclose_ FILE *f = NULL;
979 _cleanup_strv_free_ char **zones = NULL;
980 size_t n_zones = 0, n_allocated = 0;
984 zones = strv_new("UTC", NULL);
991 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
995 FOREACH_LINE(l, f, return -errno) {
1001 if (isempty(p) || *p == '#')
1004 /* Skip over country code */
1005 p += strcspn(p, WHITESPACE);
1006 p += strspn(p, WHITESPACE);
1008 /* Skip over coordinates */
1009 p += strcspn(p, WHITESPACE);
1010 p += strspn(p, WHITESPACE);
1012 /* Found timezone name */
1013 k = strcspn(p, WHITESPACE);
1021 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1026 zones[n_zones++] = w;
1027 zones[n_zones] = NULL;
1032 } else if (errno != ENOENT)
1041 bool timezone_is_valid(const char *name) {
1052 for (p = name; *p; p++) {
1053 if (!(*p >= '0' && *p <= '9') &&
1054 !(*p >= 'a' && *p <= 'z') &&
1055 !(*p >= 'A' && *p <= 'Z') &&
1056 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1072 t = strjoina("/usr/share/zoneinfo/", name);
1073 if (stat(t, &st) < 0)
1076 if (!S_ISREG(st.st_mode))
1082 clockid_t clock_boottime_or_monotonic(void) {
1083 static clockid_t clock = -1;
1089 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1091 clock = CLOCK_MONOTONIC;
1094 clock = CLOCK_BOOTTIME;
1100 int get_timezone(char **tz) {
1101 _cleanup_free_ char *t = NULL;
1106 r = readlink_malloc("/etc/localtime", &t);
1108 return r; /* returns EINVAL if not a symlink */
1110 e = path_startswith(t, "/usr/share/zoneinfo/");
1112 e = path_startswith(t, "../usr/share/zoneinfo/");
1116 if (!timezone_is_valid(e))
1127 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1128 return utc ? timegm(tm) : mktime(tm);
1132 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1133 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1136 #if 0 /// UNNEEDED by elogind
1137 unsigned long usec_to_jiffies(usec_t u) {
1138 static thread_local unsigned long hz = 0;
1142 r = sysconf(_SC_CLK_TCK);
1145 hz = (unsigned long) r;
1148 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);