]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/time-util.c
util-lib: make timestamp generation and parsing reversible (#3869)
[thirdparty/systemd.git] / src / basic / time-util.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <sys/timerfd.h>
27 #include <sys/timex.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 #include "alloc-util.h"
32 #include "fd-util.h"
33 #include "fileio.h"
34 #include "fs-util.h"
35 #include "log.h"
36 #include "macro.h"
37 #include "parse-util.h"
38 #include "path-util.h"
39 #include "string-util.h"
40 #include "strv.h"
41 #include "time-util.h"
42
43 static nsec_t timespec_load_nsec(const struct timespec *ts);
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(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(now(CLOCK_MONOTONIC), delta);
130 ts->boottime = clock_boottime_supported() ? usec_sub(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(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(ts->realtime, delta);
162 ts->monotonic = usec_sub(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 == (time_t) -1 && ts->tv_nsec == (long) -1)
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 static nsec_t timespec_load_nsec(const struct timespec *ts) {
202 assert(ts);
203
204 if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1)
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 ts->tv_sec = (time_t) -1;
218 ts->tv_nsec = (long) -1;
219 return ts;
220 }
221
222 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
223 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
224
225 return ts;
226 }
227
228 usec_t timeval_load(const struct timeval *tv) {
229 assert(tv);
230
231 if (tv->tv_sec == (time_t) -1 &&
232 tv->tv_usec == (suseconds_t) -1)
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 tv->tv_sec = (time_t) -1;
248 tv->tv_usec = (suseconds_t) -1;
249 } else {
250 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
251 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
252 }
253
254 return tv;
255 }
256
257 static char *format_timestamp_internal(
258 char *buf,
259 size_t l,
260 usec_t t,
261 bool utc,
262 bool us) {
263
264 /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
265 * generated timestamps may be parsed with parse_timestamp(), and always read the same. */
266 static const char * const weekdays[] = {
267 [0] = "Sun",
268 [1] = "Mon",
269 [2] = "Tue",
270 [3] = "Wed",
271 [4] = "Thu",
272 [5] = "Fri",
273 [6] = "Sat",
274 };
275
276 struct tm tm;
277 time_t sec;
278 size_t n;
279
280 assert(buf);
281
282 if (l <
283 3 + /* week day */
284 1 + 10 + /* space and date */
285 1 + 8 + /* space and time */
286 (us ? 1 + 6 : 0) + /* "." and microsecond part */
287 1 + 1 + /* space and shortest possible zone */
288 1)
289 return NULL; /* Not enough space even for the shortest form. */
290 if (t <= 0 || t == USEC_INFINITY)
291 return NULL; /* Timestamp is unset */
292
293 sec = (time_t) (t / USEC_PER_SEC); /* Round down */
294 if ((usec_t) sec != (t / USEC_PER_SEC))
295 return NULL; /* overflow? */
296
297 if (!localtime_or_gmtime_r(&sec, &tm, utc))
298 return NULL;
299
300 /* Start with the week day */
301 assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
302 memcpy(buf, weekdays[tm.tm_wday], 4);
303
304 /* Add the main components */
305 if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
306 return NULL; /* Doesn't fit */
307
308 /* Append the microseconds part, if that's requested */
309 if (us) {
310 n = strlen(buf);
311 if (n + 8 > l)
312 return NULL; /* Microseconds part doesn't fit. */
313
314 sprintf(buf + n, ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
315 }
316
317 /* Append the timezone */
318 n = strlen(buf);
319 if (utc) {
320 /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the
321 * obsolete "GMT" instead. */
322 if (n + 5 > l)
323 return NULL; /* "UTC" doesn't fit. */
324
325 strcpy(buf + n, " UTC");
326
327 } else if (!isempty(tm.tm_zone)) {
328 size_t tn;
329
330 /* An explicit timezone is specified, let's use it, if it fits */
331 tn = strlen(tm.tm_zone);
332 if (n + 1 + tn + 1 > l) {
333 /* The full time zone does not fit in. Yuck. */
334
335 if (n + 1 + _POSIX_TZNAME_MAX + 1 > l)
336 return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */
337
338 /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
339 * minimum time zone length. In this case suppress the timezone entirely, in order not to dump
340 * an overly long, hard to read string on the user. This should be safe, because the user will
341 * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
342 } else {
343 buf[n++] = ' ';
344 strcpy(buf + n, tm.tm_zone);
345 }
346 }
347
348 return buf;
349 }
350
351 char *format_timestamp(char *buf, size_t l, usec_t t) {
352 return format_timestamp_internal(buf, l, t, false, false);
353 }
354
355 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
356 return format_timestamp_internal(buf, l, t, true, false);
357 }
358
359 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
360 return format_timestamp_internal(buf, l, t, false, true);
361 }
362
363 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
364 return format_timestamp_internal(buf, l, t, true, true);
365 }
366
367 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
368 const char *s;
369 usec_t n, d;
370
371 if (t <= 0 || t == USEC_INFINITY)
372 return NULL;
373
374 n = now(CLOCK_REALTIME);
375 if (n > t) {
376 d = n - t;
377 s = "ago";
378 } else {
379 d = t - n;
380 s = "left";
381 }
382
383 if (d >= USEC_PER_YEAR)
384 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
385 d / USEC_PER_YEAR,
386 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
387 else if (d >= USEC_PER_MONTH)
388 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
389 d / USEC_PER_MONTH,
390 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
391 else if (d >= USEC_PER_WEEK)
392 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
393 d / USEC_PER_WEEK,
394 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
395 else if (d >= 2*USEC_PER_DAY)
396 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
397 else if (d >= 25*USEC_PER_HOUR)
398 snprintf(buf, l, "1 day " USEC_FMT "h %s",
399 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
400 else if (d >= 6*USEC_PER_HOUR)
401 snprintf(buf, l, USEC_FMT "h %s",
402 d / USEC_PER_HOUR, s);
403 else if (d >= USEC_PER_HOUR)
404 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
405 d / USEC_PER_HOUR,
406 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
407 else if (d >= 5*USEC_PER_MINUTE)
408 snprintf(buf, l, USEC_FMT "min %s",
409 d / USEC_PER_MINUTE, s);
410 else if (d >= USEC_PER_MINUTE)
411 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
412 d / USEC_PER_MINUTE,
413 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
414 else if (d >= USEC_PER_SEC)
415 snprintf(buf, l, USEC_FMT "s %s",
416 d / USEC_PER_SEC, s);
417 else if (d >= USEC_PER_MSEC)
418 snprintf(buf, l, USEC_FMT "ms %s",
419 d / USEC_PER_MSEC, s);
420 else if (d > 0)
421 snprintf(buf, l, USEC_FMT"us %s",
422 d, s);
423 else
424 snprintf(buf, l, "now");
425
426 buf[l-1] = 0;
427 return buf;
428 }
429
430 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
431 static const struct {
432 const char *suffix;
433 usec_t usec;
434 } table[] = {
435 { "y", USEC_PER_YEAR },
436 { "month", USEC_PER_MONTH },
437 { "w", USEC_PER_WEEK },
438 { "d", USEC_PER_DAY },
439 { "h", USEC_PER_HOUR },
440 { "min", USEC_PER_MINUTE },
441 { "s", USEC_PER_SEC },
442 { "ms", USEC_PER_MSEC },
443 { "us", 1 },
444 };
445
446 unsigned i;
447 char *p = buf;
448 bool something = false;
449
450 assert(buf);
451 assert(l > 0);
452
453 if (t == USEC_INFINITY) {
454 strncpy(p, "infinity", l-1);
455 p[l-1] = 0;
456 return p;
457 }
458
459 if (t <= 0) {
460 strncpy(p, "0", l-1);
461 p[l-1] = 0;
462 return p;
463 }
464
465 /* The result of this function can be parsed with parse_sec */
466
467 for (i = 0; i < ELEMENTSOF(table); i++) {
468 int k = 0;
469 size_t n;
470 bool done = false;
471 usec_t a, b;
472
473 if (t <= 0)
474 break;
475
476 if (t < accuracy && something)
477 break;
478
479 if (t < table[i].usec)
480 continue;
481
482 if (l <= 1)
483 break;
484
485 a = t / table[i].usec;
486 b = t % table[i].usec;
487
488 /* Let's see if we should shows this in dot notation */
489 if (t < USEC_PER_MINUTE && b > 0) {
490 usec_t cc;
491 int j;
492
493 j = 0;
494 for (cc = table[i].usec; cc > 1; cc /= 10)
495 j++;
496
497 for (cc = accuracy; cc > 1; cc /= 10) {
498 b /= 10;
499 j--;
500 }
501
502 if (j > 0) {
503 k = snprintf(p, l,
504 "%s"USEC_FMT".%0*llu%s",
505 p > buf ? " " : "",
506 a,
507 j,
508 (unsigned long long) b,
509 table[i].suffix);
510
511 t = 0;
512 done = true;
513 }
514 }
515
516 /* No? Then let's show it normally */
517 if (!done) {
518 k = snprintf(p, l,
519 "%s"USEC_FMT"%s",
520 p > buf ? " " : "",
521 a,
522 table[i].suffix);
523
524 t = b;
525 }
526
527 n = MIN((size_t) k, l);
528
529 l -= n;
530 p += n;
531
532 something = true;
533 }
534
535 *p = 0;
536
537 return buf;
538 }
539
540 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
541
542 assert(f);
543 assert(name);
544 assert(t);
545
546 if (!dual_timestamp_is_set(t))
547 return;
548
549 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
550 name,
551 t->realtime,
552 t->monotonic);
553 }
554
555 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
556 unsigned long long a, b;
557
558 assert(value);
559 assert(t);
560
561 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
562 log_debug("Failed to parse dual timestamp value \"%s\": %m", value);
563 return -EINVAL;
564 }
565
566 t->realtime = a;
567 t->monotonic = b;
568
569 return 0;
570 }
571
572 int timestamp_deserialize(const char *value, usec_t *timestamp) {
573 int r;
574
575 assert(value);
576
577 r = safe_atou64(value, timestamp);
578 if (r < 0)
579 return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value);
580
581 return r;
582 }
583
584 int parse_timestamp(const char *t, usec_t *usec) {
585 static const struct {
586 const char *name;
587 const int nr;
588 } day_nr[] = {
589 { "Sunday", 0 },
590 { "Sun", 0 },
591 { "Monday", 1 },
592 { "Mon", 1 },
593 { "Tuesday", 2 },
594 { "Tue", 2 },
595 { "Wednesday", 3 },
596 { "Wed", 3 },
597 { "Thursday", 4 },
598 { "Thu", 4 },
599 { "Friday", 5 },
600 { "Fri", 5 },
601 { "Saturday", 6 },
602 { "Sat", 6 },
603 };
604
605 const char *k, *utc, *tzn = NULL;
606 struct tm tm, copy;
607 time_t x;
608 usec_t x_usec, plus = 0, minus = 0, ret;
609 int r, weekday = -1, dst = -1;
610 unsigned i;
611
612 /*
613 * Allowed syntaxes:
614 *
615 * 2012-09-22 16:34:22
616 * 2012-09-22 16:34 (seconds will be set to 0)
617 * 2012-09-22 (time will be set to 00:00:00)
618 * 16:34:22 (date will be set to today)
619 * 16:34 (date will be set to today, seconds to 0)
620 * now
621 * yesterday (time is set to 00:00:00)
622 * today (time is set to 00:00:00)
623 * tomorrow (time is set to 00:00:00)
624 * +5min
625 * -5days
626 * @2147483647 (seconds since epoch)
627 *
628 */
629
630 assert(t);
631 assert(usec);
632
633 if (t[0] == '@')
634 return parse_sec(t + 1, usec);
635
636 ret = now(CLOCK_REALTIME);
637
638 if (streq(t, "now"))
639 goto finish;
640
641 else if (t[0] == '+') {
642 r = parse_sec(t+1, &plus);
643 if (r < 0)
644 return r;
645
646 goto finish;
647
648 } else if (t[0] == '-') {
649 r = parse_sec(t+1, &minus);
650 if (r < 0)
651 return r;
652
653 goto finish;
654
655 } else if ((k = endswith(t, " ago"))) {
656 t = strndupa(t, k - t);
657
658 r = parse_sec(t, &minus);
659 if (r < 0)
660 return r;
661
662 goto finish;
663
664 } else if ((k = endswith(t, " left"))) {
665 t = strndupa(t, k - t);
666
667 r = parse_sec(t, &plus);
668 if (r < 0)
669 return r;
670
671 goto finish;
672 }
673
674 /* See if the timestamp is suffixed with UTC */
675 utc = endswith_no_case(t, " UTC");
676 if (utc)
677 t = strndupa(t, utc - t);
678 else {
679 const char *e = NULL;
680 int j;
681
682 tzset();
683
684 /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
685 * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
686 * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
687 * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
688 * support arbitrary timezone specifications. */
689
690 for (j = 0; j <= 1; j++) {
691
692 if (isempty(tzname[j]))
693 continue;
694
695 e = endswith_no_case(t, tzname[j]);
696 if (!e)
697 continue;
698 if (e == t)
699 continue;
700 if (e[-1] != ' ')
701 continue;
702
703 break;
704 }
705
706 if (IN_SET(j, 0, 1)) {
707 /* Found one of the two timezones specified. */
708 t = strndupa(t, e - t - 1);
709 dst = j;
710 tzn = tzname[j];
711 }
712 }
713
714 x = (time_t) (ret / USEC_PER_SEC);
715 x_usec = 0;
716
717 if (!localtime_or_gmtime_r(&x, &tm, utc))
718 return -EINVAL;
719
720 tm.tm_isdst = dst;
721 if (tzn)
722 tm.tm_zone = tzn;
723
724 if (streq(t, "today")) {
725 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
726 goto from_tm;
727
728 } else if (streq(t, "yesterday")) {
729 tm.tm_mday--;
730 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
731 goto from_tm;
732
733 } else if (streq(t, "tomorrow")) {
734 tm.tm_mday++;
735 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
736 goto from_tm;
737 }
738
739 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
740 size_t skip;
741
742 if (!startswith_no_case(t, day_nr[i].name))
743 continue;
744
745 skip = strlen(day_nr[i].name);
746 if (t[skip] != ' ')
747 continue;
748
749 weekday = day_nr[i].nr;
750 t += skip + 1;
751 break;
752 }
753
754 copy = tm;
755 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
756 if (k) {
757 if (*k == '.')
758 goto parse_usec;
759 else if (*k == 0)
760 goto from_tm;
761 }
762
763 tm = copy;
764 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
765 if (k) {
766 if (*k == '.')
767 goto parse_usec;
768 else if (*k == 0)
769 goto from_tm;
770 }
771
772 tm = copy;
773 k = strptime(t, "%y-%m-%d %H:%M", &tm);
774 if (k && *k == 0) {
775 tm.tm_sec = 0;
776 goto from_tm;
777 }
778
779 tm = copy;
780 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
781 if (k && *k == 0) {
782 tm.tm_sec = 0;
783 goto from_tm;
784 }
785
786 tm = copy;
787 k = strptime(t, "%y-%m-%d", &tm);
788 if (k && *k == 0) {
789 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
790 goto from_tm;
791 }
792
793 tm = copy;
794 k = strptime(t, "%Y-%m-%d", &tm);
795 if (k && *k == 0) {
796 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
797 goto from_tm;
798 }
799
800 tm = copy;
801 k = strptime(t, "%H:%M:%S", &tm);
802 if (k) {
803 if (*k == '.')
804 goto parse_usec;
805 else if (*k == 0)
806 goto from_tm;
807 }
808
809 tm = copy;
810 k = strptime(t, "%H:%M", &tm);
811 if (k && *k == 0) {
812 tm.tm_sec = 0;
813 goto from_tm;
814 }
815
816 return -EINVAL;
817
818 parse_usec:
819 {
820 unsigned add;
821
822 k++;
823 r = parse_fractional_part_u(&k, 6, &add);
824 if (r < 0)
825 return -EINVAL;
826
827 if (*k)
828 return -EINVAL;
829
830 x_usec = add;
831 }
832
833 from_tm:
834 x = mktime_or_timegm(&tm, utc);
835 if (x == (time_t) -1)
836 return -EINVAL;
837
838 if (weekday >= 0 && tm.tm_wday != weekday)
839 return -EINVAL;
840
841 ret = (usec_t) x * USEC_PER_SEC + x_usec;
842
843 finish:
844 ret += plus;
845 if (ret > minus)
846 ret -= minus;
847 else
848 ret = 0;
849
850 *usec = ret;
851
852 return 0;
853 }
854
855 static char* extract_multiplier(char *p, usec_t *multiplier) {
856 static const struct {
857 const char *suffix;
858 usec_t usec;
859 } table[] = {
860 { "seconds", USEC_PER_SEC },
861 { "second", USEC_PER_SEC },
862 { "sec", USEC_PER_SEC },
863 { "s", USEC_PER_SEC },
864 { "minutes", USEC_PER_MINUTE },
865 { "minute", USEC_PER_MINUTE },
866 { "min", USEC_PER_MINUTE },
867 { "months", USEC_PER_MONTH },
868 { "month", USEC_PER_MONTH },
869 { "M", USEC_PER_MONTH },
870 { "msec", USEC_PER_MSEC },
871 { "ms", USEC_PER_MSEC },
872 { "m", USEC_PER_MINUTE },
873 { "hours", USEC_PER_HOUR },
874 { "hour", USEC_PER_HOUR },
875 { "hr", USEC_PER_HOUR },
876 { "h", USEC_PER_HOUR },
877 { "days", USEC_PER_DAY },
878 { "day", USEC_PER_DAY },
879 { "d", USEC_PER_DAY },
880 { "weeks", USEC_PER_WEEK },
881 { "week", USEC_PER_WEEK },
882 { "w", USEC_PER_WEEK },
883 { "years", USEC_PER_YEAR },
884 { "year", USEC_PER_YEAR },
885 { "y", USEC_PER_YEAR },
886 { "usec", 1ULL },
887 { "us", 1ULL },
888 };
889 unsigned i;
890
891 for (i = 0; i < ELEMENTSOF(table); i++) {
892 char *e;
893
894 e = startswith(p, table[i].suffix);
895 if (e) {
896 *multiplier = table[i].usec;
897 return e;
898 }
899 }
900
901 return p;
902 }
903
904 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
905 const char *p, *s;
906 usec_t r = 0;
907 bool something = false;
908
909 assert(t);
910 assert(usec);
911 assert(default_unit > 0);
912
913 p = t;
914
915 p += strspn(p, WHITESPACE);
916 s = startswith(p, "infinity");
917 if (s) {
918 s += strspn(s, WHITESPACE);
919 if (*s != 0)
920 return -EINVAL;
921
922 *usec = USEC_INFINITY;
923 return 0;
924 }
925
926 for (;;) {
927 long long l, z = 0;
928 char *e;
929 unsigned n = 0;
930 usec_t multiplier = default_unit, k;
931
932 p += strspn(p, WHITESPACE);
933
934 if (*p == 0) {
935 if (!something)
936 return -EINVAL;
937
938 break;
939 }
940
941 errno = 0;
942 l = strtoll(p, &e, 10);
943 if (errno > 0)
944 return -errno;
945 if (l < 0)
946 return -ERANGE;
947
948 if (*e == '.') {
949 char *b = e + 1;
950
951 errno = 0;
952 z = strtoll(b, &e, 10);
953 if (errno > 0)
954 return -errno;
955
956 if (z < 0)
957 return -ERANGE;
958
959 if (e == b)
960 return -EINVAL;
961
962 n = e - b;
963
964 } else if (e == p)
965 return -EINVAL;
966
967 e += strspn(e, WHITESPACE);
968 p = extract_multiplier(e, &multiplier);
969
970 something = true;
971
972 k = (usec_t) z * multiplier;
973
974 for (; n > 0; n--)
975 k /= 10;
976
977 r += (usec_t) l * multiplier + k;
978 }
979
980 *usec = r;
981
982 return 0;
983 }
984
985 int parse_sec(const char *t, usec_t *usec) {
986 return parse_time(t, usec, USEC_PER_SEC);
987 }
988
989 int parse_nsec(const char *t, nsec_t *nsec) {
990 static const struct {
991 const char *suffix;
992 nsec_t nsec;
993 } table[] = {
994 { "seconds", NSEC_PER_SEC },
995 { "second", NSEC_PER_SEC },
996 { "sec", NSEC_PER_SEC },
997 { "s", NSEC_PER_SEC },
998 { "minutes", NSEC_PER_MINUTE },
999 { "minute", NSEC_PER_MINUTE },
1000 { "min", NSEC_PER_MINUTE },
1001 { "months", NSEC_PER_MONTH },
1002 { "month", NSEC_PER_MONTH },
1003 { "msec", NSEC_PER_MSEC },
1004 { "ms", NSEC_PER_MSEC },
1005 { "m", NSEC_PER_MINUTE },
1006 { "hours", NSEC_PER_HOUR },
1007 { "hour", NSEC_PER_HOUR },
1008 { "hr", NSEC_PER_HOUR },
1009 { "h", NSEC_PER_HOUR },
1010 { "days", NSEC_PER_DAY },
1011 { "day", NSEC_PER_DAY },
1012 { "d", NSEC_PER_DAY },
1013 { "weeks", NSEC_PER_WEEK },
1014 { "week", NSEC_PER_WEEK },
1015 { "w", NSEC_PER_WEEK },
1016 { "years", NSEC_PER_YEAR },
1017 { "year", NSEC_PER_YEAR },
1018 { "y", NSEC_PER_YEAR },
1019 { "usec", NSEC_PER_USEC },
1020 { "us", NSEC_PER_USEC },
1021 { "nsec", 1ULL },
1022 { "ns", 1ULL },
1023 { "", 1ULL }, /* default is nsec */
1024 };
1025
1026 const char *p, *s;
1027 nsec_t r = 0;
1028 bool something = false;
1029
1030 assert(t);
1031 assert(nsec);
1032
1033 p = t;
1034
1035 p += strspn(p, WHITESPACE);
1036 s = startswith(p, "infinity");
1037 if (s) {
1038 s += strspn(s, WHITESPACE);
1039 if (*s != 0)
1040 return -EINVAL;
1041
1042 *nsec = NSEC_INFINITY;
1043 return 0;
1044 }
1045
1046 for (;;) {
1047 long long l, z = 0;
1048 char *e;
1049 unsigned i, n = 0;
1050
1051 p += strspn(p, WHITESPACE);
1052
1053 if (*p == 0) {
1054 if (!something)
1055 return -EINVAL;
1056
1057 break;
1058 }
1059
1060 errno = 0;
1061 l = strtoll(p, &e, 10);
1062
1063 if (errno > 0)
1064 return -errno;
1065
1066 if (l < 0)
1067 return -ERANGE;
1068
1069 if (*e == '.') {
1070 char *b = e + 1;
1071
1072 errno = 0;
1073 z = strtoll(b, &e, 10);
1074 if (errno > 0)
1075 return -errno;
1076
1077 if (z < 0)
1078 return -ERANGE;
1079
1080 if (e == b)
1081 return -EINVAL;
1082
1083 n = e - b;
1084
1085 } else if (e == p)
1086 return -EINVAL;
1087
1088 e += strspn(e, WHITESPACE);
1089
1090 for (i = 0; i < ELEMENTSOF(table); i++)
1091 if (startswith(e, table[i].suffix)) {
1092 nsec_t k = (nsec_t) z * table[i].nsec;
1093
1094 for (; n > 0; n--)
1095 k /= 10;
1096
1097 r += (nsec_t) l * table[i].nsec + k;
1098 p = e + strlen(table[i].suffix);
1099
1100 something = true;
1101 break;
1102 }
1103
1104 if (i >= ELEMENTSOF(table))
1105 return -EINVAL;
1106
1107 }
1108
1109 *nsec = r;
1110
1111 return 0;
1112 }
1113
1114 bool ntp_synced(void) {
1115 struct timex txc = {};
1116
1117 if (adjtimex(&txc) < 0)
1118 return false;
1119
1120 if (txc.status & STA_UNSYNC)
1121 return false;
1122
1123 return true;
1124 }
1125
1126 int get_timezones(char ***ret) {
1127 _cleanup_fclose_ FILE *f = NULL;
1128 _cleanup_strv_free_ char **zones = NULL;
1129 size_t n_zones = 0, n_allocated = 0;
1130
1131 assert(ret);
1132
1133 zones = strv_new("UTC", NULL);
1134 if (!zones)
1135 return -ENOMEM;
1136
1137 n_allocated = 2;
1138 n_zones = 1;
1139
1140 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
1141 if (f) {
1142 char l[LINE_MAX];
1143
1144 FOREACH_LINE(l, f, return -errno) {
1145 char *p, *w;
1146 size_t k;
1147
1148 p = strstrip(l);
1149
1150 if (isempty(p) || *p == '#')
1151 continue;
1152
1153 /* Skip over country code */
1154 p += strcspn(p, WHITESPACE);
1155 p += strspn(p, WHITESPACE);
1156
1157 /* Skip over coordinates */
1158 p += strcspn(p, WHITESPACE);
1159 p += strspn(p, WHITESPACE);
1160
1161 /* Found timezone name */
1162 k = strcspn(p, WHITESPACE);
1163 if (k <= 0)
1164 continue;
1165
1166 w = strndup(p, k);
1167 if (!w)
1168 return -ENOMEM;
1169
1170 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1171 free(w);
1172 return -ENOMEM;
1173 }
1174
1175 zones[n_zones++] = w;
1176 zones[n_zones] = NULL;
1177 }
1178
1179 strv_sort(zones);
1180
1181 } else if (errno != ENOENT)
1182 return -errno;
1183
1184 *ret = zones;
1185 zones = NULL;
1186
1187 return 0;
1188 }
1189
1190 bool timezone_is_valid(const char *name) {
1191 bool slash = false;
1192 const char *p, *t;
1193 struct stat st;
1194
1195 if (isempty(name))
1196 return false;
1197
1198 if (name[0] == '/')
1199 return false;
1200
1201 for (p = name; *p; p++) {
1202 if (!(*p >= '0' && *p <= '9') &&
1203 !(*p >= 'a' && *p <= 'z') &&
1204 !(*p >= 'A' && *p <= 'Z') &&
1205 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1206 return false;
1207
1208 if (*p == '/') {
1209
1210 if (slash)
1211 return false;
1212
1213 slash = true;
1214 } else
1215 slash = false;
1216 }
1217
1218 if (slash)
1219 return false;
1220
1221 t = strjoina("/usr/share/zoneinfo/", name);
1222 if (stat(t, &st) < 0)
1223 return false;
1224
1225 if (!S_ISREG(st.st_mode))
1226 return false;
1227
1228 return true;
1229 }
1230
1231 bool clock_boottime_supported(void) {
1232 static int supported = -1;
1233
1234 /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
1235
1236 if (supported < 0) {
1237 int fd;
1238
1239 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1240 if (fd < 0)
1241 supported = false;
1242 else {
1243 safe_close(fd);
1244 supported = true;
1245 }
1246 }
1247
1248 return supported;
1249 }
1250
1251 clockid_t clock_boottime_or_monotonic(void) {
1252 if (clock_boottime_supported())
1253 return CLOCK_BOOTTIME;
1254 else
1255 return CLOCK_MONOTONIC;
1256 }
1257
1258 bool clock_supported(clockid_t clock) {
1259 struct timespec ts;
1260
1261 switch (clock) {
1262
1263 case CLOCK_MONOTONIC:
1264 case CLOCK_REALTIME:
1265 return true;
1266
1267 case CLOCK_BOOTTIME:
1268 return clock_boottime_supported();
1269
1270 case CLOCK_BOOTTIME_ALARM:
1271 if (!clock_boottime_supported())
1272 return false;
1273
1274 /* fall through, after checking the cached value for CLOCK_BOOTTIME. */
1275
1276 default:
1277 /* For everything else, check properly */
1278 return clock_gettime(clock, &ts) >= 0;
1279 }
1280 }
1281
1282 int get_timezone(char **tz) {
1283 _cleanup_free_ char *t = NULL;
1284 const char *e;
1285 char *z;
1286 int r;
1287
1288 r = readlink_malloc("/etc/localtime", &t);
1289 if (r < 0)
1290 return r; /* returns EINVAL if not a symlink */
1291
1292 e = path_startswith(t, "/usr/share/zoneinfo/");
1293 if (!e)
1294 e = path_startswith(t, "../usr/share/zoneinfo/");
1295 if (!e)
1296 return -EINVAL;
1297
1298 if (!timezone_is_valid(e))
1299 return -EINVAL;
1300
1301 z = strdup(e);
1302 if (!z)
1303 return -ENOMEM;
1304
1305 *tz = z;
1306 return 0;
1307 }
1308
1309 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1310 return utc ? timegm(tm) : mktime(tm);
1311 }
1312
1313 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1314 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1315 }
1316
1317 unsigned long usec_to_jiffies(usec_t u) {
1318 static thread_local unsigned long hz = 0;
1319 long r;
1320
1321 if (hz == 0) {
1322 r = sysconf(_SC_CLK_TCK);
1323
1324 assert(r > 0);
1325 hz = (unsigned long) r;
1326 }
1327
1328 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
1329 }