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