CI opt-test: Drop Python2 & Bash in Fedora latest.
[ntpsec.git] / libntp / systime.c
blobb587f1b480e49d38bff78f82595c4c663129e960
1 /*
2 * systime -- routines to fiddle a UNIX clock.
4 * ATTENTION: Get approval from Dave Mills on all changes to this file!
6 */
7 #include "config.h"
9 #include "ntp.h"
10 #include "ntp_syslog.h"
11 #include "ntp_stdlib.h"
12 #include "timespecops.h"
13 #include "ntp_calendar.h"
15 #ifndef USE_COMPILETIME_PIVOT
16 # define USE_COMPILETIME_PIVOT 1
17 #endif
20 * These routines (get_systime, step_systime, adj_systime) implement an
21 * interface between the system independent NTP clock and the Unix
22 * system clock in various architectures and operating systems. Time is
23 * a precious quantity in these routines and every effort is made to
24 * minimize errors by unbiased rounding and amortizing adjustment
25 * residues.
27 * In order to improve the apparent resolution, provide unbiased
28 * rounding and most importantly ensure that the readings cannot be
29 * predicted, the low-order unused portion of the time below the minimum
30 * time to read the clock is filled with an unbiased random fuzz.
32 * The sys_tick variable specifies the system clock tick interval in
33 * seconds, for stepping clocks, defined as those which return times
34 * less than MINSTEP greater than the previous reading. For systems that
35 * use a high-resolution counter such that each clock reading is always
36 * at least MINSTEP greater than the prior, sys_tick is the time to read
37 * the system clock.
39 * The sys_fuzz variable measures the minimum time to read the system
40 * clock, regardless of its precision. When reading the system clock
41 * using get_systime() after sys_tick and sys_fuzz have been determined,
42 * ntpd ensures each unprocessed clock reading is no less than sys_fuzz
43 * later than the prior unprocessed reading, and then fuzzes the bits
44 * below sys_fuzz in the timestamp returned, ensuring each of its
45 * resulting readings is strictly later than the previous.
47 * When slewing the system clock using adj_systime() (with the kernel
48 * loop discipline unavailable or disabled), adjtime() offsets are
49 * quantized to sys_tick, if sys_tick is greater than sys_fuzz, which
50 * is to say if the OS presents a stepping clock. Otherwise, offsets
51 * are quantized to the microsecond resolution of adjtime()'s timeval
52 * input. The remaining correction sys_residual is carried into the
53 * next adjtime() and meanwhile is also factored into get_systime()
54 * readings.
56 * adj_systime() and step_systime() will behave sanely with these
57 * variables not set, but the adjustments may be in larger steps.
59 time_stepped_callback step_callback;
61 static doubletime_t sys_residual = 0; /* adjustment residue (s) */
63 static void get_ostime (struct timespec *tsp);
66 static void
67 get_ostime(
68 struct timespec * tsp
71 int rc;
73 rc = clock_gettime(CLOCK_REALTIME, tsp);
74 if (rc < 0) {
75 #ifndef __COVERITY__
76 msyslog(LOG_ERR, "TIME: read system clock failed: %s (%d)",
77 strerror(errno), errno);
78 #endif /* __COVERITY__ */
79 exit(1);
86 * get_systime - return system time in NTP timestamp format.
88 void
89 get_systime(
90 l_fp *now /* system time */
93 struct timespec ts; /* seconds and nanoseconds */
94 get_ostime(&ts);
95 *now = tspec_stamp_to_lfp(ts);
100 * adj_systime - adjust system time by the argument.
102 bool /* true on okay, false on error */
103 adj_systime(
104 double now, /* adjustment (s) */
105 int (*ladjtime)(const struct timeval *, struct timeval *)
108 struct timeval adjtv; /* new adjustment */
109 struct timeval oadjtv; /* residual adjustment */
110 double quant; /* quantize to multiples of */
111 doubletime_t dtemp;
112 long ticks;
113 bool isneg = false;
116 * FIXME: With the legacy Windows port gone, this might be removable.
117 * See also the related FIXME comment in ntpd/ntp_loopfilter.c.
119 * The Windows port adj_systime() depended on being called each
120 * second even when there's no additional correction, to allow
121 * emulation of adjtime() behavior on top of an API that simply
122 * sets the current rate. This POSIX implementation needs to
123 * ignore invocations with zero correction, otherwise ongoing
124 * EVNT_NSET adjtime() can be aborted by a tiny adjtime()
125 * triggered by sys_residual.
127 if ( D_ISZERO_NS(now))
128 return true;
131 * Most Unix adjtime() implementations adjust the system clock
132 * in microsecond quanta, but some adjust in 10-ms quanta. We
133 * carefully round the adjustment to the nearest quantum, then
134 * adjust in quanta and keep the residue for later.
136 dtemp = now + sys_residual;
137 if (dtemp < 0) {
138 isneg = true;
139 dtemp = -dtemp;
141 adjtv.tv_sec = (long)dtemp;
142 dtemp -= adjtv.tv_sec;
143 quant = S_PER_US;
144 ticks = (long)(dtemp / quant + .5);
145 adjtv.tv_usec = (long)(ticks * quant * US_PER_S + .5);
146 /* The rounding in the conversions could push us over the
147 * limits: make sure the result is properly normalised!
148 * note: sign comes later, all numbers non-negative here.
150 if (adjtv.tv_usec >= US_PER_S) {
151 adjtv.tv_sec += 1;
152 adjtv.tv_usec -= US_PER_S;
153 dtemp -= 1.;
155 /* set the new residual with leftover from correction */
156 sys_residual = dtemp - adjtv.tv_usec * S_PER_US;
159 * Convert to signed seconds and microseconds for the Unix
160 * adjtime() system call. Note we purposely lose the adjtime()
161 * leftover.
163 if (isneg) {
164 adjtv.tv_sec = -adjtv.tv_sec;
165 adjtv.tv_usec = -adjtv.tv_usec;
166 sys_residual = -sys_residual;
168 if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
169 if (ladjtime(&adjtv, &oadjtv) < 0) {
170 msyslog(LOG_ERR, "CLOCK: adj_systime: %s", strerror(errno));
171 return false;
174 return true;
179 * step_systime - step the system clock.
181 * if your timespec has a 64 bit time_t then you are 2038 ready.
182 * if your timespec has a 32 bit time_t, be sure to duck in 2038
185 bool
186 step_systime(
187 doubletime_t step
190 time_t pivot; /* for ntp era unfolding */
191 struct timespec timets;
192 struct timespec old, new;
193 struct calendar jd;
194 l_fp fp_ofs, fp_sys; /* offset and target system time in FP */
197 * Get pivot time for NTP era unfolding. Since we don't step
198 * very often, we can afford to do the whole calculation from
199 * scratch. And we're not in the time-critical path yet.
201 #if NTP_SIZEOF_TIME_T > 4
203 * This code makes sure the resulting time stamp for the new
204 * system time is in the 2^32 seconds starting at 1970-01-01,
205 * 00:00:00 UTC.
207 pivot = 0x80000000;
208 #if USE_COMPILETIME_PIVOT
210 * Add the compile time minus 10 years to get a possible target
211 * area of (compile time - 10 years) to (compile time + 126
212 * years). This should be sufficient for a given binary of
213 * NTPD.
215 if (ntpcal_get_build_date(&jd)) {
216 jd.year -= 10;
217 pivot += ntpcal_date_to_time(&jd);
218 } else {
219 msyslog(LOG_ERR,
220 "CLOCK: step_systime: assume 1970-01-01 as build date");
222 #else
223 UNUSED_LOCAL(jd);
224 #endif /* USE_COMPILETIME_PIVOT */
225 #else
226 UNUSED_LOCAL(jd);
227 /* This makes sure the resulting time stamp is on or after
228 * 1969-12-31/23:59:59 UTC and gives us additional two years,
229 * from the change of NTP era in 2036 to the UNIX rollover in
230 * 2038. (Minus one second, but that won't hurt.) We *really*
231 * need a longer 'time_t' after that! Or a different baseline,
232 * but that would cause other serious trouble, too.
234 pivot = 0x7FFFFFFF;
235 #endif
237 /* get the complete jump distance as l_fp */
238 fp_sys = dtolfp(sys_residual);
239 fp_ofs = dtolfp(step);
240 fp_ofs += fp_sys;
242 /* ---> time-critical path starts ---> */
244 /* get the current time as l_fp (without fuzz) and as struct timespec */
245 get_ostime(&timets);
246 old = timets;
247 fp_sys = tspec_stamp_to_lfp(timets);
249 /* get the target time as l_fp */
250 fp_sys += fp_ofs;
252 /* unfold the new system time */
253 timets = lfp_stamp_to_tspec(fp_sys, pivot);
254 new = timets;
256 /* now set new system time */
257 if (ntp_set_tod(&timets) != 0) {
258 msyslog(LOG_ERR, "CLOCK: step_systime: %s", strerror(errno));
259 return false;
262 /* <--- time-critical path ended with call to the settime hook <--- */
264 msyslog(LOG_WARNING, "CLOCK: time stepped by %Lf", step);
265 if (fabsl(step) > 86400) {
266 /* Get the full year (both old and new) into the log file.
267 * Issue #474 */
268 struct tm oldtm, newtm;
269 char oldbuf[100], newbuf[100];
270 if (!localtime_r(&old.tv_sec, &oldtm)) {
271 oldtm.tm_year = 9999-1900;
272 oldtm.tm_mon = 98;
273 oldtm.tm_mday = 99;
275 snprintf(oldbuf, sizeof(oldbuf), "%04d-%02d-%02d",
276 oldtm.tm_year+1900, oldtm.tm_mon+1, oldtm.tm_mday);
277 if (!localtime_r(&new.tv_sec, &newtm)) {
278 newtm.tm_year = 9999-1900;
279 newtm.tm_mon = 98;
280 newtm.tm_mday = 99;
282 snprintf(newbuf, sizeof(newbuf), "%04d-%02d-%02d",
283 newtm.tm_year+1900, newtm.tm_mon+1, newtm.tm_mday);
284 msyslog(LOG_WARNING, "CLOCK: time changed from %s to %s",
285 oldbuf, newbuf);
288 sys_residual = 0;
289 if (step_callback)
290 (*step_callback)();
291 return true;