Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/lib/util/gettime.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2014-2018 Todd C. Miller <[email protected]>
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
#include <config.h>
20
21
#include <sys/time.h>
22
#include <time.h>
23
24
#if defined(__MACH__) && !defined(HAVE_CLOCK_GETTIME)
25
# include <mach/mach.h>
26
# include <mach/mach_time.h>
27
# include <mach/clock.h>
28
#endif
29
30
#include <sudo_compat.h>
31
#include <sudo_debug.h>
32
#include <sudo_util.h>
33
34
/*
35
* On Linux and FreeBSD, CLOCK_MONOTONIC does not run while sleeping.
36
* Linux provides CLOCK_BOOTTIME which runs while sleeping (FreeBSD does not).
37
* Some systems provide CLOCK_UPTIME which only runs while awake.
38
*/
39
#if defined(CLOCK_BOOTTIME)
40
# define SUDO_CLOCK_BOOTTIME CLOCK_BOOTTIME
41
#elif defined(CLOCK_MONOTONIC_RAW)
42
# define SUDO_CLOCK_BOOTTIME CLOCK_MONOTONIC_RAW
43
#elif defined(CLOCK_MONOTONIC)
44
# define SUDO_CLOCK_BOOTTIME CLOCK_MONOTONIC
45
#endif
46
#if defined(CLOCK_UPTIME_RAW)
47
# define SUDO_CLOCK_UPTIME CLOCK_UPTIME_RAW
48
#elif defined(CLOCK_UPTIME)
49
# define SUDO_CLOCK_UPTIME CLOCK_UPTIME
50
#elif defined(CLOCK_MONOTONIC)
51
# define SUDO_CLOCK_UPTIME CLOCK_MONOTONIC
52
#endif
53
54
/*
55
* Wall clock time, may run backward.
56
*/
57
#if defined(HAVE_CLOCK_GETTIME)
58
int
59
sudo_gettime_real_v1(struct timespec *ts)
60
{
61
debug_decl(sudo_gettime_real, SUDO_DEBUG_UTIL);
62
63
if (clock_gettime(CLOCK_REALTIME, ts) == -1) {
64
struct timeval tv;
65
66
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
67
"clock_gettime(CLOCK_REALTIME) failed, trying gettimeofday()");
68
if (gettimeofday(&tv, NULL) == -1)
69
debug_return_int(-1);
70
TIMEVAL_TO_TIMESPEC(&tv, ts);
71
}
72
debug_return_int(0);
73
}
74
#else
75
int
76
sudo_gettime_real_v1(struct timespec *ts)
77
{
78
struct timeval tv;
79
debug_decl(sudo_gettime_real, SUDO_DEBUG_UTIL);
80
81
if (gettimeofday(&tv, NULL) == -1)
82
debug_return_int(-1);
83
TIMEVAL_TO_TIMESPEC(&tv, ts);
84
debug_return_int(0);
85
}
86
#endif
87
88
/*
89
* Monotonic time, only runs forward.
90
* We use a timer that only increments while sleeping, if possible.
91
*/
92
#if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_BOOTTIME)
93
int
94
sudo_gettime_mono_v1(struct timespec *ts)
95
{
96
static int has_monoclock = -1;
97
debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL);
98
99
/* Check whether the kernel/libc actually supports a monotonic clock. */
100
# ifdef _SC_MONOTONIC_CLOCK
101
if (has_monoclock == -1)
102
has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1;
103
# endif
104
if (!has_monoclock)
105
debug_return_int(sudo_gettime_real(ts));
106
if (clock_gettime(SUDO_CLOCK_BOOTTIME, ts) == -1) {
107
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
108
"clock_gettime(%d) failed, using wall clock",
109
(int)SUDO_CLOCK_BOOTTIME);
110
has_monoclock = 0;
111
debug_return_int(sudo_gettime_real(ts));
112
}
113
debug_return_int(0);
114
}
115
#elif defined(HAVE_GETHRTIME)
116
int
117
sudo_gettime_mono_v1(struct timespec *ts)
118
{
119
hrtime_t nsec;
120
debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL);
121
122
nsec = gethrtime();
123
ts->tv_sec = nsec / 1000000000;
124
ts->tv_nsec = nsec % 1000000000;
125
debug_return_int(0);
126
}
127
#elif defined(__MACH__)
128
int
129
sudo_gettime_mono_v1(struct timespec *ts)
130
{
131
uint64_t abstime, nsec;
132
static mach_timebase_info_data_t timebase_info;
133
debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL);
134
135
if (timebase_info.denom == 0)
136
(void) mach_timebase_info(&timebase_info);
137
#ifdef HAVE_MACH_CONTINUOUS_TIME
138
abstime = mach_continuous_time(); /* runs while asleep */
139
#else
140
abstime = mach_absolute_time(); /* doesn't run while asleep */
141
#endif
142
nsec = abstime * timebase_info.numer / timebase_info.denom;
143
ts->tv_sec = nsec / 1000000000;
144
ts->tv_nsec = nsec % 1000000000;
145
debug_return_int(0);
146
}
147
#else
148
int
149
sudo_gettime_mono_v1(struct timespec *ts)
150
{
151
/* No monotonic clock available, use wall clock. */
152
return sudo_gettime_real(ts);
153
}
154
#endif
155
156
/*
157
* Monotonic time, only runs forward.
158
* We use a timer that only increments while awake, if possible.
159
*/
160
#if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_UPTIME)
161
int
162
sudo_gettime_awake_v1(struct timespec *ts)
163
{
164
static int has_monoclock = -1;
165
debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL);
166
167
/* Check whether the kernel/libc actually supports a monotonic clock. */
168
# ifdef _SC_MONOTONIC_CLOCK
169
if (has_monoclock == -1)
170
has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1;
171
# endif
172
if (!has_monoclock)
173
debug_return_int(sudo_gettime_real(ts));
174
if (clock_gettime(SUDO_CLOCK_UPTIME, ts) == -1) {
175
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
176
"clock_gettime(%d) failed, using wall clock",
177
(int)SUDO_CLOCK_UPTIME);
178
has_monoclock = 0;
179
debug_return_int(sudo_gettime_real(ts));
180
}
181
debug_return_int(0);
182
}
183
#elif defined(HAVE_GETHRTIME)
184
int
185
sudo_gettime_awake_v1(struct timespec *ts)
186
{
187
hrtime_t nsec;
188
debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL);
189
190
/* Currently the same as sudo_gettime_mono() */
191
nsec = gethrtime();
192
ts->tv_sec = nsec / 1000000000;
193
ts->tv_nsec = nsec % 1000000000;
194
debug_return_int(0);
195
}
196
#elif defined(__MACH__)
197
int
198
sudo_gettime_awake_v1(struct timespec *ts)
199
{
200
uint64_t abstime, nsec;
201
static mach_timebase_info_data_t timebase_info;
202
debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL);
203
204
if (timebase_info.denom == 0)
205
(void) mach_timebase_info(&timebase_info);
206
abstime = mach_absolute_time();
207
nsec = abstime * timebase_info.numer / timebase_info.denom;
208
ts->tv_sec = nsec / 1000000000;
209
ts->tv_nsec = nsec % 1000000000;
210
debug_return_int(0);
211
}
212
#else
213
int
214
sudo_gettime_awake_v1(struct timespec *ts)
215
{
216
/* No monotonic uptime clock available, use wall clock. */
217
return sudo_gettime_real(ts);
218
}
219
#endif
220
221