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