]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/time-util.c
130acaa9de138949f7ae605b556fa85d714fc1ff
[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 dual timestamp value \"%s\": %m", value);
453 return -EINVAL;
454 }
455
456 t->realtime = a;
457 t->monotonic = b;
458
459 return 0;
460 }
461
462 int timestamp_deserialize(const char *value, usec_t *timestamp) {
463 int r;
464
465 assert(value);
466
467 r = safe_atou64(value, timestamp);
468 if (r < 0)
469 return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value);
470
471 return r;
472 }
473
474 int parse_timestamp(const char *t, usec_t *usec) {
475 static const struct {
476 const char *name;
477 const int nr;
478 } day_nr[] = {
479 { "Sunday", 0 },
480 { "Sun", 0 },
481 { "Monday", 1 },
482 { "Mon", 1 },
483 { "Tuesday", 2 },
484 { "Tue", 2 },
485 { "Wednesday", 3 },
486 { "Wed", 3 },
487 { "Thursday", 4 },
488 { "Thu", 4 },
489 { "Friday", 5 },
490 { "Fri", 5 },
491 { "Saturday", 6 },
492 { "Sat", 6 },
493 };
494
495 const char *k;
496 const char *utc;
497 struct tm tm, copy;
498 time_t x;
499 usec_t x_usec, plus = 0, minus = 0, ret;
500 int r, weekday = -1;
501 unsigned i;
502
503 /*
504 * Allowed syntaxes:
505 *
506 * 2012-09-22 16:34:22
507 * 2012-09-22 16:34 (seconds will be set to 0)
508 * 2012-09-22 (time will be set to 00:00:00)
509 * 16:34:22 (date will be set to today)
510 * 16:34 (date will be set to today, seconds to 0)
511 * now
512 * yesterday (time is set to 00:00:00)
513 * today (time is set to 00:00:00)
514 * tomorrow (time is set to 00:00:00)
515 * +5min
516 * -5days
517 * @2147483647 (seconds since epoch)
518 *
519 */
520
521 assert(t);
522 assert(usec);
523
524 if (t[0] == '@')
525 return parse_sec(t + 1, usec);
526
527 ret = now(CLOCK_REALTIME);
528
529 if (streq(t, "now"))
530 goto finish;
531
532 else if (t[0] == '+') {
533 r = parse_sec(t+1, &plus);
534 if (r < 0)
535 return r;
536
537 goto finish;
538
539 } else if (t[0] == '-') {
540 r = parse_sec(t+1, &minus);
541 if (r < 0)
542 return r;
543
544 goto finish;
545
546 } else if ((k = endswith(t, " ago"))) {
547 t = strndupa(t, k - t);
548
549 r = parse_sec(t, &minus);
550 if (r < 0)
551 return r;
552
553 goto finish;
554
555 } else if ((k = endswith(t, " left"))) {
556 t = strndupa(t, k - t);
557
558 r = parse_sec(t, &plus);
559 if (r < 0)
560 return r;
561
562 goto finish;
563 }
564
565 utc = endswith_no_case(t, " UTC");
566 if (utc)
567 t = strndupa(t, utc - t);
568
569 x = ret / USEC_PER_SEC;
570 x_usec = 0;
571
572 assert_se(localtime_or_gmtime_r(&x, &tm, utc));
573 tm.tm_isdst = -1;
574
575 if (streq(t, "today")) {
576 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
577 goto from_tm;
578
579 } else if (streq(t, "yesterday")) {
580 tm.tm_mday --;
581 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
582 goto from_tm;
583
584 } else if (streq(t, "tomorrow")) {
585 tm.tm_mday ++;
586 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
587 goto from_tm;
588 }
589
590
591 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
592 size_t skip;
593
594 if (!startswith_no_case(t, day_nr[i].name))
595 continue;
596
597 skip = strlen(day_nr[i].name);
598 if (t[skip] != ' ')
599 continue;
600
601 weekday = day_nr[i].nr;
602 t += skip + 1;
603 break;
604 }
605
606 copy = tm;
607 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
608 if (k) {
609 if (*k == '.')
610 goto parse_usec;
611 else if (*k == 0)
612 goto from_tm;
613 }
614
615 tm = copy;
616 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
617 if (k) {
618 if (*k == '.')
619 goto parse_usec;
620 else if (*k == 0)
621 goto from_tm;
622 }
623
624 tm = copy;
625 k = strptime(t, "%y-%m-%d %H:%M", &tm);
626 if (k && *k == 0) {
627 tm.tm_sec = 0;
628 goto from_tm;
629 }
630
631 tm = copy;
632 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
633 if (k && *k == 0) {
634 tm.tm_sec = 0;
635 goto from_tm;
636 }
637
638 tm = copy;
639 k = strptime(t, "%y-%m-%d", &tm);
640 if (k && *k == 0) {
641 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
642 goto from_tm;
643 }
644
645 tm = copy;
646 k = strptime(t, "%Y-%m-%d", &tm);
647 if (k && *k == 0) {
648 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
649 goto from_tm;
650 }
651
652 tm = copy;
653 k = strptime(t, "%H:%M:%S", &tm);
654 if (k) {
655 if (*k == '.')
656 goto parse_usec;
657 else if (*k == 0)
658 goto from_tm;
659 }
660
661 tm = copy;
662 k = strptime(t, "%H:%M", &tm);
663 if (k && *k == 0) {
664 tm.tm_sec = 0;
665 goto from_tm;
666 }
667
668 return -EINVAL;
669
670 parse_usec:
671 {
672 unsigned add;
673
674 k++;
675 r = parse_fractional_part_u(&k, 6, &add);
676 if (r < 0)
677 return -EINVAL;
678
679 if (*k)
680 return -EINVAL;
681
682 x_usec = add;
683
684 }
685
686 from_tm:
687 x = mktime_or_timegm(&tm, utc);
688 if (x == (time_t) -1)
689 return -EINVAL;
690
691 if (weekday >= 0 && tm.tm_wday != weekday)
692 return -EINVAL;
693
694 ret = (usec_t) x * USEC_PER_SEC + x_usec;
695
696 finish:
697 ret += plus;
698 if (ret > minus)
699 ret -= minus;
700 else
701 ret = 0;
702
703 *usec = ret;
704
705 return 0;
706 }
707
708 static char* extract_multiplier(char *p, usec_t *multiplier) {
709 static const struct {
710 const char *suffix;
711 usec_t usec;
712 } table[] = {
713 { "seconds", USEC_PER_SEC },
714 { "second", USEC_PER_SEC },
715 { "sec", USEC_PER_SEC },
716 { "s", USEC_PER_SEC },
717 { "minutes", USEC_PER_MINUTE },
718 { "minute", USEC_PER_MINUTE },
719 { "min", USEC_PER_MINUTE },
720 { "months", USEC_PER_MONTH },
721 { "month", USEC_PER_MONTH },
722 { "M", USEC_PER_MONTH },
723 { "msec", USEC_PER_MSEC },
724 { "ms", USEC_PER_MSEC },
725 { "m", USEC_PER_MINUTE },
726 { "hours", USEC_PER_HOUR },
727 { "hour", USEC_PER_HOUR },
728 { "hr", USEC_PER_HOUR },
729 { "h", USEC_PER_HOUR },
730 { "days", USEC_PER_DAY },
731 { "day", USEC_PER_DAY },
732 { "d", USEC_PER_DAY },
733 { "weeks", USEC_PER_WEEK },
734 { "week", USEC_PER_WEEK },
735 { "w", USEC_PER_WEEK },
736 { "years", USEC_PER_YEAR },
737 { "year", USEC_PER_YEAR },
738 { "y", USEC_PER_YEAR },
739 { "usec", 1ULL },
740 { "us", 1ULL },
741 };
742 unsigned i;
743
744 for (i = 0; i < ELEMENTSOF(table); i++) {
745 char *e;
746
747 e = startswith(p, table[i].suffix);
748 if (e) {
749 *multiplier = table[i].usec;
750 return e;
751 }
752 }
753
754 return p;
755 }
756
757 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
758 const char *p, *s;
759 usec_t r = 0;
760 bool something = false;
761
762 assert(t);
763 assert(usec);
764 assert(default_unit > 0);
765
766 p = t;
767
768 p += strspn(p, WHITESPACE);
769 s = startswith(p, "infinity");
770 if (s) {
771 s += strspn(s, WHITESPACE);
772 if (*s != 0)
773 return -EINVAL;
774
775 *usec = USEC_INFINITY;
776 return 0;
777 }
778
779 for (;;) {
780 long long l, z = 0;
781 char *e;
782 unsigned n = 0;
783 usec_t multiplier = default_unit, k;
784
785 p += strspn(p, WHITESPACE);
786
787 if (*p == 0) {
788 if (!something)
789 return -EINVAL;
790
791 break;
792 }
793
794 errno = 0;
795 l = strtoll(p, &e, 10);
796 if (errno > 0)
797 return -errno;
798 if (l < 0)
799 return -ERANGE;
800
801 if (*e == '.') {
802 char *b = e + 1;
803
804 errno = 0;
805 z = strtoll(b, &e, 10);
806 if (errno > 0)
807 return -errno;
808
809 if (z < 0)
810 return -ERANGE;
811
812 if (e == b)
813 return -EINVAL;
814
815 n = e - b;
816
817 } else if (e == p)
818 return -EINVAL;
819
820 e += strspn(e, WHITESPACE);
821 p = extract_multiplier(e, &multiplier);
822
823 something = true;
824
825 k = (usec_t) z * multiplier;
826
827 for (; n > 0; n--)
828 k /= 10;
829
830 r += (usec_t) l * multiplier + k;
831 }
832
833 *usec = r;
834
835 return 0;
836 }
837
838 int parse_sec(const char *t, usec_t *usec) {
839 return parse_time(t, usec, USEC_PER_SEC);
840 }
841
842 int parse_nsec(const char *t, nsec_t *nsec) {
843 static const struct {
844 const char *suffix;
845 nsec_t nsec;
846 } table[] = {
847 { "seconds", NSEC_PER_SEC },
848 { "second", NSEC_PER_SEC },
849 { "sec", NSEC_PER_SEC },
850 { "s", NSEC_PER_SEC },
851 { "minutes", NSEC_PER_MINUTE },
852 { "minute", NSEC_PER_MINUTE },
853 { "min", NSEC_PER_MINUTE },
854 { "months", NSEC_PER_MONTH },
855 { "month", NSEC_PER_MONTH },
856 { "msec", NSEC_PER_MSEC },
857 { "ms", NSEC_PER_MSEC },
858 { "m", NSEC_PER_MINUTE },
859 { "hours", NSEC_PER_HOUR },
860 { "hour", NSEC_PER_HOUR },
861 { "hr", NSEC_PER_HOUR },
862 { "h", NSEC_PER_HOUR },
863 { "days", NSEC_PER_DAY },
864 { "day", NSEC_PER_DAY },
865 { "d", NSEC_PER_DAY },
866 { "weeks", NSEC_PER_WEEK },
867 { "week", NSEC_PER_WEEK },
868 { "w", NSEC_PER_WEEK },
869 { "years", NSEC_PER_YEAR },
870 { "year", NSEC_PER_YEAR },
871 { "y", NSEC_PER_YEAR },
872 { "usec", NSEC_PER_USEC },
873 { "us", NSEC_PER_USEC },
874 { "nsec", 1ULL },
875 { "ns", 1ULL },
876 { "", 1ULL }, /* default is nsec */
877 };
878
879 const char *p, *s;
880 nsec_t r = 0;
881 bool something = false;
882
883 assert(t);
884 assert(nsec);
885
886 p = t;
887
888 p += strspn(p, WHITESPACE);
889 s = startswith(p, "infinity");
890 if (s) {
891 s += strspn(s, WHITESPACE);
892 if (*s != 0)
893 return -EINVAL;
894
895 *nsec = NSEC_INFINITY;
896 return 0;
897 }
898
899 for (;;) {
900 long long l, z = 0;
901 char *e;
902 unsigned i, n = 0;
903
904 p += strspn(p, WHITESPACE);
905
906 if (*p == 0) {
907 if (!something)
908 return -EINVAL;
909
910 break;
911 }
912
913 errno = 0;
914 l = strtoll(p, &e, 10);
915
916 if (errno > 0)
917 return -errno;
918
919 if (l < 0)
920 return -ERANGE;
921
922 if (*e == '.') {
923 char *b = e + 1;
924
925 errno = 0;
926 z = strtoll(b, &e, 10);
927 if (errno > 0)
928 return -errno;
929
930 if (z < 0)
931 return -ERANGE;
932
933 if (e == b)
934 return -EINVAL;
935
936 n = e - b;
937
938 } else if (e == p)
939 return -EINVAL;
940
941 e += strspn(e, WHITESPACE);
942
943 for (i = 0; i < ELEMENTSOF(table); i++)
944 if (startswith(e, table[i].suffix)) {
945 nsec_t k = (nsec_t) z * table[i].nsec;
946
947 for (; n > 0; n--)
948 k /= 10;
949
950 r += (nsec_t) l * table[i].nsec + k;
951 p = e + strlen(table[i].suffix);
952
953 something = true;
954 break;
955 }
956
957 if (i >= ELEMENTSOF(table))
958 return -EINVAL;
959
960 }
961
962 *nsec = r;
963
964 return 0;
965 }
966
967 bool ntp_synced(void) {
968 struct timex txc = {};
969
970 if (adjtimex(&txc) < 0)
971 return false;
972
973 if (txc.status & STA_UNSYNC)
974 return false;
975
976 return true;
977 }
978
979 int get_timezones(char ***ret) {
980 _cleanup_fclose_ FILE *f = NULL;
981 _cleanup_strv_free_ char **zones = NULL;
982 size_t n_zones = 0, n_allocated = 0;
983
984 assert(ret);
985
986 zones = strv_new("UTC", NULL);
987 if (!zones)
988 return -ENOMEM;
989
990 n_allocated = 2;
991 n_zones = 1;
992
993 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
994 if (f) {
995 char l[LINE_MAX];
996
997 FOREACH_LINE(l, f, return -errno) {
998 char *p, *w;
999 size_t k;
1000
1001 p = strstrip(l);
1002
1003 if (isempty(p) || *p == '#')
1004 continue;
1005
1006 /* Skip over country code */
1007 p += strcspn(p, WHITESPACE);
1008 p += strspn(p, WHITESPACE);
1009
1010 /* Skip over coordinates */
1011 p += strcspn(p, WHITESPACE);
1012 p += strspn(p, WHITESPACE);
1013
1014 /* Found timezone name */
1015 k = strcspn(p, WHITESPACE);
1016 if (k <= 0)
1017 continue;
1018
1019 w = strndup(p, k);
1020 if (!w)
1021 return -ENOMEM;
1022
1023 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1024 free(w);
1025 return -ENOMEM;
1026 }
1027
1028 zones[n_zones++] = w;
1029 zones[n_zones] = NULL;
1030 }
1031
1032 strv_sort(zones);
1033
1034 } else if (errno != ENOENT)
1035 return -errno;
1036
1037 *ret = zones;
1038 zones = NULL;
1039
1040 return 0;
1041 }
1042
1043 bool timezone_is_valid(const char *name) {
1044 bool slash = false;
1045 const char *p, *t;
1046 struct stat st;
1047
1048 if (isempty(name))
1049 return false;
1050
1051 if (name[0] == '/')
1052 return false;
1053
1054 for (p = name; *p; p++) {
1055 if (!(*p >= '0' && *p <= '9') &&
1056 !(*p >= 'a' && *p <= 'z') &&
1057 !(*p >= 'A' && *p <= 'Z') &&
1058 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1059 return false;
1060
1061 if (*p == '/') {
1062
1063 if (slash)
1064 return false;
1065
1066 slash = true;
1067 } else
1068 slash = false;
1069 }
1070
1071 if (slash)
1072 return false;
1073
1074 t = strjoina("/usr/share/zoneinfo/", name);
1075 if (stat(t, &st) < 0)
1076 return false;
1077
1078 if (!S_ISREG(st.st_mode))
1079 return false;
1080
1081 return true;
1082 }
1083
1084 clockid_t clock_boottime_or_monotonic(void) {
1085 static clockid_t clock = -1;
1086 int fd;
1087
1088 if (clock != -1)
1089 return clock;
1090
1091 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1092 if (fd < 0)
1093 clock = CLOCK_MONOTONIC;
1094 else {
1095 safe_close(fd);
1096 clock = CLOCK_BOOTTIME;
1097 }
1098
1099 return clock;
1100 }
1101
1102 int get_timezone(char **tz) {
1103 _cleanup_free_ char *t = NULL;
1104 const char *e;
1105 char *z;
1106 int r;
1107
1108 r = readlink_malloc("/etc/localtime", &t);
1109 if (r < 0)
1110 return r; /* returns EINVAL if not a symlink */
1111
1112 e = path_startswith(t, "/usr/share/zoneinfo/");
1113 if (!e)
1114 e = path_startswith(t, "../usr/share/zoneinfo/");
1115 if (!e)
1116 return -EINVAL;
1117
1118 if (!timezone_is_valid(e))
1119 return -EINVAL;
1120
1121 z = strdup(e);
1122 if (!z)
1123 return -ENOMEM;
1124
1125 *tz = z;
1126 return 0;
1127 }
1128
1129 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1130 return utc ? timegm(tm) : mktime(tm);
1131 }
1132
1133 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1134 return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1135 }
1136
1137 unsigned long usec_to_jiffies(usec_t u) {
1138 static thread_local unsigned long hz = 0;
1139 long r;
1140
1141 if (hz == 0) {
1142 r = sysconf(_SC_CLK_TCK);
1143
1144 assert(r > 0);
1145 hz = (unsigned long) r;
1146 }
1147
1148 return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
1149 }