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
map_clock_id(clockid_t c)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
now(clockid_t clock_id)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
now_nsec(clockid_t clock_id)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
dual_timestamp_get(dual_timestamp * ts)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
triple_timestamp_get(triple_timestamp * ts)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
map_clock_usec_internal(usec_t from,usec_t from_base,usec_t to_base)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
map_clock_usec(usec_t from,clockid_t from_clock,clockid_t to_clock)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
dual_timestamp_from_realtime(dual_timestamp * ts,usec_t u)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
triple_timestamp_from_realtime(triple_timestamp * ts,usec_t u)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
dual_timestamp_from_monotonic(dual_timestamp * ts,usec_t u)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
dual_timestamp_from_boottime(dual_timestamp * ts,usec_t u)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
triple_timestamp_by_clock(triple_timestamp * ts,clockid_t clock)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
timespec_load(const struct timespec * ts)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
timespec_load_nsec(const struct timespec * ts)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
timespec_store(struct timespec * ts,usec_t u)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
timespec_store_nsec(struct timespec * ts,nsec_t n)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
timeval_load(const struct timeval * tv)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
timeval_store(struct timeval * tv,usec_t u)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
format_timestamp_style(char * buf,size_t l,usec_t t,TimestampStyle style)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
format_timestamp_relative(char * buf,size_t l,usec_t t)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
format_timespan(char * buf,size_t l,usec_t t,usec_t accuracy)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 = buf;
517 bool something = false;
518
519 assert(buf);
520 assert(l > 0);
521
522 if (t == USEC_INFINITY) {
523 strncpy(p, "infinity", l-1);
524 p[l-1] = 0;
525 return p;
526 }
527
528 if (t <= 0) {
529 strncpy(p, "0", l-1);
530 p[l-1] = 0;
531 return p;
532 }
533
534 /* The result of this function can be parsed with parse_sec */
535
536 for (size_t i = 0; i < ELEMENTSOF(table); i++) {
537 int k = 0;
538 size_t n;
539 bool done = false;
540 usec_t a, b;
541
542 if (t <= 0)
543 break;
544
545 if (t < accuracy && something)
546 break;
547
548 if (t < table[i].usec)
549 continue;
550
551 if (l <= 1)
552 break;
553
554 a = t / table[i].usec;
555 b = t % table[i].usec;
556
557 /* Let's see if we should shows this in dot notation */
558 if (t < USEC_PER_MINUTE && b > 0) {
559 signed char j = 0;
560
561 for (usec_t cc = table[i].usec; cc > 1; cc /= 10)
562 j++;
563
564 for (usec_t cc = accuracy; cc > 1; cc /= 10) {
565 b /= 10;
566 j--;
567 }
568
569 if (j > 0) {
570 k = snprintf(p, l,
571 "%s"USEC_FMT".%0*"PRI_USEC"%s",
572 p > buf ? " " : "",
573 a,
574 j,
575 b,
576 table[i].suffix);
577
578 t = 0;
579 done = true;
580 }
581 }
582
583 /* No? Then let's show it normally */
584 if (!done) {
585 k = snprintf(p, l,
586 "%s"USEC_FMT"%s",
587 p > buf ? " " : "",
588 a,
589 table[i].suffix);
590
591 t = b;
592 }
593
594 n = MIN((size_t) k, l);
595
596 l -= n;
597 p += n;
598
599 something = true;
600 }
601
602 *p = 0;
603
604 return buf;
605 }
606
parse_timestamp_impl(const char * t,usec_t * usec,bool with_tz)607 static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
608 static const struct {
609 const char *name;
610 const int nr;
611 } day_nr[] = {
612 { "Sunday", 0 },
613 { "Sun", 0 },
614 { "Monday", 1 },
615 { "Mon", 1 },
616 { "Tuesday", 2 },
617 { "Tue", 2 },
618 { "Wednesday", 3 },
619 { "Wed", 3 },
620 { "Thursday", 4 },
621 { "Thu", 4 },
622 { "Friday", 5 },
623 { "Fri", 5 },
624 { "Saturday", 6 },
625 { "Sat", 6 },
626 };
627
628 const char *k, *utc = NULL, *tzn = NULL;
629 struct tm tm, copy;
630 time_t x;
631 usec_t x_usec, plus = 0, minus = 0, ret;
632 int r, weekday = -1, dst = -1;
633 size_t i;
634
635 /* Allowed syntaxes:
636 *
637 * 2012-09-22 16:34:22
638 * 2012-09-22 16:34 (seconds will be set to 0)
639 * 2012-09-22 (time will be set to 00:00:00)
640 * 16:34:22 (date will be set to today)
641 * 16:34 (date will be set to today, seconds to 0)
642 * now
643 * yesterday (time is set to 00:00:00)
644 * today (time is set to 00:00:00)
645 * tomorrow (time is set to 00:00:00)
646 * +5min
647 * -5days
648 * @2147483647 (seconds since epoch)
649 */
650
651 assert(t);
652
653 if (t[0] == '@' && !with_tz)
654 return parse_sec(t + 1, usec);
655
656 ret = now(CLOCK_REALTIME);
657
658 if (!with_tz) {
659 if (streq(t, "now"))
660 goto finish;
661
662 else if (t[0] == '+') {
663 r = parse_sec(t+1, &plus);
664 if (r < 0)
665 return r;
666
667 goto finish;
668
669 } else if (t[0] == '-') {
670 r = parse_sec(t+1, &minus);
671 if (r < 0)
672 return r;
673
674 goto finish;
675
676 } else if ((k = endswith(t, " ago"))) {
677 t = strndupa_safe(t, k - t);
678
679 r = parse_sec(t, &minus);
680 if (r < 0)
681 return r;
682
683 goto finish;
684
685 } else if ((k = endswith(t, " left"))) {
686 t = strndupa_safe(t, k - t);
687
688 r = parse_sec(t, &plus);
689 if (r < 0)
690 return r;
691
692 goto finish;
693 }
694
695 /* See if the timestamp is suffixed with UTC */
696 utc = endswith_no_case(t, " UTC");
697 if (utc)
698 t = strndupa_safe(t, utc - t);
699 else {
700 const char *e = NULL;
701 int j;
702
703 tzset();
704
705 /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note
706 * that we only support the local timezones here, nothing else. Not because we
707 * wouldn't want to, but simply because there are no nice APIs available to cover
708 * this. By accepting the local time zone strings, we make sure that all timestamps
709 * written by format_timestamp() can be parsed correctly, even though we don't
710 * support arbitrary timezone specifications. */
711
712 for (j = 0; j <= 1; j++) {
713
714 if (isempty(tzname[j]))
715 continue;
716
717 e = endswith_no_case(t, tzname[j]);
718 if (!e)
719 continue;
720 if (e == t)
721 continue;
722 if (e[-1] != ' ')
723 continue;
724
725 break;
726 }
727
728 if (IN_SET(j, 0, 1)) {
729 /* Found one of the two timezones specified. */
730 t = strndupa_safe(t, e - t - 1);
731 dst = j;
732 tzn = tzname[j];
733 }
734 }
735 }
736
737 x = (time_t) (ret / USEC_PER_SEC);
738 x_usec = 0;
739
740 if (!localtime_or_gmtime_r(&x, &tm, utc))
741 return -EINVAL;
742
743 tm.tm_isdst = dst;
744 if (!with_tz && tzn)
745 tm.tm_zone = tzn;
746
747 if (streq(t, "today")) {
748 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
749 goto from_tm;
750
751 } else if (streq(t, "yesterday")) {
752 tm.tm_mday--;
753 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
754 goto from_tm;
755
756 } else if (streq(t, "tomorrow")) {
757 tm.tm_mday++;
758 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
759 goto from_tm;
760 }
761
762 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
763 size_t skip;
764
765 if (!startswith_no_case(t, day_nr[i].name))
766 continue;
767
768 skip = strlen(day_nr[i].name);
769 if (t[skip] != ' ')
770 continue;
771
772 weekday = day_nr[i].nr;
773 t += skip + 1;
774 break;
775 }
776
777 copy = tm;
778 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
779 if (k) {
780 if (*k == '.')
781 goto parse_usec;
782 else if (*k == 0)
783 goto from_tm;
784 }
785
786 tm = copy;
787 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
788 if (k) {
789 if (*k == '.')
790 goto parse_usec;
791 else if (*k == 0)
792 goto from_tm;
793 }
794
795 /* Support OUTPUT_SHORT and OUTPUT_SHORT_PRECISE formats */
796 tm = copy;
797 k = strptime(t, "%b %d %H:%M:%S", &tm);
798 if (k) {
799 if (*k == '.')
800 goto parse_usec;
801 else if (*k == 0)
802 goto from_tm;
803 }
804
805 tm = copy;
806 k = strptime(t, "%y-%m-%d %H:%M", &tm);
807 if (k && *k == 0) {
808 tm.tm_sec = 0;
809 goto from_tm;
810 }
811
812 tm = copy;
813 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
814 if (k && *k == 0) {
815 tm.tm_sec = 0;
816 goto from_tm;
817 }
818
819 tm = copy;
820 k = strptime(t, "%y-%m-%d", &tm);
821 if (k && *k == 0) {
822 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
823 goto from_tm;
824 }
825
826 tm = copy;
827 k = strptime(t, "%Y-%m-%d", &tm);
828 if (k && *k == 0) {
829 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
830 goto from_tm;
831 }
832
833 tm = copy;
834 k = strptime(t, "%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 tm = copy;
843 k = strptime(t, "%H:%M", &tm);
844 if (k && *k == 0) {
845 tm.tm_sec = 0;
846 goto from_tm;
847 }
848
849 return -EINVAL;
850
851 parse_usec:
852 {
853 unsigned add;
854
855 k++;
856 r = parse_fractional_part_u(&k, 6, &add);
857 if (r < 0)
858 return -EINVAL;
859
860 if (*k)
861 return -EINVAL;
862
863 x_usec = add;
864 }
865
866 from_tm:
867 if (weekday >= 0 && tm.tm_wday != weekday)
868 return -EINVAL;
869
870 x = mktime_or_timegm(&tm, utc);
871 if (x < 0)
872 return -EINVAL;
873
874 ret = (usec_t) x * USEC_PER_SEC + x_usec;
875 if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
876 return -EINVAL;
877
878 finish:
879 if (ret + plus < ret) /* overflow? */
880 return -EINVAL;
881 ret += plus;
882 if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
883 return -EINVAL;
884
885 if (ret >= minus)
886 ret -= minus;
887 else
888 return -EINVAL;
889
890 if (usec)
891 *usec = ret;
892 return 0;
893 }
894
895 typedef struct ParseTimestampResult {
896 usec_t usec;
897 int return_value;
898 } ParseTimestampResult;
899
parse_timestamp(const char * t,usec_t * usec)900 int parse_timestamp(const char *t, usec_t *usec) {
901 char *last_space, *tz = NULL;
902 ParseTimestampResult *shared, tmp;
903 int r;
904
905 last_space = strrchr(t, ' ');
906 if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
907 tz = last_space + 1;
908
909 if (!tz || endswith_no_case(t, " UTC"))
910 return parse_timestamp_impl(t, usec, false);
911
912 shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
913 if (shared == MAP_FAILED)
914 return negative_errno();
915
916 r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
917 if (r < 0) {
918 (void) munmap(shared, sizeof *shared);
919 return r;
920 }
921 if (r == 0) {
922 bool with_tz = true;
923 char *colon_tz;
924
925 /* tzset(3) says $TZ should be prefixed with ":" if we reference timezone files */
926 colon_tz = strjoina(":", tz);
927
928 if (setenv("TZ", colon_tz, 1) != 0) {
929 shared->return_value = negative_errno();
930 _exit(EXIT_FAILURE);
931 }
932
933 tzset();
934
935 /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
936 * Otherwise just cut it off. */
937 with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
938
939 /* Cut off the timezone if we don't need it. */
940 if (with_tz)
941 t = strndupa_safe(t, last_space - t);
942
943 shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
944
945 _exit(EXIT_SUCCESS);
946 }
947
948 tmp = *shared;
949 if (munmap(shared, sizeof *shared) != 0)
950 return negative_errno();
951
952 if (tmp.return_value == 0 && usec)
953 *usec = tmp.usec;
954
955 return tmp.return_value;
956 }
957
extract_multiplier(const char * p,usec_t * multiplier)958 static const char* extract_multiplier(const char *p, usec_t *multiplier) {
959 static const struct {
960 const char *suffix;
961 usec_t usec;
962 } table[] = {
963 { "seconds", USEC_PER_SEC },
964 { "second", USEC_PER_SEC },
965 { "sec", USEC_PER_SEC },
966 { "s", USEC_PER_SEC },
967 { "minutes", USEC_PER_MINUTE },
968 { "minute", USEC_PER_MINUTE },
969 { "min", USEC_PER_MINUTE },
970 { "months", USEC_PER_MONTH },
971 { "month", USEC_PER_MONTH },
972 { "M", USEC_PER_MONTH },
973 { "msec", USEC_PER_MSEC },
974 { "ms", USEC_PER_MSEC },
975 { "m", USEC_PER_MINUTE },
976 { "hours", USEC_PER_HOUR },
977 { "hour", USEC_PER_HOUR },
978 { "hr", USEC_PER_HOUR },
979 { "h", USEC_PER_HOUR },
980 { "days", USEC_PER_DAY },
981 { "day", USEC_PER_DAY },
982 { "d", USEC_PER_DAY },
983 { "weeks", USEC_PER_WEEK },
984 { "week", USEC_PER_WEEK },
985 { "w", USEC_PER_WEEK },
986 { "years", USEC_PER_YEAR },
987 { "year", USEC_PER_YEAR },
988 { "y", USEC_PER_YEAR },
989 { "usec", 1ULL },
990 { "us", 1ULL },
991 { "µs", 1ULL },
992 };
993
994 for (size_t i = 0; i < ELEMENTSOF(table); i++) {
995 char *e;
996
997 e = startswith(p, table[i].suffix);
998 if (e) {
999 *multiplier = table[i].usec;
1000 return e;
1001 }
1002 }
1003
1004 return p;
1005 }
1006
parse_time(const char * t,usec_t * usec,usec_t default_unit)1007 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
1008 const char *p, *s;
1009 usec_t r = 0;
1010 bool something = false;
1011
1012 assert(t);
1013 assert(default_unit > 0);
1014
1015 p = t;
1016
1017 p += strspn(p, WHITESPACE);
1018 s = startswith(p, "infinity");
1019 if (s) {
1020 s += strspn(s, WHITESPACE);
1021 if (*s != 0)
1022 return -EINVAL;
1023
1024 if (usec)
1025 *usec = USEC_INFINITY;
1026 return 0;
1027 }
1028
1029 for (;;) {
1030 usec_t multiplier = default_unit, k;
1031 long long l;
1032 char *e;
1033
1034 p += strspn(p, WHITESPACE);
1035
1036 if (*p == 0) {
1037 if (!something)
1038 return -EINVAL;
1039
1040 break;
1041 }
1042
1043 if (*p == '-') /* Don't allow "-0" */
1044 return -ERANGE;
1045
1046 errno = 0;
1047 l = strtoll(p, &e, 10);
1048 if (errno > 0)
1049 return -errno;
1050 if (l < 0)
1051 return -ERANGE;
1052
1053 if (*e == '.') {
1054 p = e + 1;
1055 p += strspn(p, DIGITS);
1056 } else if (e == p)
1057 return -EINVAL;
1058 else
1059 p = e;
1060
1061 s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
1062 if (s == p && *s != '\0')
1063 /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56' */
1064 return -EINVAL;
1065
1066 p = s;
1067
1068 if ((usec_t) l >= USEC_INFINITY / multiplier)
1069 return -ERANGE;
1070
1071 k = (usec_t) l * multiplier;
1072 if (k >= USEC_INFINITY - r)
1073 return -ERANGE;
1074
1075 r += k;
1076
1077 something = true;
1078
1079 if (*e == '.') {
1080 usec_t m = multiplier / 10;
1081 const char *b;
1082
1083 for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
1084 k = (usec_t) (*b - '0') * m;
1085 if (k >= USEC_INFINITY - r)
1086 return -ERANGE;
1087
1088 r += k;
1089 }
1090
1091 /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */
1092 if (b == e + 1)
1093 return -EINVAL;
1094 }
1095 }
1096
1097 if (usec)
1098 *usec = r;
1099 return 0;
1100 }
1101
parse_sec(const char * t,usec_t * usec)1102 int parse_sec(const char *t, usec_t *usec) {
1103 return parse_time(t, usec, USEC_PER_SEC);
1104 }
1105
parse_sec_fix_0(const char * t,usec_t * ret)1106 int parse_sec_fix_0(const char *t, usec_t *ret) {
1107 usec_t k;
1108 int r;
1109
1110 assert(t);
1111 assert(ret);
1112
1113 r = parse_sec(t, &k);
1114 if (r < 0)
1115 return r;
1116
1117 *ret = k == 0 ? USEC_INFINITY : k;
1118 return r;
1119 }
1120
parse_sec_def_infinity(const char * t,usec_t * ret)1121 int parse_sec_def_infinity(const char *t, usec_t *ret) {
1122 t += strspn(t, WHITESPACE);
1123 if (isempty(t)) {
1124 *ret = USEC_INFINITY;
1125 return 0;
1126 }
1127 return parse_sec(t, ret);
1128 }
1129
extract_nsec_multiplier(const char * p,nsec_t * multiplier)1130 static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
1131 static const struct {
1132 const char *suffix;
1133 nsec_t nsec;
1134 } table[] = {
1135 { "seconds", NSEC_PER_SEC },
1136 { "second", NSEC_PER_SEC },
1137 { "sec", NSEC_PER_SEC },
1138 { "s", NSEC_PER_SEC },
1139 { "minutes", NSEC_PER_MINUTE },
1140 { "minute", NSEC_PER_MINUTE },
1141 { "min", NSEC_PER_MINUTE },
1142 { "months", NSEC_PER_MONTH },
1143 { "month", NSEC_PER_MONTH },
1144 { "M", NSEC_PER_MONTH },
1145 { "msec", NSEC_PER_MSEC },
1146 { "ms", NSEC_PER_MSEC },
1147 { "m", NSEC_PER_MINUTE },
1148 { "hours", NSEC_PER_HOUR },
1149 { "hour", NSEC_PER_HOUR },
1150 { "hr", NSEC_PER_HOUR },
1151 { "h", NSEC_PER_HOUR },
1152 { "days", NSEC_PER_DAY },
1153 { "day", NSEC_PER_DAY },
1154 { "d", NSEC_PER_DAY },
1155 { "weeks", NSEC_PER_WEEK },
1156 { "week", NSEC_PER_WEEK },
1157 { "w", NSEC_PER_WEEK },
1158 { "years", NSEC_PER_YEAR },
1159 { "year", NSEC_PER_YEAR },
1160 { "y", NSEC_PER_YEAR },
1161 { "usec", NSEC_PER_USEC },
1162 { "us", NSEC_PER_USEC },
1163 { "µs", NSEC_PER_USEC },
1164 { "nsec", 1ULL },
1165 { "ns", 1ULL },
1166 { "", 1ULL }, /* default is nsec */
1167 };
1168 size_t i;
1169
1170 for (i = 0; i < ELEMENTSOF(table); i++) {
1171 char *e;
1172
1173 e = startswith(p, table[i].suffix);
1174 if (e) {
1175 *multiplier = table[i].nsec;
1176 return e;
1177 }
1178 }
1179
1180 return p;
1181 }
1182
parse_nsec(const char * t,nsec_t * nsec)1183 int parse_nsec(const char *t, nsec_t *nsec) {
1184 const char *p, *s;
1185 nsec_t r = 0;
1186 bool something = false;
1187
1188 assert(t);
1189 assert(nsec);
1190
1191 p = t;
1192
1193 p += strspn(p, WHITESPACE);
1194 s = startswith(p, "infinity");
1195 if (s) {
1196 s += strspn(s, WHITESPACE);
1197 if (*s != 0)
1198 return -EINVAL;
1199
1200 *nsec = NSEC_INFINITY;
1201 return 0;
1202 }
1203
1204 for (;;) {
1205 nsec_t multiplier = 1, k;
1206 long long l;
1207 char *e;
1208
1209 p += strspn(p, WHITESPACE);
1210
1211 if (*p == 0) {
1212 if (!something)
1213 return -EINVAL;
1214
1215 break;
1216 }
1217
1218 if (*p == '-') /* Don't allow "-0" */
1219 return -ERANGE;
1220
1221 errno = 0;
1222 l = strtoll(p, &e, 10);
1223 if (errno > 0)
1224 return -errno;
1225 if (l < 0)
1226 return -ERANGE;
1227
1228 if (*e == '.') {
1229 p = e + 1;
1230 p += strspn(p, DIGITS);
1231 } else if (e == p)
1232 return -EINVAL;
1233 else
1234 p = e;
1235
1236 s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
1237 if (s == p && *s != '\0')
1238 /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56' */
1239 return -EINVAL;
1240
1241 p = s;
1242
1243 if ((nsec_t) l >= NSEC_INFINITY / multiplier)
1244 return -ERANGE;
1245
1246 k = (nsec_t) l * multiplier;
1247 if (k >= NSEC_INFINITY - r)
1248 return -ERANGE;
1249
1250 r += k;
1251
1252 something = true;
1253
1254 if (*e == '.') {
1255 nsec_t m = multiplier / 10;
1256 const char *b;
1257
1258 for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
1259 k = (nsec_t) (*b - '0') * m;
1260 if (k >= NSEC_INFINITY - r)
1261 return -ERANGE;
1262
1263 r += k;
1264 }
1265
1266 /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */
1267 if (b == e + 1)
1268 return -EINVAL;
1269 }
1270 }
1271
1272 *nsec = r;
1273
1274 return 0;
1275 }
1276
get_timezones_from_zone1970_tab(char *** ret)1277 static int get_timezones_from_zone1970_tab(char ***ret) {
1278 _cleanup_fclose_ FILE *f = NULL;
1279 _cleanup_strv_free_ char **zones = NULL;
1280 int r;
1281
1282 assert(ret);
1283
1284 f = fopen("/usr/share/zoneinfo/zone1970.tab", "re");
1285 if (!f)
1286 return -errno;
1287
1288 for (;;) {
1289 _cleanup_free_ char *line = NULL, *cc = NULL, *co = NULL, *tz = NULL;
1290
1291 r = read_line(f, LONG_LINE_MAX, &line);
1292 if (r < 0)
1293 return r;
1294 if (r == 0)
1295 break;
1296
1297 const char *p = line;
1298
1299 /* Line format is:
1300 * 'country codes' 'coordinates' 'timezone' 'comments' */
1301 r = extract_many_words(&p, NULL, 0, &cc, &co, &tz, NULL);
1302 if (r < 0)
1303 continue;
1304
1305 /* Lines that start with # are comments. */
1306 if (*cc == '#')
1307 continue;
1308
1309 r = strv_extend(&zones, tz);
1310 if (r < 0)
1311 return r;
1312 }
1313
1314 *ret = TAKE_PTR(zones);
1315 return 0;
1316 }
1317
get_timezones_from_tzdata_zi(char *** ret)1318 static int get_timezones_from_tzdata_zi(char ***ret) {
1319 _cleanup_fclose_ FILE *f = NULL;
1320 _cleanup_strv_free_ char **zones = NULL;
1321 int r;
1322
1323 f = fopen("/usr/share/zoneinfo/tzdata.zi", "re");
1324 if (!f)
1325 return -errno;
1326
1327 for (;;) {
1328 _cleanup_free_ char *line = NULL, *type = NULL, *f1 = NULL, *f2 = NULL;
1329
1330 r = read_line(f, LONG_LINE_MAX, &line);
1331 if (r < 0)
1332 return r;
1333 if (r == 0)
1334 break;
1335
1336 const char *p = line;
1337
1338 /* The only lines we care about are Zone and Link lines.
1339 * Zone line format is:
1340 * 'Zone' 'timezone' ...
1341 * Link line format is:
1342 * 'Link' 'target' 'alias'
1343 * See 'man zic' for more detail. */
1344 r = extract_many_words(&p, NULL, 0, &type, &f1, &f2, NULL);
1345 if (r < 0)
1346 continue;
1347
1348 char *tz;
1349 if (IN_SET(*type, 'Z', 'z'))
1350 /* Zone lines have timezone in field 1. */
1351 tz = f1;
1352 else if (IN_SET(*type, 'L', 'l'))
1353 /* Link lines have timezone in field 2. */
1354 tz = f2;
1355 else
1356 /* Not a line we care about. */
1357 continue;
1358
1359 r = strv_extend(&zones, tz);
1360 if (r < 0)
1361 return r;
1362 }
1363
1364 *ret = TAKE_PTR(zones);
1365 return 0;
1366 }
1367
get_timezones(char *** ret)1368 int get_timezones(char ***ret) {
1369 _cleanup_strv_free_ char **zones = NULL;
1370 int r;
1371
1372 assert(ret);
1373
1374 r = get_timezones_from_tzdata_zi(&zones);
1375 if (r == -ENOENT) {
1376 log_debug_errno(r, "Could not get timezone data from tzdata.zi, using zone1970.tab: %m");
1377 r = get_timezones_from_zone1970_tab(&zones);
1378 if (r == -ENOENT)
1379 log_debug_errno(r, "Could not get timezone data from zone1970.tab, using UTC: %m");
1380 }
1381 if (r < 0 && r != -ENOENT)
1382 return r;
1383
1384 /* Always include UTC */
1385 r = strv_extend(&zones, "UTC");
1386 if (r < 0)
1387 return -ENOMEM;
1388
1389 strv_sort(zones);
1390 strv_uniq(zones);
1391
1392 *ret = TAKE_PTR(zones);
1393 return 0;
1394 }
1395
verify_timezone(const char * name,int log_level)1396 int verify_timezone(const char *name, int log_level) {
1397 bool slash = false;
1398 const char *p, *t;
1399 _cleanup_close_ int fd = -1;
1400 char buf[4];
1401 int r;
1402
1403 if (isempty(name))
1404 return -EINVAL;
1405
1406 /* Always accept "UTC" as valid timezone, since it's the fallback, even if user has no timezones installed. */
1407 if (streq(name, "UTC"))
1408 return 0;
1409
1410 if (name[0] == '/')
1411 return -EINVAL;
1412
1413 for (p = name; *p; p++) {
1414 if (!(*p >= '0' && *p <= '9') &&
1415 !(*p >= 'a' && *p <= 'z') &&
1416 !(*p >= 'A' && *p <= 'Z') &&
1417 !IN_SET(*p, '-', '_', '+', '/'))
1418 return -EINVAL;
1419
1420 if (*p == '/') {
1421
1422 if (slash)
1423 return -EINVAL;
1424
1425 slash = true;
1426 } else
1427 slash = false;
1428 }
1429
1430 if (slash)
1431 return -EINVAL;
1432
1433 if (p - name >= PATH_MAX)
1434 return -ENAMETOOLONG;
1435
1436 t = strjoina("/usr/share/zoneinfo/", name);
1437
1438 fd = open(t, O_RDONLY|O_CLOEXEC);
1439 if (fd < 0)
1440 return log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
1441
1442 r = fd_verify_regular(fd);
1443 if (r < 0)
1444 return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
1445
1446 r = loop_read_exact(fd, buf, 4, false);
1447 if (r < 0)
1448 return log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
1449
1450 /* Magic from tzfile(5) */
1451 if (memcmp(buf, "TZif", 4) != 0)
1452 return log_full_errno(log_level, SYNTHETIC_ERRNO(EBADMSG),
1453 "Timezone file '%s' has wrong magic bytes", t);
1454
1455 return 0;
1456 }
1457
clock_supported(clockid_t clock)1458 bool clock_supported(clockid_t clock) {
1459 struct timespec ts;
1460
1461 switch (clock) {
1462
1463 case CLOCK_MONOTONIC:
1464 case CLOCK_REALTIME:
1465 case CLOCK_BOOTTIME:
1466 /* These three are always available in our baseline, and work in timerfd, as of kernel 3.15 */
1467 return true;
1468
1469 default:
1470 /* For everything else, check properly */
1471 return clock_gettime(clock, &ts) >= 0;
1472 }
1473 }
1474
get_timezone(char ** ret)1475 int get_timezone(char **ret) {
1476 _cleanup_free_ char *t = NULL;
1477 const char *e;
1478 char *z;
1479 int r;
1480
1481 r = readlink_malloc("/etc/localtime", &t);
1482 if (r == -ENOENT) {
1483 /* If the symlink does not exist, assume "UTC", like glibc does */
1484 z = strdup("UTC");
1485 if (!z)
1486 return -ENOMEM;
1487
1488 *ret = z;
1489 return 0;
1490 }
1491 if (r < 0)
1492 return r; /* returns EINVAL if not a symlink */
1493
1494 e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
1495 if (!e)
1496 return -EINVAL;
1497
1498 if (!timezone_is_valid(e, LOG_DEBUG))
1499 return -EINVAL;
1500
1501 z = strdup(e);
1502 if (!z)
1503 return -ENOMEM;
1504
1505 *ret = z;
1506 return 0;
1507 }
1508
mktime_or_timegm(struct tm * tm,bool utc)1509 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1510 return utc ? timegm(tm) : mktime(tm);
1511 }
1512
localtime_or_gmtime_r(const time_t * t,struct tm * tm,bool utc)1513 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1514 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1515 }
1516
sysconf_clock_ticks_cached(void)1517 static uint32_t sysconf_clock_ticks_cached(void) {
1518 static thread_local uint32_t hz = 0;
1519 long r;
1520
1521 if (hz == 0) {
1522 r = sysconf(_SC_CLK_TCK);
1523
1524 assert(r > 0);
1525 hz = r;
1526 }
1527
1528 return hz;
1529 }
1530
usec_to_jiffies(usec_t u)1531 uint32_t usec_to_jiffies(usec_t u) {
1532 uint32_t hz = sysconf_clock_ticks_cached();
1533 return DIV_ROUND_UP(u, USEC_PER_SEC / hz);
1534 }
1535
jiffies_to_usec(uint32_t j)1536 usec_t jiffies_to_usec(uint32_t j) {
1537 uint32_t hz = sysconf_clock_ticks_cached();
1538 return DIV_ROUND_UP(j * USEC_PER_SEC, hz);
1539 }
1540
usec_shift_clock(usec_t x,clockid_t from,clockid_t to)1541 usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
1542 usec_t a, b;
1543
1544 if (x == USEC_INFINITY)
1545 return USEC_INFINITY;
1546 if (map_clock_id(from) == map_clock_id(to))
1547 return x;
1548
1549 a = now(from);
1550 b = now(to);
1551
1552 if (x > a)
1553 /* x lies in the future */
1554 return usec_add(b, usec_sub_unsigned(x, a));
1555 else
1556 /* x lies in the past */
1557 return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
1558 }
1559
in_utc_timezone(void)1560 bool in_utc_timezone(void) {
1561 tzset();
1562
1563 return timezone == 0 && daylight == 0;
1564 }
1565
time_change_fd(void)1566 int time_change_fd(void) {
1567
1568 /* We only care for the cancellation event, hence we set the timeout to the latest possible value. */
1569 static const struct itimerspec its = {
1570 .it_value.tv_sec = TIME_T_MAX,
1571 };
1572
1573 _cleanup_close_ int fd = -1;
1574
1575 assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
1576
1577 /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever CLOCK_REALTIME makes a jump relative to
1578 * CLOCK_MONOTONIC. */
1579
1580 fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1581 if (fd < 0)
1582 return -errno;
1583
1584 if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) >= 0)
1585 return TAKE_FD(fd);
1586
1587 /* So apparently there are systems where time_t is 64bit, but the kernel actually doesn't support
1588 * 64bit time_t. In that case configuring a timer to TIME_T_MAX will fail with EOPNOTSUPP or a
1589 * similar error. If that's the case let's try with INT32_MAX instead, maybe that works. It's a bit
1590 * of a black magic thing though, but what can we do?
1591 *
1592 * We don't want this code on x86-64, hence let's conditionalize this for systems with 64bit time_t
1593 * but where "long" is shorter than 64bit, i.e. 32bit archs.
1594 *
1595 * See: https://github.com/systemd/systemd/issues/14362 */
1596
1597 #if SIZEOF_TIME_T == 8 && ULONG_MAX < UINT64_MAX
1598 if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EOVERFLOW) {
1599 static const struct itimerspec its32 = {
1600 .it_value.tv_sec = INT32_MAX,
1601 };
1602
1603 if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its32, NULL) >= 0)
1604 return TAKE_FD(fd);
1605 }
1606 #endif
1607
1608 return -errno;
1609 }
1610
1611 static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
1612 [TIMESTAMP_PRETTY] = "pretty",
1613 [TIMESTAMP_US] = "us",
1614 [TIMESTAMP_UTC] = "utc",
1615 [TIMESTAMP_US_UTC] = "us+utc",
1616 [TIMESTAMP_UNIX] = "unix",
1617 };
1618
1619 /* Use the macro for enum → string to allow for aliases */
1620 _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(timestamp_style, TimestampStyle,);
1621
1622 /* For the string → enum mapping we use the generic implementation, but also support two aliases */
timestamp_style_from_string(const char * s)1623 TimestampStyle timestamp_style_from_string(const char *s) {
1624 TimestampStyle t;
1625
1626 t = (TimestampStyle) string_table_lookup(timestamp_style_table, ELEMENTSOF(timestamp_style_table), s);
1627 if (t >= 0)
1628 return t;
1629 if (streq_ptr(s, "µs"))
1630 return TIMESTAMP_US;
1631 if (streq_ptr(s, "µs+utc"))
1632 return TIMESTAMP_US_UTC;
1633 return t;
1634 }
1635