/src/systemd/src/basic/time-util.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | #pragma once |
3 | | |
4 | | #include <inttypes.h> |
5 | | #include <stdbool.h> |
6 | | #include <stddef.h> |
7 | | #include <stdint.h> |
8 | | #include <stdio.h> |
9 | | #include <time.h> |
10 | | |
11 | | typedef uint64_t usec_t; |
12 | | typedef uint64_t nsec_t; |
13 | | |
14 | | #define PRI_NSEC PRIu64 |
15 | | #define PRI_USEC PRIu64 |
16 | | #define NSEC_FMT "%" PRI_NSEC |
17 | | #define USEC_FMT "%" PRI_USEC |
18 | | |
19 | | #include "macro.h" |
20 | | |
21 | | typedef struct dual_timestamp { |
22 | | usec_t realtime; |
23 | | usec_t monotonic; |
24 | | } dual_timestamp; |
25 | | |
26 | | typedef struct triple_timestamp { |
27 | | usec_t realtime; |
28 | | usec_t monotonic; |
29 | | usec_t boottime; |
30 | | } triple_timestamp; |
31 | | |
32 | | typedef enum TimestampStyle { |
33 | | TIMESTAMP_PRETTY, |
34 | | TIMESTAMP_US, |
35 | | TIMESTAMP_UTC, |
36 | | TIMESTAMP_US_UTC, |
37 | | TIMESTAMP_UNIX, |
38 | | _TIMESTAMP_STYLE_MAX, |
39 | | _TIMESTAMP_STYLE_INVALID = -EINVAL, |
40 | | } TimestampStyle; |
41 | | |
42 | | #define USEC_INFINITY ((usec_t) UINT64_MAX) |
43 | | #define NSEC_INFINITY ((nsec_t) UINT64_MAX) |
44 | | |
45 | | #define MSEC_PER_SEC 1000ULL |
46 | | #define USEC_PER_SEC ((usec_t) 1000000ULL) |
47 | | #define USEC_PER_MSEC ((usec_t) 1000ULL) |
48 | | #define NSEC_PER_SEC ((nsec_t) 1000000000ULL) |
49 | | #define NSEC_PER_MSEC ((nsec_t) 1000000ULL) |
50 | | #define NSEC_PER_USEC ((nsec_t) 1000ULL) |
51 | | |
52 | | #define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC)) |
53 | | #define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC)) |
54 | | #define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE)) |
55 | | #define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE)) |
56 | | #define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR)) |
57 | | #define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR)) |
58 | | #define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY)) |
59 | | #define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY)) |
60 | | #define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC)) |
61 | | #define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC)) |
62 | | #define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC)) |
63 | | #define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC)) |
64 | | |
65 | | /* We assume a maximum timezone length of 6. TZNAME_MAX is not defined on Linux, but glibc internally initializes this |
66 | | * to 6. Let's rely on that. */ |
67 | | #define FORMAT_TIMESTAMP_MAX (3U+1U+10U+1U+8U+1U+6U+1U+6U+1U) |
68 | | #define FORMAT_TIMESTAMP_WIDTH 28U /* when outputting, assume this width */ |
69 | | #define FORMAT_TIMESTAMP_RELATIVE_MAX 256U |
70 | | #define FORMAT_TIMESPAN_MAX 64U |
71 | | |
72 | | #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1) |
73 | | |
74 | | #define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {}) |
75 | | #define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {}) |
76 | | |
77 | | usec_t now(clockid_t clock); |
78 | | nsec_t now_nsec(clockid_t clock); |
79 | | |
80 | | usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock); |
81 | | |
82 | | dual_timestamp* dual_timestamp_get(dual_timestamp *ts); |
83 | | dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); |
84 | | dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); |
85 | | dual_timestamp* dual_timestamp_from_boottime(dual_timestamp *ts, usec_t u); |
86 | | |
87 | | triple_timestamp* triple_timestamp_get(triple_timestamp *ts); |
88 | | triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u); |
89 | | |
90 | | #define DUAL_TIMESTAMP_HAS_CLOCK(clock) \ |
91 | | IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC) |
92 | | |
93 | | #define TRIPLE_TIMESTAMP_HAS_CLOCK(clock) \ |
94 | | IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) |
95 | | |
96 | 0 | static inline bool timestamp_is_set(usec_t timestamp) { |
97 | 0 | return timestamp > 0 && timestamp != USEC_INFINITY; |
98 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:timestamp_is_set Unexecuted instantiation: link-config.c:timestamp_is_set Unexecuted instantiation: link-config-gperf.c:timestamp_is_set |
99 | | |
100 | 0 | static inline bool dual_timestamp_is_set(const dual_timestamp *ts) { |
101 | 0 | return timestamp_is_set(ts->realtime) || |
102 | 0 | timestamp_is_set(ts->monotonic); |
103 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:dual_timestamp_is_set Unexecuted instantiation: link-config.c:dual_timestamp_is_set Unexecuted instantiation: link-config-gperf.c:dual_timestamp_is_set |
104 | | |
105 | 0 | static inline bool triple_timestamp_is_set(const triple_timestamp *ts) { |
106 | 0 | return timestamp_is_set(ts->realtime) || |
107 | 0 | timestamp_is_set(ts->monotonic) || |
108 | 0 | timestamp_is_set(ts->boottime); |
109 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:triple_timestamp_is_set Unexecuted instantiation: link-config.c:triple_timestamp_is_set Unexecuted instantiation: link-config-gperf.c:triple_timestamp_is_set |
110 | | |
111 | | usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock); |
112 | | |
113 | | usec_t timespec_load(const struct timespec *ts) _pure_; |
114 | | nsec_t timespec_load_nsec(const struct timespec *ts) _pure_; |
115 | | struct timespec* timespec_store(struct timespec *ts, usec_t u); |
116 | | struct timespec* timespec_store_nsec(struct timespec *ts, nsec_t n); |
117 | | |
118 | | #define TIMESPEC_STORE(u) timespec_store(&(struct timespec) {}, (u)) |
119 | | |
120 | | usec_t timeval_load(const struct timeval *tv) _pure_; |
121 | | struct timeval* timeval_store(struct timeval *tv, usec_t u); |
122 | | |
123 | | #define TIMEVAL_STORE(u) timeval_store(&(struct timeval) {}, (u)) |
124 | | |
125 | | char* format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style) _warn_unused_result_; |
126 | | char* format_timestamp_relative(char *buf, size_t l, usec_t t) _warn_unused_result_; |
127 | | char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) _warn_unused_result_; |
128 | | |
129 | | _warn_unused_result_ |
130 | 0 | static inline char* format_timestamp(char *buf, size_t l, usec_t t) { |
131 | 0 | return format_timestamp_style(buf, l, t, TIMESTAMP_PRETTY); |
132 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:format_timestamp Unexecuted instantiation: link-config.c:format_timestamp Unexecuted instantiation: link-config-gperf.c:format_timestamp |
133 | | |
134 | | /* Note: the lifetime of the compound literal is the immediately surrounding block, |
135 | | * see C11 ยง6.5.2.5, and |
136 | | * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */ |
137 | | #define FORMAT_TIMESTAMP(t) format_timestamp((char[FORMAT_TIMESTAMP_MAX]){}, FORMAT_TIMESTAMP_MAX, t) |
138 | | #define FORMAT_TIMESTAMP_RELATIVE(t) \ |
139 | | format_timestamp_relative((char[FORMAT_TIMESTAMP_RELATIVE_MAX]){}, FORMAT_TIMESTAMP_RELATIVE_MAX, t) |
140 | | #define FORMAT_TIMESPAN(t, accuracy) format_timespan((char[FORMAT_TIMESPAN_MAX]){}, FORMAT_TIMESPAN_MAX, t, accuracy) |
141 | | #define FORMAT_TIMESTAMP_STYLE(t, style) \ |
142 | | format_timestamp_style((char[FORMAT_TIMESTAMP_MAX]){}, FORMAT_TIMESTAMP_MAX, t, style) |
143 | | |
144 | | int parse_timestamp(const char *t, usec_t *usec); |
145 | | |
146 | | int parse_sec(const char *t, usec_t *usec); |
147 | | int parse_sec_fix_0(const char *t, usec_t *usec); |
148 | | int parse_sec_def_infinity(const char *t, usec_t *usec); |
149 | | int parse_time(const char *t, usec_t *usec, usec_t default_unit); |
150 | | int parse_nsec(const char *t, nsec_t *nsec); |
151 | | |
152 | | int get_timezones(char ***l); |
153 | | int verify_timezone(const char *name, int log_level); |
154 | 0 | static inline bool timezone_is_valid(const char *name, int log_level) { |
155 | 0 | return verify_timezone(name, log_level) >= 0; |
156 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:timezone_is_valid Unexecuted instantiation: link-config.c:timezone_is_valid Unexecuted instantiation: link-config-gperf.c:timezone_is_valid |
157 | | |
158 | | bool clock_supported(clockid_t clock); |
159 | | |
160 | | usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to); |
161 | | |
162 | | int get_timezone(char **timezone); |
163 | | |
164 | | time_t mktime_or_timegm(struct tm *tm, bool utc); |
165 | | struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc); |
166 | | |
167 | | uint32_t usec_to_jiffies(usec_t usec); |
168 | | usec_t jiffies_to_usec(uint32_t jiffies); |
169 | | |
170 | | bool in_utc_timezone(void); |
171 | | |
172 | 0 | static inline usec_t usec_add(usec_t a, usec_t b) { |
173 | 0 | /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, |
174 | 0 | * and doesn't overflow. */ |
175 | 0 |
|
176 | 0 | if (a > USEC_INFINITY - b) /* overflow check */ |
177 | 0 | return USEC_INFINITY; |
178 | 0 |
|
179 | 0 | return a + b; |
180 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:usec_add Unexecuted instantiation: link-config.c:usec_add Unexecuted instantiation: link-config-gperf.c:usec_add |
181 | | |
182 | 0 | static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) { |
183 | 0 | if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */ |
184 | 0 | return USEC_INFINITY; |
185 | 0 | if (timestamp < delta) |
186 | 0 | return 0; |
187 | 0 |
|
188 | 0 | return timestamp - delta; |
189 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:usec_sub_unsigned Unexecuted instantiation: link-config.c:usec_sub_unsigned Unexecuted instantiation: link-config-gperf.c:usec_sub_unsigned |
190 | | |
191 | 0 | static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) { |
192 | 0 | if (delta == INT64_MIN) { /* prevent overflow */ |
193 | 0 | assert_cc(-(INT64_MIN + 1) == INT64_MAX); |
194 | 0 | assert_cc(USEC_INFINITY > INT64_MAX); |
195 | 0 | return usec_add(timestamp, (usec_t) INT64_MAX + 1); |
196 | 0 | } |
197 | 0 | if (delta < 0) |
198 | 0 | return usec_add(timestamp, (usec_t) (-delta)); |
199 | 0 |
|
200 | 0 | return usec_sub_unsigned(timestamp, (usec_t) delta); |
201 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:usec_sub_signed Unexecuted instantiation: link-config.c:usec_sub_signed Unexecuted instantiation: link-config-gperf.c:usec_sub_signed |
202 | | |
203 | | #if SIZEOF_TIME_T == 8 |
204 | | /* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit |
205 | | * year territory. However, since we want to stay away from this in all timezones we take one day off. */ |
206 | | # define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 253402214399000000) |
207 | | #elif SIZEOF_TIME_T == 4 |
208 | | /* With a 32bit time_t we can't go beyond 2038... */ |
209 | | # define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000) |
210 | | #else |
211 | | # error "Yuck, time_t is neither 4 nor 8 bytes wide?" |
212 | | #endif |
213 | | |
214 | | int time_change_fd(void); |
215 | | |
216 | | const char* timestamp_style_to_string(TimestampStyle t) _const_; |
217 | | TimestampStyle timestamp_style_from_string(const char *s) _pure_; |