Coverage Report

Created: 2025-10-10 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sudo/lib/util/gettime.c
Line
Count
Source
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
#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
0
# 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
5.51k
# 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
0
{
61
0
    debug_decl(sudo_gettime_real, SUDO_DEBUG_UTIL);
62
63
0
    if (clock_gettime(CLOCK_REALTIME, ts) == -1) {
64
0
  struct timeval tv;
65
66
0
  sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
67
0
      "clock_gettime(CLOCK_REALTIME) failed, trying gettimeofday()");
68
0
  if (gettimeofday(&tv, NULL) == -1)
69
0
      debug_return_int(-1);
70
0
  TIMEVAL_TO_TIMESPEC(&tv, ts);
71
0
    }
72
0
    debug_return_int(0);
73
0
}
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
0
{
96
0
    static int has_monoclock = -1;
97
0
    debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL);
98
99
    /* Check whether the kernel/libc actually supports a monotonic clock. */
100
0
# ifdef _SC_MONOTONIC_CLOCK
101
0
    if (has_monoclock == -1)
102
0
  has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1;
103
0
# endif
104
0
    if (!has_monoclock)
105
0
  debug_return_int(sudo_gettime_real(ts));
106
0
    if (clock_gettime(SUDO_CLOCK_BOOTTIME, ts) == -1) {
107
0
  sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
108
0
      "clock_gettime(%d) failed, using wall clock",
109
0
      (int)SUDO_CLOCK_BOOTTIME);
110
0
  has_monoclock = 0;
111
0
  debug_return_int(sudo_gettime_real(ts));
112
0
    }
113
0
    debug_return_int(0);
114
0
}
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
5.51k
{
164
5.51k
    static int has_monoclock = -1;
165
5.51k
    debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL);
166
167
    /* Check whether the kernel/libc actually supports a monotonic clock. */
168
5.51k
# ifdef _SC_MONOTONIC_CLOCK
169
5.51k
    if (has_monoclock == -1)
170
1
  has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1;
171
5.51k
# endif
172
5.51k
    if (!has_monoclock)
173
0
  debug_return_int(sudo_gettime_real(ts));
174
5.51k
    if (clock_gettime(SUDO_CLOCK_UPTIME, ts) == -1) {
175
0
  sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
176
0
      "clock_gettime(%d) failed, using wall clock",
177
0
      (int)SUDO_CLOCK_UPTIME);
178
0
  has_monoclock = 0;
179
0
  debug_return_int(sudo_gettime_real(ts));
180
0
    }
181
5.51k
    debug_return_int(0);
182
5.51k
}
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