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