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