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