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