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