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