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