chiark / gitweb /
28b20f41805379dd6661974f62c3cfe141805d80
[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 "parse-util.h"
31 #include "path-util.h"
32 #include "string-util.h"
33 #include "strv.h"
34 #include "time-util.h"
35 #include "util.h"
36
37 usec_t now(clockid_t clock_id) {
38         struct timespec ts;
39
40         assert_se(clock_gettime(clock_id, &ts) == 0);
41
42         return timespec_load(&ts);
43 }
44
45 #if 0 /// UNNEEDED by elogind
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 #if 0 /// UNNEEDED by elogind
87 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
88         int64_t delta;
89         assert(ts);
90
91         if (u == USEC_INFINITY) {
92                 ts->realtime = ts->monotonic = USEC_INFINITY;
93                 return ts;
94         }
95
96         ts->monotonic = u;
97         delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
98
99         ts->realtime = now(CLOCK_REALTIME);
100         if ((int64_t) ts->realtime > delta)
101                 ts->realtime -= delta;
102         else
103                 ts->realtime = 0;
104
105         return ts;
106 }
107
108 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
109         int64_t delta;
110
111         if (u == USEC_INFINITY) {
112                 ts->realtime = ts->monotonic = USEC_INFINITY;
113                 return ts;
114         }
115
116         dual_timestamp_get(ts);
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                 unsigned add;
670
671                 k++;
672                 r = parse_fractional_part_u(&k, 6, &add);
673                 if (r < 0)
674                         return -EINVAL;
675
676                 if (*k)
677                         return -EINVAL;
678
679                 x_usec = add;
680
681         }
682
683 from_tm:
684         x = mktime_or_timegm(&tm, utc);
685         if (x == (time_t) -1)
686                 return -EINVAL;
687
688         if (weekday >= 0 && tm.tm_wday != weekday)
689                 return -EINVAL;
690
691         ret = (usec_t) x * USEC_PER_SEC + x_usec;
692
693 finish:
694         ret += plus;
695         if (ret > minus)
696                 ret -= minus;
697         else
698                 ret = 0;
699
700         *usec = ret;
701
702         return 0;
703 }
704 #endif // 0
705
706 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
707
708         static const struct {
709                 const char *suffix;
710                 usec_t usec;
711         } table[] = {
712                 { "seconds", USEC_PER_SEC },
713                 { "second", USEC_PER_SEC },
714                 { "sec", USEC_PER_SEC },
715                 { "s", USEC_PER_SEC },
716                 { "minutes", USEC_PER_MINUTE },
717                 { "minute", USEC_PER_MINUTE },
718                 { "min", USEC_PER_MINUTE },
719                 { "months", USEC_PER_MONTH },
720                 { "month", USEC_PER_MONTH },
721                 { "M",       USEC_PER_MONTH  },
722                 { "msec", USEC_PER_MSEC },
723                 { "ms", USEC_PER_MSEC },
724                 { "m", USEC_PER_MINUTE },
725                 { "hours", USEC_PER_HOUR },
726                 { "hour", USEC_PER_HOUR },
727                 { "hr", USEC_PER_HOUR },
728                 { "h", USEC_PER_HOUR },
729                 { "days", USEC_PER_DAY },
730                 { "day", USEC_PER_DAY },
731                 { "d", USEC_PER_DAY },
732                 { "weeks", USEC_PER_WEEK },
733                 { "week", USEC_PER_WEEK },
734                 { "w", USEC_PER_WEEK },
735                 { "years", USEC_PER_YEAR },
736                 { "year", USEC_PER_YEAR },
737                 { "y", USEC_PER_YEAR },
738                 { "usec", 1ULL },
739                 { "us", 1ULL },
740         };
741
742         const char *p, *s;
743         usec_t r = 0;
744         bool something = false;
745
746         assert(t);
747         assert(usec);
748         assert(default_unit > 0);
749
750         p = t;
751
752         p += strspn(p, WHITESPACE);
753         s = startswith(p, "infinity");
754         if (s) {
755                 s += strspn(s, WHITESPACE);
756                 if (*s != 0)
757                         return -EINVAL;
758
759                 *usec = USEC_INFINITY;
760                 return 0;
761         }
762
763         for (;;) {
764                 long long l, z = 0;
765                 char *e;
766                 unsigned i, n = 0;
767                 usec_t multiplier, k;
768
769                 p += strspn(p, WHITESPACE);
770
771                 if (*p == 0) {
772                         if (!something)
773                                 return -EINVAL;
774
775                         break;
776                 }
777
778                 errno = 0;
779                 l = strtoll(p, &e, 10);
780
781                 if (errno > 0)
782                         return -errno;
783
784                 if (l < 0)
785                         return -ERANGE;
786
787                 if (*e == '.') {
788                         char *b = e + 1;
789
790                         errno = 0;
791                         z = strtoll(b, &e, 10);
792                         if (errno > 0)
793                                 return -errno;
794
795                         if (z < 0)
796                                 return -ERANGE;
797
798                         if (e == b)
799                                 return -EINVAL;
800
801                         n = e - b;
802
803                 } else if (e == p)
804                         return -EINVAL;
805
806                 e += strspn(e, WHITESPACE);
807
808                 for (i = 0; i < ELEMENTSOF(table); i++)
809                         if (startswith(e, table[i].suffix)) {
810                                 multiplier = table[i].usec;
811                                 p = e + strlen(table[i].suffix);
812                                 break;
813                         }
814
815                 if (i >= ELEMENTSOF(table)) {
816                         multiplier = default_unit;
817                         p = e;
818                 }
819
820                 something = true;
821
822                 k = (usec_t) z * multiplier;
823
824                 for (; n > 0; n--)
825                         k /= 10;
826
827                 r += (usec_t) l * multiplier + k;
828         }
829
830         *usec = r;
831
832         return 0;
833 }
834
835 int parse_sec(const char *t, usec_t *usec) {
836         return parse_time(t, usec, USEC_PER_SEC);
837 }
838
839 #if 0 /// UNNEEDED by elogind
840 int parse_nsec(const char *t, nsec_t *nsec) {
841         static const struct {
842                 const char *suffix;
843                 nsec_t nsec;
844         } table[] = {
845                 { "seconds", NSEC_PER_SEC },
846                 { "second", NSEC_PER_SEC },
847                 { "sec", NSEC_PER_SEC },
848                 { "s", NSEC_PER_SEC },
849                 { "minutes", NSEC_PER_MINUTE },
850                 { "minute", NSEC_PER_MINUTE },
851                 { "min", NSEC_PER_MINUTE },
852                 { "months", NSEC_PER_MONTH },
853                 { "month", NSEC_PER_MONTH },
854                 { "msec", NSEC_PER_MSEC },
855                 { "ms", NSEC_PER_MSEC },
856                 { "m", NSEC_PER_MINUTE },
857                 { "hours", NSEC_PER_HOUR },
858                 { "hour", NSEC_PER_HOUR },
859                 { "hr", NSEC_PER_HOUR },
860                 { "h", NSEC_PER_HOUR },
861                 { "days", NSEC_PER_DAY },
862                 { "day", NSEC_PER_DAY },
863                 { "d", NSEC_PER_DAY },
864                 { "weeks", NSEC_PER_WEEK },
865                 { "week", NSEC_PER_WEEK },
866                 { "w", NSEC_PER_WEEK },
867                 { "years", NSEC_PER_YEAR },
868                 { "year", NSEC_PER_YEAR },
869                 { "y", NSEC_PER_YEAR },
870                 { "usec", NSEC_PER_USEC },
871                 { "us", NSEC_PER_USEC },
872                 { "nsec", 1ULL },
873                 { "ns", 1ULL },
874                 { "", 1ULL }, /* default is nsec */
875         };
876
877         const char *p, *s;
878         nsec_t r = 0;
879         bool something = false;
880
881         assert(t);
882         assert(nsec);
883
884         p = t;
885
886         p += strspn(p, WHITESPACE);
887         s = startswith(p, "infinity");
888         if (s) {
889                 s += strspn(s, WHITESPACE);
890                 if (*s != 0)
891                         return -EINVAL;
892
893                 *nsec = NSEC_INFINITY;
894                 return 0;
895         }
896
897         for (;;) {
898                 long long l, z = 0;
899                 char *e;
900                 unsigned i, n = 0;
901
902                 p += strspn(p, WHITESPACE);
903
904                 if (*p == 0) {
905                         if (!something)
906                                 return -EINVAL;
907
908                         break;
909                 }
910
911                 errno = 0;
912                 l = strtoll(p, &e, 10);
913
914                 if (errno > 0)
915                         return -errno;
916
917                 if (l < 0)
918                         return -ERANGE;
919
920                 if (*e == '.') {
921                         char *b = e + 1;
922
923                         errno = 0;
924                         z = strtoll(b, &e, 10);
925                         if (errno > 0)
926                                 return -errno;
927
928                         if (z < 0)
929                                 return -ERANGE;
930
931                         if (e == b)
932                                 return -EINVAL;
933
934                         n = e - b;
935
936                 } else if (e == p)
937                         return -EINVAL;
938
939                 e += strspn(e, WHITESPACE);
940
941                 for (i = 0; i < ELEMENTSOF(table); i++)
942                         if (startswith(e, table[i].suffix)) {
943                                 nsec_t k = (nsec_t) z * table[i].nsec;
944
945                                 for (; n > 0; n--)
946                                         k /= 10;
947
948                                 r += (nsec_t) l * table[i].nsec + k;
949                                 p = e + strlen(table[i].suffix);
950
951                                 something = true;
952                                 break;
953                         }
954
955                 if (i >= ELEMENTSOF(table))
956                         return -EINVAL;
957
958         }
959
960         *nsec = r;
961
962         return 0;
963 }
964
965 bool ntp_synced(void) {
966         struct timex txc = {};
967
968         if (adjtimex(&txc) < 0)
969                 return false;
970
971         if (txc.status & STA_UNSYNC)
972                 return false;
973
974         return true;
975 }
976
977 int get_timezones(char ***ret) {
978         _cleanup_fclose_ FILE *f = NULL;
979         _cleanup_strv_free_ char **zones = NULL;
980         size_t n_zones = 0, n_allocated = 0;
981
982         assert(ret);
983
984         zones = strv_new("UTC", NULL);
985         if (!zones)
986                 return -ENOMEM;
987
988         n_allocated = 2;
989         n_zones = 1;
990
991         f = fopen("/usr/share/zoneinfo/zone.tab", "re");
992         if (f) {
993                 char l[LINE_MAX];
994
995                 FOREACH_LINE(l, f, return -errno) {
996                         char *p, *w;
997                         size_t k;
998
999                         p = strstrip(l);
1000
1001                         if (isempty(p) || *p == '#')
1002                                 continue;
1003
1004                         /* Skip over country code */
1005                         p += strcspn(p, WHITESPACE);
1006                         p += strspn(p, WHITESPACE);
1007
1008                         /* Skip over coordinates */
1009                         p += strcspn(p, WHITESPACE);
1010                         p += strspn(p, WHITESPACE);
1011
1012                         /* Found timezone name */
1013                         k = strcspn(p, WHITESPACE);
1014                         if (k <= 0)
1015                                 continue;
1016
1017                         w = strndup(p, k);
1018                         if (!w)
1019                                 return -ENOMEM;
1020
1021                         if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1022                                 free(w);
1023                                 return -ENOMEM;
1024                         }
1025
1026                         zones[n_zones++] = w;
1027                         zones[n_zones] = NULL;
1028                 }
1029
1030                 strv_sort(zones);
1031
1032         } else if (errno != ENOENT)
1033                 return -errno;
1034
1035         *ret = zones;
1036         zones = NULL;
1037
1038         return 0;
1039 }
1040
1041 bool timezone_is_valid(const char *name) {
1042         bool slash = false;
1043         const char *p, *t;
1044         struct stat st;
1045
1046         if (isempty(name))
1047                 return false;
1048
1049         if (name[0] == '/')
1050                 return false;
1051
1052         for (p = name; *p; p++) {
1053                 if (!(*p >= '0' && *p <= '9') &&
1054                     !(*p >= 'a' && *p <= 'z') &&
1055                     !(*p >= 'A' && *p <= 'Z') &&
1056                     !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1057                         return false;
1058
1059                 if (*p == '/') {
1060
1061                         if (slash)
1062                                 return false;
1063
1064                         slash = true;
1065                 } else
1066                         slash = false;
1067         }
1068
1069         if (slash)
1070                 return false;
1071
1072         t = strjoina("/usr/share/zoneinfo/", name);
1073         if (stat(t, &st) < 0)
1074                 return false;
1075
1076         if (!S_ISREG(st.st_mode))
1077                 return false;
1078
1079         return true;
1080 }
1081
1082 clockid_t clock_boottime_or_monotonic(void) {
1083         static clockid_t clock = -1;
1084         int fd;
1085
1086         if (clock != -1)
1087                 return clock;
1088
1089         fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1090         if (fd < 0)
1091                 clock = CLOCK_MONOTONIC;
1092         else {
1093                 safe_close(fd);
1094                 clock = CLOCK_BOOTTIME;
1095         }
1096
1097         return clock;
1098 }
1099
1100 int get_timezone(char **tz) {
1101         _cleanup_free_ char *t = NULL;
1102         const char *e;
1103         char *z;
1104         int r;
1105
1106         r = readlink_malloc("/etc/localtime", &t);
1107         if (r < 0)
1108                 return r; /* returns EINVAL if not a symlink */
1109
1110         e = path_startswith(t, "/usr/share/zoneinfo/");
1111         if (!e)
1112                 e = path_startswith(t, "../usr/share/zoneinfo/");
1113         if (!e)
1114                 return -EINVAL;
1115
1116         if (!timezone_is_valid(e))
1117                 return -EINVAL;
1118
1119         z = strdup(e);
1120         if (!z)
1121                 return -ENOMEM;
1122
1123         *tz = z;
1124         return 0;
1125 }
1126
1127 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1128         return utc ? timegm(tm) : mktime(tm);
1129 }
1130 #endif // 0
1131
1132 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1133         return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1134 }
1135
1136 #if 0 /// UNNEEDED by elogind
1137 unsigned long usec_to_jiffies(usec_t u) {
1138         static thread_local unsigned long hz = 0;
1139         long r;
1140
1141         if (hz == 0) {
1142                 r = sysconf(_SC_CLK_TCK);
1143
1144                 assert(r > 0);
1145                 hz = (unsigned long) r;
1146         }
1147
1148         return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
1149 }
1150 #endif // 0