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 = usec_sub(now(CLOCK_MONOTONIC), delta);
81 #if 0 /// UNNEEDED by elogind
82 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
86 if (u == USEC_INFINITY) {
87 ts->realtime = ts->monotonic = USEC_INFINITY;
92 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
93 ts->realtime = usec_sub(now(CLOCK_REALTIME), delta);
98 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
101 if (u == USEC_INFINITY) {
102 ts->realtime = ts->monotonic = USEC_INFINITY;
106 dual_timestamp_get(ts);
107 delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
108 ts->realtime = usec_sub(ts->realtime, delta);
109 ts->monotonic = usec_sub(ts->monotonic, delta);
115 usec_t timespec_load(const struct timespec *ts) {
118 if (ts->tv_sec == (time_t) -1 &&
119 ts->tv_nsec == (long) -1)
120 return USEC_INFINITY;
122 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
123 return USEC_INFINITY;
126 (usec_t) ts->tv_sec * USEC_PER_SEC +
127 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
130 nsec_t timespec_load_nsec(const struct timespec *ts) {
133 if (ts->tv_sec == (time_t) -1 &&
134 ts->tv_nsec == (long) -1)
135 return NSEC_INFINITY;
138 (nsec_t) ts->tv_sec * NSEC_PER_SEC +
139 (nsec_t) ts->tv_nsec;
142 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
145 if (u == USEC_INFINITY) {
146 ts->tv_sec = (time_t) -1;
147 ts->tv_nsec = (long) -1;
151 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
152 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
157 usec_t timeval_load(const struct timeval *tv) {
160 if (tv->tv_sec == (time_t) -1 &&
161 tv->tv_usec == (suseconds_t) -1)
162 return USEC_INFINITY;
164 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
165 return USEC_INFINITY;
168 (usec_t) tv->tv_sec * USEC_PER_SEC +
169 (usec_t) tv->tv_usec;
172 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
175 if (u == USEC_INFINITY) {
176 tv->tv_sec = (time_t) -1;
177 tv->tv_usec = (suseconds_t) -1;
179 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
180 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
186 static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
193 if (t <= 0 || t == USEC_INFINITY)
196 sec = (time_t) (t / USEC_PER_SEC);
197 localtime_or_gmtime_r(&sec, &tm, utc);
199 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
205 char *format_timestamp(char *buf, size_t l, usec_t t) {
206 return format_timestamp_internal(buf, l, t, false);
209 #if 0 /// UNNEEDED by elogind
210 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
211 return format_timestamp_internal(buf, l, t, true);
215 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
222 if (t <= 0 || t == USEC_INFINITY)
225 sec = (time_t) (t / USEC_PER_SEC);
226 localtime_or_gmtime_r(&sec, &tm, utc);
228 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
230 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
231 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
237 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
238 return format_timestamp_internal_us(buf, l, t, false);
241 #if 0 /// UNNEEDED by elogind
242 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
243 return format_timestamp_internal_us(buf, l, t, true);
247 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
251 if (t <= 0 || t == USEC_INFINITY)
254 n = now(CLOCK_REALTIME);
263 if (d >= USEC_PER_YEAR)
264 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
266 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
267 else if (d >= USEC_PER_MONTH)
268 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
270 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
271 else if (d >= USEC_PER_WEEK)
272 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
274 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
275 else if (d >= 2*USEC_PER_DAY)
276 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
277 else if (d >= 25*USEC_PER_HOUR)
278 snprintf(buf, l, "1 day " USEC_FMT "h %s",
279 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
280 else if (d >= 6*USEC_PER_HOUR)
281 snprintf(buf, l, USEC_FMT "h %s",
282 d / USEC_PER_HOUR, s);
283 else if (d >= USEC_PER_HOUR)
284 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
286 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
287 else if (d >= 5*USEC_PER_MINUTE)
288 snprintf(buf, l, USEC_FMT "min %s",
289 d / USEC_PER_MINUTE, s);
290 else if (d >= USEC_PER_MINUTE)
291 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
293 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
294 else if (d >= USEC_PER_SEC)
295 snprintf(buf, l, USEC_FMT "s %s",
296 d / USEC_PER_SEC, s);
297 else if (d >= USEC_PER_MSEC)
298 snprintf(buf, l, USEC_FMT "ms %s",
299 d / USEC_PER_MSEC, s);
301 snprintf(buf, l, USEC_FMT"us %s",
304 snprintf(buf, l, "now");
310 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
311 static const struct {
315 { "y", USEC_PER_YEAR },
316 { "month", USEC_PER_MONTH },
317 { "w", USEC_PER_WEEK },
318 { "d", USEC_PER_DAY },
319 { "h", USEC_PER_HOUR },
320 { "min", USEC_PER_MINUTE },
321 { "s", USEC_PER_SEC },
322 { "ms", USEC_PER_MSEC },
328 bool something = false;
333 if (t == USEC_INFINITY) {
334 strncpy(p, "infinity", l-1);
340 strncpy(p, "0", l-1);
345 /* The result of this function can be parsed with parse_sec */
347 for (i = 0; i < ELEMENTSOF(table); i++) {
356 if (t < accuracy && something)
359 if (t < table[i].usec)
365 a = t / table[i].usec;
366 b = t % table[i].usec;
368 /* Let's see if we should shows this in dot notation */
369 if (t < USEC_PER_MINUTE && b > 0) {
374 for (cc = table[i].usec; cc > 1; cc /= 10)
377 for (cc = accuracy; cc > 1; cc /= 10) {
384 "%s"USEC_FMT".%0*llu%s",
388 (unsigned long long) b,
396 /* No? Then let's show it normally */
407 n = MIN((size_t) k, l);
420 #if 0 /// UNNEEDED by elogind
421 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
427 if (!dual_timestamp_is_set(t))
430 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
436 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
437 unsigned long long a, b;
442 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
443 log_debug("Failed to parse finish timestamp value %s.", value);
453 int parse_timestamp(const char *t, usec_t *usec) {
454 static const struct {
478 usec_t x_usec, plus = 0, minus = 0, ret;
485 * 2012-09-22 16:34:22
486 * 2012-09-22 16:34 (seconds will be set to 0)
487 * 2012-09-22 (time will be set to 00:00:00)
488 * 16:34:22 (date will be set to today)
489 * 16:34 (date will be set to today, seconds to 0)
491 * yesterday (time is set to 00:00:00)
492 * today (time is set to 00:00:00)
493 * tomorrow (time is set to 00:00:00)
496 * @2147483647 (seconds since epoch)
504 return parse_sec(t + 1, usec);
506 ret = now(CLOCK_REALTIME);
511 else if (t[0] == '+') {
512 r = parse_sec(t+1, &plus);
518 } else if (t[0] == '-') {
519 r = parse_sec(t+1, &minus);
525 } else if ((k = endswith(t, " ago"))) {
526 t = strndupa(t, k - t);
528 r = parse_sec(t, &minus);
534 } else if ((k = endswith(t, " left"))) {
535 t = strndupa(t, k - t);
537 r = parse_sec(t, &plus);
544 utc = endswith_no_case(t, " UTC");
546 t = strndupa(t, utc - t);
548 x = ret / USEC_PER_SEC;
551 assert_se(localtime_or_gmtime_r(&x, &tm, utc));
554 if (streq(t, "today")) {
555 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
558 } else if (streq(t, "yesterday")) {
560 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
563 } else if (streq(t, "tomorrow")) {
565 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
570 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
573 if (!startswith_no_case(t, day_nr[i].name))
576 skip = strlen(day_nr[i].name);
580 weekday = day_nr[i].nr;
586 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
595 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
604 k = strptime(t, "%y-%m-%d %H:%M", &tm);
611 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
618 k = strptime(t, "%y-%m-%d", &tm);
620 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
625 k = strptime(t, "%Y-%m-%d", &tm);
627 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
632 k = strptime(t, "%H:%M:%S", &tm);
641 k = strptime(t, "%H:%M", &tm);
654 r = parse_fractional_part_u(&k, 6, &add);
666 x = mktime_or_timegm(&tm, utc);
667 if (x == (time_t) -1)
670 if (weekday >= 0 && tm.tm_wday != weekday)
673 ret = (usec_t) x * USEC_PER_SEC + x_usec;
688 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
690 static const struct {
694 { "seconds", USEC_PER_SEC },
695 { "second", USEC_PER_SEC },
696 { "sec", USEC_PER_SEC },
697 { "s", USEC_PER_SEC },
698 { "minutes", USEC_PER_MINUTE },
699 { "minute", USEC_PER_MINUTE },
700 { "min", USEC_PER_MINUTE },
701 { "months", USEC_PER_MONTH },
702 { "month", USEC_PER_MONTH },
703 { "M", USEC_PER_MONTH },
704 { "msec", USEC_PER_MSEC },
705 { "ms", USEC_PER_MSEC },
706 { "m", USEC_PER_MINUTE },
707 { "hours", USEC_PER_HOUR },
708 { "hour", USEC_PER_HOUR },
709 { "hr", USEC_PER_HOUR },
710 { "h", USEC_PER_HOUR },
711 { "days", USEC_PER_DAY },
712 { "day", USEC_PER_DAY },
713 { "d", USEC_PER_DAY },
714 { "weeks", USEC_PER_WEEK },
715 { "week", USEC_PER_WEEK },
716 { "w", USEC_PER_WEEK },
717 { "years", USEC_PER_YEAR },
718 { "year", USEC_PER_YEAR },
719 { "y", USEC_PER_YEAR },
726 bool something = false;
730 assert(default_unit > 0);
734 p += strspn(p, WHITESPACE);
735 s = startswith(p, "infinity");
737 s += strspn(s, WHITESPACE);
741 *usec = USEC_INFINITY;
749 usec_t multiplier, k;
751 p += strspn(p, WHITESPACE);
761 l = strtoll(p, &e, 10);
773 z = strtoll(b, &e, 10);
788 e += strspn(e, WHITESPACE);
790 for (i = 0; i < ELEMENTSOF(table); i++)
791 if (startswith(e, table[i].suffix)) {
792 multiplier = table[i].usec;
793 p = e + strlen(table[i].suffix);
797 if (i >= ELEMENTSOF(table)) {
798 multiplier = default_unit;
804 k = (usec_t) z * multiplier;
809 r += (usec_t) l * multiplier + k;
817 int parse_sec(const char *t, usec_t *usec) {
818 return parse_time(t, usec, USEC_PER_SEC);
821 #if 0 /// UNNEEDED by elogind
822 int parse_nsec(const char *t, nsec_t *nsec) {
823 static const struct {
827 { "seconds", NSEC_PER_SEC },
828 { "second", NSEC_PER_SEC },
829 { "sec", NSEC_PER_SEC },
830 { "s", NSEC_PER_SEC },
831 { "minutes", NSEC_PER_MINUTE },
832 { "minute", NSEC_PER_MINUTE },
833 { "min", NSEC_PER_MINUTE },
834 { "months", NSEC_PER_MONTH },
835 { "month", NSEC_PER_MONTH },
836 { "msec", NSEC_PER_MSEC },
837 { "ms", NSEC_PER_MSEC },
838 { "m", NSEC_PER_MINUTE },
839 { "hours", NSEC_PER_HOUR },
840 { "hour", NSEC_PER_HOUR },
841 { "hr", NSEC_PER_HOUR },
842 { "h", NSEC_PER_HOUR },
843 { "days", NSEC_PER_DAY },
844 { "day", NSEC_PER_DAY },
845 { "d", NSEC_PER_DAY },
846 { "weeks", NSEC_PER_WEEK },
847 { "week", NSEC_PER_WEEK },
848 { "w", NSEC_PER_WEEK },
849 { "years", NSEC_PER_YEAR },
850 { "year", NSEC_PER_YEAR },
851 { "y", NSEC_PER_YEAR },
852 { "usec", NSEC_PER_USEC },
853 { "us", NSEC_PER_USEC },
856 { "", 1ULL }, /* default is nsec */
861 bool something = false;
868 p += strspn(p, WHITESPACE);
869 s = startswith(p, "infinity");
871 s += strspn(s, WHITESPACE);
875 *nsec = NSEC_INFINITY;
884 p += strspn(p, WHITESPACE);
894 l = strtoll(p, &e, 10);
906 z = strtoll(b, &e, 10);
921 e += strspn(e, WHITESPACE);
923 for (i = 0; i < ELEMENTSOF(table); i++)
924 if (startswith(e, table[i].suffix)) {
925 nsec_t k = (nsec_t) z * table[i].nsec;
930 r += (nsec_t) l * table[i].nsec + k;
931 p = e + strlen(table[i].suffix);
937 if (i >= ELEMENTSOF(table))
947 bool ntp_synced(void) {
948 struct timex txc = {};
950 if (adjtimex(&txc) < 0)
953 if (txc.status & STA_UNSYNC)
959 int get_timezones(char ***ret) {
960 _cleanup_fclose_ FILE *f = NULL;
961 _cleanup_strv_free_ char **zones = NULL;
962 size_t n_zones = 0, n_allocated = 0;
966 zones = strv_new("UTC", NULL);
973 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
977 FOREACH_LINE(l, f, return -errno) {
983 if (isempty(p) || *p == '#')
986 /* Skip over country code */
987 p += strcspn(p, WHITESPACE);
988 p += strspn(p, WHITESPACE);
990 /* Skip over coordinates */
991 p += strcspn(p, WHITESPACE);
992 p += strspn(p, WHITESPACE);
994 /* Found timezone name */
995 k = strcspn(p, WHITESPACE);
1003 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1008 zones[n_zones++] = w;
1009 zones[n_zones] = NULL;
1014 } else if (errno != ENOENT)
1023 bool timezone_is_valid(const char *name) {
1034 for (p = name; *p; p++) {
1035 if (!(*p >= '0' && *p <= '9') &&
1036 !(*p >= 'a' && *p <= 'z') &&
1037 !(*p >= 'A' && *p <= 'Z') &&
1038 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1054 t = strjoina("/usr/share/zoneinfo/", name);
1055 if (stat(t, &st) < 0)
1058 if (!S_ISREG(st.st_mode))
1064 clockid_t clock_boottime_or_monotonic(void) {
1065 static clockid_t clock = -1;
1071 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1073 clock = CLOCK_MONOTONIC;
1076 clock = CLOCK_BOOTTIME;
1082 int get_timezone(char **tz) {
1083 _cleanup_free_ char *t = NULL;
1088 r = readlink_malloc("/etc/localtime", &t);
1090 return r; /* returns EINVAL if not a symlink */
1092 e = path_startswith(t, "/usr/share/zoneinfo/");
1094 e = path_startswith(t, "../usr/share/zoneinfo/");
1098 if (!timezone_is_valid(e))
1109 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1110 return utc ? timegm(tm) : mktime(tm);
1114 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1115 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1118 #if 0 /// UNNEEDED by elogind
1119 unsigned long usec_to_jiffies(usec_t u) {
1120 static thread_local unsigned long hz = 0;
1124 r = sysconf(_SC_CLK_TCK);
1127 hz = (unsigned long) r;
1130 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);