Bug Summary

File:build-scan/../src/basic/time-util.c
Warning:line 751, column 29
The left operand of '!=' is a garbage value due to array index out of bounds

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name time-util.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/basic/libbasic.a.p -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/blkid -I /usr/include/libmount -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/basic/time-util.c

../src/basic/time-util.c

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

../src/basic/string-util.h

1/* SPDX-License-Identifier: LGPL-2.1+ */
2#pragma once
3
4#include <alloca.h>
5#include <stdbool.h>
6#include <stddef.h>
7#include <string.h>
8
9#include "macro.h"
10
11/* What is interpreted as whitespace? */
12#define WHITESPACE" \t\n\r" " \t\n\r"
13#define NEWLINE"\n\r" "\n\r"
14#define QUOTES"\"\'" "\"\'"
15#define COMMENTS"#;" "#;"
16#define GLOB_CHARS"*?[" "*?["
17#define DIGITS"0123456789" "0123456789"
18#define LOWERCASE_LETTERS"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
19#define UPPERCASE_LETTERS"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
20#define LETTERS"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" LOWERCASE_LETTERS"abcdefghijklmnopqrstuvwxyz" UPPERCASE_LETTERS"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
21#define ALPHANUMERICAL"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" LETTERS"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" DIGITS"0123456789"
22#define HEXDIGITS"0123456789" "abcdefABCDEF" DIGITS"0123456789" "abcdefABCDEF"
23
24#define streq(a,b)(strcmp((a),(b)) == 0) (strcmp((a),(b)) == 0)
25#define strneq(a, b, n)(strncmp((a), (b), (n)) == 0) (strncmp((a), (b), (n)) == 0)
26#define strcaseeq(a,b)(strcasecmp((a),(b)) == 0) (strcasecmp((a),(b)) == 0)
27#define strncaseeq(a, b, n)(strncasecmp((a), (b), (n)) == 0) (strncasecmp((a), (b), (n)) == 0)
28
29int strcmp_ptr(const char *a, const char *b) _pure___attribute__ ((pure));
30
31static inline bool_Bool streq_ptr(const char *a, const char *b) {
32 return strcmp_ptr(a, b) == 0;
33}
34
35static inline const char* strempty(const char *s) {
36 return s ?: "";
37}
38
39static inline const char* strnull(const char *s) {
40 return s ?: "(null)";
41}
42
43static inline const char *strna(const char *s) {
44 return s ?: "n/a";
45}
46
47static inline bool_Bool isempty(const char *p) {
48 return !p || !p[0];
49}
50
51static inline const char *empty_to_null(const char *p) {
52 return isempty(p) ? NULL((void*)0) : p;
53}
54
55static inline const char *empty_to_dash(const char *str) {
56 return isempty(str) ? "-" : str;
57}
58
59static inline char *startswith(const char *s, const char *prefix) {
60 size_t l;
61
62 l = strlen(prefix);
63 if (strncmp(s, prefix, l) == 0)
64 return (char*) s + l;
65
66 return NULL((void*)0);
67}
68
69static inline char *startswith_no_case(const char *s, const char *prefix) {
70 size_t l;
71
72 l = strlen(prefix);
73 if (strncasecmp(s, prefix, l) == 0)
37
Assuming the condition is true
38
Taking true branch
74 return (char*) s + l;
39
Returning pointer, which participates in a condition later
75
76 return NULL((void*)0);
77}
78
79char *endswith(const char *s, const char *postfix) _pure___attribute__ ((pure));
80char *endswith_no_case(const char *s, const char *postfix) _pure___attribute__ ((pure));
81
82char *first_word(const char *s, const char *word) _pure___attribute__ ((pure));
83
84const char* split(const char **state, size_t *l, const char *separator, bool_Bool quoted);
85
86#define FOREACH_WORD(word, length, s, state)for ((state) = (s), (word) = split(&(state), &(length
), (" \t\n\r"), (0)); (word); (word) = split(&(state), &
(length), (" \t\n\r"), (0)))
\
87 _FOREACH_WORD(word, length, s, WHITESPACE, false, state)for ((state) = (s), (word) = split(&(state), &(length
), (" \t\n\r"), (0)); (word); (word) = split(&(state), &
(length), (" \t\n\r"), (0)))
88
89#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)for ((state) = (s), (word) = split(&(state), &(length
), (separator), (0)); (word); (word) = split(&(state), &
(length), (separator), (0)))
\
90 _FOREACH_WORD(word, length, s, separator, false, state)for ((state) = (s), (word) = split(&(state), &(length
), (separator), (0)); (word); (word) = split(&(state), &
(length), (separator), (0)))
91
92#define _FOREACH_WORD(word, length, s, separator, quoted, state)for ((state) = (s), (word) = split(&(state), &(length
), (separator), (quoted)); (word); (word) = split(&(state
), &(length), (separator), (quoted)))
\
93 for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
94
95char *strappend(const char *s, const char *suffix);
96char *strnappend(const char *s, const char *suffix, size_t length);
97
98char *strjoin_real(const char *x, ...) _sentinel___attribute__ ((sentinel));
99#define strjoin(a, ...)strjoin_real((a), ..., ((void*)0)) strjoin_real((a), __VA_ARGS__, NULL((void*)0))
100
101#define strjoina(a, ...)({ const char *_appendees_[] = { a, ... }; char *_d_, *_p_; size_t
_len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (
__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_
), typeof(&*(_appendees_))), sizeof(_appendees_)/sizeof((
_appendees_)[0]), ((void)0))) && _appendees_[_i_]; _i_
++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
\
102 ({ \
103 const char *_appendees_[] = { a, __VA_ARGS__ }; \
104 char *_d_, *_p_; \
105 size_t _len_ = 0; \
106 size_t _i_; \
107 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0)))
&& _appendees_[_i_]; _i_++) \
108 _len_ += strlen(_appendees_[_i_]); \
109 _p_ = _d_ = alloca(_len_ + 1)__builtin_alloca (_len_ + 1); \
110 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0)))
&& _appendees_[_i_]; _i_++) \
111 _p_ = stpcpy(_p_, _appendees_[_i_]); \
112 *_p_ = 0; \
113 _d_; \
114 })
115
116char *strstrip(char *s);
117char *delete_chars(char *s, const char *bad);
118char *delete_trailing_chars(char *s, const char *bad);
119char *truncate_nl(char *s);
120
121static inline char *skip_leading_chars(const char *s, const char *bad) {
122
123 if (!s)
124 return NULL((void*)0);
125
126 if (!bad)
127 bad = WHITESPACE" \t\n\r";
128
129 return (char*) s + strspn(s, bad);
130}
131
132char ascii_tolower(char x);
133char *ascii_strlower(char *s);
134char *ascii_strlower_n(char *s, size_t n);
135
136char ascii_toupper(char x);
137char *ascii_strupper(char *s);
138
139int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
140int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);
141
142bool_Bool chars_intersect(const char *a, const char *b) _pure___attribute__ ((pure));
143
144static inline bool_Bool _pure___attribute__ ((pure)) in_charset(const char *s, const char* charset) {
145 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/string-util.h", 145,
__PRETTY_FUNCTION__); } while (0)
;
146 assert(charset)do { if ((__builtin_expect(!!(!(charset)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("charset"), "../src/basic/string-util.h"
, 146, __PRETTY_FUNCTION__); } while (0)
;
147 return s[strspn(s, charset)] == '\0';
148}
149
150bool_Bool string_has_cc(const char *p, const char *ok) _pure___attribute__ ((pure));
151
152char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
153static inline char *ellipsize(const char *s, size_t length, unsigned percent) {
154 return ellipsize_mem(s, strlen(s), length, percent);
155}
156
157char *cellescape(char *buf, size_t len, const char *s);
158
159/* This limit is arbitrary, enough to give some idea what the string contains */
160#define CELLESCAPE_DEFAULT_LENGTH64 64
161
162bool_Bool nulstr_contains(const char *nulstr, const char *needle);
163
164char* strshorten(char *s, size_t l);
165
166char *strreplace(const char *text, const char *old_string, const char *new_string);
167
168char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
169
170char *strextend_with_separator(char **x, const char *separator, ...) _sentinel___attribute__ ((sentinel));
171
172#define strextend(x, ...)strextend_with_separator(x, ((void*)0), ...) strextend_with_separator(x, NULL((void*)0), __VA_ARGS__)
173
174char *strrep(const char *s, unsigned n);
175
176int split_pair(const char *s, const char *sep, char **l, char **r);
177
178int free_and_strdup(char **p, const char *s);
179int free_and_strndup(char **p, const char *s, size_t l);
180
181/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
182static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
183
184 if (needlelen <= 0)
185 return (void*) haystack;
186
187 if (haystacklen < needlelen)
188 return NULL((void*)0);
189
190 assert(haystack)do { if ((__builtin_expect(!!(!(haystack)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("haystack"), "../src/basic/string-util.h"
, 190, __PRETTY_FUNCTION__); } while (0)
;
191 assert(needle)do { if ((__builtin_expect(!!(!(needle)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("needle"), "../src/basic/string-util.h",
191, __PRETTY_FUNCTION__); } while (0)
;
192
193 return memmem(haystack, haystacklen, needle, needlelen);
194}
195
196#if !HAVE_EXPLICIT_BZERO1
197void explicit_bzero(void *p, size_t l);
198#endif
199
200char *string_erase(char *x);
201
202char *string_free_erase(char *s);
203DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase)static inline void string_free_erasep(char * *p) { if (*p) string_free_erase
(*p); }
;
204#define _cleanup_string_free_erase___attribute__((cleanup(string_free_erasep))) _cleanup_(string_free_erasep)__attribute__((cleanup(string_free_erasep)))
205
206bool_Bool string_is_safe(const char *p) _pure___attribute__ ((pure));
207
208static inline size_t strlen_ptr(const char *s) {
209 if (!s)
210 return 0;
211
212 return strlen(s);
213}
214
215/* Like startswith(), but operates on arbitrary memory blocks */
216static inline void *memory_startswith(const void *p, size_t sz, const char *token) {
217 size_t n;
218
219 assert(token)do { if ((__builtin_expect(!!(!(token)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("token"), "../src/basic/string-util.h", 219
, __PRETTY_FUNCTION__); } while (0)
;
220
221 n = strlen(token);
222 if (sz < n)
223 return NULL((void*)0);
224
225 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/string-util.h", 225,
__PRETTY_FUNCTION__); } while (0)
;
226
227 if (memcmp(p, token, n) != 0)
228 return NULL((void*)0);
229
230 return (uint8_t*) p + n;
231}