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