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