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