systime.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 1996, 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* systime -- routines to fiddle a UNIX clock.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_SYS_PARAM_H
#endif
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif /* HAVE_UTMP_H */
#ifdef HAVE_UTMPX_H
# include <utmpx.h>
#endif /* HAVE_UTMPX_H */
#include "ntp_fp.h"
#include "ntp_syslog.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
#if defined(GDT_SURVEYING)
#endif
#ifdef SLEWALWAYS
int slewalways = 1;
#else
int slewalways = 0;
#endif
extern int debug;
int allow_set_backward;
/*
* These routines (init_systime, get_systime, step_systime, adj_systime)
* implement an interface between the (more or less) system independent
* bits of NTP and the peculiarities of dealing with the Unix system
* clock. These routines will run with good precision fairly independently
* of your kernel's value of tickadj. I couldn't tell the difference
* between tickadj==40 and tickadj==5 on a microvax, though I prefer
* to set tickadj == 500/hz when in doubt. At your option you
* may compile this so that your system's clock is always slewed to the
* correct time even for large corrections. Of course, all of this takes
* a lot of code which wouldn't be needed with a reasonable tickadj and
* a willingness to let the clock be stepped occasionally. Oh well.
*/
/*
* Clock variables. We round calls to adjtime() to adj_precision
* microseconds, and limit the adjustment to tvu_maxslew microseconds
* (tsf_maxslew fractional sec) in one adjustment interval. As we are
* thus limited in the speed and precision with which we can adjust the
* clock, we compensate by keeping the known "error" in the system time
* in sys_clock_offset. This is added to timestamps returned by get_systime().
* We also remember the clock precision we computed from the kernel in
* case someone asks us.
*/
long sys_clock;
long adj_precision; /* adj precision in usec (tickadj) */
long tvu_maxslew; /* maximum adjust doable in 1 second */
#ifdef SYS_WINNT
/*
* number of 100 nanosecond units added to the clock at each tick
* determined by GetSystemTimeAdjustment() in clock_parms()
*/
long units_per_tick;
#endif /* SYS_WINNT */
/*
* get_systime - return the system time in timestamp format
* As a side effect, update sys_clock.
*/
void
{
#ifdef HAVE_GETCLOCK
#endif
/*
* Get the time of day, convert to time stamp format
* and add in the current time offset. Then round
* appropriately.
*/
#ifdef HAVE_GETCLOCK
#else /* not HAVE_GETCLOCK */
#endif /* not HAVE_GETCLOCK */
}
/*
* step_systime - do a step adjustment in the system time (at least from
* NTP's point of view.
*/
int
{
int isneg;
#ifdef STEP_SLEW
int n;
#endif
/*
* Take the absolute value of the offset
*/
isneg = 1;
} else
isneg = 0;
#ifdef STEP_SLEW
n = step_systime_real(now);
if (!n) return n;
if (isneg)
else
}
/*
* Just add adjustment into the current offset. The update
* routine will take care of bringing the system clock into
* line.
*/
#if defined(GDT_SURVEYING)
#endif
return 1;
#else /* STEP_SLEW */
if (slewalways) {
/*
* Just add adjustment into the current offset. The update
* routine will take care of bringing the system clock into
* line.
*/
#if defined(GDT_SURVEYING)
#endif
return 1;
} else {
#ifdef DEBUG
if (debug > 2)
#endif
if (isneg && !allow_set_backward) {
return 1;
}
else {
#ifdef DEBUG
if (debug > 2)
printf ("calling step_systime_real from not slewalways\n");
#endif
return step_systime_real(now);
}
}
#endif /* STEP_SLEW */
}
int max_no_complete = 20;
/*
* adj_systime - called once every second to make system time adjustments.
*/
int
{
register long temp;
register int isneg = 0;
#ifndef SYS_WINNT
#endif
int rval;
#ifdef SYS_WINNT
#endif /* SYS_WINNT */
#if defined(GDT_SURVEYING)
/* add to record of increments */
#endif
#ifdef DEBUG
if (debug > 4)
#endif
/*
* Move the current offset into the registers
*/
/*
* Add the new adjustment into the system offset. Adjust the
* system clock to minimize this.
*/
isneg = 1;
}
/*
* Slew is bigger than we can complete in
* the adjustment interval. Make a maximum
* sized slew and reduce sys_clock_offset by this
* much.
*/
if (!isneg) {
#ifndef SYS_WINNT
#else
#endif /* SYS_WINNT */
} else {
#ifndef SYS_WINNT
#else
#endif /* SYS_WINNT */
}
#ifdef DEBUG
if (debug > 4)
printf("systime: maximum slew: %s%s, remainder = %s\n",
#endif
} else {
/*
* We can do this slew in the time period. Do our
* best approximation (rounded), save residual for
* next adjustment.
*
* Note that offset_i is guaranteed to be 0 here.
*/
#ifndef ADJTIME_IS_ACCURATE
/*
* Round value to be an even multiple of adj_precision
*/
temp += adj_precision;
#endif /* ADJTIME_IS_ACCURATE */
if (isneg) {
#ifndef SYS_WINNT
#else
#endif /* SYS_WINNT */
} else {
#ifndef SYS_WINNT
#else
#endif /* SYS_WINNT */
}
#ifdef DEBUG
if (debug > 4) {
#ifndef SYS_WINNT
"systime: adjtv = %s sec, adjts = %s sec, sys_clock_offset = %s sec\n",
#else
"systime: dwTimeAdjustment = %d, sys_clock_offset = %s sec\n",
#endif /* SYS_WINNT */
printf("sys_adjtime: zeroing offset_i and offset_f\n");
}
#endif /* DEBUG */
}
/*
* Here we do the actual adjustment. If for some reason the adjtime()
* call fails, like it is not implemented or something like that,
* we honk to the log. If the previous adjustment did not complete,
* we correct the residual offset and honk to the log, but only for
* a little while.
*/
if (
#ifndef SYS_WINNT
/* casey - we need a posix type thang here */
#else
#endif /* SYS_WINNT */
) {
rval = 0;
} else {
rval = 1;
#ifndef SYS_WINNT
#if defined(GDT_SURVEYING)
#endif
if (max_no_complete > 0) {
"Previous time adjustment incomplete; residual %s sec\n",
}
}
#endif /* SYS_WINNT */
}
return(rval);
}
/*
* This is used by ntpdate even when xntpd does not use it! WLJ
*/
int
{
int isneg = 0;
#if defined(HAVE_GETCLOCK) || defined(HAVE_CLOCK_SETTIME)
#endif
#if DEBUG
if (debug)
printf("step_systime: offset %s sys_offset %s\n",
#endif
/*
* We can afford to be sloppy here since if this is called
* the time is really screwed and everything is being reset.
*/
#if defined(GDT_SURVEYING)
#endif
if (L_ISNEG(&sys_clock_offset)) {
isneg = 1;
}
#ifdef HAVE_GETCLOCK
#else /* not HAVE_GETCLOCK */
#endif /* not HAVE_GETCLOCK */
#ifdef DEBUG
if (debug)
printf("step: %s sec, sys_clock_offset = %s sec, adjtv = %s sec, timetv = %s sec\n",
#endif
if (isneg) {
}
} else {
}
}
#ifdef DEBUG
if (debug)
#endif
#endif /* HAVE_CLOCK_SETTIME */
if (
#else /* HAVE_CLOCK_SETTIME */
#endif /* HAVE_CLOCK_SETTIME */
) {
return (0);
}
#if DEBUG
if (debug) {
#ifdef HAVE_GETCLOCK
#else /* not HAVE_GETCLOCK */
#endif /* not HAVE_GETCLOCK */
}
#endif
#ifdef NEED_HPUX_ADJTIME
/*
* CHECKME: is this correct when called by ntpdate?????
*/
#endif
/*
* FreeBSD, for example, has:
* struct utmp {
* char ut_line[UT_LINESIZE];
* char ut_name[UT_NAMESIZE];
* char ut_host[UT_HOSTSIZE];
* long ut_time;
* };
* and appends line="|", name="date", host="", time for the OLD
* and appends line="{", name="date", host="", time for the NEW
* to _PATH_WTMP .
*
* Some OSes have utmp, some have utmpx.
*/
/*
* Write old and new time entries in utmp and wtmp if step adjustment
* is greater than one second.
*
* This might become even Uglier...
*/
{
#ifdef HAVE_UTMP_H
#endif
#ifdef HAVE_UTMPX_H
#endif
#ifdef HAVE_UTMP_H
#endif
#ifdef HAVE_UTMPX_H
#endif
/* UTMP */
#ifdef UPDATE_UTMP
# ifdef HAVE_PUTUTLINE
setutent();
endutent();
# else /* not HAVE_PUTUTLINE */
# endif /* not HAVE_PUTUTLINE */
#endif /* UPDATE_UTMP */
/* UTMPX */
#ifdef UPDATE_UTMPX
# ifdef HAVE_PUTUTXLINE
pututxline(&utx);
setutxent();
pututxline(&utx);
endutxent();
# else /* not HAVE_PUTUTXLINE */
# endif /* not HAVE_PUTUTXLINE */
#endif /* UPDATE_UTMPX */
/* WTMP */
#ifdef UPDATE_WTMP
# ifdef HAVE_PUTUTLINE
endutent();
# else /* not HAVE_PUTUTLINE */
# endif /* not HAVE_PUTUTLINE */
#endif /* UPDATE_WTMP */
/* WTMPX */
#ifdef UPDATE_WTMPX
# ifdef HAVE_PUTUTXLINE
# ifdef HAVE_UPDWTMPX
# else /* not HAVE_UPDWTMPX */
# endif /* not HAVE_UPDWTMPX */
# else /* not HAVE_PUTUTXLINE */
# endif /* not HAVE_PUTUTXLINE */
# ifdef HAVE_PUTUTXLINE
# ifdef HAVE_UPDWTMPX
# else /* not HAVE_UPDWTMPX */
# endif /* not HAVE_UPDWTMPX */
# else /* not HAVE_PUTUTXLINE */
# endif /* not HAVE_PUTUTXLINE */
#endif /* UPDATE_WTMPX */
}
return (1);
}