]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/time-util.c
tree-wide: drop stat.h or statfs.h when stat-util.h is included
[thirdparty/systemd.git] / src / basic / time-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <ctype.h>
4 #include <errno.h>
5 #include <limits.h>
6 #include <stdlib.h>
7 #include <sys/mman.h>
8 #include <sys/time.h>
9 #include <sys/timerfd.h>
10 #include <sys/timex.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13
14 #include "alloc-util.h"
15 #include "fd-util.h"
16 #include "fileio.h"
17 #include "fs-util.h"
18 #include "io-util.h"
19 #include "log.h"
20 #include "macro.h"
21 #include "missing_timerfd.h"
22 #include "parse-util.h"
23 #include "path-util.h"
24 #include "process-util.h"
25 #include "stat-util.h"
26 #include "string-util.h"
27 #include "strv.h"
28 #include "time-util.h"
29
30 static clockid_t map_clock_id(clockid_t c) {
31
32 /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
33 * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
34 * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
35 * those archs. */
36
37 switch (c) {
38
39 case CLOCK_BOOTTIME_ALARM:
40 return CLOCK_BOOTTIME;
41
42 case CLOCK_REALTIME_ALARM:
43 return CLOCK_REALTIME;
44
45 default:
46 return c;
47 }
48 }
49
50 usec_t now(clockid_t clock_id) {
51 struct timespec ts;
52
53 assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
54
55 return timespec_load(&ts);
56 }
57
58 nsec_t now_nsec(clockid_t clock_id) {
59 struct timespec ts;
60
61 assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
62
63 return timespec_load_nsec(&ts);
64 }
65
66 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
67 assert(ts);
68
69 ts->realtime = now(CLOCK_REALTIME);
70 ts->monotonic = now(CLOCK_MONOTONIC);
71
72 return ts;
73 }
74
75 triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
76 assert(ts);
77
78 ts->realtime = now(CLOCK_REALTIME);
79 ts->monotonic = now(CLOCK_MONOTONIC);
80 ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
81
82 return ts;
83 }
84
85 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
86 int64_t delta;
87 assert(ts);
88
89 if (u == USEC_INFINITY || u <= 0) {
90 ts->realtime = ts->monotonic = u;
91 return ts;
92 }
93
94 ts->realtime = u;
95
96 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
97 ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
98
99 return ts;
100 }
101
102 triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) {
103 int64_t delta;
104
105 assert(ts);
106
107 if (u == USEC_INFINITY || u <= 0) {
108 ts->realtime = ts->monotonic = ts->boottime = u;
109 return ts;
110 }
111
112 ts->realtime = u;
113 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
114 ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
115 ts->boottime = clock_boottime_supported() ? usec_sub_signed(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
116
117 return ts;
118 }
119
120 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
121 int64_t delta;
122 assert(ts);
123
124 if (u == USEC_INFINITY) {
125 ts->realtime = ts->monotonic = USEC_INFINITY;
126 return ts;
127 }
128
129 ts->monotonic = u;
130 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
131 ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta);
132
133 return ts;
134 }
135
136 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
137 int64_t delta;
138
139 if (u == USEC_INFINITY) {
140 ts->realtime = ts->monotonic = USEC_INFINITY;
141 return ts;
142 }
143
144 dual_timestamp_get(ts);
145 delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
146 ts->realtime = usec_sub_signed(ts->realtime, delta);
147 ts->monotonic = usec_sub_signed(ts->monotonic, delta);
148
149 return ts;
150 }
151
152 usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
153
154 switch (clock) {
155
156 case CLOCK_REALTIME:
157 case CLOCK_REALTIME_ALARM:
158 return ts->realtime;
159
160 case CLOCK_MONOTONIC:
161 return ts->monotonic;
162
163 case CLOCK_BOOTTIME:
164 case CLOCK_BOOTTIME_ALARM:
165 return ts->boottime;
166
167 default:
168 return USEC_INFINITY;
169 }
170 }
171
172 usec_t timespec_load(const struct timespec *ts) {
173 assert(ts);
174
175 if (ts->tv_sec < 0 || ts->tv_nsec < 0)
176 return USEC_INFINITY;
177
178 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
179 return USEC_INFINITY;
180
181 return
182 (usec_t) ts->tv_sec * USEC_PER_SEC +
183 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
184 }
185
186 nsec_t timespec_load_nsec(const struct timespec *ts) {
187 assert(ts);
188
189 if (ts->tv_sec < 0 || ts->tv_nsec < 0)
190 return NSEC_INFINITY;
191
192 if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC)
193 return NSEC_INFINITY;
194
195 return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec;
196 }
197
198 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
199 assert(ts);
200
201 if (u == USEC_INFINITY ||
202 u / USEC_PER_SEC >= TIME_T_MAX) {
203 ts->tv_sec = (time_t) -1;
204 ts->tv_nsec = (long) -1;
205 return ts;
206 }
207
208 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
209 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
210
211 return ts;
212 }
213
214 usec_t timeval_load(const struct timeval *tv) {
215 assert(tv);
216
217 if (tv->tv_sec < 0 || tv->tv_usec < 0)
218 return USEC_INFINITY;
219
220 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
221 return USEC_INFINITY;
222
223 return
224 (usec_t) tv->tv_sec * USEC_PER_SEC +
225 (usec_t) tv->tv_usec;
226 }
227
228 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
229 assert(tv);
230
231 if (u == USEC_INFINITY ||
232 u / USEC_PER_SEC > TIME_T_MAX) {
233 tv->tv_sec = (time_t) -1;
234 tv->tv_usec = (suseconds_t) -1;
235 } else {
236 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
237 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
238 }
239
240 return tv;
241 }
242
243 static char *format_timestamp_internal(
244 char *buf,
245 size_t l,
246 usec_t t,
247 bool utc,
248 bool us) {
249
250 /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
251 * generated timestamps may be parsed with parse_timestamp(), and always read the same. */
252 static const char * const weekdays[] = {
253 [0] = "Sun",
254 [1] = "Mon",
255 [2] = "Tue",
256 [3] = "Wed",
257 [4] = "Thu",
258 [5] = "Fri",
259 [6] = "Sat",
260 };
261
262 struct tm tm;
263 time_t sec;
264 size_t n;
265
266 assert(buf);
267
268 if (l < (size_t) (3 + /* week day */
269 1 + 10 + /* space and date */
270 1 + 8 + /* space and time */
271 (us ? 1 + 6 : 0) + /* "." and microsecond part */
272 1 + 1 + /* space and shortest possible zone */
273 1))
274 return NULL; /* Not enough space even for the shortest form. */
275 if (t <= 0 || t == USEC_INFINITY)
276 return NULL; /* Timestamp is unset */
277
278 /* Let's not format times with years > 9999 */
279 if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
280 assert(l >= STRLEN("--- XXXX-XX-XX XX:XX:XX") + 1);
281 strcpy(buf, "--- XXXX-XX-XX XX:XX:XX");
282 return buf;
283 }
284
285 sec = (time_t) (t / USEC_PER_SEC); /* Round down */
286
287 if (!localtime_or_gmtime_r(&sec, &tm, utc))
288 return NULL;
289
290 /* Start with the week day */
291 assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
292 memcpy(buf, weekdays[tm.tm_wday], 4);
293
294 /* Add the main components */
295 if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
296 return NULL; /* Doesn't fit */
297
298 /* Append the microseconds part, if that's requested */
299 if (us) {
300 n = strlen(buf);
301 if (n + 8 > l)
302 return NULL; /* Microseconds part doesn't fit. */
303
304 sprintf(buf + n, ".%06"PRI_USEC, t % USEC_PER_SEC);
305 }
306
307 /* Append the timezone */
308 n = strlen(buf);
309 if (utc) {
310 /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the
311 * obsolete "GMT" instead. */
312 if (n + 5 > l)
313 return NULL; /* "UTC" doesn't fit. */
314
315 strcpy(buf + n, " UTC");
316
317 } else if (!isempty(tm.tm_zone)) {
318 size_t tn;
319
320 /* An explicit timezone is specified, let's use it, if it fits */
321 tn = strlen(tm.tm_zone);
322 if (n + 1 + tn + 1 > l) {
323 /* The full time zone does not fit in. Yuck. */
324
325 if (n + 1 + _POSIX_TZNAME_MAX + 1 > l)
326 return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */
327
328 /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
329 * minimum time zone length. In this case suppress the timezone entirely, in order not to dump
330 * an overly long, hard to read string on the user. This should be safe, because the user will
331 * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
332 } else {
333 buf[n++] = ' ';
334 strcpy(buf + n, tm.tm_zone);
335 }
336 }
337
338 return buf;
339 }
340
341 char *format_timestamp(char *buf, size_t l, usec_t t) {
342 return format_timestamp_internal(buf, l, t, false, false);
343 }
344
345 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
346 return format_timestamp_internal(buf, l, t, true, false);
347 }
348
349 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
350 return format_timestamp_internal(buf, l, t, false, true);
351 }
352
353 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
354 return format_timestamp_internal(buf, l, t, true, true);
355 }
356
357 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
358 const char *s;
359 usec_t n, d;
360
361 if (t <= 0 || t == USEC_INFINITY)
362 return NULL;
363
364 n = now(CLOCK_REALTIME);
365 if (n > t) {
366 d = n - t;
367 s = "ago";
368 } else {
369 d = t - n;
370 s = "left";
371 }
372
373 if (d >= USEC_PER_YEAR)
374 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
375 d / USEC_PER_YEAR,
376 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
377 else if (d >= USEC_PER_MONTH)
378 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
379 d / USEC_PER_MONTH,
380 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
381 else if (d >= USEC_PER_WEEK)
382 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
383 d / USEC_PER_WEEK,
384 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
385 else if (d >= 2*USEC_PER_DAY)
386 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
387 else if (d >= 25*USEC_PER_HOUR)
388 snprintf(buf, l, "1 day " USEC_FMT "h %s",
389 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
390 else if (d >= 6*USEC_PER_HOUR)
391 snprintf(buf, l, USEC_FMT "h %s",
392 d / USEC_PER_HOUR, s);
393 else if (d >= USEC_PER_HOUR)
394 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
395 d / USEC_PER_HOUR,
396 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
397 else if (d >= 5*USEC_PER_MINUTE)
398 snprintf(buf, l, USEC_FMT "min %s",
399 d / USEC_PER_MINUTE, s);
400 else if (d >= USEC_PER_MINUTE)
401 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
402 d / USEC_PER_MINUTE,
403 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
404 else if (d >= USEC_PER_SEC)
405 snprintf(buf, l, USEC_FMT "s %s",
406 d / USEC_PER_SEC, s);
407 else if (d >= USEC_PER_MSEC)
408 snprintf(buf, l, USEC_FMT "ms %s",
409 d / USEC_PER_MSEC, s);
410 else if (d > 0)
411 snprintf(buf, l, USEC_FMT"us %s",
412 d, s);
413 else
414 snprintf(buf, l, "now");
415
416 buf[l-1] = 0;
417 return buf;
418 }
419
420 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
421 static const struct {
422 const char *suffix;
423 usec_t usec;
424 } table[] = {
425 { "y", USEC_PER_YEAR },
426 { "month", USEC_PER_MONTH },
427 { "w", USEC_PER_WEEK },
428 { "d", USEC_PER_DAY },
429 { "h", USEC_PER_HOUR },
430 { "min", USEC_PER_MINUTE },
431 { "s", USEC_PER_SEC },
432 { "ms", USEC_PER_MSEC },
433 { "us", 1 },
434 };
435
436 size_t i;
437 char *p = buf;
438 bool something = false;
439
440 assert(buf);
441 assert(l > 0);
442
443 if (t == USEC_INFINITY) {
444 strncpy(p, "infinity", l-1);
445 p[l-1] = 0;
446 return p;
447 }
448
449 if (t <= 0) {
450 strncpy(p, "0", l-1);
451 p[l-1] = 0;
452 return p;
453 }
454
455 /* The result of this function can be parsed with parse_sec */
456
457 for (i = 0; i < ELEMENTSOF(table); i++) {
458 int k = 0;
459 size_t n;
460 bool done = false;
461 usec_t a, b;
462
463 if (t <= 0)
464 break;
465
466 if (t < accuracy && something)
467 break;
468
469 if (t < table[i].usec)
470 continue;
471
472 if (l <= 1)
473 break;
474
475 a = t / table[i].usec;
476 b = t % table[i].usec;
477
478 /* Let's see if we should shows this in dot notation */
479 if (t < USEC_PER_MINUTE && b > 0) {
480 usec_t cc;
481 signed char j;
482
483 j = 0;
484 for (cc = table[i].usec; cc > 1; cc /= 10)
485 j++;
486
487 for (cc = accuracy; cc > 1; cc /= 10) {
488 b /= 10;
489 j--;
490 }
491
492 if (j > 0) {
493 k = snprintf(p, l,
494 "%s"USEC_FMT".%0*"PRI_USEC"%s",
495 p > buf ? " " : "",
496 a,
497 j,
498 b,
499 table[i].suffix);
500
501 t = 0;
502 done = true;
503 }
504 }
505
506 /* No? Then let's show it normally */
507 if (!done) {
508 k = snprintf(p, l,
509 "%s"USEC_FMT"%s",
510 p > buf ? " " : "",
511 a,
512 table[i].suffix);
513
514 t = b;
515 }
516
517 n = MIN((size_t) k, l);
518
519 l -= n;
520 p += n;
521
522 something = true;
523 }
524
525 *p = 0;
526
527 return buf;
528 }
529
530 static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
531 static const struct {
532 const char *name;
533 const int nr;
534 } day_nr[] = {
535 { "Sunday", 0 },
536 { "Sun", 0 },
537 { "Monday", 1 },
538 { "Mon", 1 },
539 { "Tuesday", 2 },
540 { "Tue", 2 },
541 { "Wednesday", 3 },
542 { "Wed", 3 },
543 { "Thursday", 4 },
544 { "Thu", 4 },
545 { "Friday", 5 },
546 { "Fri", 5 },
547 { "Saturday", 6 },
548 { "Sat", 6 },
549 };
550
551 const char *k, *utc = NULL, *tzn = NULL;
552 struct tm tm, copy;
553 time_t x;
554 usec_t x_usec, plus = 0, minus = 0, ret;
555 int r, weekday = -1, dst = -1;
556 size_t i;
557
558 /* Allowed syntaxes:
559 *
560 * 2012-09-22 16:34:22
561 * 2012-09-22 16:34 (seconds will be set to 0)
562 * 2012-09-22 (time will be set to 00:00:00)
563 * 16:34:22 (date will be set to today)
564 * 16:34 (date will be set to today, seconds to 0)
565 * now
566 * yesterday (time is set to 00:00:00)
567 * today (time is set to 00:00:00)
568 * tomorrow (time is set to 00:00:00)
569 * +5min
570 * -5days
571 * @2147483647 (seconds since epoch)
572 */
573
574 assert(t);
575
576 if (t[0] == '@' && !with_tz)
577 return parse_sec(t + 1, usec);
578
579 ret = now(CLOCK_REALTIME);
580
581 if (!with_tz) {
582 if (streq(t, "now"))
583 goto finish;
584
585 else if (t[0] == '+') {
586 r = parse_sec(t+1, &plus);
587 if (r < 0)
588 return r;
589
590 goto finish;
591
592 } else if (t[0] == '-') {
593 r = parse_sec(t+1, &minus);
594 if (r < 0)
595 return r;
596
597 goto finish;
598
599 } else if ((k = endswith(t, " ago"))) {
600 t = strndupa(t, k - t);
601
602 r = parse_sec(t, &minus);
603 if (r < 0)
604 return r;
605
606 goto finish;
607
608 } else if ((k = endswith(t, " left"))) {
609 t = strndupa(t, k - t);
610
611 r = parse_sec(t, &plus);
612 if (r < 0)
613 return r;
614
615 goto finish;
616 }
617
618 /* See if the timestamp is suffixed with UTC */
619 utc = endswith_no_case(t, " UTC");
620 if (utc)
621 t = strndupa(t, utc - t);
622 else {
623 const char *e = NULL;
624 int j;
625
626 tzset();
627
628 /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
629 * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
630 * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
631 * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
632 * support arbitrary timezone specifications. */
633
634 for (j = 0; j <= 1; j++) {
635
636 if (isempty(tzname[j]))
637 continue;
638
639 e = endswith_no_case(t, tzname[j]);
640 if (!e)
641 continue;
642 if (e == t)
643 continue;
644 if (e[-1] != ' ')
645 continue;
646
647 break;
648 }
649
650 if (IN_SET(j, 0, 1)) {
651 /* Found one of the two timezones specified. */
652 t = strndupa(t, e - t - 1);
653 dst = j;
654 tzn = tzname[j];
655 }
656 }
657 }
658
659 x = (time_t) (ret / USEC_PER_SEC);
660 x_usec = 0;
661
662 if (!localtime_or_gmtime_r(&x, &tm, utc))
663 return -EINVAL;
664
665 tm.tm_isdst = dst;
666 if (!with_tz && tzn)
667 tm.tm_zone = tzn;
668
669 if (streq(t, "today")) {
670 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
671 goto from_tm;
672
673 } else if (streq(t, "yesterday")) {
674 tm.tm_mday--;
675 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
676 goto from_tm;
677
678 } else if (streq(t, "tomorrow")) {
679 tm.tm_mday++;
680 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
681 goto from_tm;
682 }
683
684 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
685 size_t skip;
686
687 if (!startswith_no_case(t, day_nr[i].name))
688 continue;
689
690 skip = strlen(day_nr[i].name);
691 if (t[skip] != ' ')
692 continue;
693
694 weekday = day_nr[i].nr;
695 t += skip + 1;
696 break;
697 }
698
699 copy = tm;
700 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
701 if (k) {
702 if (*k == '.')
703 goto parse_usec;
704 else if (*k == 0)
705 goto from_tm;
706 }
707
708 tm = copy;
709 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
710 if (k) {
711 if (*k == '.')
712 goto parse_usec;
713 else if (*k == 0)
714 goto from_tm;
715 }
716
717 tm = copy;
718 k = strptime(t, "%y-%m-%d %H:%M", &tm);
719 if (k && *k == 0) {
720 tm.tm_sec = 0;
721 goto from_tm;
722 }
723
724 tm = copy;
725 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
726 if (k && *k == 0) {
727 tm.tm_sec = 0;
728 goto from_tm;
729 }
730
731 tm = copy;
732 k = strptime(t, "%y-%m-%d", &tm);
733 if (k && *k == 0) {
734 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
735 goto from_tm;
736 }
737
738 tm = copy;
739 k = strptime(t, "%Y-%m-%d", &tm);
740 if (k && *k == 0) {
741 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
742 goto from_tm;
743 }
744
745 tm = copy;
746 k = strptime(t, "%H:%M:%S", &tm);
747 if (k) {
748 if (*k == '.')
749 goto parse_usec;
750 else if (*k == 0)
751 goto from_tm;
752 }
753
754 tm = copy;
755 k = strptime(t, "%H:%M", &tm);
756 if (k && *k == 0) {
757 tm.tm_sec = 0;
758 goto from_tm;
759 }
760
761 return -EINVAL;
762
763 parse_usec:
764 {
765 unsigned add;
766
767 k++;
768 r = parse_fractional_part_u(&k, 6, &add);
769 if (r < 0)
770 return -EINVAL;
771
772 if (*k)
773 return -EINVAL;
774
775 x_usec = add;
776 }
777
778 from_tm:
779 if (weekday >= 0 && tm.tm_wday != weekday)
780 return -EINVAL;
781
782 x = mktime_or_timegm(&tm, utc);
783 if (x < 0)
784 return -EINVAL;
785
786 ret = (usec_t) x * USEC_PER_SEC + x_usec;
787 if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
788 return -EINVAL;
789
790 finish:
791 if (ret + plus < ret) /* overflow? */
792 return -EINVAL;
793 ret += plus;
794 if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
795 return -EINVAL;
796
797 if (ret >= minus)
798 ret -= minus;
799 else
800 return -EINVAL;
801
802 if (usec)
803 *usec = ret;
804 return 0;
805 }
806
807 typedef struct ParseTimestampResult {
808 usec_t usec;
809 int return_value;
810 } ParseTimestampResult;
811
812 int parse_timestamp(const char *t, usec_t *usec) {
813 char *last_space, *tz = NULL;
814 ParseTimestampResult *shared, tmp;
815 int r;
816
817 last_space = strrchr(t, ' ');
818 if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
819 tz = last_space + 1;
820
821 if (!tz || endswith_no_case(t, " UTC"))
822 return parse_timestamp_impl(t, usec, false);
823
824 shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
825 if (shared == MAP_FAILED)
826 return negative_errno();
827
828 r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
829 if (r < 0) {
830 (void) munmap(shared, sizeof *shared);
831 return r;
832 }
833 if (r == 0) {
834 bool with_tz = true;
835
836 if (setenv("TZ", tz, 1) != 0) {
837 shared->return_value = negative_errno();
838 _exit(EXIT_FAILURE);
839 }
840
841 tzset();
842
843 /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
844 * Otherwise just cut it off. */
845 with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
846
847 /* Cut off the timezone if we don't need it. */
848 if (with_tz)
849 t = strndupa(t, last_space - t);
850
851 shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
852
853 _exit(EXIT_SUCCESS);
854 }
855
856 tmp = *shared;
857 if (munmap(shared, sizeof *shared) != 0)
858 return negative_errno();
859
860 if (tmp.return_value == 0 && usec)
861 *usec = tmp.usec;
862
863 return tmp.return_value;
864 }
865
866 static const char* extract_multiplier(const char *p, usec_t *multiplier) {
867 static const struct {
868 const char *suffix;
869 usec_t usec;
870 } table[] = {
871 { "seconds", USEC_PER_SEC },
872 { "second", USEC_PER_SEC },
873 { "sec", USEC_PER_SEC },
874 { "s", USEC_PER_SEC },
875 { "minutes", USEC_PER_MINUTE },
876 { "minute", USEC_PER_MINUTE },
877 { "min", USEC_PER_MINUTE },
878 { "months", USEC_PER_MONTH },
879 { "month", USEC_PER_MONTH },
880 { "M", USEC_PER_MONTH },
881 { "msec", USEC_PER_MSEC },
882 { "ms", USEC_PER_MSEC },
883 { "m", USEC_PER_MINUTE },
884 { "hours", USEC_PER_HOUR },
885 { "hour", USEC_PER_HOUR },
886 { "hr", USEC_PER_HOUR },
887 { "h", USEC_PER_HOUR },
888 { "days", USEC_PER_DAY },
889 { "day", USEC_PER_DAY },
890 { "d", USEC_PER_DAY },
891 { "weeks", USEC_PER_WEEK },
892 { "week", USEC_PER_WEEK },
893 { "w", USEC_PER_WEEK },
894 { "years", USEC_PER_YEAR },
895 { "year", USEC_PER_YEAR },
896 { "y", USEC_PER_YEAR },
897 { "usec", 1ULL },
898 { "us", 1ULL },
899 { "µs", 1ULL },
900 };
901 size_t i;
902
903 for (i = 0; i < ELEMENTSOF(table); i++) {
904 char *e;
905
906 e = startswith(p, table[i].suffix);
907 if (e) {
908 *multiplier = table[i].usec;
909 return e;
910 }
911 }
912
913 return p;
914 }
915
916 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
917 const char *p, *s;
918 usec_t r = 0;
919 bool something = false;
920
921 assert(t);
922 assert(default_unit > 0);
923
924 p = t;
925
926 p += strspn(p, WHITESPACE);
927 s = startswith(p, "infinity");
928 if (s) {
929 s += strspn(s, WHITESPACE);
930 if (*s != 0)
931 return -EINVAL;
932
933 if (usec)
934 *usec = USEC_INFINITY;
935 return 0;
936 }
937
938 for (;;) {
939 usec_t multiplier = default_unit, k;
940 long long l;
941 char *e;
942
943 p += strspn(p, WHITESPACE);
944
945 if (*p == 0) {
946 if (!something)
947 return -EINVAL;
948
949 break;
950 }
951
952 if (*p == '-') /* Don't allow "-0" */
953 return -ERANGE;
954
955 errno = 0;
956 l = strtoll(p, &e, 10);
957 if (errno > 0)
958 return -errno;
959 if (l < 0)
960 return -ERANGE;
961
962 if (*e == '.') {
963 p = e + 1;
964 p += strspn(p, DIGITS);
965 } else if (e == p)
966 return -EINVAL;
967 else
968 p = e;
969
970 s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
971 if (s == p && *s != '\0')
972 /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
973 return -EINVAL;
974
975 p = s;
976
977 if ((usec_t) l >= USEC_INFINITY / multiplier)
978 return -ERANGE;
979
980 k = (usec_t) l * multiplier;
981 if (k >= USEC_INFINITY - r)
982 return -ERANGE;
983
984 r += k;
985
986 something = true;
987
988 if (*e == '.') {
989 usec_t m = multiplier / 10;
990 const char *b;
991
992 for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
993 k = (usec_t) (*b - '0') * m;
994 if (k >= USEC_INFINITY - r)
995 return -ERANGE;
996
997 r += k;
998 }
999
1000 /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
1001 if (b == e + 1)
1002 return -EINVAL;
1003 }
1004 }
1005
1006 if (usec)
1007 *usec = r;
1008 return 0;
1009 }
1010
1011 int parse_sec(const char *t, usec_t *usec) {
1012 return parse_time(t, usec, USEC_PER_SEC);
1013 }
1014
1015 int parse_sec_fix_0(const char *t, usec_t *ret) {
1016 usec_t k;
1017 int r;
1018
1019 assert(t);
1020 assert(ret);
1021
1022 r = parse_sec(t, &k);
1023 if (r < 0)
1024 return r;
1025
1026 *ret = k == 0 ? USEC_INFINITY : k;
1027 return r;
1028 }
1029
1030 int parse_sec_def_infinity(const char *t, usec_t *ret) {
1031 t += strspn(t, WHITESPACE);
1032 if (isempty(t)) {
1033 *ret = USEC_INFINITY;
1034 return 0;
1035 }
1036 return parse_sec(t, ret);
1037 }
1038
1039 static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
1040 static const struct {
1041 const char *suffix;
1042 nsec_t nsec;
1043 } table[] = {
1044 { "seconds", NSEC_PER_SEC },
1045 { "second", NSEC_PER_SEC },
1046 { "sec", NSEC_PER_SEC },
1047 { "s", NSEC_PER_SEC },
1048 { "minutes", NSEC_PER_MINUTE },
1049 { "minute", NSEC_PER_MINUTE },
1050 { "min", NSEC_PER_MINUTE },
1051 { "months", NSEC_PER_MONTH },
1052 { "month", NSEC_PER_MONTH },
1053 { "M", NSEC_PER_MONTH },
1054 { "msec", NSEC_PER_MSEC },
1055 { "ms", NSEC_PER_MSEC },
1056 { "m", NSEC_PER_MINUTE },
1057 { "hours", NSEC_PER_HOUR },
1058 { "hour", NSEC_PER_HOUR },
1059 { "hr", NSEC_PER_HOUR },
1060 { "h", NSEC_PER_HOUR },
1061 { "days", NSEC_PER_DAY },
1062 { "day", NSEC_PER_DAY },
1063 { "d", NSEC_PER_DAY },
1064 { "weeks", NSEC_PER_WEEK },
1065 { "week", NSEC_PER_WEEK },
1066 { "w", NSEC_PER_WEEK },
1067 { "years", NSEC_PER_YEAR },
1068 { "year", NSEC_PER_YEAR },
1069 { "y", NSEC_PER_YEAR },
1070 { "usec", NSEC_PER_USEC },
1071 { "us", NSEC_PER_USEC },
1072 { "µs", NSEC_PER_USEC },
1073 { "nsec", 1ULL },
1074 { "ns", 1ULL },
1075 { "", 1ULL }, /* default is nsec */
1076 };
1077 size_t i;
1078
1079 for (i = 0; i < ELEMENTSOF(table); i++) {
1080 char *e;
1081
1082 e = startswith(p, table[i].suffix);
1083 if (e) {
1084 *multiplier = table[i].nsec;
1085 return e;
1086 }
1087 }
1088
1089 return p;
1090 }
1091
1092 int parse_nsec(const char *t, nsec_t *nsec) {
1093 const char *p, *s;
1094 nsec_t r = 0;
1095 bool something = false;
1096
1097 assert(t);
1098 assert(nsec);
1099
1100 p = t;
1101
1102 p += strspn(p, WHITESPACE);
1103 s = startswith(p, "infinity");
1104 if (s) {
1105 s += strspn(s, WHITESPACE);
1106 if (*s != 0)
1107 return -EINVAL;
1108
1109 *nsec = NSEC_INFINITY;
1110 return 0;
1111 }
1112
1113 for (;;) {
1114 nsec_t multiplier = 1, k;
1115 long long l;
1116 char *e;
1117
1118 p += strspn(p, WHITESPACE);
1119
1120 if (*p == 0) {
1121 if (!something)
1122 return -EINVAL;
1123
1124 break;
1125 }
1126
1127 if (*p == '-') /* Don't allow "-0" */
1128 return -ERANGE;
1129
1130 errno = 0;
1131 l = strtoll(p, &e, 10);
1132 if (errno > 0)
1133 return -errno;
1134 if (l < 0)
1135 return -ERANGE;
1136
1137 if (*e == '.') {
1138 p = e + 1;
1139 p += strspn(p, DIGITS);
1140 } else if (e == p)
1141 return -EINVAL;
1142 else
1143 p = e;
1144
1145 s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
1146 if (s == p && *s != '\0')
1147 /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
1148 return -EINVAL;
1149
1150 p = s;
1151
1152 if ((nsec_t) l >= NSEC_INFINITY / multiplier)
1153 return -ERANGE;
1154
1155 k = (nsec_t) l * multiplier;
1156 if (k >= NSEC_INFINITY - r)
1157 return -ERANGE;
1158
1159 r += k;
1160
1161 something = true;
1162
1163 if (*e == '.') {
1164 nsec_t m = multiplier / 10;
1165 const char *b;
1166
1167 for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
1168 k = (nsec_t) (*b - '0') * m;
1169 if (k >= NSEC_INFINITY - r)
1170 return -ERANGE;
1171
1172 r += k;
1173 }
1174
1175 /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
1176 if (b == e + 1)
1177 return -EINVAL;
1178 }
1179 }
1180
1181 *nsec = r;
1182
1183 return 0;
1184 }
1185
1186 bool ntp_synced(void) {
1187 struct timex txc = {};
1188
1189 if (adjtimex(&txc) < 0)
1190 return false;
1191
1192 /* Consider the system clock synchronized if the reported maximum error is smaller than the maximum
1193 * value (16 seconds). Ignore the STA_UNSYNC flag as it may have been set to prevent the kernel from
1194 * touching the RTC. */
1195 if (txc.maxerror >= 16000000)
1196 return false;
1197
1198 return true;
1199 }
1200
1201 int get_timezones(char ***ret) {
1202 _cleanup_fclose_ FILE *f = NULL;
1203 _cleanup_strv_free_ char **zones = NULL;
1204 size_t n_zones = 0, n_allocated = 0;
1205 int r;
1206
1207 assert(ret);
1208
1209 zones = strv_new("UTC");
1210 if (!zones)
1211 return -ENOMEM;
1212
1213 n_allocated = 2;
1214 n_zones = 1;
1215
1216 f = fopen("/usr/share/zoneinfo/zone1970.tab", "re");
1217 if (f) {
1218 for (;;) {
1219 _cleanup_free_ char *line = NULL;
1220 char *p, *w;
1221 size_t k;
1222
1223 r = read_line(f, LONG_LINE_MAX, &line);
1224 if (r < 0)
1225 return r;
1226 if (r == 0)
1227 break;
1228
1229 p = strstrip(line);
1230
1231 if (isempty(p) || *p == '#')
1232 continue;
1233
1234 /* Skip over country code */
1235 p += strcspn(p, WHITESPACE);
1236 p += strspn(p, WHITESPACE);
1237
1238 /* Skip over coordinates */
1239 p += strcspn(p, WHITESPACE);
1240 p += strspn(p, WHITESPACE);
1241
1242 /* Found timezone name */
1243 k = strcspn(p, WHITESPACE);
1244 if (k <= 0)
1245 continue;
1246
1247 w = strndup(p, k);
1248 if (!w)
1249 return -ENOMEM;
1250
1251 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1252 free(w);
1253 return -ENOMEM;
1254 }
1255
1256 zones[n_zones++] = w;
1257 zones[n_zones] = NULL;
1258 }
1259
1260 strv_sort(zones);
1261
1262 } else if (errno != ENOENT)
1263 return -errno;
1264
1265 *ret = TAKE_PTR(zones);
1266
1267 return 0;
1268 }
1269
1270 bool timezone_is_valid(const char *name, int log_level) {
1271 bool slash = false;
1272 const char *p, *t;
1273 _cleanup_close_ int fd = -1;
1274 char buf[4];
1275 int r;
1276
1277 if (isempty(name))
1278 return false;
1279
1280 if (name[0] == '/')
1281 return false;
1282
1283 for (p = name; *p; p++) {
1284 if (!(*p >= '0' && *p <= '9') &&
1285 !(*p >= 'a' && *p <= 'z') &&
1286 !(*p >= 'A' && *p <= 'Z') &&
1287 !IN_SET(*p, '-', '_', '+', '/'))
1288 return false;
1289
1290 if (*p == '/') {
1291
1292 if (slash)
1293 return false;
1294
1295 slash = true;
1296 } else
1297 slash = false;
1298 }
1299
1300 if (slash)
1301 return false;
1302
1303 if (p - name >= PATH_MAX)
1304 return false;
1305
1306 t = strjoina("/usr/share/zoneinfo/", name);
1307
1308 fd = open(t, O_RDONLY|O_CLOEXEC);
1309 if (fd < 0) {
1310 log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
1311 return false;
1312 }
1313
1314 r = fd_verify_regular(fd);
1315 if (r < 0) {
1316 log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
1317 return false;
1318 }
1319
1320 r = loop_read_exact(fd, buf, 4, false);
1321 if (r < 0) {
1322 log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
1323 return false;
1324 }
1325
1326 /* Magic from tzfile(5) */
1327 if (memcmp(buf, "TZif", 4) != 0) {
1328 log_full(log_level, "Timezone file '%s' has wrong magic bytes", t);
1329 return false;
1330 }
1331
1332 return true;
1333 }
1334
1335 bool clock_boottime_supported(void) {
1336 static int supported = -1;
1337
1338 /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
1339
1340 if (supported < 0) {
1341 int fd;
1342
1343 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1344 if (fd < 0)
1345 supported = false;
1346 else {
1347 safe_close(fd);
1348 supported = true;
1349 }
1350 }
1351
1352 return supported;
1353 }
1354
1355 clockid_t clock_boottime_or_monotonic(void) {
1356 if (clock_boottime_supported())
1357 return CLOCK_BOOTTIME;
1358 else
1359 return CLOCK_MONOTONIC;
1360 }
1361
1362 bool clock_supported(clockid_t clock) {
1363 struct timespec ts;
1364
1365 switch (clock) {
1366
1367 case CLOCK_MONOTONIC:
1368 case CLOCK_REALTIME:
1369 return true;
1370
1371 case CLOCK_BOOTTIME:
1372 return clock_boottime_supported();
1373
1374 case CLOCK_BOOTTIME_ALARM:
1375 if (!clock_boottime_supported())
1376 return false;
1377
1378 _fallthrough_;
1379 default:
1380 /* For everything else, check properly */
1381 return clock_gettime(clock, &ts) >= 0;
1382 }
1383 }
1384
1385 int get_timezone(char **tz) {
1386 _cleanup_free_ char *t = NULL;
1387 const char *e;
1388 char *z;
1389 int r;
1390
1391 r = readlink_malloc("/etc/localtime", &t);
1392 if (r < 0)
1393 return r; /* returns EINVAL if not a symlink */
1394
1395 e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
1396 if (!e)
1397 return -EINVAL;
1398
1399 if (!timezone_is_valid(e, LOG_DEBUG))
1400 return -EINVAL;
1401
1402 z = strdup(e);
1403 if (!z)
1404 return -ENOMEM;
1405
1406 *tz = z;
1407 return 0;
1408 }
1409
1410 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1411 return utc ? timegm(tm) : mktime(tm);
1412 }
1413
1414 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1415 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1416 }
1417
1418 static uint32_t sysconf_clock_ticks_cached(void) {
1419 static thread_local uint32_t hz = 0;
1420 long r;
1421
1422 if (hz == 0) {
1423 r = sysconf(_SC_CLK_TCK);
1424
1425 assert(r > 0);
1426 hz = r;
1427 }
1428
1429 return hz;
1430 }
1431
1432 uint32_t usec_to_jiffies(usec_t u) {
1433 uint32_t hz = sysconf_clock_ticks_cached();
1434 return DIV_ROUND_UP(u, USEC_PER_SEC / hz);
1435 }
1436
1437 usec_t jiffies_to_usec(uint32_t j) {
1438 uint32_t hz = sysconf_clock_ticks_cached();
1439 return DIV_ROUND_UP(j * USEC_PER_SEC, hz);
1440 }
1441
1442 usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
1443 usec_t a, b;
1444
1445 if (x == USEC_INFINITY)
1446 return USEC_INFINITY;
1447 if (map_clock_id(from) == map_clock_id(to))
1448 return x;
1449
1450 a = now(from);
1451 b = now(to);
1452
1453 if (x > a)
1454 /* x lies in the future */
1455 return usec_add(b, usec_sub_unsigned(x, a));
1456 else
1457 /* x lies in the past */
1458 return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
1459 }
1460
1461 bool in_utc_timezone(void) {
1462 tzset();
1463
1464 return timezone == 0 && daylight == 0;
1465 }
1466
1467 int time_change_fd(void) {
1468
1469 /* We only care for the cancellation event, hence we set the timeout to the latest possible value. */
1470 static const struct itimerspec its = {
1471 .it_value.tv_sec = TIME_T_MAX,
1472 };
1473
1474 _cleanup_close_ int fd;
1475
1476 assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
1477
1478 /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever CLOCK_REALTIME makes a jump relative to
1479 * CLOCK_MONOTONIC. */
1480
1481 fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1482 if (fd < 0)
1483 return -errno;
1484
1485 if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0)
1486 return -errno;
1487
1488 return TAKE_FD(fd);
1489 }