]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/time-util.c
time-util: map ALARM clockids to non-ALARM clockids in now()
[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 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
91 int64_t delta;
92 assert(ts);
93
94 if (u == USEC_INFINITY || u <= 0) {
95 ts->realtime = ts->monotonic = u;
96 return ts;
97 }
98
99 ts->realtime = u;
100
101 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
102 ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
103
104 return ts;
105 }
106
107 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
108 int64_t delta;
109 assert(ts);
110
111 if (u == USEC_INFINITY) {
112 ts->realtime = ts->monotonic = USEC_INFINITY;
113 return ts;
114 }
115
116 ts->monotonic = u;
117 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
118 ts->realtime = usec_sub(now(CLOCK_REALTIME), delta);
119
120 return ts;
121 }
122
123 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
124 int64_t delta;
125
126 if (u == USEC_INFINITY) {
127 ts->realtime = ts->monotonic = USEC_INFINITY;
128 return ts;
129 }
130
131 dual_timestamp_get(ts);
132 delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
133 ts->realtime = usec_sub(ts->realtime, delta);
134 ts->monotonic = usec_sub(ts->monotonic, delta);
135
136 return ts;
137 }
138
139 usec_t timespec_load(const struct timespec *ts) {
140 assert(ts);
141
142 if (ts->tv_sec == (time_t) -1 &&
143 ts->tv_nsec == (long) -1)
144 return USEC_INFINITY;
145
146 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
147 return USEC_INFINITY;
148
149 return
150 (usec_t) ts->tv_sec * USEC_PER_SEC +
151 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
152 }
153
154 static nsec_t timespec_load_nsec(const struct timespec *ts) {
155 assert(ts);
156
157 if (ts->tv_sec == (time_t) -1 &&
158 ts->tv_nsec == (long) -1)
159 return NSEC_INFINITY;
160
161 return
162 (nsec_t) ts->tv_sec * NSEC_PER_SEC +
163 (nsec_t) ts->tv_nsec;
164 }
165
166 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
167 assert(ts);
168
169 if (u == USEC_INFINITY) {
170 ts->tv_sec = (time_t) -1;
171 ts->tv_nsec = (long) -1;
172 return ts;
173 }
174
175 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
176 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
177
178 return ts;
179 }
180
181 usec_t timeval_load(const struct timeval *tv) {
182 assert(tv);
183
184 if (tv->tv_sec == (time_t) -1 &&
185 tv->tv_usec == (suseconds_t) -1)
186 return USEC_INFINITY;
187
188 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
189 return USEC_INFINITY;
190
191 return
192 (usec_t) tv->tv_sec * USEC_PER_SEC +
193 (usec_t) tv->tv_usec;
194 }
195
196 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
197 assert(tv);
198
199 if (u == USEC_INFINITY) {
200 tv->tv_sec = (time_t) -1;
201 tv->tv_usec = (suseconds_t) -1;
202 } else {
203 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
204 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
205 }
206
207 return tv;
208 }
209
210 static char *format_timestamp_internal(char *buf, size_t l, usec_t t,
211 bool utc, bool us) {
212 struct tm tm;
213 time_t sec;
214 int k;
215
216 assert(buf);
217 assert(l > 0);
218
219 if (t <= 0 || t == USEC_INFINITY)
220 return NULL;
221
222 sec = (time_t) (t / USEC_PER_SEC);
223 localtime_or_gmtime_r(&sec, &tm, utc);
224
225 if (us)
226 k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm);
227 else
228 k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm);
229
230 if (k <= 0)
231 return NULL;
232 if (us) {
233 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
234 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
235 return NULL;
236 }
237
238 return buf;
239 }
240
241 char *format_timestamp(char *buf, size_t l, usec_t t) {
242 return format_timestamp_internal(buf, l, t, false, false);
243 }
244
245 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
246 return format_timestamp_internal(buf, l, t, true, false);
247 }
248
249 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
250 return format_timestamp_internal(buf, l, t, false, true);
251 }
252
253 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
254 return format_timestamp_internal(buf, l, t, true, true);
255 }
256
257 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
258 const char *s;
259 usec_t n, d;
260
261 if (t <= 0 || t == USEC_INFINITY)
262 return NULL;
263
264 n = now(CLOCK_REALTIME);
265 if (n > t) {
266 d = n - t;
267 s = "ago";
268 } else {
269 d = t - n;
270 s = "left";
271 }
272
273 if (d >= USEC_PER_YEAR)
274 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
275 d / USEC_PER_YEAR,
276 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
277 else if (d >= USEC_PER_MONTH)
278 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
279 d / USEC_PER_MONTH,
280 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
281 else if (d >= USEC_PER_WEEK)
282 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
283 d / USEC_PER_WEEK,
284 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
285 else if (d >= 2*USEC_PER_DAY)
286 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
287 else if (d >= 25*USEC_PER_HOUR)
288 snprintf(buf, l, "1 day " USEC_FMT "h %s",
289 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
290 else if (d >= 6*USEC_PER_HOUR)
291 snprintf(buf, l, USEC_FMT "h %s",
292 d / USEC_PER_HOUR, s);
293 else if (d >= USEC_PER_HOUR)
294 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
295 d / USEC_PER_HOUR,
296 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
297 else if (d >= 5*USEC_PER_MINUTE)
298 snprintf(buf, l, USEC_FMT "min %s",
299 d / USEC_PER_MINUTE, s);
300 else if (d >= USEC_PER_MINUTE)
301 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
302 d / USEC_PER_MINUTE,
303 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
304 else if (d >= USEC_PER_SEC)
305 snprintf(buf, l, USEC_FMT "s %s",
306 d / USEC_PER_SEC, s);
307 else if (d >= USEC_PER_MSEC)
308 snprintf(buf, l, USEC_FMT "ms %s",
309 d / USEC_PER_MSEC, s);
310 else if (d > 0)
311 snprintf(buf, l, USEC_FMT"us %s",
312 d, s);
313 else
314 snprintf(buf, l, "now");
315
316 buf[l-1] = 0;
317 return buf;
318 }
319
320 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
321 static const struct {
322 const char *suffix;
323 usec_t usec;
324 } table[] = {
325 { "y", USEC_PER_YEAR },
326 { "month", USEC_PER_MONTH },
327 { "w", USEC_PER_WEEK },
328 { "d", USEC_PER_DAY },
329 { "h", USEC_PER_HOUR },
330 { "min", USEC_PER_MINUTE },
331 { "s", USEC_PER_SEC },
332 { "ms", USEC_PER_MSEC },
333 { "us", 1 },
334 };
335
336 unsigned i;
337 char *p = buf;
338 bool something = false;
339
340 assert(buf);
341 assert(l > 0);
342
343 if (t == USEC_INFINITY) {
344 strncpy(p, "infinity", l-1);
345 p[l-1] = 0;
346 return p;
347 }
348
349 if (t <= 0) {
350 strncpy(p, "0", l-1);
351 p[l-1] = 0;
352 return p;
353 }
354
355 /* The result of this function can be parsed with parse_sec */
356
357 for (i = 0; i < ELEMENTSOF(table); i++) {
358 int k = 0;
359 size_t n;
360 bool done = false;
361 usec_t a, b;
362
363 if (t <= 0)
364 break;
365
366 if (t < accuracy && something)
367 break;
368
369 if (t < table[i].usec)
370 continue;
371
372 if (l <= 1)
373 break;
374
375 a = t / table[i].usec;
376 b = t % table[i].usec;
377
378 /* Let's see if we should shows this in dot notation */
379 if (t < USEC_PER_MINUTE && b > 0) {
380 usec_t cc;
381 int j;
382
383 j = 0;
384 for (cc = table[i].usec; cc > 1; cc /= 10)
385 j++;
386
387 for (cc = accuracy; cc > 1; cc /= 10) {
388 b /= 10;
389 j--;
390 }
391
392 if (j > 0) {
393 k = snprintf(p, l,
394 "%s"USEC_FMT".%0*llu%s",
395 p > buf ? " " : "",
396 a,
397 j,
398 (unsigned long long) b,
399 table[i].suffix);
400
401 t = 0;
402 done = true;
403 }
404 }
405
406 /* No? Then let's show it normally */
407 if (!done) {
408 k = snprintf(p, l,
409 "%s"USEC_FMT"%s",
410 p > buf ? " " : "",
411 a,
412 table[i].suffix);
413
414 t = b;
415 }
416
417 n = MIN((size_t) k, l);
418
419 l -= n;
420 p += n;
421
422 something = true;
423 }
424
425 *p = 0;
426
427 return buf;
428 }
429
430 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
431
432 assert(f);
433 assert(name);
434 assert(t);
435
436 if (!dual_timestamp_is_set(t))
437 return;
438
439 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
440 name,
441 t->realtime,
442 t->monotonic);
443 }
444
445 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
446 unsigned long long a, b;
447
448 assert(value);
449 assert(t);
450
451 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
452 log_debug("Failed to parse finish timestamp value %s.", value);
453 return -EINVAL;
454 }
455
456 t->realtime = a;
457 t->monotonic = b;
458
459 return 0;
460 }
461
462 int parse_timestamp(const char *t, usec_t *usec) {
463 static const struct {
464 const char *name;
465 const int nr;
466 } day_nr[] = {
467 { "Sunday", 0 },
468 { "Sun", 0 },
469 { "Monday", 1 },
470 { "Mon", 1 },
471 { "Tuesday", 2 },
472 { "Tue", 2 },
473 { "Wednesday", 3 },
474 { "Wed", 3 },
475 { "Thursday", 4 },
476 { "Thu", 4 },
477 { "Friday", 5 },
478 { "Fri", 5 },
479 { "Saturday", 6 },
480 { "Sat", 6 },
481 };
482
483 const char *k;
484 const char *utc;
485 struct tm tm, copy;
486 time_t x;
487 usec_t x_usec, plus = 0, minus = 0, ret;
488 int r, weekday = -1;
489 unsigned i;
490
491 /*
492 * Allowed syntaxes:
493 *
494 * 2012-09-22 16:34:22
495 * 2012-09-22 16:34 (seconds will be set to 0)
496 * 2012-09-22 (time will be set to 00:00:00)
497 * 16:34:22 (date will be set to today)
498 * 16:34 (date will be set to today, seconds to 0)
499 * now
500 * yesterday (time is set to 00:00:00)
501 * today (time is set to 00:00:00)
502 * tomorrow (time is set to 00:00:00)
503 * +5min
504 * -5days
505 * @2147483647 (seconds since epoch)
506 *
507 */
508
509 assert(t);
510 assert(usec);
511
512 if (t[0] == '@')
513 return parse_sec(t + 1, usec);
514
515 ret = now(CLOCK_REALTIME);
516
517 if (streq(t, "now"))
518 goto finish;
519
520 else if (t[0] == '+') {
521 r = parse_sec(t+1, &plus);
522 if (r < 0)
523 return r;
524
525 goto finish;
526
527 } else if (t[0] == '-') {
528 r = parse_sec(t+1, &minus);
529 if (r < 0)
530 return r;
531
532 goto finish;
533
534 } else if ((k = endswith(t, " ago"))) {
535 t = strndupa(t, k - t);
536
537 r = parse_sec(t, &minus);
538 if (r < 0)
539 return r;
540
541 goto finish;
542
543 } else if ((k = endswith(t, " left"))) {
544 t = strndupa(t, k - t);
545
546 r = parse_sec(t, &plus);
547 if (r < 0)
548 return r;
549
550 goto finish;
551 }
552
553 utc = endswith_no_case(t, " UTC");
554 if (utc)
555 t = strndupa(t, utc - t);
556
557 x = ret / USEC_PER_SEC;
558 x_usec = 0;
559
560 assert_se(localtime_or_gmtime_r(&x, &tm, utc));
561 tm.tm_isdst = -1;
562
563 if (streq(t, "today")) {
564 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
565 goto from_tm;
566
567 } else if (streq(t, "yesterday")) {
568 tm.tm_mday --;
569 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
570 goto from_tm;
571
572 } else if (streq(t, "tomorrow")) {
573 tm.tm_mday ++;
574 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
575 goto from_tm;
576 }
577
578
579 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
580 size_t skip;
581
582 if (!startswith_no_case(t, day_nr[i].name))
583 continue;
584
585 skip = strlen(day_nr[i].name);
586 if (t[skip] != ' ')
587 continue;
588
589 weekday = day_nr[i].nr;
590 t += skip + 1;
591 break;
592 }
593
594 copy = tm;
595 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
596 if (k) {
597 if (*k == '.')
598 goto parse_usec;
599 else if (*k == 0)
600 goto from_tm;
601 }
602
603 tm = copy;
604 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
605 if (k) {
606 if (*k == '.')
607 goto parse_usec;
608 else if (*k == 0)
609 goto from_tm;
610 }
611
612 tm = copy;
613 k = strptime(t, "%y-%m-%d %H:%M", &tm);
614 if (k && *k == 0) {
615 tm.tm_sec = 0;
616 goto from_tm;
617 }
618
619 tm = copy;
620 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
621 if (k && *k == 0) {
622 tm.tm_sec = 0;
623 goto from_tm;
624 }
625
626 tm = copy;
627 k = strptime(t, "%y-%m-%d", &tm);
628 if (k && *k == 0) {
629 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
630 goto from_tm;
631 }
632
633 tm = copy;
634 k = strptime(t, "%Y-%m-%d", &tm);
635 if (k && *k == 0) {
636 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
637 goto from_tm;
638 }
639
640 tm = copy;
641 k = strptime(t, "%H:%M:%S", &tm);
642 if (k) {
643 if (*k == '.')
644 goto parse_usec;
645 else if (*k == 0)
646 goto from_tm;
647 }
648
649 tm = copy;
650 k = strptime(t, "%H:%M", &tm);
651 if (k && *k == 0) {
652 tm.tm_sec = 0;
653 goto from_tm;
654 }
655
656 return -EINVAL;
657
658 parse_usec:
659 {
660 unsigned add;
661
662 k++;
663 r = parse_fractional_part_u(&k, 6, &add);
664 if (r < 0)
665 return -EINVAL;
666
667 if (*k)
668 return -EINVAL;
669
670 x_usec = add;
671
672 }
673
674 from_tm:
675 x = mktime_or_timegm(&tm, utc);
676 if (x == (time_t) -1)
677 return -EINVAL;
678
679 if (weekday >= 0 && tm.tm_wday != weekday)
680 return -EINVAL;
681
682 ret = (usec_t) x * USEC_PER_SEC + x_usec;
683
684 finish:
685 ret += plus;
686 if (ret > minus)
687 ret -= minus;
688 else
689 ret = 0;
690
691 *usec = ret;
692
693 return 0;
694 }
695
696 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
697
698 static const struct {
699 const char *suffix;
700 usec_t usec;
701 } table[] = {
702 { "seconds", USEC_PER_SEC },
703 { "second", USEC_PER_SEC },
704 { "sec", USEC_PER_SEC },
705 { "s", USEC_PER_SEC },
706 { "minutes", USEC_PER_MINUTE },
707 { "minute", USEC_PER_MINUTE },
708 { "min", USEC_PER_MINUTE },
709 { "months", USEC_PER_MONTH },
710 { "month", USEC_PER_MONTH },
711 { "M", USEC_PER_MONTH },
712 { "msec", USEC_PER_MSEC },
713 { "ms", USEC_PER_MSEC },
714 { "m", USEC_PER_MINUTE },
715 { "hours", USEC_PER_HOUR },
716 { "hour", USEC_PER_HOUR },
717 { "hr", USEC_PER_HOUR },
718 { "h", USEC_PER_HOUR },
719 { "days", USEC_PER_DAY },
720 { "day", USEC_PER_DAY },
721 { "d", USEC_PER_DAY },
722 { "weeks", USEC_PER_WEEK },
723 { "week", USEC_PER_WEEK },
724 { "w", USEC_PER_WEEK },
725 { "years", USEC_PER_YEAR },
726 { "year", USEC_PER_YEAR },
727 { "y", USEC_PER_YEAR },
728 { "usec", 1ULL },
729 { "us", 1ULL },
730 };
731
732 const char *p, *s;
733 usec_t r = 0;
734 bool something = false;
735
736 assert(t);
737 assert(usec);
738 assert(default_unit > 0);
739
740 p = t;
741
742 p += strspn(p, WHITESPACE);
743 s = startswith(p, "infinity");
744 if (s) {
745 s += strspn(s, WHITESPACE);
746 if (*s != 0)
747 return -EINVAL;
748
749 *usec = USEC_INFINITY;
750 return 0;
751 }
752
753 for (;;) {
754 long long l, z = 0;
755 char *e;
756 unsigned i, n = 0;
757 usec_t multiplier, k;
758
759 p += strspn(p, WHITESPACE);
760
761 if (*p == 0) {
762 if (!something)
763 return -EINVAL;
764
765 break;
766 }
767
768 errno = 0;
769 l = strtoll(p, &e, 10);
770
771 if (errno > 0)
772 return -errno;
773
774 if (l < 0)
775 return -ERANGE;
776
777 if (*e == '.') {
778 char *b = e + 1;
779
780 errno = 0;
781 z = strtoll(b, &e, 10);
782 if (errno > 0)
783 return -errno;
784
785 if (z < 0)
786 return -ERANGE;
787
788 if (e == b)
789 return -EINVAL;
790
791 n = e - b;
792
793 } else if (e == p)
794 return -EINVAL;
795
796 e += strspn(e, WHITESPACE);
797
798 for (i = 0; i < ELEMENTSOF(table); i++)
799 if (startswith(e, table[i].suffix)) {
800 multiplier = table[i].usec;
801 p = e + strlen(table[i].suffix);
802 break;
803 }
804
805 if (i >= ELEMENTSOF(table)) {
806 multiplier = default_unit;
807 p = e;
808 }
809
810 something = true;
811
812 k = (usec_t) z * multiplier;
813
814 for (; n > 0; n--)
815 k /= 10;
816
817 r += (usec_t) l * multiplier + k;
818 }
819
820 *usec = r;
821
822 return 0;
823 }
824
825 int parse_sec(const char *t, usec_t *usec) {
826 return parse_time(t, usec, USEC_PER_SEC);
827 }
828
829 int parse_nsec(const char *t, nsec_t *nsec) {
830 static const struct {
831 const char *suffix;
832 nsec_t nsec;
833 } table[] = {
834 { "seconds", NSEC_PER_SEC },
835 { "second", NSEC_PER_SEC },
836 { "sec", NSEC_PER_SEC },
837 { "s", NSEC_PER_SEC },
838 { "minutes", NSEC_PER_MINUTE },
839 { "minute", NSEC_PER_MINUTE },
840 { "min", NSEC_PER_MINUTE },
841 { "months", NSEC_PER_MONTH },
842 { "month", NSEC_PER_MONTH },
843 { "msec", NSEC_PER_MSEC },
844 { "ms", NSEC_PER_MSEC },
845 { "m", NSEC_PER_MINUTE },
846 { "hours", NSEC_PER_HOUR },
847 { "hour", NSEC_PER_HOUR },
848 { "hr", NSEC_PER_HOUR },
849 { "h", NSEC_PER_HOUR },
850 { "days", NSEC_PER_DAY },
851 { "day", NSEC_PER_DAY },
852 { "d", NSEC_PER_DAY },
853 { "weeks", NSEC_PER_WEEK },
854 { "week", NSEC_PER_WEEK },
855 { "w", NSEC_PER_WEEK },
856 { "years", NSEC_PER_YEAR },
857 { "year", NSEC_PER_YEAR },
858 { "y", NSEC_PER_YEAR },
859 { "usec", NSEC_PER_USEC },
860 { "us", NSEC_PER_USEC },
861 { "nsec", 1ULL },
862 { "ns", 1ULL },
863 { "", 1ULL }, /* default is nsec */
864 };
865
866 const char *p, *s;
867 nsec_t r = 0;
868 bool something = false;
869
870 assert(t);
871 assert(nsec);
872
873 p = t;
874
875 p += strspn(p, WHITESPACE);
876 s = startswith(p, "infinity");
877 if (s) {
878 s += strspn(s, WHITESPACE);
879 if (*s != 0)
880 return -EINVAL;
881
882 *nsec = NSEC_INFINITY;
883 return 0;
884 }
885
886 for (;;) {
887 long long l, z = 0;
888 char *e;
889 unsigned i, n = 0;
890
891 p += strspn(p, WHITESPACE);
892
893 if (*p == 0) {
894 if (!something)
895 return -EINVAL;
896
897 break;
898 }
899
900 errno = 0;
901 l = strtoll(p, &e, 10);
902
903 if (errno > 0)
904 return -errno;
905
906 if (l < 0)
907 return -ERANGE;
908
909 if (*e == '.') {
910 char *b = e + 1;
911
912 errno = 0;
913 z = strtoll(b, &e, 10);
914 if (errno > 0)
915 return -errno;
916
917 if (z < 0)
918 return -ERANGE;
919
920 if (e == b)
921 return -EINVAL;
922
923 n = e - b;
924
925 } else if (e == p)
926 return -EINVAL;
927
928 e += strspn(e, WHITESPACE);
929
930 for (i = 0; i < ELEMENTSOF(table); i++)
931 if (startswith(e, table[i].suffix)) {
932 nsec_t k = (nsec_t) z * table[i].nsec;
933
934 for (; n > 0; n--)
935 k /= 10;
936
937 r += (nsec_t) l * table[i].nsec + k;
938 p = e + strlen(table[i].suffix);
939
940 something = true;
941 break;
942 }
943
944 if (i >= ELEMENTSOF(table))
945 return -EINVAL;
946
947 }
948
949 *nsec = r;
950
951 return 0;
952 }
953
954 bool ntp_synced(void) {
955 struct timex txc = {};
956
957 if (adjtimex(&txc) < 0)
958 return false;
959
960 if (txc.status & STA_UNSYNC)
961 return false;
962
963 return true;
964 }
965
966 int get_timezones(char ***ret) {
967 _cleanup_fclose_ FILE *f = NULL;
968 _cleanup_strv_free_ char **zones = NULL;
969 size_t n_zones = 0, n_allocated = 0;
970
971 assert(ret);
972
973 zones = strv_new("UTC", NULL);
974 if (!zones)
975 return -ENOMEM;
976
977 n_allocated = 2;
978 n_zones = 1;
979
980 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
981 if (f) {
982 char l[LINE_MAX];
983
984 FOREACH_LINE(l, f, return -errno) {
985 char *p, *w;
986 size_t k;
987
988 p = strstrip(l);
989
990 if (isempty(p) || *p == '#')
991 continue;
992
993 /* Skip over country code */
994 p += strcspn(p, WHITESPACE);
995 p += strspn(p, WHITESPACE);
996
997 /* Skip over coordinates */
998 p += strcspn(p, WHITESPACE);
999 p += strspn(p, WHITESPACE);
1000
1001 /* Found timezone name */
1002 k = strcspn(p, WHITESPACE);
1003 if (k <= 0)
1004 continue;
1005
1006 w = strndup(p, k);
1007 if (!w)
1008 return -ENOMEM;
1009
1010 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1011 free(w);
1012 return -ENOMEM;
1013 }
1014
1015 zones[n_zones++] = w;
1016 zones[n_zones] = NULL;
1017 }
1018
1019 strv_sort(zones);
1020
1021 } else if (errno != ENOENT)
1022 return -errno;
1023
1024 *ret = zones;
1025 zones = NULL;
1026
1027 return 0;
1028 }
1029
1030 bool timezone_is_valid(const char *name) {
1031 bool slash = false;
1032 const char *p, *t;
1033 struct stat st;
1034
1035 if (isempty(name))
1036 return false;
1037
1038 if (name[0] == '/')
1039 return false;
1040
1041 for (p = name; *p; p++) {
1042 if (!(*p >= '0' && *p <= '9') &&
1043 !(*p >= 'a' && *p <= 'z') &&
1044 !(*p >= 'A' && *p <= 'Z') &&
1045 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1046 return false;
1047
1048 if (*p == '/') {
1049
1050 if (slash)
1051 return false;
1052
1053 slash = true;
1054 } else
1055 slash = false;
1056 }
1057
1058 if (slash)
1059 return false;
1060
1061 t = strjoina("/usr/share/zoneinfo/", name);
1062 if (stat(t, &st) < 0)
1063 return false;
1064
1065 if (!S_ISREG(st.st_mode))
1066 return false;
1067
1068 return true;
1069 }
1070
1071 clockid_t clock_boottime_or_monotonic(void) {
1072 static clockid_t clock = -1;
1073 int fd;
1074
1075 if (clock != -1)
1076 return clock;
1077
1078 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1079 if (fd < 0)
1080 clock = CLOCK_MONOTONIC;
1081 else {
1082 safe_close(fd);
1083 clock = CLOCK_BOOTTIME;
1084 }
1085
1086 return clock;
1087 }
1088
1089 int get_timezone(char **tz) {
1090 _cleanup_free_ char *t = NULL;
1091 const char *e;
1092 char *z;
1093 int r;
1094
1095 r = readlink_malloc("/etc/localtime", &t);
1096 if (r < 0)
1097 return r; /* returns EINVAL if not a symlink */
1098
1099 e = path_startswith(t, "/usr/share/zoneinfo/");
1100 if (!e)
1101 e = path_startswith(t, "../usr/share/zoneinfo/");
1102 if (!e)
1103 return -EINVAL;
1104
1105 if (!timezone_is_valid(e))
1106 return -EINVAL;
1107
1108 z = strdup(e);
1109 if (!z)
1110 return -ENOMEM;
1111
1112 *tz = z;
1113 return 0;
1114 }
1115
1116 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1117 return utc ? timegm(tm) : mktime(tm);
1118 }
1119
1120 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1121 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1122 }
1123
1124 unsigned long usec_to_jiffies(usec_t u) {
1125 static thread_local unsigned long hz = 0;
1126 long r;
1127
1128 if (hz == 0) {
1129 r = sysconf(_SC_CLK_TCK);
1130
1131 assert(r > 0);
1132 hz = (unsigned long) r;
1133 }
1134
1135 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
1136 }