/src/sudo/lib/util/gettime.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * SPDX-License-Identifier: ISC |
3 | | * |
4 | | * Copyright (c) 2014-2018 Todd C. Miller <Todd.Miller@sudo.ws> |
5 | | * |
6 | | * Permission to use, copy, modify, and distribute this software for any |
7 | | * purpose with or without fee is hereby granted, provided that the above |
8 | | * copyright notice and this permission notice appear in all copies. |
9 | | * |
10 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | | */ |
18 | | |
19 | | /* |
20 | | * This is an open source non-commercial project. Dear PVS-Studio, please check it. |
21 | | * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com |
22 | | */ |
23 | | |
24 | | #include <config.h> |
25 | | |
26 | | #include <sys/time.h> |
27 | | #include <time.h> |
28 | | |
29 | | #if defined(__MACH__) && !defined(HAVE_CLOCK_GETTIME) |
30 | | # include <mach/mach.h> |
31 | | # include <mach/mach_time.h> |
32 | | # include <mach/clock.h> |
33 | | #endif |
34 | | |
35 | | #include "sudo_compat.h" |
36 | | #include "sudo_debug.h" |
37 | | #include "sudo_util.h" |
38 | | |
39 | | /* |
40 | | * On Linux and FreeBSD, CLOCK_MONOTONIC does not run while sleeping. |
41 | | * Linux provides CLOCK_BOOTTIME which runs while sleeping (FreeBSD does not). |
42 | | * Some systems provide CLOCK_UPTIME which only runs while awake. |
43 | | */ |
44 | | #if defined(CLOCK_BOOTTIME) |
45 | 0 | # define SUDO_CLOCK_BOOTTIME CLOCK_BOOTTIME |
46 | | #elif defined(CLOCK_MONOTONIC_RAW) |
47 | | # define SUDO_CLOCK_BOOTTIME CLOCK_MONOTONIC_RAW |
48 | | #elif defined(CLOCK_MONOTONIC) |
49 | | # define SUDO_CLOCK_BOOTTIME CLOCK_MONOTONIC |
50 | | #endif |
51 | | #if defined(CLOCK_UPTIME_RAW) |
52 | | # define SUDO_CLOCK_UPTIME CLOCK_UPTIME_RAW |
53 | | #elif defined(CLOCK_UPTIME) |
54 | | # define SUDO_CLOCK_UPTIME CLOCK_UPTIME |
55 | | #elif defined(CLOCK_MONOTONIC) |
56 | 0 | # define SUDO_CLOCK_UPTIME CLOCK_MONOTONIC |
57 | | #endif |
58 | | |
59 | | /* |
60 | | * Wall clock time, may run backward. |
61 | | */ |
62 | | #if defined(HAVE_CLOCK_GETTIME) |
63 | | int |
64 | | sudo_gettime_real_v1(struct timespec *ts) |
65 | 26.9k | { |
66 | 26.9k | debug_decl(sudo_gettime_real, SUDO_DEBUG_UTIL); |
67 | | |
68 | 26.9k | if (clock_gettime(CLOCK_REALTIME, ts) == -1) { |
69 | 0 | struct timeval tv; |
70 | |
|
71 | 0 | sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, |
72 | 0 | "clock_gettime(CLOCK_REALTIME) failed, trying gettimeofday()"); |
73 | 0 | if (gettimeofday(&tv, NULL) == -1) |
74 | 0 | debug_return_int(-1); |
75 | 0 | TIMEVAL_TO_TIMESPEC(&tv, ts); |
76 | 0 | } |
77 | 26.9k | debug_return_int(0); |
78 | 26.9k | } |
79 | | #else |
80 | | int |
81 | | sudo_gettime_real_v1(struct timespec *ts) |
82 | | { |
83 | | struct timeval tv; |
84 | | debug_decl(sudo_gettime_real, SUDO_DEBUG_UTIL); |
85 | | |
86 | | if (gettimeofday(&tv, NULL) == -1) |
87 | | debug_return_int(-1); |
88 | | TIMEVAL_TO_TIMESPEC(&tv, ts); |
89 | | debug_return_int(0); |
90 | | } |
91 | | #endif |
92 | | |
93 | | /* |
94 | | * Monotonic time, only runs forward. |
95 | | * We use a timer that only increments while sleeping, if possible. |
96 | | */ |
97 | | #if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_BOOTTIME) |
98 | | int |
99 | | sudo_gettime_mono_v1(struct timespec *ts) |
100 | 0 | { |
101 | 0 | static int has_monoclock = -1; |
102 | 0 | debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL); |
103 | | |
104 | | /* Check whether the kernel/libc actually supports a monotonic clock. */ |
105 | 0 | # ifdef _SC_MONOTONIC_CLOCK |
106 | 0 | if (has_monoclock == -1) |
107 | 0 | has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1; |
108 | 0 | # endif |
109 | 0 | if (!has_monoclock) |
110 | 0 | debug_return_int(sudo_gettime_real(ts)); |
111 | 0 | if (clock_gettime(SUDO_CLOCK_BOOTTIME, ts) == -1) { |
112 | 0 | sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, |
113 | 0 | "clock_gettime(%d) failed, using wall clock", |
114 | 0 | (int)SUDO_CLOCK_BOOTTIME); |
115 | 0 | has_monoclock = 0; |
116 | 0 | debug_return_int(sudo_gettime_real(ts)); |
117 | 0 | } |
118 | 0 | debug_return_int(0); |
119 | 0 | } |
120 | | #elif defined(HAVE_GETHRTIME) |
121 | | int |
122 | | sudo_gettime_mono_v1(struct timespec *ts) |
123 | | { |
124 | | hrtime_t nsec; |
125 | | debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL); |
126 | | |
127 | | nsec = gethrtime(); |
128 | | ts->tv_sec = nsec / 1000000000; |
129 | | ts->tv_nsec = nsec % 1000000000; |
130 | | debug_return_int(0); |
131 | | } |
132 | | #elif defined(__MACH__) |
133 | | int |
134 | | sudo_gettime_mono_v1(struct timespec *ts) |
135 | | { |
136 | | uint64_t abstime, nsec; |
137 | | static mach_timebase_info_data_t timebase_info; |
138 | | debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL); |
139 | | |
140 | | if (timebase_info.denom == 0) |
141 | | (void) mach_timebase_info(&timebase_info); |
142 | | #ifdef HAVE_MACH_CONTINUOUS_TIME |
143 | | abstime = mach_continuous_time(); /* runs while asleep */ |
144 | | #else |
145 | | abstime = mach_absolute_time(); /* doesn't run while asleep */ |
146 | | #endif |
147 | | nsec = abstime * timebase_info.numer / timebase_info.denom; |
148 | | ts->tv_sec = nsec / 1000000000; |
149 | | ts->tv_nsec = nsec % 1000000000; |
150 | | debug_return_int(0); |
151 | | } |
152 | | #else |
153 | | int |
154 | | sudo_gettime_mono_v1(struct timespec *ts) |
155 | | { |
156 | | /* No monotonic clock available, use wall clock. */ |
157 | | return sudo_gettime_real(ts); |
158 | | } |
159 | | #endif |
160 | | |
161 | | /* |
162 | | * Monotonic time, only runs forward. |
163 | | * We use a timer that only increments while awake, if possible. |
164 | | */ |
165 | | #if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_UPTIME) |
166 | | int |
167 | | sudo_gettime_awake_v1(struct timespec *ts) |
168 | 0 | { |
169 | 0 | static int has_monoclock = -1; |
170 | 0 | debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL); |
171 | | |
172 | | /* Check whether the kernel/libc actually supports a monotonic clock. */ |
173 | 0 | # ifdef _SC_MONOTONIC_CLOCK |
174 | 0 | if (has_monoclock == -1) |
175 | 0 | has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1; |
176 | 0 | # endif |
177 | 0 | if (!has_monoclock) |
178 | 0 | debug_return_int(sudo_gettime_real(ts)); |
179 | 0 | if (clock_gettime(SUDO_CLOCK_UPTIME, ts) == -1) { |
180 | 0 | sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, |
181 | 0 | "clock_gettime(%d) failed, using wall clock", |
182 | 0 | (int)SUDO_CLOCK_UPTIME); |
183 | 0 | has_monoclock = 0; |
184 | 0 | debug_return_int(sudo_gettime_real(ts)); |
185 | 0 | } |
186 | 0 | debug_return_int(0); |
187 | 0 | } |
188 | | #elif defined(HAVE_GETHRTIME) |
189 | | int |
190 | | sudo_gettime_awake_v1(struct timespec *ts) |
191 | | { |
192 | | hrtime_t nsec; |
193 | | debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL); |
194 | | |
195 | | /* Currently the same as sudo_gettime_mono() */ |
196 | | nsec = gethrtime(); |
197 | | ts->tv_sec = nsec / 1000000000; |
198 | | ts->tv_nsec = nsec % 1000000000; |
199 | | debug_return_int(0); |
200 | | } |
201 | | #elif defined(__MACH__) |
202 | | int |
203 | | sudo_gettime_awake_v1(struct timespec *ts) |
204 | | { |
205 | | uint64_t abstime, nsec; |
206 | | static mach_timebase_info_data_t timebase_info; |
207 | | debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL); |
208 | | |
209 | | if (timebase_info.denom == 0) |
210 | | (void) mach_timebase_info(&timebase_info); |
211 | | abstime = mach_absolute_time(); |
212 | | nsec = abstime * timebase_info.numer / timebase_info.denom; |
213 | | ts->tv_sec = nsec / 1000000000; |
214 | | ts->tv_nsec = nsec % 1000000000; |
215 | | debug_return_int(0); |
216 | | } |
217 | | #else |
218 | | int |
219 | | sudo_gettime_awake_v1(struct timespec *ts) |
220 | | { |
221 | | /* No monotonic uptime clock available, use wall clock. */ |
222 | | return sudo_gettime_real(ts); |
223 | | } |
224 | | #endif |