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