chiark / gitweb /
2e465296fca739645a9c2ed017e0e89cc2639146
[elogind.git] / src / basic / time-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2010 Lennart Poettering
6 ***/
7
8 #include <errno.h>
9 #include <limits.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h>
14 #include <sys/time.h>
15 #include <sys/timerfd.h>
16 #include <sys/timex.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19
20 #include "alloc-util.h"
21 #include "fd-util.h"
22 #include "fileio.h"
23 #include "fs-util.h"
24 //#include "io-util.h"
25 #include "log.h"
26 #include "macro.h"
27 #include "parse-util.h"
28 #include "path-util.h"
29 //#include "process-util.h"
30 //#include "stat-util.h"
31 #include "string-util.h"
32 #include "strv.h"
33 #include "time-util.h"
34
35 static clockid_t map_clock_id(clockid_t c) {
36
37         /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
38          * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
39          * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
40          * those archs. */
41
42         switch (c) {
43
44         case CLOCK_BOOTTIME_ALARM:
45                 return CLOCK_BOOTTIME;
46
47         case CLOCK_REALTIME_ALARM:
48                 return CLOCK_REALTIME;
49
50         default:
51                 return c;
52         }
53 }
54
55 usec_t now(clockid_t clock_id) {
56         struct timespec ts;
57
58         assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
59
60         return timespec_load(&ts);
61 }
62
63 #if 0 /// UNNEEDED by elogind
64 nsec_t now_nsec(clockid_t clock_id) {
65         struct timespec ts;
66
67         assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
68
69         return timespec_load_nsec(&ts);
70 }
71 #endif // 0
72
73 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
74         assert(ts);
75
76         ts->realtime = now(CLOCK_REALTIME);
77         ts->monotonic = now(CLOCK_MONOTONIC);
78
79         return ts;
80 }
81
82 triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
83         assert(ts);
84
85         ts->realtime = now(CLOCK_REALTIME);
86         ts->monotonic = now(CLOCK_MONOTONIC);
87         ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
88
89         return ts;
90 }
91
92 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
93         int64_t delta;
94         assert(ts);
95
96         if (u == USEC_INFINITY || u <= 0) {
97                 ts->realtime = ts->monotonic = u;
98                 return ts;
99         }
100
101         ts->realtime = u;
102
103         delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
104         ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
105
106         return ts;
107 }
108
109 #if 0 /// UNNEEDED by elogind
110 triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) {
111         int64_t delta;
112
113         assert(ts);
114
115         if (u == USEC_INFINITY || u <= 0) {
116                 ts->realtime = ts->monotonic = ts->boottime = u;
117                 return ts;
118         }
119
120         ts->realtime = u;
121         delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
122         ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
123         ts->boottime = clock_boottime_supported() ? usec_sub_signed(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
124
125         return ts;
126 }
127
128 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
129         int64_t delta;
130         assert(ts);
131
132         if (u == USEC_INFINITY) {
133                 ts->realtime = ts->monotonic = USEC_INFINITY;
134                 return ts;
135         }
136
137         ts->monotonic = u;
138         delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
139         ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta);
140
141         return ts;
142 }
143
144 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
145         int64_t delta;
146
147         if (u == USEC_INFINITY) {
148                 ts->realtime = ts->monotonic = USEC_INFINITY;
149                 return ts;
150         }
151
152         dual_timestamp_get(ts);
153         delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
154         ts->realtime = usec_sub_signed(ts->realtime, delta);
155         ts->monotonic = usec_sub_signed(ts->monotonic, delta);
156
157         return ts;
158 }
159 #endif // 0
160
161 usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
162
163         switch (clock) {
164
165         case CLOCK_REALTIME:
166         case CLOCK_REALTIME_ALARM:
167                 return ts->realtime;
168
169         case CLOCK_MONOTONIC:
170                 return ts->monotonic;
171
172         case CLOCK_BOOTTIME:
173         case CLOCK_BOOTTIME_ALARM:
174                 return ts->boottime;
175
176         default:
177                 return USEC_INFINITY;
178         }
179 }
180
181 usec_t timespec_load(const struct timespec *ts) {
182         assert(ts);
183
184         if (ts->tv_sec < 0 || ts->tv_nsec < 0)
185                 return USEC_INFINITY;
186
187         if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
188                 return USEC_INFINITY;
189
190         return
191                 (usec_t) ts->tv_sec * USEC_PER_SEC +
192                 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
193 }
194
195 #if 0 /// UNNEEDED by elogind
196 nsec_t timespec_load_nsec(const struct timespec *ts) {
197         assert(ts);
198
199         if (ts->tv_sec < 0 || ts->tv_nsec < 0)
200                 return NSEC_INFINITY;
201
202         if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC)
203                 return NSEC_INFINITY;
204
205         return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec;
206 }
207 #endif // 0
208
209 struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
210         assert(ts);
211
212         if (u == USEC_INFINITY ||
213             u / USEC_PER_SEC >= TIME_T_MAX) {
214                 ts->tv_sec = (time_t) -1;
215                 ts->tv_nsec = (long) -1;
216                 return ts;
217         }
218
219         ts->tv_sec = (time_t) (u / USEC_PER_SEC);
220         ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
221
222         return ts;
223 }
224
225 usec_t timeval_load(const struct timeval *tv) {
226         assert(tv);
227
228         if (tv->tv_sec < 0 || tv->tv_usec < 0)
229                 return USEC_INFINITY;
230
231         if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
232                 return USEC_INFINITY;
233
234         return
235                 (usec_t) tv->tv_sec * USEC_PER_SEC +
236                 (usec_t) tv->tv_usec;
237 }
238
239 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
240         assert(tv);
241
242         if (u == USEC_INFINITY ||
243             u / USEC_PER_SEC > TIME_T_MAX) {
244                 tv->tv_sec = (time_t) -1;
245                 tv->tv_usec = (suseconds_t) -1;
246         } else {
247                 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
248                 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
249         }
250
251         return tv;
252 }
253
254 static char *format_timestamp_internal(
255                 char *buf,
256                 size_t l,
257                 usec_t t,
258                 bool utc,
259                 bool us) {
260
261         /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
262          * generated timestamps may be parsed with parse_timestamp(), and always read the same. */
263         static const char * const weekdays[] = {
264                 [0] = "Sun",
265                 [1] = "Mon",
266                 [2] = "Tue",
267                 [3] = "Wed",
268                 [4] = "Thu",
269                 [5] = "Fri",
270                 [6] = "Sat",
271         };
272
273         struct tm tm;
274         time_t sec;
275         size_t n;
276
277         assert(buf);
278
279         if (l <
280             3 +                  /* week day */
281             1 + 10 +             /* space and date */
282             1 + 8 +              /* space and time */
283             (us ? 1 + 6 : 0) +   /* "." and microsecond part */
284             1 + 1 +              /* space and shortest possible zone */
285             1)
286                 return NULL; /* Not enough space even for the shortest form. */
287         if (t <= 0 || t == USEC_INFINITY)
288                 return NULL; /* Timestamp is unset */
289
290         /* Let's not format times with years > 9999 */
291         if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
292                 assert(l >= strlen("--- XXXX-XX-XX XX:XX:XX") + 1);
293                 strcpy(buf, "--- XXXX-XX-XX XX:XX:XX");
294                 return buf;
295         }
296
297         sec = (time_t) (t / USEC_PER_SEC); /* Round down */
298
299         if (!localtime_or_gmtime_r(&sec, &tm, utc))
300                 return NULL;
301
302         /* Start with the week day */
303         assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
304         memcpy(buf, weekdays[tm.tm_wday], 4);
305
306         /* Add the main components */
307         if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
308                 return NULL; /* Doesn't fit */
309
310         /* Append the microseconds part, if that's requested */
311         if (us) {
312                 n = strlen(buf);
313                 if (n + 8 > l)
314                         return NULL; /* Microseconds part doesn't fit. */
315
316                 sprintf(buf + n, ".%06"PRI_USEC, t % USEC_PER_SEC);
317         }
318
319         /* Append the timezone */
320         n = strlen(buf);
321         if (utc) {
322                 /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the
323                  * obsolete "GMT" instead. */
324                 if (n + 5 > l)
325                         return NULL; /* "UTC" doesn't fit. */
326
327                 strcpy(buf + n, " UTC");
328
329         } else if (!isempty(tm.tm_zone)) {
330                 size_t tn;
331
332                 /* An explicit timezone is specified, let's use it, if it fits */
333                 tn = strlen(tm.tm_zone);
334                 if (n + 1 + tn + 1 > l) {
335                         /* The full time zone does not fit in. Yuck. */
336
337                         if (n + 1 + _POSIX_TZNAME_MAX + 1 > l)
338                                 return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */
339
340                         /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
341                          * minimum time zone length. In this case suppress the timezone entirely, in order not to dump
342                          * an overly long, hard to read string on the user. This should be safe, because the user will
343                          * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
344                 } else {
345                         buf[n++] = ' ';
346                         strcpy(buf + n, tm.tm_zone);
347                 }
348         }
349
350         return buf;
351 }
352
353 char *format_timestamp(char *buf, size_t l, usec_t t) {
354         return format_timestamp_internal(buf, l, t, false, false);
355 }
356
357 #if 0 /// UNNEEDED by elogind
358 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
359         return format_timestamp_internal(buf, l, t, true, false);
360 }
361 #endif // 0
362
363 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
364         return format_timestamp_internal(buf, l, t, false, true);
365 }
366
367 #if 0 /// UNNEEDED by elogind
368 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
369         return format_timestamp_internal(buf, l, t, true, true);
370 }
371 #endif // 0
372
373 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
374         const char *s;
375         usec_t n, d;
376
377         if (t <= 0 || t == USEC_INFINITY)
378                 return NULL;
379
380         n = now(CLOCK_REALTIME);
381         if (n > t) {
382                 d = n - t;
383                 s = "ago";
384         } else {
385                 d = t - n;
386                 s = "left";
387         }
388
389         if (d >= USEC_PER_YEAR)
390                 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
391                          d / USEC_PER_YEAR,
392                          (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
393         else if (d >= USEC_PER_MONTH)
394                 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
395                          d / USEC_PER_MONTH,
396                          (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
397         else if (d >= USEC_PER_WEEK)
398                 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
399                          d / USEC_PER_WEEK,
400                          (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
401         else if (d >= 2*USEC_PER_DAY)
402                 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
403         else if (d >= 25*USEC_PER_HOUR)
404                 snprintf(buf, l, "1 day " USEC_FMT "h %s",
405                          (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
406         else if (d >= 6*USEC_PER_HOUR)
407                 snprintf(buf, l, USEC_FMT "h %s",
408                          d / USEC_PER_HOUR, s);
409         else if (d >= USEC_PER_HOUR)
410                 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
411                          d / USEC_PER_HOUR,
412                          (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
413         else if (d >= 5*USEC_PER_MINUTE)
414                 snprintf(buf, l, USEC_FMT "min %s",
415                          d / USEC_PER_MINUTE, s);
416         else if (d >= USEC_PER_MINUTE)
417                 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
418                          d / USEC_PER_MINUTE,
419                          (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
420         else if (d >= USEC_PER_SEC)
421                 snprintf(buf, l, USEC_FMT "s %s",
422                          d / USEC_PER_SEC, s);
423         else if (d >= USEC_PER_MSEC)
424                 snprintf(buf, l, USEC_FMT "ms %s",
425                          d / USEC_PER_MSEC, s);
426         else if (d > 0)
427                 snprintf(buf, l, USEC_FMT"us %s",
428                          d, s);
429         else
430                 snprintf(buf, l, "now");
431
432         buf[l-1] = 0;
433         return buf;
434 }
435
436 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
437         static const struct {
438                 const char *suffix;
439                 usec_t usec;
440         } table[] = {
441                 { "y",     USEC_PER_YEAR   },
442                 { "month", USEC_PER_MONTH  },
443                 { "w",     USEC_PER_WEEK   },
444                 { "d",     USEC_PER_DAY    },
445                 { "h",     USEC_PER_HOUR   },
446                 { "min",   USEC_PER_MINUTE },
447                 { "s",     USEC_PER_SEC    },
448                 { "ms",    USEC_PER_MSEC   },
449                 { "us",    1               },
450         };
451
452         size_t i;
453         char *p = buf;
454         bool something = false;
455
456         assert(buf);
457         assert(l > 0);
458
459         if (t == USEC_INFINITY) {
460                 strncpy(p, "infinity", l-1);
461                 p[l-1] = 0;
462                 return p;
463         }
464
465         if (t <= 0) {
466                 strncpy(p, "0", l-1);
467                 p[l-1] = 0;
468                 return p;
469         }
470
471         /* The result of this function can be parsed with parse_sec */
472
473         for (i = 0; i < ELEMENTSOF(table); i++) {
474                 int k = 0;
475                 size_t n;
476                 bool done = false;
477                 usec_t a, b;
478
479                 if (t <= 0)
480                         break;
481
482                 if (t < accuracy && something)
483                         break;
484
485                 if (t < table[i].usec)
486                         continue;
487
488                 if (l <= 1)
489                         break;
490
491                 a = t / table[i].usec;
492                 b = t % table[i].usec;
493
494                 /* Let's see if we should shows this in dot notation */
495                 if (t < USEC_PER_MINUTE && b > 0) {
496                         usec_t cc;
497                         signed char j;
498
499                         j = 0;
500                         for (cc = table[i].usec; cc > 1; cc /= 10)
501                                 j++;
502
503                         for (cc = accuracy; cc > 1; cc /= 10) {
504                                 b /= 10;
505                                 j--;
506                         }
507
508                         if (j > 0) {
509                                 k = snprintf(p, l,
510                                              "%s"USEC_FMT".%0*"PRI_USEC"%s",
511                                              p > buf ? " " : "",
512                                              a,
513                                              j,
514                                              b,
515                                              table[i].suffix);
516
517                                 t = 0;
518                                 done = true;
519                         }
520                 }
521
522                 /* No? Then let's show it normally */
523                 if (!done) {
524                         k = snprintf(p, l,
525                                      "%s"USEC_FMT"%s",
526                                      p > buf ? " " : "",
527                                      a,
528                                      table[i].suffix);
529
530                         t = b;
531                 }
532
533                 n = MIN((size_t) k, l);
534
535                 l -= n;
536                 p += n;
537
538                 something = true;
539         }
540
541         *p = 0;
542
543         return buf;
544 }
545
546 #if 0 /// UNNEEDED by elogind
547 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
548
549         assert(f);
550         assert(name);
551         assert(t);
552
553         if (!dual_timestamp_is_set(t))
554                 return;
555
556         fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
557                 name,
558                 t->realtime,
559                 t->monotonic);
560 }
561
562 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
563         uint64_t a, b;
564         int r, pos;
565
566         assert(value);
567         assert(t);
568
569         pos = strspn(value, WHITESPACE);
570         if (value[pos] == '-')
571                 return -EINVAL;
572         pos += strspn(value + pos, DIGITS);
573         pos += strspn(value + pos, WHITESPACE);
574         if (value[pos] == '-')
575                 return -EINVAL;
576
577         r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos);
578         if (r != 2) {
579                 log_debug("Failed to parse dual timestamp value \"%s\".", value);
580                 return -EINVAL;
581         }
582
583         if (value[pos] != '\0')
584                 /* trailing garbage */
585                 return -EINVAL;
586
587         t->realtime = a;
588         t->monotonic = b;
589
590         return 0;
591 }
592
593 #endif // 0
594 int timestamp_deserialize(const char *value, usec_t *timestamp) {
595         int r;
596
597         assert(value);
598
599         r = safe_atou64(value, timestamp);
600         if (r < 0)
601                 return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value);
602
603         return r;
604 }
605
606 #if 0 /// UNNEEDED by elogind
607 static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
608         static const struct {
609                 const char *name;
610                 const int nr;
611         } day_nr[] = {
612                 { "Sunday",    0 },
613                 { "Sun",       0 },
614                 { "Monday",    1 },
615                 { "Mon",       1 },
616                 { "Tuesday",   2 },
617                 { "Tue",       2 },
618                 { "Wednesday", 3 },
619                 { "Wed",       3 },
620                 { "Thursday",  4 },
621                 { "Thu",       4 },
622                 { "Friday",    5 },
623                 { "Fri",       5 },
624                 { "Saturday",  6 },
625                 { "Sat",       6 },
626         };
627
628         const char *k, *utc = NULL, *tzn = NULL;
629         struct tm tm, copy;
630         time_t x;
631         usec_t x_usec, plus = 0, minus = 0, ret;
632         int r, weekday = -1, dst = -1;
633         size_t i;
634
635         /* Allowed syntaxes:
636          *
637          *   2012-09-22 16:34:22
638          *   2012-09-22 16:34     (seconds will be set to 0)
639          *   2012-09-22           (time will be set to 00:00:00)
640          *   16:34:22             (date will be set to today)
641          *   16:34                (date will be set to today, seconds to 0)
642          *   now
643          *   yesterday            (time is set to 00:00:00)
644          *   today                (time is set to 00:00:00)
645          *   tomorrow             (time is set to 00:00:00)
646          *   +5min
647          *   -5days
648          *   @2147483647          (seconds since epoch)
649          */
650
651         assert(t);
652         assert(usec);
653
654         if (t[0] == '@' && !with_tz)
655                 return parse_sec(t + 1, usec);
656
657         ret = now(CLOCK_REALTIME);
658
659         if (!with_tz) {
660                 if (streq(t, "now"))
661                         goto finish;
662
663                 else if (t[0] == '+') {
664                         r = parse_sec(t+1, &plus);
665                         if (r < 0)
666                                 return r;
667
668                         goto finish;
669
670                 } else if (t[0] == '-') {
671                         r = parse_sec(t+1, &minus);
672                         if (r < 0)
673                                 return r;
674
675                         goto finish;
676
677                 } else if ((k = endswith(t, " ago"))) {
678                         t = strndupa(t, k - t);
679
680                         r = parse_sec(t, &minus);
681                         if (r < 0)
682                                 return r;
683
684                         goto finish;
685
686                 } else if ((k = endswith(t, " left"))) {
687                         t = strndupa(t, k - t);
688
689                         r = parse_sec(t, &plus);
690                         if (r < 0)
691                                 return r;
692
693                         goto finish;
694                 }
695
696                 /* See if the timestamp is suffixed with UTC */
697                 utc = endswith_no_case(t, " UTC");
698                 if (utc)
699                         t = strndupa(t, utc - t);
700                 else {
701                         const char *e = NULL;
702                         int j;
703
704                         tzset();
705
706                         /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
707                          * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
708                          * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
709                          * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
710                          * support arbitrary timezone specifications. */
711
712                         for (j = 0; j <= 1; j++) {
713
714                                 if (isempty(tzname[j]))
715                                         continue;
716
717                                 e = endswith_no_case(t, tzname[j]);
718                                 if (!e)
719                                         continue;
720                                 if (e == t)
721                                         continue;
722                                 if (e[-1] != ' ')
723                                         continue;
724
725                                 break;
726                         }
727
728                         if (IN_SET(j, 0, 1)) {
729                                 /* Found one of the two timezones specified. */
730                                 t = strndupa(t, e - t - 1);
731                                 dst = j;
732                                 tzn = tzname[j];
733                         }
734                 }
735         }
736
737         x = (time_t) (ret / USEC_PER_SEC);
738         x_usec = 0;
739
740         if (!localtime_or_gmtime_r(&x, &tm, utc))
741                 return -EINVAL;
742
743         tm.tm_isdst = dst;
744         if (!with_tz && tzn)
745                 tm.tm_zone = tzn;
746
747         if (streq(t, "today")) {
748                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
749                 goto from_tm;
750
751         } else if (streq(t, "yesterday")) {
752                 tm.tm_mday--;
753                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
754                 goto from_tm;
755
756         } else if (streq(t, "tomorrow")) {
757                 tm.tm_mday++;
758                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
759                 goto from_tm;
760         }
761
762         for (i = 0; i < ELEMENTSOF(day_nr); i++) {
763                 size_t skip;
764
765                 if (!startswith_no_case(t, day_nr[i].name))
766                         continue;
767
768                 skip = strlen(day_nr[i].name);
769                 if (t[skip] != ' ')
770                         continue;
771
772                 weekday = day_nr[i].nr;
773                 t += skip + 1;
774                 break;
775         }
776
777         copy = tm;
778         k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
779         if (k) {
780                 if (*k == '.')
781                         goto parse_usec;
782                 else if (*k == 0)
783                         goto from_tm;
784         }
785
786         tm = copy;
787         k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
788         if (k) {
789                 if (*k == '.')
790                         goto parse_usec;
791                 else if (*k == 0)
792                         goto from_tm;
793         }
794
795         tm = copy;
796         k = strptime(t, "%y-%m-%d %H:%M", &tm);
797         if (k && *k == 0) {
798                 tm.tm_sec = 0;
799                 goto from_tm;
800         }
801
802         tm = copy;
803         k = strptime(t, "%Y-%m-%d %H:%M", &tm);
804         if (k && *k == 0) {
805                 tm.tm_sec = 0;
806                 goto from_tm;
807         }
808
809         tm = copy;
810         k = strptime(t, "%y-%m-%d", &tm);
811         if (k && *k == 0) {
812                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
813                 goto from_tm;
814         }
815
816         tm = copy;
817         k = strptime(t, "%Y-%m-%d", &tm);
818         if (k && *k == 0) {
819                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
820                 goto from_tm;
821         }
822
823         tm = copy;
824         k = strptime(t, "%H:%M:%S", &tm);
825         if (k) {
826                 if (*k == '.')
827                         goto parse_usec;
828                 else if (*k == 0)
829                         goto from_tm;
830         }
831
832         tm = copy;
833         k = strptime(t, "%H:%M", &tm);
834         if (k && *k == 0) {
835                 tm.tm_sec = 0;
836                 goto from_tm;
837         }
838
839         return -EINVAL;
840
841 parse_usec:
842         {
843                 unsigned add;
844
845                 k++;
846                 r = parse_fractional_part_u(&k, 6, &add);
847                 if (r < 0)
848                         return -EINVAL;
849
850                 if (*k)
851                         return -EINVAL;
852
853                 x_usec = add;
854         }
855
856 from_tm:
857         if (weekday >= 0 && tm.tm_wday != weekday)
858                 return -EINVAL;
859
860         x = mktime_or_timegm(&tm, utc);
861         if (x < 0)
862                 return -EINVAL;
863
864         ret = (usec_t) x * USEC_PER_SEC + x_usec;
865         if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
866                 return -EINVAL;
867
868 finish:
869         if (ret + plus < ret) /* overflow? */
870                 return -EINVAL;
871         ret += plus;
872         if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
873                 return -EINVAL;
874
875         if (ret >= minus)
876                 ret -= minus;
877         else
878                 return -EINVAL;
879
880         *usec = ret;
881
882         return 0;
883 }
884
885 typedef struct ParseTimestampResult {
886         usec_t usec;
887         int return_value;
888 } ParseTimestampResult;
889
890 int parse_timestamp(const char *t, usec_t *usec) {
891         char *last_space, *tz = NULL;
892         ParseTimestampResult *shared, tmp;
893         int r;
894
895         last_space = strrchr(t, ' ');
896         if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
897                 tz = last_space + 1;
898
899         if (!tz || endswith_no_case(t, " UTC"))
900                 return parse_timestamp_impl(t, usec, false);
901
902         shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
903         if (shared == MAP_FAILED)
904                 return negative_errno();
905
906         r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
907         if (r < 0) {
908                 (void) munmap(shared, sizeof *shared);
909                 return r;
910         }
911         if (r == 0) {
912                 bool with_tz = true;
913
914                 if (setenv("TZ", tz, 1) != 0) {
915                         shared->return_value = negative_errno();
916                         _exit(EXIT_FAILURE);
917                 }
918
919                 tzset();
920
921                 /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
922                  * Otherwise just cut it off. */
923                 with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
924
925                 /* Cut off the timezone if we dont need it. */
926                 if (with_tz)
927                         t = strndupa(t, last_space - t);
928
929                 shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
930
931                 _exit(EXIT_SUCCESS);
932         }
933
934         tmp = *shared;
935         if (munmap(shared, sizeof *shared) != 0)
936                 return negative_errno();
937
938         if (tmp.return_value == 0)
939                 *usec = tmp.usec;
940
941         return tmp.return_value;
942 }
943 #endif // 0
944
945 static char* extract_multiplier(char *p, usec_t *multiplier) {
946         static const struct {
947                 const char *suffix;
948                 usec_t usec;
949         } table[] = {
950                 { "seconds", USEC_PER_SEC    },
951                 { "second",  USEC_PER_SEC    },
952                 { "sec",     USEC_PER_SEC    },
953                 { "s",       USEC_PER_SEC    },
954                 { "minutes", USEC_PER_MINUTE },
955                 { "minute",  USEC_PER_MINUTE },
956                 { "min",     USEC_PER_MINUTE },
957                 { "months",  USEC_PER_MONTH  },
958                 { "month",   USEC_PER_MONTH  },
959                 { "M",       USEC_PER_MONTH  },
960                 { "msec",    USEC_PER_MSEC   },
961                 { "ms",      USEC_PER_MSEC   },
962                 { "m",       USEC_PER_MINUTE },
963                 { "hours",   USEC_PER_HOUR   },
964                 { "hour",    USEC_PER_HOUR   },
965                 { "hr",      USEC_PER_HOUR   },
966                 { "h",       USEC_PER_HOUR   },
967                 { "days",    USEC_PER_DAY    },
968                 { "day",     USEC_PER_DAY    },
969                 { "d",       USEC_PER_DAY    },
970                 { "weeks",   USEC_PER_WEEK   },
971                 { "week",    USEC_PER_WEEK   },
972                 { "w",       USEC_PER_WEEK   },
973                 { "years",   USEC_PER_YEAR   },
974                 { "year",    USEC_PER_YEAR   },
975                 { "y",       USEC_PER_YEAR   },
976                 { "usec",    1ULL            },
977                 { "us",      1ULL            },
978                 { "µs",      1ULL            },
979         };
980         size_t i;
981
982         for (i = 0; i < ELEMENTSOF(table); i++) {
983                 char *e;
984
985                 e = startswith(p, table[i].suffix);
986                 if (e) {
987                         *multiplier = table[i].usec;
988                         return e;
989                 }
990         }
991
992         return p;
993 }
994
995 int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
996         const char *p, *s;
997         usec_t r = 0;
998         bool something = false;
999
1000         assert(t);
1001         assert(usec);
1002         assert(default_unit > 0);
1003
1004         p = t;
1005
1006         p += strspn(p, WHITESPACE);
1007         s = startswith(p, "infinity");
1008         if (s) {
1009                 s += strspn(s, WHITESPACE);
1010                 if (*s != 0)
1011                         return -EINVAL;
1012
1013                 *usec = USEC_INFINITY;
1014                 return 0;
1015         }
1016
1017         for (;;) {
1018                 long long l, z = 0;
1019                 char *e;
1020                 unsigned n = 0;
1021                 usec_t multiplier = default_unit, k;
1022
1023                 p += strspn(p, WHITESPACE);
1024
1025                 if (*p == 0) {
1026                         if (!something)
1027                                 return -EINVAL;
1028
1029                         break;
1030                 }
1031
1032                 errno = 0;
1033                 l = strtoll(p, &e, 10);
1034                 if (errno > 0)
1035                         return -errno;
1036                 if (l < 0)
1037                         return -ERANGE;
1038
1039                 if (*e == '.') {
1040                         char *b = e + 1;
1041
1042                         errno = 0;
1043                         z = strtoll(b, &e, 10);
1044                         if (errno > 0)
1045                                 return -errno;
1046
1047                         if (z < 0)
1048                                 return -ERANGE;
1049
1050                         if (e == b)
1051                                 return -EINVAL;
1052
1053                         n = e - b;
1054
1055                 } else if (e == p)
1056                         return -EINVAL;
1057
1058                 e += strspn(e, WHITESPACE);
1059                 p = extract_multiplier(e, &multiplier);
1060
1061                 something = true;
1062
1063                 k = (usec_t) z * multiplier;
1064
1065                 for (; n > 0; n--)
1066                         k /= 10;
1067
1068                 r += (usec_t) l * multiplier + k;
1069         }
1070
1071         *usec = r;
1072
1073         return 0;
1074 }
1075
1076 int parse_sec(const char *t, usec_t *usec) {
1077         return parse_time(t, usec, USEC_PER_SEC);
1078 }
1079
1080 #if 0 /// UNNEEDED by elogind
1081 int parse_sec_fix_0(const char *t, usec_t *usec) {
1082         assert(t);
1083         assert(usec);
1084
1085         t += strspn(t, WHITESPACE);
1086
1087         if (streq(t, "0")) {
1088                 *usec = USEC_INFINITY;
1089                 return 0;
1090         }
1091
1092         return parse_sec(t, usec);
1093 }
1094
1095 int parse_nsec(const char *t, nsec_t *nsec) {
1096         static const struct {
1097                 const char *suffix;
1098                 nsec_t nsec;
1099         } table[] = {
1100                 { "seconds", NSEC_PER_SEC },
1101                 { "second", NSEC_PER_SEC },
1102                 { "sec", NSEC_PER_SEC },
1103                 { "s", NSEC_PER_SEC },
1104                 { "minutes", NSEC_PER_MINUTE },
1105                 { "minute", NSEC_PER_MINUTE },
1106                 { "min", NSEC_PER_MINUTE },
1107                 { "months", NSEC_PER_MONTH },
1108                 { "month", NSEC_PER_MONTH },
1109                 { "msec", NSEC_PER_MSEC },
1110                 { "ms", NSEC_PER_MSEC },
1111                 { "m", NSEC_PER_MINUTE },
1112                 { "hours", NSEC_PER_HOUR },
1113                 { "hour", NSEC_PER_HOUR },
1114                 { "hr", NSEC_PER_HOUR },
1115                 { "h", NSEC_PER_HOUR },
1116                 { "days", NSEC_PER_DAY },
1117                 { "day", NSEC_PER_DAY },
1118                 { "d", NSEC_PER_DAY },
1119                 { "weeks", NSEC_PER_WEEK },
1120                 { "week", NSEC_PER_WEEK },
1121                 { "w", NSEC_PER_WEEK },
1122                 { "years", NSEC_PER_YEAR },
1123                 { "year", NSEC_PER_YEAR },
1124                 { "y", NSEC_PER_YEAR },
1125                 { "usec", NSEC_PER_USEC },
1126                 { "us", NSEC_PER_USEC },
1127                 { "µs", NSEC_PER_USEC },
1128                 { "nsec", 1ULL },
1129                 { "ns", 1ULL },
1130                 { "", 1ULL }, /* default is nsec */
1131         };
1132
1133         const char *p, *s;
1134         nsec_t r = 0;
1135         bool something = false;
1136
1137         assert(t);
1138         assert(nsec);
1139
1140         p = t;
1141
1142         p += strspn(p, WHITESPACE);
1143         s = startswith(p, "infinity");
1144         if (s) {
1145                 s += strspn(s, WHITESPACE);
1146                 if (*s != 0)
1147                         return -EINVAL;
1148
1149                 *nsec = NSEC_INFINITY;
1150                 return 0;
1151         }
1152
1153         for (;;) {
1154                 long long l, z = 0;
1155                 size_t n = 0, i;
1156                 char *e;
1157
1158                 p += strspn(p, WHITESPACE);
1159
1160                 if (*p == 0) {
1161                         if (!something)
1162                                 return -EINVAL;
1163
1164                         break;
1165                 }
1166
1167                 errno = 0;
1168                 l = strtoll(p, &e, 10);
1169
1170                 if (errno > 0)
1171                         return -errno;
1172
1173                 if (l < 0)
1174                         return -ERANGE;
1175
1176                 if (*e == '.') {
1177                         char *b = e + 1;
1178
1179                         errno = 0;
1180                         z = strtoll(b, &e, 10);
1181                         if (errno > 0)
1182                                 return -errno;
1183
1184                         if (z < 0)
1185                                 return -ERANGE;
1186
1187                         if (e == b)
1188                                 return -EINVAL;
1189
1190                         n = e - b;
1191
1192                 } else if (e == p)
1193                         return -EINVAL;
1194
1195                 e += strspn(e, WHITESPACE);
1196
1197                 for (i = 0; i < ELEMENTSOF(table); i++)
1198                         if (startswith(e, table[i].suffix)) {
1199                                 nsec_t k = (nsec_t) z * table[i].nsec;
1200
1201                                 for (; n > 0; n--)
1202                                         k /= 10;
1203
1204                                 r += (nsec_t) l * table[i].nsec + k;
1205                                 p = e + strlen(table[i].suffix);
1206
1207                                 something = true;
1208                                 break;
1209                         }
1210
1211                 if (i >= ELEMENTSOF(table))
1212                         return -EINVAL;
1213
1214         }
1215
1216         *nsec = r;
1217
1218         return 0;
1219 }
1220
1221 bool ntp_synced(void) {
1222         struct timex txc = {};
1223
1224         if (adjtimex(&txc) < 0)
1225                 return false;
1226
1227         if (txc.status & STA_UNSYNC)
1228                 return false;
1229
1230         return true;
1231 }
1232
1233 int get_timezones(char ***ret) {
1234         _cleanup_fclose_ FILE *f = NULL;
1235         _cleanup_strv_free_ char **zones = NULL;
1236         size_t n_zones = 0, n_allocated = 0;
1237
1238         assert(ret);
1239
1240         zones = strv_new("UTC", NULL);
1241         if (!zones)
1242                 return -ENOMEM;
1243
1244         n_allocated = 2;
1245         n_zones = 1;
1246
1247         f = fopen("/usr/share/zoneinfo/zone.tab", "re");
1248         if (f) {
1249                 char l[LINE_MAX];
1250
1251                 FOREACH_LINE(l, f, return -errno) {
1252                         char *p, *w;
1253                         size_t k;
1254
1255                         p = strstrip(l);
1256
1257                         if (isempty(p) || *p == '#')
1258                                 continue;
1259
1260                         /* Skip over country code */
1261                         p += strcspn(p, WHITESPACE);
1262                         p += strspn(p, WHITESPACE);
1263
1264                         /* Skip over coordinates */
1265                         p += strcspn(p, WHITESPACE);
1266                         p += strspn(p, WHITESPACE);
1267
1268                         /* Found timezone name */
1269                         k = strcspn(p, WHITESPACE);
1270                         if (k <= 0)
1271                                 continue;
1272
1273                         w = strndup(p, k);
1274                         if (!w)
1275                                 return -ENOMEM;
1276
1277                         if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
1278                                 free(w);
1279                                 return -ENOMEM;
1280                         }
1281
1282                         zones[n_zones++] = w;
1283                         zones[n_zones] = NULL;
1284                 }
1285
1286                 strv_sort(zones);
1287
1288         } else if (errno != ENOENT)
1289                 return -errno;
1290
1291         *ret = TAKE_PTR(zones);
1292
1293         return 0;
1294 }
1295
1296 bool timezone_is_valid(const char *name, int log_level) {
1297         bool slash = false;
1298         const char *p, *t;
1299         _cleanup_close_ int fd = -1;
1300         char buf[4];
1301         int r;
1302
1303         if (isempty(name))
1304                 return false;
1305
1306         if (name[0] == '/')
1307                 return false;
1308
1309         for (p = name; *p; p++) {
1310                 if (!(*p >= '0' && *p <= '9') &&
1311                     !(*p >= 'a' && *p <= 'z') &&
1312                     !(*p >= 'A' && *p <= 'Z') &&
1313                     !IN_SET(*p, '-', '_', '+', '/'))
1314                         return false;
1315
1316                 if (*p == '/') {
1317
1318                         if (slash)
1319                                 return false;
1320
1321                         slash = true;
1322                 } else
1323                         slash = false;
1324         }
1325
1326         if (slash)
1327                 return false;
1328
1329         if (p - name >= PATH_MAX)
1330                 return false;
1331
1332         t = strjoina("/usr/share/zoneinfo/", name);
1333
1334         fd = open(t, O_RDONLY|O_CLOEXEC);
1335         if (fd < 0) {
1336                 log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
1337                 return false;
1338         }
1339
1340         r = fd_verify_regular(fd);
1341         if (r < 0) {
1342                 log_full_errno(log_level, r, "Timezone file '%s' is not  a regular file: %m", t);
1343                 return false;
1344         }
1345
1346         r = loop_read_exact(fd, buf, 4, false);
1347         if (r < 0) {
1348                 log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
1349                 return false;
1350         }
1351
1352         /* Magic from tzfile(5) */
1353         if (memcmp(buf, "TZif", 4) != 0) {
1354                 log_full(log_level, "Timezone file '%s' has wrong magic bytes", t);
1355                 return false;
1356         }
1357
1358         return true;
1359 }
1360
1361 #endif // 0
1362 bool clock_boottime_supported(void) {
1363         static int supported = -1;
1364
1365         /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
1366
1367         if (supported < 0) {
1368                 int fd;
1369
1370                 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1371                 if (fd < 0)
1372                         supported = false;
1373                 else {
1374                         safe_close(fd);
1375                         supported = true;
1376                 }
1377         }
1378
1379         return supported;
1380 }
1381
1382 #if 0 /// UNNEEDED by elogind
1383 clockid_t clock_boottime_or_monotonic(void) {
1384         if (clock_boottime_supported())
1385                 return CLOCK_BOOTTIME;
1386         else
1387                 return CLOCK_MONOTONIC;
1388 }
1389 #endif // 0
1390
1391 #if 1 /// let's add a diagnostic push to silence -Wimplicit-fallthrough to elogind
1392 #  if defined(__GNUC__) && (__GNUC__ > 6)
1393 #    pragma GCC diagnostic push
1394 #    pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
1395 #  endif // __GNUC__
1396 #endif // 1
1397 bool clock_supported(clockid_t clock) {
1398         struct timespec ts;
1399
1400         switch (clock) {
1401
1402         case CLOCK_MONOTONIC:
1403         case CLOCK_REALTIME:
1404                 return true;
1405
1406         case CLOCK_BOOTTIME:
1407                 return clock_boottime_supported();
1408
1409         case CLOCK_BOOTTIME_ALARM:
1410                 if (!clock_boottime_supported())
1411                         return false;
1412
1413                 _fallthrough_;
1414         default:
1415                 /* For everything else, check properly */
1416                 return clock_gettime(clock, &ts) >= 0;
1417         }
1418 }
1419 #if 1 /// end diagnostic push in elogind
1420 #  ifdef __GNUC__
1421 #    pragma GCC diagnostic pop
1422 #  endif // __GNUC__
1423 #endif // 1
1424
1425 #if 0 /// UNNEEDED by elogind
1426 int get_timezone(char **tz) {
1427         _cleanup_free_ char *t = NULL;
1428         const char *e;
1429         char *z;
1430         int r;
1431
1432         r = readlink_malloc("/etc/localtime", &t);
1433         if (r < 0)
1434                 return r; /* returns EINVAL if not a symlink */
1435
1436         e = path_startswith(t, "/usr/share/zoneinfo/");
1437         if (!e)
1438                 e = path_startswith(t, "../usr/share/zoneinfo/");
1439         if (!e)
1440                 return -EINVAL;
1441
1442         if (!timezone_is_valid(e, LOG_DEBUG))
1443                 return -EINVAL;
1444
1445         z = strdup(e);
1446         if (!z)
1447                 return -ENOMEM;
1448
1449         *tz = z;
1450         return 0;
1451 }
1452
1453 time_t mktime_or_timegm(struct tm *tm, bool utc) {
1454         return utc ? timegm(tm) : mktime(tm);
1455 }
1456 #endif // 0
1457
1458 struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
1459         return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
1460 }
1461
1462 #if 0 /// UNNEEDED by elogind
1463 unsigned long usec_to_jiffies(usec_t u) {
1464         static thread_local unsigned long hz = 0;
1465         long r;
1466
1467         if (hz == 0) {
1468                 r = sysconf(_SC_CLK_TCK);
1469
1470                 assert(r > 0);
1471                 hz = r;
1472         }
1473
1474         return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
1475 }
1476
1477 usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
1478         usec_t a, b;
1479
1480         if (x == USEC_INFINITY)
1481                 return USEC_INFINITY;
1482         if (map_clock_id(from) == map_clock_id(to))
1483                 return x;
1484
1485         a = now(from);
1486         b = now(to);
1487
1488         if (x > a)
1489                 /* x lies in the future */
1490                 return usec_add(b, usec_sub_unsigned(x, a));
1491         else
1492                 /* x lies in the past */
1493                 return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
1494 }
1495 #endif // 0
1496
1497 bool in_utc_timezone(void) {
1498         tzset();
1499
1500         return timezone == 0 && daylight == 0;
1501 }
1502
1503 int time_change_fd(void) {
1504
1505         /* We only care for the cancellation event, hence we set the timeout to the latest possible value. */
1506         static const struct itimerspec its = {
1507                 .it_value.tv_sec = TIME_T_MAX,
1508         };
1509
1510         _cleanup_close_ int fd;
1511
1512         assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
1513
1514         /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever CLOCK_REALTIME makes a jump relative to
1515          * CLOCK_MONOTONIC. */
1516
1517         fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1518         if (fd < 0)
1519                 return -errno;
1520
1521         if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0)
1522                 return -errno;
1523
1524         return TAKE_FD(fd);
1525 }