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 /// 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 /// UNNEEDED by elogind
88 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
92 if (u == USEC_INFINITY) {
93 ts->realtime = ts->monotonic = USEC_INFINITY;
98 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
100 ts->realtime = now(CLOCK_REALTIME);
101 if ((int64_t) ts->realtime > delta)
102 ts->realtime -= delta;
109 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
112 if (u == USEC_INFINITY) {
113 ts->realtime = ts->monotonic = USEC_INFINITY;
116 ts->realtime = now(CLOCK_REALTIME);
117 ts->monotonic = now(CLOCK_MONOTONIC);
119 delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
121 if ((int64_t) ts->realtime > delta)
122 ts->realtime -= delta;
126 if ((int64_t) ts->monotonic > delta)
127 ts->monotonic -= delta;
135 usec_t timespec_load(const struct timespec *ts) {
138 if (ts->tv_sec == (time_t) -1 &&
139 ts->tv_nsec == (long) -1)
140 return USEC_INFINITY;
142 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
143 return USEC_INFINITY;
146 (usec_t) ts->tv_sec * USEC_PER_SEC +
147 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
150 nsec_t timespec_load_nsec(const struct timespec *ts) {
153 if (ts->tv_sec == (time_t) -1 &&
154 ts->tv_nsec == (long) -1)
155 return NSEC_INFINITY;
158 (nsec_t) ts->tv_sec * NSEC_PER_SEC +
159 (nsec_t) ts->tv_nsec;
162 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
165 if (u == USEC_INFINITY) {
166 ts->tv_sec = (time_t) -1;
167 ts->tv_nsec = (long) -1;
171 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
172 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
177 usec_t timeval_load(const struct timeval *tv) {
180 if (tv->tv_sec == (time_t) -1 &&
181 tv->tv_usec == (suseconds_t) -1)
182 return USEC_INFINITY;
184 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
185 return USEC_INFINITY;
188 (usec_t) tv->tv_sec * USEC_PER_SEC +
189 (usec_t) tv->tv_usec;
192 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
195 if (u == USEC_INFINITY) {
196 tv->tv_sec = (time_t) -1;
197 tv->tv_usec = (suseconds_t) -1;
199 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
200 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
206 static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
213 if (t <= 0 || t == USEC_INFINITY)
216 sec = (time_t) (t / USEC_PER_SEC);
217 localtime_or_gmtime_r(&sec, &tm, utc);
219 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
225 char *format_timestamp(char *buf, size_t l, usec_t t) {
226 return format_timestamp_internal(buf, l, t, false);
229 /// UNNEEDED by elogind
231 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
232 return format_timestamp_internal(buf, l, t, true);
236 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
243 if (t <= 0 || t == USEC_INFINITY)
246 sec = (time_t) (t / USEC_PER_SEC);
247 localtime_or_gmtime_r(&sec, &tm, utc);
249 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
251 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
252 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
258 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
259 return format_timestamp_internal_us(buf, l, t, false);
262 /// UNNEEDED by elogind
264 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
265 return format_timestamp_internal_us(buf, l, t, true);
269 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
273 if (t <= 0 || t == USEC_INFINITY)
276 n = now(CLOCK_REALTIME);
285 if (d >= USEC_PER_YEAR)
286 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
288 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
289 else if (d >= USEC_PER_MONTH)
290 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
292 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
293 else if (d >= USEC_PER_WEEK)
294 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
296 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
297 else if (d >= 2*USEC_PER_DAY)
298 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
299 else if (d >= 25*USEC_PER_HOUR)
300 snprintf(buf, l, "1 day " USEC_FMT "h %s",
301 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
302 else if (d >= 6*USEC_PER_HOUR)
303 snprintf(buf, l, USEC_FMT "h %s",
304 d / USEC_PER_HOUR, s);
305 else if (d >= USEC_PER_HOUR)
306 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
308 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
309 else if (d >= 5*USEC_PER_MINUTE)
310 snprintf(buf, l, USEC_FMT "min %s",
311 d / USEC_PER_MINUTE, s);
312 else if (d >= USEC_PER_MINUTE)
313 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
315 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
316 else if (d >= USEC_PER_SEC)
317 snprintf(buf, l, USEC_FMT "s %s",
318 d / USEC_PER_SEC, s);
319 else if (d >= USEC_PER_MSEC)
320 snprintf(buf, l, USEC_FMT "ms %s",
321 d / USEC_PER_MSEC, s);
323 snprintf(buf, l, USEC_FMT"us %s",
326 snprintf(buf, l, "now");
332 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
333 static const struct {
337 { "y", USEC_PER_YEAR },
338 { "month", USEC_PER_MONTH },
339 { "w", USEC_PER_WEEK },
340 { "d", USEC_PER_DAY },
341 { "h", USEC_PER_HOUR },
342 { "min", USEC_PER_MINUTE },
343 { "s", USEC_PER_SEC },
344 { "ms", USEC_PER_MSEC },
350 bool something = false;
355 if (t == USEC_INFINITY) {
356 strncpy(p, "infinity", l-1);
362 strncpy(p, "0", l-1);
367 /* The result of this function can be parsed with parse_sec */
369 for (i = 0; i < ELEMENTSOF(table); i++) {
378 if (t < accuracy && something)
381 if (t < table[i].usec)
387 a = t / table[i].usec;
388 b = t % table[i].usec;
390 /* Let's see if we should shows this in dot notation */
391 if (t < USEC_PER_MINUTE && b > 0) {
396 for (cc = table[i].usec; cc > 1; cc /= 10)
399 for (cc = accuracy; cc > 1; cc /= 10) {
406 "%s"USEC_FMT".%0*llu%s",
410 (unsigned long long) b,
418 /* No? Then let's show it normally */
429 n = MIN((size_t) k, l);
442 /// UNNEEDED by elogind
444 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
450 if (!dual_timestamp_is_set(t))
453 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
459 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
460 unsigned long long a, b;
465 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
466 log_debug("Failed to parse finish timestamp value %s.", value);
476 int parse_timestamp(const char *t, usec_t *usec) {
477 static const struct {
501 usec_t x_usec, plus = 0, minus = 0, ret;
508 * 2012-09-22 16:34:22
509 * 2012-09-22 16:34 (seconds will be set to 0)
510 * 2012-09-22 (time will be set to 00:00:00)
511 * 16:34:22 (date will be set to today)
512 * 16:34 (date will be set to today, seconds to 0)
514 * yesterday (time is set to 00:00:00)
515 * today (time is set to 00:00:00)
516 * tomorrow (time is set to 00:00:00)
519 * @2147483647 (seconds since epoch)
527 return parse_sec(t + 1, usec);
529 ret = now(CLOCK_REALTIME);
534 else if (t[0] == '+') {
535 r = parse_sec(t+1, &plus);
541 } else if (t[0] == '-') {
542 r = parse_sec(t+1, &minus);
548 } else if ((k = endswith(t, " ago"))) {
549 t = strndupa(t, k - t);
551 r = parse_sec(t, &minus);
557 } else if ((k = endswith(t, " left"))) {
558 t = strndupa(t, k - t);
560 r = parse_sec(t, &plus);
567 utc = endswith_no_case(t, " UTC");
569 t = strndupa(t, utc - t);
571 x = ret / USEC_PER_SEC;
574 assert_se(localtime_or_gmtime_r(&x, &tm, utc));
577 if (streq(t, "today")) {
578 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
581 } else if (streq(t, "yesterday")) {
583 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
586 } else if (streq(t, "tomorrow")) {
588 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
593 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
596 if (!startswith_no_case(t, day_nr[i].name))
599 skip = strlen(day_nr[i].name);
603 weekday = day_nr[i].nr;
609 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
618 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
627 k = strptime(t, "%y-%m-%d %H:%M", &tm);
634 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
641 k = strptime(t, "%y-%m-%d", &tm);
643 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
648 k = strptime(t, "%Y-%m-%d", &tm);
650 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
655 k = strptime(t, "%H:%M:%S", &tm);
664 k = strptime(t, "%H:%M", &tm);
675 unsigned long long val;
679 if (*k < '0' || *k > '9')
682 /* base 10 instead of base 0, .09 is not base 8 */
684 val = strtoull(k, &end, 10);
690 /* val has l digits, make them 6 */
700 x = mktime_or_timegm(&tm, utc);
701 if (x == (time_t) -1)
704 if (weekday >= 0 && tm.tm_wday != weekday)
707 ret = (usec_t) x * USEC_PER_SEC + x_usec;
722 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
724 static const struct {
728 { "seconds", USEC_PER_SEC },
729 { "second", USEC_PER_SEC },
730 { "sec", USEC_PER_SEC },
731 { "s", USEC_PER_SEC },
732 { "minutes", USEC_PER_MINUTE },
733 { "minute", USEC_PER_MINUTE },
734 { "min", USEC_PER_MINUTE },
735 { "months", USEC_PER_MONTH },
736 { "month", USEC_PER_MONTH },
737 { "M", USEC_PER_MONTH },
738 { "msec", USEC_PER_MSEC },
739 { "ms", USEC_PER_MSEC },
740 { "m", USEC_PER_MINUTE },
741 { "hours", USEC_PER_HOUR },
742 { "hour", USEC_PER_HOUR },
743 { "hr", USEC_PER_HOUR },
744 { "h", USEC_PER_HOUR },
745 { "days", USEC_PER_DAY },
746 { "day", USEC_PER_DAY },
747 { "d", USEC_PER_DAY },
748 { "weeks", USEC_PER_WEEK },
749 { "week", USEC_PER_WEEK },
750 { "w", USEC_PER_WEEK },
751 { "years", USEC_PER_YEAR },
752 { "year", USEC_PER_YEAR },
753 { "y", USEC_PER_YEAR },
760 bool something = false;
764 assert(default_unit > 0);
768 p += strspn(p, WHITESPACE);
769 s = startswith(p, "infinity");
771 s += strspn(s, WHITESPACE);
775 *usec = USEC_INFINITY;
783 usec_t multiplier, k;
785 p += strspn(p, WHITESPACE);
795 l = strtoll(p, &e, 10);
807 z = strtoll(b, &e, 10);
822 e += strspn(e, WHITESPACE);
824 for (i = 0; i < ELEMENTSOF(table); i++)
825 if (startswith(e, table[i].suffix)) {
826 multiplier = table[i].usec;
827 p = e + strlen(table[i].suffix);
831 if (i >= ELEMENTSOF(table)) {
832 multiplier = default_unit;
838 k = (usec_t) z * multiplier;
843 r += (usec_t) l * multiplier + k;
851 int parse_sec(const char *t, usec_t *usec) {
852 return parse_time(t, usec, USEC_PER_SEC);
855 /// UNNEEDED by elogind
857 int parse_nsec(const char *t, nsec_t *nsec) {
858 static const struct {
862 { "seconds", NSEC_PER_SEC },
863 { "second", NSEC_PER_SEC },
864 { "sec", NSEC_PER_SEC },
865 { "s", NSEC_PER_SEC },
866 { "minutes", NSEC_PER_MINUTE },
867 { "minute", NSEC_PER_MINUTE },
868 { "min", NSEC_PER_MINUTE },
869 { "months", NSEC_PER_MONTH },
870 { "month", NSEC_PER_MONTH },
871 { "msec", NSEC_PER_MSEC },
872 { "ms", NSEC_PER_MSEC },
873 { "m", NSEC_PER_MINUTE },
874 { "hours", NSEC_PER_HOUR },
875 { "hour", NSEC_PER_HOUR },
876 { "hr", NSEC_PER_HOUR },
877 { "h", NSEC_PER_HOUR },
878 { "days", NSEC_PER_DAY },
879 { "day", NSEC_PER_DAY },
880 { "d", NSEC_PER_DAY },
881 { "weeks", NSEC_PER_WEEK },
882 { "week", NSEC_PER_WEEK },
883 { "w", NSEC_PER_WEEK },
884 { "years", NSEC_PER_YEAR },
885 { "year", NSEC_PER_YEAR },
886 { "y", NSEC_PER_YEAR },
887 { "usec", NSEC_PER_USEC },
888 { "us", NSEC_PER_USEC },
891 { "", 1ULL }, /* default is nsec */
896 bool something = false;
903 p += strspn(p, WHITESPACE);
904 s = startswith(p, "infinity");
906 s += strspn(s, WHITESPACE);
910 *nsec = NSEC_INFINITY;
919 p += strspn(p, WHITESPACE);
929 l = strtoll(p, &e, 10);
941 z = strtoll(b, &e, 10);
956 e += strspn(e, WHITESPACE);
958 for (i = 0; i < ELEMENTSOF(table); i++)
959 if (startswith(e, table[i].suffix)) {
960 nsec_t k = (nsec_t) z * table[i].nsec;
965 r += (nsec_t) l * table[i].nsec + k;
966 p = e + strlen(table[i].suffix);
972 if (i >= ELEMENTSOF(table))
982 bool ntp_synced(void) {
983 struct timex txc = {};
985 if (adjtimex(&txc) < 0)
988 if (txc.status & STA_UNSYNC)
994 int get_timezones(char ***ret) {
995 _cleanup_fclose_ FILE *f = NULL;
996 _cleanup_strv_free_ char **zones = NULL;
997 size_t n_zones = 0, n_allocated = 0;
1001 zones = strv_new("UTC", NULL);
1008 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
1012 FOREACH_LINE(l, f, return -errno) {
1018 if (isempty(p) || *p == '#')
1021 /* Skip over country code */
1022 p += strcspn(p, WHITESPACE);
1023 p += strspn(p, WHITESPACE);
1025 /* Skip over coordinates */
1026 p += strcspn(p, WHITESPACE);
1027 p += strspn(p, WHITESPACE);
1029 /* Found timezone name */
1030 k = strcspn(p, WHITESPACE);
1038 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1043 zones[n_zones++] = w;
1044 zones[n_zones] = NULL;
1049 } else if (errno != ENOENT)
1058 bool timezone_is_valid(const char *name) {
1069 for (p = name; *p; p++) {
1070 if (!(*p >= '0' && *p <= '9') &&
1071 !(*p >= 'a' && *p <= 'z') &&
1072 !(*p >= 'A' && *p <= 'Z') &&
1073 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1089 t = strjoina("/usr/share/zoneinfo/", name);
1090 if (stat(t, &st) < 0)
1093 if (!S_ISREG(st.st_mode))
1099 clockid_t clock_boottime_or_monotonic(void) {
1100 static clockid_t clock = -1;
1106 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1108 clock = CLOCK_MONOTONIC;
1111 clock = CLOCK_BOOTTIME;
1117 int get_timezone(char **tz) {
1118 _cleanup_free_ char *t = NULL;
1123 r = readlink_malloc("/etc/localtime", &t);
1125 return r; /* returns EINVAL if not a symlink */
1127 e = path_startswith(t, "/usr/share/zoneinfo/");
1129 e = path_startswith(t, "../usr/share/zoneinfo/");
1133 if (!timezone_is_valid(e))
1144 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1145 return utc ? timegm(tm) : mktime(tm);
1149 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1150 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1153 /// UNNEEDED by elogind
1155 unsigned long usec_to_jiffies(usec_t u) {
1156 static thread_local unsigned long hz = 0;
1160 r = sysconf(_SC_CLK_TCK);
1163 hz = (unsigned long) r;
1166 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);