Coverage Report

Created: 2026-02-26 06:20

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