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