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