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 "path-util.h"
31 #include "string-util.h"
33 #include "time-util.h"
36 usec_t now(clockid_t clock_id) {
39 assert_se(clock_gettime(clock_id, &ts) == 0);
41 return timespec_load(&ts);
44 #if 0 /// UNNEEDED by elogind
45 nsec_t now_nsec(clockid_t clock_id) {
48 assert_se(clock_gettime(clock_id, &ts) == 0);
50 return timespec_load_nsec(&ts);
54 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
57 ts->realtime = now(CLOCK_REALTIME);
58 ts->monotonic = now(CLOCK_MONOTONIC);
63 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
67 if (u == USEC_INFINITY || u <= 0) {
68 ts->realtime = ts->monotonic = u;
74 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
75 ts->monotonic = now(CLOCK_MONOTONIC);
77 if ((int64_t) ts->monotonic > delta)
78 ts->monotonic -= delta;
85 #if 0 /// UNNEEDED by elogind
86 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
90 if (u == USEC_INFINITY) {
91 ts->realtime = ts->monotonic = USEC_INFINITY;
96 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
98 ts->realtime = now(CLOCK_REALTIME);
99 if ((int64_t) ts->realtime > delta)
100 ts->realtime -= delta;
107 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
110 if (u == USEC_INFINITY) {
111 ts->realtime = ts->monotonic = USEC_INFINITY;
114 ts->realtime = now(CLOCK_REALTIME);
115 ts->monotonic = now(CLOCK_MONOTONIC);
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);
670 unsigned long long val;
674 if (*k < '0' || *k > '9')
677 /* base 10 instead of base 0, .09 is not base 8 */
679 val = strtoull(k, &end, 10);
685 /* val has l digits, make them 6 */
695 x = mktime_or_timegm(&tm, utc);
696 if (x == (time_t) -1)
699 if (weekday >= 0 && tm.tm_wday != weekday)
702 ret = (usec_t) x * USEC_PER_SEC + x_usec;
717 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
719 static const struct {
723 { "seconds", USEC_PER_SEC },
724 { "second", USEC_PER_SEC },
725 { "sec", USEC_PER_SEC },
726 { "s", USEC_PER_SEC },
727 { "minutes", USEC_PER_MINUTE },
728 { "minute", USEC_PER_MINUTE },
729 { "min", USEC_PER_MINUTE },
730 { "months", USEC_PER_MONTH },
731 { "month", USEC_PER_MONTH },
732 { "M", USEC_PER_MONTH },
733 { "msec", USEC_PER_MSEC },
734 { "ms", USEC_PER_MSEC },
735 { "m", USEC_PER_MINUTE },
736 { "hours", USEC_PER_HOUR },
737 { "hour", USEC_PER_HOUR },
738 { "hr", USEC_PER_HOUR },
739 { "h", USEC_PER_HOUR },
740 { "days", USEC_PER_DAY },
741 { "day", USEC_PER_DAY },
742 { "d", USEC_PER_DAY },
743 { "weeks", USEC_PER_WEEK },
744 { "week", USEC_PER_WEEK },
745 { "w", USEC_PER_WEEK },
746 { "years", USEC_PER_YEAR },
747 { "year", USEC_PER_YEAR },
748 { "y", USEC_PER_YEAR },
755 bool something = false;
759 assert(default_unit > 0);
763 p += strspn(p, WHITESPACE);
764 s = startswith(p, "infinity");
766 s += strspn(s, WHITESPACE);
770 *usec = USEC_INFINITY;
778 usec_t multiplier, k;
780 p += strspn(p, WHITESPACE);
790 l = strtoll(p, &e, 10);
802 z = strtoll(b, &e, 10);
817 e += strspn(e, WHITESPACE);
819 for (i = 0; i < ELEMENTSOF(table); i++)
820 if (startswith(e, table[i].suffix)) {
821 multiplier = table[i].usec;
822 p = e + strlen(table[i].suffix);
826 if (i >= ELEMENTSOF(table)) {
827 multiplier = default_unit;
833 k = (usec_t) z * multiplier;
838 r += (usec_t) l * multiplier + k;
846 int parse_sec(const char *t, usec_t *usec) {
847 return parse_time(t, usec, USEC_PER_SEC);
850 #if 0 /// UNNEEDED by elogind
851 int parse_nsec(const char *t, nsec_t *nsec) {
852 static const struct {
856 { "seconds", NSEC_PER_SEC },
857 { "second", NSEC_PER_SEC },
858 { "sec", NSEC_PER_SEC },
859 { "s", NSEC_PER_SEC },
860 { "minutes", NSEC_PER_MINUTE },
861 { "minute", NSEC_PER_MINUTE },
862 { "min", NSEC_PER_MINUTE },
863 { "months", NSEC_PER_MONTH },
864 { "month", NSEC_PER_MONTH },
865 { "msec", NSEC_PER_MSEC },
866 { "ms", NSEC_PER_MSEC },
867 { "m", NSEC_PER_MINUTE },
868 { "hours", NSEC_PER_HOUR },
869 { "hour", NSEC_PER_HOUR },
870 { "hr", NSEC_PER_HOUR },
871 { "h", NSEC_PER_HOUR },
872 { "days", NSEC_PER_DAY },
873 { "day", NSEC_PER_DAY },
874 { "d", NSEC_PER_DAY },
875 { "weeks", NSEC_PER_WEEK },
876 { "week", NSEC_PER_WEEK },
877 { "w", NSEC_PER_WEEK },
878 { "years", NSEC_PER_YEAR },
879 { "year", NSEC_PER_YEAR },
880 { "y", NSEC_PER_YEAR },
881 { "usec", NSEC_PER_USEC },
882 { "us", NSEC_PER_USEC },
885 { "", 1ULL }, /* default is nsec */
890 bool something = false;
897 p += strspn(p, WHITESPACE);
898 s = startswith(p, "infinity");
900 s += strspn(s, WHITESPACE);
904 *nsec = NSEC_INFINITY;
913 p += strspn(p, WHITESPACE);
923 l = strtoll(p, &e, 10);
935 z = strtoll(b, &e, 10);
950 e += strspn(e, WHITESPACE);
952 for (i = 0; i < ELEMENTSOF(table); i++)
953 if (startswith(e, table[i].suffix)) {
954 nsec_t k = (nsec_t) z * table[i].nsec;
959 r += (nsec_t) l * table[i].nsec + k;
960 p = e + strlen(table[i].suffix);
966 if (i >= ELEMENTSOF(table))
976 bool ntp_synced(void) {
977 struct timex txc = {};
979 if (adjtimex(&txc) < 0)
982 if (txc.status & STA_UNSYNC)
988 int get_timezones(char ***ret) {
989 _cleanup_fclose_ FILE *f = NULL;
990 _cleanup_strv_free_ char **zones = NULL;
991 size_t n_zones = 0, n_allocated = 0;
995 zones = strv_new("UTC", NULL);
1002 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
1006 FOREACH_LINE(l, f, return -errno) {
1012 if (isempty(p) || *p == '#')
1015 /* Skip over country code */
1016 p += strcspn(p, WHITESPACE);
1017 p += strspn(p, WHITESPACE);
1019 /* Skip over coordinates */
1020 p += strcspn(p, WHITESPACE);
1021 p += strspn(p, WHITESPACE);
1023 /* Found timezone name */
1024 k = strcspn(p, WHITESPACE);
1032 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1037 zones[n_zones++] = w;
1038 zones[n_zones] = NULL;
1043 } else if (errno != ENOENT)
1052 bool timezone_is_valid(const char *name) {
1063 for (p = name; *p; p++) {
1064 if (!(*p >= '0' && *p <= '9') &&
1065 !(*p >= 'a' && *p <= 'z') &&
1066 !(*p >= 'A' && *p <= 'Z') &&
1067 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1083 t = strjoina("/usr/share/zoneinfo/", name);
1084 if (stat(t, &st) < 0)
1087 if (!S_ISREG(st.st_mode))
1093 clockid_t clock_boottime_or_monotonic(void) {
1094 static clockid_t clock = -1;
1100 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1102 clock = CLOCK_MONOTONIC;
1105 clock = CLOCK_BOOTTIME;
1111 int get_timezone(char **tz) {
1112 _cleanup_free_ char *t = NULL;
1117 r = readlink_malloc("/etc/localtime", &t);
1119 return r; /* returns EINVAL if not a symlink */
1121 e = path_startswith(t, "/usr/share/zoneinfo/");
1123 e = path_startswith(t, "../usr/share/zoneinfo/");
1127 if (!timezone_is_valid(e))
1138 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1139 return utc ? timegm(tm) : mktime(tm);
1143 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1144 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1147 #if 0 /// UNNEEDED by elogind
1148 unsigned long usec_to_jiffies(usec_t u) {
1149 static thread_local unsigned long hz = 0;
1153 r = sysconf(_SC_CLK_TCK);
1156 hz = (unsigned long) r;
1159 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);