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