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