Coverage Report

Created: 2023-03-26 07:11

/src/ntp-dev/libntp/systime.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * systime -- routines to fiddle a UNIX clock.
3
 *
4
 * ATTENTION: Get approval from Dave Mills on all changes to this file!
5
 *
6
 */
7
#include <config.h>
8
#include <math.h>
9
10
#include "ntp.h"
11
#include "ntpd.h"
12
#include "ntp_syslog.h"
13
#include "ntp_stdlib.h"
14
#include "ntp_random.h"
15
#include "iosignal.h"
16
#include "timevalops.h"
17
#include "timespecops.h"
18
#include "ntp_calendar.h"
19
#include "lib_strbuf.h"
20
21
#ifdef HAVE_SYS_PARAM_H
22
# include <sys/param.h>
23
#endif
24
#ifdef HAVE_UTMP_H
25
# include <utmp.h>
26
#endif /* HAVE_UTMP_H */
27
#ifdef HAVE_UTMPX_H
28
# include <utmpx.h>
29
#endif /* HAVE_UTMPX_H */
30
31
int allow_panic = FALSE;    /* allow panic correction (-g) */
32
int enable_panic_check = TRUE;  /* Can we check allow_panic's state? */
33
34
u_long  sys_lamport;      /* Lamport violation */
35
u_long  sys_tsrounding;     /* timestamp rounding errors */
36
37
#ifndef USE_COMPILETIME_PIVOT
38
# define USE_COMPILETIME_PIVOT 1
39
#endif
40
41
/*
42
 * These routines (get_systime, step_systime, adj_systime) implement an
43
 * interface between the system independent NTP clock and the Unix
44
 * system clock in various architectures and operating systems. Time is
45
 * a precious quantity in these routines and every effort is made to
46
 * minimize errors by unbiased rounding and amortizing adjustment
47
 * residues.
48
 *
49
 * In order to improve the apparent resolution, provide unbiased
50
 * rounding and most importantly ensure that the readings cannot be
51
 * predicted, the low-order unused portion of the time below the minimum
52
 * time to read the clock is filled with an unbiased random fuzz.
53
 *
54
 * The sys_tick variable specifies the system clock tick interval in
55
 * seconds, for stepping clocks, defined as those which return times
56
 * less than MINSTEP greater than the previous reading. For systems that
57
 * use a high-resolution counter such that each clock reading is always
58
 * at least MINSTEP greater than the prior, sys_tick is the time to read
59
 * the system clock.
60
 *
61
 * The sys_fuzz variable measures the minimum time to read the system
62
 * clock, regardless of its precision.  When reading the system clock
63
 * using get_systime() after sys_tick and sys_fuzz have been determined,
64
 * ntpd ensures each unprocessed clock reading is no less than sys_fuzz
65
 * later than the prior unprocessed reading, and then fuzzes the bits
66
 * below sys_fuzz in the timestamp returned, ensuring each of its
67
 * resulting readings is strictly later than the previous.
68
 *
69
 * When slewing the system clock using adj_systime() (with the kernel
70
 * loop discipline unavailable or disabled), adjtime() offsets are
71
 * quantized to sys_tick, if sys_tick is greater than sys_fuzz, which
72
 * is to say if the OS presents a stepping clock.  Otherwise, offsets
73
 * are quantized to the microsecond resolution of adjtime()'s timeval
74
 * input.  The remaining correction sys_residual is carried into the
75
 * next adjtime() and meanwhile is also factored into get_systime()
76
 * readings.
77
 */
78
double  sys_tick = 0;   /* tick size or time to read (s) */
79
double  sys_fuzz = 0;   /* min. time to read the clock (s) */
80
long  sys_fuzz_nsec = 0;  /* min. time to read the clock (ns) */
81
double  measured_tick;    /* non-overridable sys_tick (s) */
82
double  sys_residual = 0; /* adjustment residue (s) */
83
int trunc_os_clock;   /* sys_tick > measured_tick */
84
time_stepped_callback step_callback;
85
86
#ifndef SIM
87
/* perlinger@ntp.org: As 'get_sysime()' does it's own check for clock
88
 * backstepping, this could probably become a local variable in
89
 * 'get_systime()' and the cruft associated with communicating via a
90
 * static value could be removed after the v4.2.8 release.
91
 */
92
static int lamport_violated;  /* clock was stepped back */
93
#endif  /* !SIM */
94
95
#ifdef DEBUG
96
static int systime_init_done;
97
1
# define DONE_SYSTIME_INIT()  systime_init_done = TRUE
98
#else
99
# define DONE_SYSTIME_INIT()  do {} while (FALSE)
100
#endif
101
102
#ifdef HAVE_SIGNALED_IO
103
int using_sigio;
104
#endif
105
106
#ifdef SYS_WINNT
107
CRITICAL_SECTION get_systime_cs;
108
#endif
109
110
111
void
112
set_sys_fuzz(
113
  double  fuzz_val
114
  )
115
2
{
116
2
  sys_fuzz = fuzz_val;
117
2
  INSIST(sys_fuzz >= 0);
118
2
  INSIST(sys_fuzz <= 1.0);
119
  /* [Bug 3450] ensure nsec fuzz >= sys_fuzz to reduce chance of
120
   * short-falling fuzz advance
121
   */
122
0
  sys_fuzz_nsec = (long)ceil(sys_fuzz * 1e9);
123
2
}
124
125
126
void
127
init_systime(void)
128
1
{
129
1
  INIT_GET_SYSTIME_CRITSEC();
130
1
  INIT_WIN_PRECISE_TIME();
131
1
  DONE_SYSTIME_INIT();
132
1
}
133
134
135
#ifndef SIM /* ntpsim.c has get_systime() and friends for sim */
136
137
static inline void
138
get_ostime(
139
  struct timespec * tsp
140
  )
141
1.37k
{
142
1.37k
  int rc;
143
1.37k
  long  ticks;
144
145
1.37k
#if defined(HAVE_CLOCK_GETTIME)
146
1.37k
  rc = clock_gettime(CLOCK_REALTIME, tsp);
147
#elif defined(HAVE_GETCLOCK)
148
  rc = getclock(TIMEOFDAY, tsp);
149
#else
150
  struct timeval    tv;
151
152
  rc = GETTIMEOFDAY(&tv, NULL);
153
  tsp->tv_sec = tv.tv_sec;
154
  tsp->tv_nsec = tv.tv_usec * 1000;
155
#endif
156
1.37k
  if (rc < 0) {
157
0
    msyslog(LOG_ERR, "read system clock failed: %m (%d)",
158
0
      errno);
159
0
    exit(1);
160
0
  }
161
162
1.37k
  if (trunc_os_clock) {
163
0
    ticks = (long)((tsp->tv_nsec * 1e-9) / sys_tick);
164
0
    tsp->tv_nsec = (long)(ticks * 1e9 * sys_tick);
165
0
  }
166
1.37k
}
167
168
169
/*
170
 * get_systime - return system time in NTP timestamp format.
171
 */
172
void
173
get_systime(
174
  l_fp *now   /* system time */
175
  )
176
1.37k
{
177
1.37k
        static struct timespec  ts_last;        /* last sampled os time */
178
1.37k
  static struct timespec  ts_prev;  /* prior os time */
179
1.37k
  static l_fp   lfp_prev; /* prior result */
180
1.37k
  struct timespec ts; /* seconds and nanoseconds */
181
1.37k
  struct timespec ts_min; /* earliest permissible */
182
1.37k
  struct timespec ts_lam; /* lamport fictional increment */
183
1.37k
  double  dfuzz;
184
1.37k
  l_fp  result;
185
1.37k
  l_fp  lfpfuzz;
186
1.37k
  l_fp  lfpdelta;
187
188
1.37k
  get_ostime(&ts);
189
1.37k
  DEBUG_REQUIRE(systime_init_done);
190
1.37k
  ENTER_GET_SYSTIME_CRITSEC();
191
192
        /* First check if here was a Lamport violation, that is, two
193
         * successive calls to 'get_ostime()' resulted in negative
194
         * time difference. Use a few milliseconds of permissible
195
         * tolerance -- being too sharp can hurt here. (This is intented
196
         * for the Win32 target, where the HPC interpolation might
197
         * introduce small steps backward. It should not be an issue on
198
         * systems where get_ostime() results in a true syscall.)
199
         */
200
1.37k
        if (cmp_tspec(add_tspec_ns(ts, 50000000), ts_last) < 0) {
201
0
                lamport_violated = 1;
202
0
                sys_lamport++;
203
0
  }
204
1.37k
        ts_last = ts;
205
206
  /*
207
   * After default_get_precision() has set a nonzero sys_fuzz,
208
   * ensure every reading of the OS clock advances by at least
209
   * sys_fuzz over the prior reading, thereby assuring each
210
   * fuzzed result is strictly later than the prior.  Limit the
211
   * necessary fiction to 1 second.
212
   */
213
1.37k
  if (!USING_SIGIO()) {
214
1.37k
    ts_min = add_tspec_ns(ts_prev, sys_fuzz_nsec);
215
1.37k
    if (cmp_tspec(ts, ts_min) < 0) {
216
2
      ts_lam = sub_tspec(ts_min, ts);
217
2
      if (ts_lam.tv_sec > 0 && !lamport_violated) {
218
0
        msyslog(LOG_ERR,
219
0
          "get_systime Lamport advance exceeds one second (%.9f)",
220
0
          ts_lam.tv_sec +
221
0
              1e-9 * ts_lam.tv_nsec);
222
0
        exit(1);
223
0
      }
224
2
      if (!lamport_violated)
225
2
        ts = ts_min;
226
2
    }
227
1.37k
    ts_prev = ts;
228
1.37k
  }
229
230
  /* convert from timespec to l_fp fixed-point */
231
1.37k
  result = tspec_stamp_to_lfp(ts);
232
233
  /*
234
   * Add in the fuzz. 'ntp_random()' returns [0..2**31-1] so we
235
   * must scale up the result by 2.0 to cover the full fractional
236
   * range.
237
   */
238
1.37k
  dfuzz = ntp_random() * 2. / FRAC * sys_fuzz;
239
1.37k
  DTOLFP(dfuzz, &lfpfuzz);
240
1.37k
  L_ADD(&result, &lfpfuzz);
241
242
  /*
243
   * Ensure result is strictly greater than prior result (ignoring
244
   * sys_residual's effect for now) once sys_fuzz has been
245
   * determined.
246
   *
247
   * [Bug 3450] Rounding errors and time slew can lead to a
248
   * violation of the expected postcondition. This is bound to
249
   * happen from time to time (depending on state of the random
250
   * generator, the current slew and the closeness of system time
251
   * stamps drawn) and does not warrant a syslog entry. Instead it
252
   * makes much more sense to ensure the postcondition and hop
253
   * along silently.
254
   */
255
1.37k
  if (!USING_SIGIO()) {
256
1.37k
    if (   !L_ISZERO(&lfp_prev)
257
1.37k
        && !lamport_violated
258
1.37k
        && (sys_fuzz > 0.0)
259
1.37k
       ) {
260
1.36k
      lfpdelta = result;
261
1.36k
      L_SUB(&lfpdelta, &lfp_prev);
262
1.36k
      L_SUBUF(&lfpdelta, 1);
263
1.36k
      if (lfpdelta.l_i < 0)
264
0
      {
265
0
        L_NEG(&lfpdelta);
266
0
        DPRINTF(1, ("get_systime: postcond failed by %s secs, fixed\n",
267
0
              lfptoa(&lfpdelta, 9)));
268
0
        result = lfp_prev;
269
0
        L_ADDUF(&result, 1);
270
0
        sys_tsrounding++;
271
0
      }
272
1.36k
    }
273
1.37k
    lfp_prev = result;
274
1.37k
    if (lamport_violated) 
275
0
      lamport_violated = FALSE;
276
1.37k
  }
277
1.37k
  LEAVE_GET_SYSTIME_CRITSEC();
278
1.37k
  *now = result;
279
1.37k
}
280
281
282
/*
283
 * adj_systime - adjust system time by the argument.
284
 */
285
#if !defined SYS_WINNT
286
int       /* 0 okay, 1 error */
287
adj_systime(
288
  double now    /* adjustment (s) */
289
  )
290
0
{
291
0
  struct timeval adjtv; /* new adjustment */
292
0
  struct timeval oadjtv;  /* residual adjustment */
293
0
  double  quant;    /* quantize to multiples of */
294
0
  double  dtemp;
295
0
  long  ticks;
296
0
  int isneg = 0;
297
298
  /*
299
   * The Windows port adj_systime() depends on being called each
300
   * second even when there's no additional correction, to allow
301
   * emulation of adjtime() behavior on top of an API that simply
302
   * sets the current rate.  This POSIX implementation needs to
303
   * ignore invocations with zero correction, otherwise ongoing
304
   * EVNT_NSET adjtime() can be aborted by a tiny adjtime()
305
   * triggered by sys_residual.
306
   */
307
0
  if (0. == now) {
308
0
    if (enable_panic_check && allow_panic) {
309
0
      msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
310
0
      INSIST(!allow_panic);
311
0
    }
312
0
    return TRUE;
313
0
  }
314
315
  /*
316
   * Most Unix adjtime() implementations adjust the system clock
317
   * in microsecond quanta, but some adjust in 10-ms quanta. We
318
   * carefully round the adjustment to the nearest quantum, then
319
   * adjust in quanta and keep the residue for later.
320
   */
321
0
  dtemp = now + sys_residual;
322
0
  if (dtemp < 0) {
323
0
    isneg = 1;
324
0
    dtemp = -dtemp;
325
0
  }
326
0
  adjtv.tv_sec = (long)dtemp;
327
0
  dtemp -= adjtv.tv_sec;
328
0
  if (sys_tick > sys_fuzz)
329
0
    quant = sys_tick;
330
0
  else
331
0
    quant = 1e-6;
332
0
  ticks = (long)(dtemp / quant + .5);
333
0
  adjtv.tv_usec = (long)(ticks * quant * 1.e6 + .5);
334
  /* The rounding in the conversions could us push over the
335
   * limits: make sure the result is properly normalised!
336
   * note: sign comes later, all numbers non-negative here.
337
   */
338
0
  if (adjtv.tv_usec >= 1000000) {
339
0
    adjtv.tv_sec  += 1;
340
0
    adjtv.tv_usec -= 1000000;
341
0
    dtemp         -= 1.;
342
0
  }
343
  /* set the new residual with leftover from correction */
344
0
  sys_residual = dtemp - adjtv.tv_usec * 1.e-6;
345
346
  /*
347
   * Convert to signed seconds and microseconds for the Unix
348
   * adjtime() system call. Note we purposely lose the adjtime()
349
   * leftover.
350
   */
351
0
  if (isneg) {
352
0
    adjtv.tv_sec = -adjtv.tv_sec;
353
0
    adjtv.tv_usec = -adjtv.tv_usec;
354
0
    sys_residual = -sys_residual;
355
0
  }
356
0
  if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
357
0
    if (adjtime(&adjtv, &oadjtv) < 0) {
358
0
      msyslog(LOG_ERR, "adj_systime: %m");
359
0
      if (enable_panic_check && allow_panic) {
360
0
        msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
361
0
      }
362
0
      return FALSE;
363
0
    }
364
0
  }
365
0
  if (enable_panic_check && allow_panic) {
366
0
    msyslog(LOG_ERR, "adj_systime: allow_panic is TRUE!");
367
0
  }
368
0
  return TRUE;
369
0
}
370
#endif
371
372
/*
373
 * helper to keep utmp/wtmp up to date
374
 */
375
static void
376
update_uwtmp(
377
  struct timeval timetv,
378
  struct timeval tvlast
379
  )
380
0
{
381
0
  struct timeval tvdiff;
382
  /*
383
   * FreeBSD, for example, has:
384
   * struct utmp {
385
   *     char    ut_line[UT_LINESIZE];
386
   *     char    ut_name[UT_NAMESIZE];
387
   *     char    ut_host[UT_HOSTSIZE];
388
   *     long    ut_time;
389
   * };
390
   * and appends line="|", name="date", host="", time for the OLD
391
   * and appends line="{", name="date", host="", time for the NEW // }
392
   * to _PATH_WTMP .
393
   *
394
   * Some OSes have utmp, some have utmpx.
395
   */
396
397
  /*
398
   * Write old and new time entries in utmp and wtmp if step
399
   * adjustment is greater than one second.
400
   *
401
   * This might become even Uglier...
402
   */
403
0
  tvdiff = abs_tval(sub_tval(timetv, tvlast));
404
0
  if (tvdiff.tv_sec > 0) {
405
0
#ifdef HAVE_UTMP_H
406
0
    struct utmp ut;
407
0
#endif
408
0
#ifdef HAVE_UTMPX_H
409
0
    struct utmpx utx;
410
0
#endif
411
412
0
#ifdef HAVE_UTMP_H
413
0
    ZERO(ut);
414
0
#endif
415
0
#ifdef HAVE_UTMPX_H
416
0
    ZERO(utx);
417
0
#endif
418
419
    /* UTMP */
420
421
#ifdef UPDATE_UTMP
422
# ifdef HAVE_PUTUTLINE
423
#  ifndef _PATH_UTMP
424
#   define _PATH_UTMP UTMP_FILE
425
#  endif
426
    utmpname(_PATH_UTMP);
427
    ut.ut_type = OLD_TIME;
428
    strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
429
    ut.ut_time = tvlast.tv_sec;
430
    setutent();
431
    pututline(&ut);
432
    ut.ut_type = NEW_TIME;
433
    strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line));
434
    ut.ut_time = timetv.tv_sec;
435
    setutent();
436
    pututline(&ut);
437
    endutent();
438
# else /* not HAVE_PUTUTLINE */
439
# endif /* not HAVE_PUTUTLINE */
440
#endif /* UPDATE_UTMP */
441
442
    /* UTMPX */
443
444
#ifdef UPDATE_UTMPX
445
# ifdef HAVE_PUTUTXLINE
446
    utx.ut_type = OLD_TIME;
447
    strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
448
    utx.ut_tv = tvlast;
449
    setutxent();
450
    pututxline(&utx);
451
    utx.ut_type = NEW_TIME;
452
    strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line));
453
    utx.ut_tv = timetv;
454
    setutxent();
455
    pututxline(&utx);
456
    endutxent();
457
# else /* not HAVE_PUTUTXLINE */
458
# endif /* not HAVE_PUTUTXLINE */
459
#endif /* UPDATE_UTMPX */
460
461
    /* WTMP */
462
463
#ifdef UPDATE_WTMP
464
# ifdef HAVE_PUTUTLINE
465
#  ifndef _PATH_WTMP
466
#   define _PATH_WTMP WTMP_FILE
467
#  endif
468
    utmpname(_PATH_WTMP);
469
    ut.ut_type = OLD_TIME;
470
    strlcpy(ut.ut_line, OTIME_MSG, sizeof(ut.ut_line));
471
    ut.ut_time = tvlast.tv_sec;
472
    setutent();
473
    pututline(&ut);
474
    ut.ut_type = NEW_TIME;
475
    strlcpy(ut.ut_line, NTIME_MSG, sizeof(ut.ut_line));
476
    ut.ut_time = timetv.tv_sec;
477
    setutent();
478
    pututline(&ut);
479
    endutent();
480
# else /* not HAVE_PUTUTLINE */
481
# endif /* not HAVE_PUTUTLINE */
482
#endif /* UPDATE_WTMP */
483
484
    /* WTMPX */
485
486
#ifdef UPDATE_WTMPX
487
# ifdef HAVE_PUTUTXLINE
488
    utx.ut_type = OLD_TIME;
489
    utx.ut_tv = tvlast;
490
    strlcpy(utx.ut_line, OTIME_MSG, sizeof(utx.ut_line));
491
#  ifdef HAVE_UPDWTMPX
492
    updwtmpx(WTMPX_FILE, &utx);
493
#  else /* not HAVE_UPDWTMPX */
494
#  endif /* not HAVE_UPDWTMPX */
495
# else /* not HAVE_PUTUTXLINE */
496
# endif /* not HAVE_PUTUTXLINE */
497
# ifdef HAVE_PUTUTXLINE
498
    utx.ut_type = NEW_TIME;
499
    utx.ut_tv = timetv;
500
    strlcpy(utx.ut_line, NTIME_MSG, sizeof(utx.ut_line));
501
#  ifdef HAVE_UPDWTMPX
502
    updwtmpx(WTMPX_FILE, &utx);
503
#  else /* not HAVE_UPDWTMPX */
504
#  endif /* not HAVE_UPDWTMPX */
505
# else /* not HAVE_PUTUTXLINE */
506
# endif /* not HAVE_PUTUTXLINE */
507
#endif /* UPDATE_WTMPX */
508
509
0
  }
510
0
}
511
512
/*
513
 * step_systime - step the system clock.
514
 */
515
516
int
517
step_systime(
518
  double step
519
  )
520
0
{
521
0
  time_t pivot; /* for ntp era unfolding */
522
0
  struct timeval timetv, tvlast;
523
0
  struct timespec timets;
524
0
  l_fp fp_ofs, fp_sys; /* offset and target system time in FP */
525
526
  /*
527
   * Get pivot time for NTP era unfolding. Since we don't step
528
   * very often, we can afford to do the whole calculation from
529
   * scratch. And we're not in the time-critical path yet.
530
   */
531
0
#if SIZEOF_TIME_T > 4
532
0
  pivot = basedate_get_eracenter();
533
#else
534
  /* This makes sure the resulting time stamp is on or after
535
   * 1969-12-31/23:59:59 UTC and gives us additional two years,
536
   * from the change of NTP era in 2036 to the UNIX rollover in
537
   * 2038. (Minus one second, but that won't hurt.) We *really*
538
   * need a longer 'time_t' after that!  Or a different baseline,
539
   * but that would cause other serious trouble, too.
540
   */
541
  pivot = 0x7FFFFFFF;
542
#endif
543
544
  /* get the complete jump distance as l_fp */
545
0
  DTOLFP(sys_residual, &fp_sys);
546
0
  DTOLFP(step,         &fp_ofs);
547
0
  L_ADD(&fp_ofs, &fp_sys);
548
549
  /* ---> time-critical path starts ---> */
550
551
  /* get the current time as l_fp (without fuzz) and as struct timeval */
552
0
  get_ostime(&timets);
553
0
  fp_sys = tspec_stamp_to_lfp(timets);
554
0
  tvlast.tv_sec = timets.tv_sec;
555
0
  tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;
556
557
  /* get the target time as l_fp */
558
0
  L_ADD(&fp_sys, &fp_ofs);
559
560
  /* unfold the new system time */
561
0
  timetv = lfp_stamp_to_tval(fp_sys, &pivot);
562
563
  /* now set new system time */
564
0
  if (ntp_set_tod(&timetv, NULL) != 0) {
565
0
    msyslog(LOG_ERR, "step-systime: %m");
566
0
    if (enable_panic_check && allow_panic) {
567
0
      msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
568
0
    }
569
0
    return FALSE;
570
0
  }
571
572
  /* <--- time-critical path ended with 'ntp_set_tod()' <--- */
573
574
0
  sys_residual = 0;
575
0
  lamport_violated = (step < 0);
576
0
  if (step_callback)
577
0
    (*step_callback)();
578
579
#ifdef NEED_HPUX_ADJTIME
580
  /*
581
   * CHECKME: is this correct when called by ntpdate?????
582
   */
583
  _clear_adjtime();
584
#endif
585
586
0
  update_uwtmp(timetv, tvlast);
587
0
  if (enable_panic_check && allow_panic) {
588
0
    msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
589
0
    INSIST(!allow_panic);
590
0
  }
591
0
  return TRUE;
592
0
}
593
594
static const char *
595
tv_fmt_libbuf(
596
  const struct timeval * ptv
597
  )
598
0
{
599
0
  char *    retv;
600
0
  vint64    secs;
601
0
  ntpcal_split  dds;
602
0
  struct calendar jd;
603
604
0
  secs = time_to_vint64(&ptv->tv_sec);
605
0
  dds  = ntpcal_daysplit(&secs);
606
0
  ntpcal_daysplit_to_date(&jd, &dds, DAY_UNIX_STARTS);
607
0
  LIB_GETBUF(retv);
608
0
  snprintf(retv, LIB_BUFLENGTH,
609
0
     "%04hu-%02hu-%02hu/%02hu:%02hu:%02hu.%06u",
610
0
     jd.year, (u_short)jd.month, (u_short)jd.monthday,
611
0
     (u_short)jd.hour, (u_short)jd.minute, (u_short)jd.second,
612
0
     (u_int)ptv->tv_usec);
613
0
  return retv;
614
0
}
615
616
617
int /*BOOL*/
618
clamp_systime(void)
619
0
{
620
0
#if SIZEOF_TIME_T > 4
621
622
0
  struct timeval timetv, tvlast;
623
0
  struct timespec timets;
624
0
  uint32_t  tdiff;
625
626
  
627
0
  timetv.tv_sec = basedate_get_erabase();
628
  
629
  /* ---> time-critical path starts ---> */
630
631
  /* get the current time as l_fp (without fuzz) and as struct timeval */
632
0
  get_ostime(&timets);
633
0
  tvlast.tv_sec = timets.tv_sec;
634
0
  tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;
635
0
  if (tvlast.tv_usec >= 1000000) {
636
0
    tvlast.tv_usec -= 1000000;
637
0
    tvlast.tv_sec  += 1;
638
0
  }
639
0
  timetv.tv_usec = tvlast.tv_usec;
640
641
0
  tdiff = (uint32_t)(tvlast.tv_sec & UINT32_MAX) -
642
0
          (uint32_t)(timetv.tv_sec & UINT32_MAX);
643
0
  timetv.tv_sec += tdiff;
644
0
  if (timetv.tv_sec != tvlast.tv_sec) {
645
    /* now set new system time */
646
0
    if (ntp_set_tod(&timetv, NULL) != 0) {
647
0
      msyslog(LOG_ERR, "clamp-systime: %m");
648
0
      return FALSE;
649
0
    }
650
0
  } else {
651
0
    msyslog(LOG_INFO,
652
0
      "clamp-systime: clock (%s) in allowed range",
653
0
      tv_fmt_libbuf(&timetv));
654
0
    return FALSE;
655
0
  }
656
657
  /* <--- time-critical path ended with 'ntp_set_tod()' <--- */
658
659
0
  sys_residual = 0;
660
0
  lamport_violated = (timetv.tv_sec < tvlast.tv_sec);
661
0
  if (step_callback)
662
0
    (*step_callback)();
663
664
#   ifdef NEED_HPUX_ADJTIME
665
  /*
666
   * CHECKME: is this correct when called by ntpdate?????
667
   */
668
  _clear_adjtime();
669
#   endif
670
671
0
  update_uwtmp(timetv, tvlast);
672
0
  msyslog(LOG_WARNING,
673
0
    "clamp-systime: clock stepped from %s to %s!",
674
0
    tv_fmt_libbuf(&tvlast), tv_fmt_libbuf(&timetv));
675
0
  return TRUE;
676
    
677
#else
678
679
  return 0;
680
#endif
681
0
}
682
683
#endif  /* !SIM */