]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/time-util.c
4a341e208fb97e1a985aad9ddda91a66835972c7
[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 = zones;
1287 zones = NULL;
1288
1289 return 0;
1290 }
1291
1292 bool timezone_is_valid(const char *name) {
1293 bool slash = false;
1294 const char *p, *t;
1295 struct stat st;
1296
1297 if (isempty(name))
1298 return false;
1299
1300 if (name[0] == '/')
1301 return false;
1302
1303 for (p = name; *p; p++) {
1304 if (!(*p >= '0' && *p <= '9') &&
1305 !(*p >= 'a' && *p <= 'z') &&
1306 !(*p >= 'A' && *p <= 'Z') &&
1307 !IN_SET(*p, '-', '_', '+', '/'))
1308 return false;
1309
1310 if (*p == '/') {
1311
1312 if (slash)
1313 return false;
1314
1315 slash = true;
1316 } else
1317 slash = false;
1318 }
1319
1320 if (slash)
1321 return false;
1322
1323 t = strjoina("/usr/share/zoneinfo/", name);
1324 if (stat(t, &st) < 0)
1325 return false;
1326
1327 if (!S_ISREG(st.st_mode))
1328 return false;
1329
1330 return true;
1331 }
1332
1333 bool clock_boottime_supported(void) {
1334 static int supported = -1;
1335
1336 /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
1337
1338 if (supported < 0) {
1339 int fd;
1340
1341 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1342 if (fd < 0)
1343 supported = false;
1344 else {
1345 safe_close(fd);
1346 supported = true;
1347 }
1348 }
1349
1350 return supported;
1351 }
1352
1353 clockid_t clock_boottime_or_monotonic(void) {
1354 if (clock_boottime_supported())
1355 return CLOCK_BOOTTIME;
1356 else
1357 return CLOCK_MONOTONIC;
1358 }
1359
1360 bool clock_supported(clockid_t clock) {
1361 struct timespec ts;
1362
1363 switch (clock) {
1364
1365 case CLOCK_MONOTONIC:
1366 case CLOCK_REALTIME:
1367 return true;
1368
1369 case CLOCK_BOOTTIME:
1370 return clock_boottime_supported();
1371
1372 case CLOCK_BOOTTIME_ALARM:
1373 if (!clock_boottime_supported())
1374 return false;
1375
1376 _fallthrough_;
1377 default:
1378 /* For everything else, check properly */
1379 return clock_gettime(clock, &ts) >= 0;
1380 }
1381 }
1382
1383 int get_timezone(char **tz) {
1384 _cleanup_free_ char *t = NULL;
1385 const char *e;
1386 char *z;
1387 int r;
1388
1389 r = readlink_malloc("/etc/localtime", &t);
1390 if (r < 0)
1391 return r; /* returns EINVAL if not a symlink */
1392
1393 e = path_startswith(t, "/usr/share/zoneinfo/");
1394 if (!e)
1395 e = path_startswith(t, "../usr/share/zoneinfo/");
1396 if (!e)
1397 return -EINVAL;
1398
1399 if (!timezone_is_valid(e))
1400 return -EINVAL;
1401
1402 z = strdup(e);
1403 if (!z)
1404 return -ENOMEM;
1405
1406 *tz = z;
1407 return 0;
1408 }
1409
1410 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1411 return utc ? timegm(tm) : mktime(tm);
1412 }
1413
1414 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1415 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1416 }
1417
1418 unsigned long usec_to_jiffies(usec_t u) {
1419 static thread_local unsigned long hz = 0;
1420 long r;
1421
1422 if (hz == 0) {
1423 r = sysconf(_SC_CLK_TCK);
1424
1425 assert(r > 0);
1426 hz = r;
1427 }
1428
1429 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
1430 }
1431
1432 usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
1433 usec_t a, b;
1434
1435 if (x == USEC_INFINITY)
1436 return USEC_INFINITY;
1437 if (map_clock_id(from) == map_clock_id(to))
1438 return x;
1439
1440 a = now(from);
1441 b = now(to);
1442
1443 if (x > a)
1444 /* x lies in the future */
1445 return usec_add(b, usec_sub_unsigned(x, a));
1446 else
1447 /* x lies in the past */
1448 return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
1449 }
1450
1451 bool in_utc_timezone(void) {
1452 tzset();
1453
1454 return timezone == 0 && daylight == 0;
1455 }