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