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