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