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