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