754 lines
17 KiB
C
754 lines
17 KiB
C
/* $NetBSD: ntp_unixclock.c,v 1.4 1998/03/06 18:17:22 christos Exp $ */
|
|
|
|
/*
|
|
* ntp_unixclock.c - routines for reading and adjusting a 4BSD-style
|
|
* system clock. Emacs has hide-ifdef-mode ...
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif /* HAVE_UNISTD_H */
|
|
#ifdef NLIST_STRUCT
|
|
# include <nlist.h>
|
|
# ifdef NLIST_NAME_UNION
|
|
# define N_NAME n_un.n_name
|
|
# else /* not NLIST_NAME_UNION */
|
|
# define N_NAME n_name
|
|
# endif /* not NLIST_NAME_UNION */
|
|
#endif /* NLIST_STRUCT */
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
|
|
#ifdef HAVE_SYS_PARAM_H
|
|
# include <sys/param.h>
|
|
#endif
|
|
#ifdef HAVE_UTMP_H
|
|
# include <utmp.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_SYSCTL_H
|
|
#include <sys/sysctl.h>
|
|
#endif
|
|
|
|
#if defined(HAVE_GETBOOTFILE)
|
|
# include <paths.h>
|
|
#endif
|
|
|
|
#include "ntpd.h"
|
|
#include "ntp_io.h"
|
|
#include "ntp_unixtime.h"
|
|
#include "ntp_stdlib.h"
|
|
|
|
#if defined(HAVE_LIBKVM)
|
|
# ifdef HAVE_SYS_PROC_H
|
|
# include <sys/proc.h>
|
|
# endif
|
|
# include <kvm.h>
|
|
# include <limits.h>
|
|
|
|
# ifndef _POSIX2_LINE_MAX
|
|
# define _POSIX2_LINE_MAX 2048
|
|
# endif
|
|
#endif /* HAVE_LIBKVM */
|
|
|
|
#ifdef HAVE_SYS_TIMEX_H /* Linux - also HAVE___ADJTIMEX */
|
|
# include <sys/timex.h>
|
|
#endif
|
|
|
|
#ifdef hz /* Was: RS6000 */
|
|
# undef hz
|
|
#endif /* hz */
|
|
|
|
extern int debug;
|
|
/*
|
|
* 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.
|
|
*/
|
|
extern long adj_precision; /* adj precision in usec (tickadj) */
|
|
extern long tvu_maxslew; /* maximum adjust doable in one sec (usec) */
|
|
|
|
#ifdef SYS_WINNT
|
|
extern long units_per_tick; /* imported from lib/systime.c module */
|
|
#endif /* SYS_WINNT */
|
|
|
|
extern u_long tsf_maxslew; /* same as above, as long format */
|
|
|
|
extern l_fp sys_clock_offset; /* correction for current system time */
|
|
|
|
#if defined(GDT_SURVEYING)
|
|
extern l_fp gdt_rsadj; /* running sum of adjustments to time */
|
|
#endif
|
|
|
|
/*
|
|
* Import sys_clock (it is updated in get_systime)
|
|
*/
|
|
extern long sys_clock;
|
|
|
|
/*
|
|
* Export default_tick and default_tickadj (for ntp_config)
|
|
*/
|
|
u_long default_tick = 0;
|
|
u_long default_tickadj = 0;
|
|
|
|
static void clock_parms P((u_long *, u_long *));
|
|
|
|
/*
|
|
* init_systime - initialize the system clock support code, return
|
|
* clock precision.
|
|
*
|
|
* Note that this code obtains to kernel variables related to the local
|
|
* clock, tickadj and tick. The code knows how the Berkeley adjtime
|
|
* call works, and assumes these two variables are obtainable and are
|
|
* used in the same manner. Tick is supposed to be the number of
|
|
* microseconds which are added to the system clock at clock interrupt
|
|
* time when the time isn't being slewed. Tickadj is supposed to be
|
|
* the number of microseconds which are added or subtracted from tick when
|
|
* the time is being slewed.
|
|
*
|
|
* If either of these two variables is missing, or is there but is used
|
|
* for a purpose different than that described, you are SOL and may have
|
|
* to do some custom kludging.
|
|
*
|
|
* This really shouldn't be in here.
|
|
*/
|
|
void
|
|
init_systime()
|
|
{
|
|
u_long tickadj;
|
|
u_long tick;
|
|
u_long hz;
|
|
|
|
/*
|
|
* Obtain the values
|
|
*/
|
|
#if !defined(VMS)
|
|
clock_parms(&tickadj, &tick);
|
|
#else
|
|
{
|
|
extern int get_tickfreq(int *FREQ, int *SYSTICK);
|
|
int freq,systick,sts;
|
|
|
|
sts = get_tickfreq(&freq,&systick);
|
|
if(!(sts & 1)) lib$stop(sts);
|
|
|
|
tick = 1000000/freq; /* (usec) */
|
|
}
|
|
tickadj = tick/10; /* VMS_{ADJTIME,TICTIME}.C will do up to 10% */
|
|
#endif /* VMS */
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
printf("kernel vars: tickadj = %ld, tick = %ld\n", tickadj, tick);
|
|
#endif
|
|
|
|
/*
|
|
* If tickadj or hz wasn't found, we're doomed. If hz is
|
|
* unreasonably small, forget it.
|
|
*/
|
|
if (tickadj == 0 || tick == 0) {
|
|
msyslog(LOG_ERR, "tickadj or tick unknown, exiting");
|
|
exit(3);
|
|
}
|
|
if (tick > 65535) {
|
|
msyslog(LOG_ERR, "tick value of %lu is unreasonably large",
|
|
tick);
|
|
exit(3);
|
|
}
|
|
|
|
/*
|
|
* Estimate hz from tick
|
|
*/
|
|
#ifndef SYS_VXWORKS
|
|
hz = 1000000L / tick;
|
|
#else
|
|
hz =sysClkRateGet();
|
|
#endif
|
|
|
|
#ifdef SYS_WINNT
|
|
if ((1000000L % tick) > tick/2)
|
|
hz += 1;
|
|
#endif /* SYS_WINNT */
|
|
|
|
/*
|
|
* Set adj_precision and the maximum slew based on this. Note
|
|
* that maxslew is set slightly shorter than it needs to be as
|
|
* insurance that all slews requested will complete in one second.
|
|
*/
|
|
#ifdef ADJTIME_IS_ACCURATE
|
|
adj_precision = 1;
|
|
#else
|
|
# if defined(SCO3_TICKADJ) || defined(SCO5_TICKADJ)
|
|
adj_precision = tickadj * hz;
|
|
# else
|
|
# ifndef SYS_WINNT
|
|
adj_precision = tickadj;
|
|
# else
|
|
/* minimum adjustment is one 100 nanosecond unit at each clock tick */
|
|
adj_precision = (long)(hz * 0.1);
|
|
# endif /* SYS_WINNT */
|
|
# endif /* not SCO[35]_TICKADJ */
|
|
#endif /* ADJTIME_IS_ACCURATE */
|
|
#ifdef NEED_HPUX_ADJTIME
|
|
/*
|
|
* when using adjtimed daemon, need to allow more time
|
|
* because daemon may not run right away
|
|
*/
|
|
tvu_maxslew = tickadj * (hz - 3);
|
|
#else
|
|
# if defined(SLEWALWAYS) && !defined(ADJTIME_IS_ACCURATE)
|
|
/*
|
|
* give us more time if we are always slewing... just in case
|
|
*/
|
|
tvu_maxslew = tickadj * (hz - 3);
|
|
# else
|
|
# if !defined(SYS_WINNT) && !defined(SCO3_TICKADJ) && !defined(SCO5_TICKADJ)
|
|
tvu_maxslew = tickadj * (hz - 1);
|
|
# else
|
|
tvu_maxslew = tickadj * hz;
|
|
# endif /* SYS_WINTNT */
|
|
# endif /* SLEWALWAYS */
|
|
#endif /* NEED_HPUX_ADJTIME */
|
|
if (tvu_maxslew > 999990) {
|
|
/*
|
|
* Don't let the maximum slew exceed 1 second in 4. This
|
|
* simplifies calculations a lot since we can then deal
|
|
* with less-than-one-second fractions.
|
|
*/
|
|
tvu_maxslew = (999990/adj_precision) * adj_precision;
|
|
}
|
|
TVUTOTSF(tvu_maxslew, tsf_maxslew);
|
|
NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
|
|
msyslog(LOG_NOTICE, "tickadj = %d, tick = %d, tvu_maxslew = %d, est. hz = %d",
|
|
tickadj, tick, tvu_maxslew, hz);
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
printf(
|
|
"adj_precision = %ld, tvu_maxslew = %ld, tsf_maxslew = 0.%08lx\n",
|
|
adj_precision, tvu_maxslew, tsf_maxslew);
|
|
#endif
|
|
|
|
/*
|
|
* Set the current offset to 0
|
|
*/
|
|
L_CLR(&sys_clock_offset);
|
|
#if defined(GDT_SURVEYING)
|
|
/*
|
|
* Set the current increment
|
|
*/
|
|
|
|
L_CLR(&gdt_rsadj);
|
|
#endif /* GDT_SURVEYING */
|
|
}
|
|
|
|
|
|
#if !defined(VMS)
|
|
|
|
# ifndef HZ
|
|
# define HZ DEFAULT_HZ
|
|
# endif
|
|
|
|
# ifdef NLIST_STRUCT
|
|
# ifdef NLIST_NAME_UNION
|
|
# define NL_B {{
|
|
# define NL_E }}
|
|
# else
|
|
# define NL_B {
|
|
# define NL_E }
|
|
# endif
|
|
# endif
|
|
|
|
#define K_FILLER_NAME "DavidLetterman"
|
|
|
|
/*
|
|
* clock_parms - return the local clock tickadj and tick parameters
|
|
*
|
|
*/
|
|
|
|
static void
|
|
clock_parms(ptickadj, ptick)
|
|
u_long *ptickadj;
|
|
u_long *ptick;
|
|
{
|
|
u_long tick;
|
|
int got_tick = 0;
|
|
int got_tickadj = 0;
|
|
int hz = 0;
|
|
int got_hz = 0;
|
|
# ifdef SYS_WINNT
|
|
DWORD add, every;
|
|
BOOL noslew;
|
|
# else /* not SYS_WINNT */
|
|
# if defined(HAVE_SYSCTL) && defined(CTL_KERN) && defined(KERN_CLOCKRATE)
|
|
int mib[2];
|
|
size_t ci_len;
|
|
struct clockinfo c;
|
|
int rc;
|
|
# endif /* HAVE_SYSCTL && CTL_KERN && KERN_CLOCKRATE */
|
|
# ifndef NOKMEM
|
|
static struct nlist nl[] =
|
|
{
|
|
NL_B
|
|
# ifdef K_TICKADJ_NAME
|
|
# define N_TICKADJ 0
|
|
K_TICKADJ_NAME
|
|
# else
|
|
K_FILLER_NAME
|
|
# endif /* K_TICKADJ_NAME */
|
|
NL_E,
|
|
NL_B
|
|
# ifdef K_TICK_NAME
|
|
# define N_TICK 1
|
|
K_TICK_NAME
|
|
# else
|
|
K_FILLER_NAME
|
|
# endif /* K_TICK_NAME */
|
|
NL_E,
|
|
NL_B "" NL_E,
|
|
};
|
|
# ifdef HAVE_K_OPEN
|
|
# else /* not HAVE_K_OPEN */
|
|
# ifdef HAVE_KVM_OPEN
|
|
register kvm_t *kd;
|
|
# else /* not HAVE_KVM_OPEN */
|
|
register int i;
|
|
int kmem;
|
|
struct stat stbuf;
|
|
off_t where;
|
|
# ifdef HAVE_BOOTFILE
|
|
const char *kernelname;
|
|
# else /* not HAVE_BOOTFILE */
|
|
static char *kernelnames[] =
|
|
{
|
|
"/kernel/unix",
|
|
"/kernel",
|
|
"/vmunix",
|
|
"/unix",
|
|
"/mach",
|
|
"/hp-ux",
|
|
"/386bsd",
|
|
"/netbsd",
|
|
"/stand/vmunix",
|
|
"/bsd",
|
|
# ifdef KERNELFILE
|
|
KERNELFILE,
|
|
# endif
|
|
NULL
|
|
};
|
|
# endif /* not HAVE_BOOTFILE */
|
|
# endif /* not HAVE_KVM_OPEN */
|
|
# endif /* not HAVE_K_OPEN */
|
|
# endif /* not NOKMEM */
|
|
# endif /* not SYS_WINNT */
|
|
|
|
# ifdef SYS_WINNT
|
|
if (!GetSystemTimeAdjustment(&add, &every, &noslew))
|
|
{
|
|
*ptick = 0;
|
|
*ptickadj = 0;
|
|
return;
|
|
}
|
|
units_per_tick = add;
|
|
# else /* not SYS_WINNT */
|
|
|
|
# if defined(HAVE_SYSCTL) && defined(CTL_KERN) && defined(KERN_CLOCKRATE)
|
|
mib[0] = CTL_KERN;
|
|
mib[1] = KERN_CLOCKRATE;
|
|
ci_len = sizeof(c);
|
|
rc = sysctl(mib, 2, &c, &ci_len, NULL, 0);
|
|
if (rc == -1)
|
|
{
|
|
NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
|
|
syslog(LOG_NOTICE, "sysctl returned %d: %m", rc);
|
|
}
|
|
*ptick = c.tick;
|
|
++got_tick;
|
|
# ifdef HAVE_TICKADJ_IN_STRUCT_CLOCKINFO
|
|
*ptickadj = c.tickadj;
|
|
++got_tickadj;
|
|
# endif /* HAVE_TICKADJ_IN_STRUCT_CLOCKINFO */
|
|
# ifdef HAVE_HZ_IN_STRUCT_CLOCKINFO
|
|
hz = c.hz;
|
|
++got_hz;
|
|
# endif /* HAVE_HZ_IN_STRUCT_CLOCKINFO */
|
|
# endif /* HAVE_SYSCTL && CTL_KERN && KERN_CLOCKRATE */
|
|
|
|
if (!got_hz)
|
|
{
|
|
hz = HZ;
|
|
# if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
|
|
hz = (int) sysconf (_SC_CLK_TCK);
|
|
# endif /* HAVE_SYSCONF && _SC_CLK_TCK */
|
|
# ifdef OVERRIDE_HZ
|
|
hz = DEFAULT_HZ;
|
|
# endif
|
|
++got_hz;
|
|
}
|
|
|
|
{
|
|
# ifndef NOKMEM
|
|
# ifdef HAVE_K_OPEN /* { */
|
|
if (K_open((char *)0, O_RDONLY, "/vmunix")!=0)
|
|
{
|
|
msyslog(LOG_ERR, "K_open failed");
|
|
exit(3);
|
|
}
|
|
kusenlist(1);
|
|
if (knlist(nl) != 0)
|
|
{
|
|
msyslog(LOG_ERR, "knlist failed");
|
|
exit(3);
|
|
}
|
|
# else /* } not HAVE_K_OPEN { */
|
|
# ifdef HAVE_KVM_OPEN /* { */
|
|
if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
|
|
{
|
|
msyslog(LOG_ERR, "kvm_open failed");
|
|
exit(3);
|
|
}
|
|
if (kvm_nlist(kd, nl) == -1)
|
|
{
|
|
msyslog(LOG_ERR, "kvm_nlist failed");
|
|
exit(3);
|
|
}
|
|
# else /* } not HAVE_KVM_OPEN { */
|
|
# ifdef HAVE_GETBOOTFILE
|
|
kernelname = getbootfile();
|
|
if (!kernelname)
|
|
{
|
|
msyslog(LOG_ERR, "getbootfile() didn't find kernel name!");
|
|
exit(3);
|
|
}
|
|
else if (stat(kernelname, &stbuf) == -1)
|
|
{
|
|
msyslog(LOG_ERR, "stat(%s) failed: %m", kernelname);
|
|
exit(3);
|
|
}
|
|
else if (nlist(kernelname, nl) < 0)
|
|
{
|
|
msyslog(LOG_ERR, "nlist(%s) failed: %m", kernelname);
|
|
exit(3);
|
|
}
|
|
# else /* not HAVE_GETBOOTFILE */
|
|
for (i = 0; kernelnames[i] != NULL; i++)
|
|
{
|
|
if (stat(kernelnames[i], &stbuf) == -1)
|
|
continue;
|
|
if (nlist(kernelnames[i], nl) >= 0)
|
|
break;
|
|
}
|
|
if (kernelnames[i] == NULL)
|
|
{
|
|
msyslog(LOG_ERR, "Clock init couldn't find kernel object file");
|
|
}
|
|
# endif /* not HAVE_GETBOOTFILE */
|
|
kmem = open("/dev/kmem", O_RDONLY);
|
|
if (kmem < 0)
|
|
{
|
|
msyslog(LOG_ERR, "Can't open /dev/kmem for reading: %m");
|
|
#ifdef DEBUG
|
|
if (debug)
|
|
perror("/dev/kmem");
|
|
#endif
|
|
}
|
|
# endif /* } not HAVE_KVM_OPEN */
|
|
# endif /* } not HAVE_K_OPEN */
|
|
# endif /* not NOKMEM */
|
|
}
|
|
# endif /* not SYS_WINNT */
|
|
|
|
/* Skippy says we need to know TICK before handling TICKADJ */
|
|
if (got_tick != 1)
|
|
{
|
|
# if defined(HAVE_SYS_TIMEX_H) && defined(HAVE___ADJTIMEX)
|
|
struct timex txc;
|
|
# endif /* HAVE_SYS_TIMEX_H && HAVE___ADJTIMEX */
|
|
|
|
# if !defined(NOKMEM) && defined(N_TICK)
|
|
# ifdef HAVE_K_OPEN
|
|
if (K_read(ptick, sizeof(*ptick), nl[N_TICK].n_value) != sizeof(*ptick))
|
|
{
|
|
msyslog(LOG_ERR, "K_read tick failed");
|
|
}
|
|
else
|
|
{
|
|
if (*ptick) ++got_tick;
|
|
}
|
|
# else /* not HAVE_K_OPEN */
|
|
# ifdef HAVE_KVM_OPEN
|
|
if (kvm_read(kd, nl[N_TICK].n_value, (char *)ptick, sizeof(*ptick)) !=
|
|
sizeof(*ptick))
|
|
{
|
|
msyslog(LOG_ERR, "kvm_read tick failed");
|
|
}
|
|
else
|
|
{
|
|
if (*ptick) ++got_tick;
|
|
}
|
|
# else /* not HAVE_KVM_OPEN */
|
|
if ((where = nl[N_TICK].n_value) == 0)
|
|
{
|
|
msyslog(LOG_ERR, "Unknown kernel var <%s>",
|
|
nl[N_TICK].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
if (lseek(kmem, where, SEEK_SET) == -1)
|
|
{
|
|
msyslog(LOG_ERR, "lseek for %s fails: %m",
|
|
nl[N_TICK].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
if (read(kmem, ptick, sizeof(*ptick)) != sizeof(*ptick))
|
|
{
|
|
msyslog(LOG_ERR, "read for %s fails: %m",
|
|
nl[N_TICK].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
# ifdef NLIST_EXTRA_INDIRECTION
|
|
/*
|
|
* Aix requires one more round of indirection
|
|
* if storage class a pointer.
|
|
*/
|
|
if ( nl[N_TICK].n_sclass == 0x6b)
|
|
{
|
|
if (lseek(kmem, *ptick, SEEK_SET) == -1)
|
|
{
|
|
msyslog(LOG_ERR, "lseek2 for %s fails: %m",
|
|
nl[N_TICK].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
if (read(kmem, ptick, sizeof(*ptick)) !=
|
|
sizeof(*ptick))
|
|
{
|
|
msyslog(LOG_ERR, "read2 for %s fails: %m",
|
|
nl[N_TICK].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
if (*ptick) ++got_tick;
|
|
}
|
|
}
|
|
}
|
|
# else /* not NLIST_EXTRA_INDIRECTION */
|
|
if (*ptick) ++got_tick;
|
|
# endif /* not NLIST_EXTRA_INDIRECTION */
|
|
}
|
|
}
|
|
}
|
|
# endif /* not HAVE_KVM_OPEN */
|
|
# endif /* not HAVE_K_OPEN */
|
|
# ifdef TICK_NANO
|
|
if (got_tick)
|
|
{
|
|
*ptick /= 1000;
|
|
}
|
|
# endif /* TICK_NANO */
|
|
# endif /* not NOKMEM && N_TICK */
|
|
|
|
if (!got_tick && default_tick)
|
|
{
|
|
*ptick = default_tick;
|
|
if (*ptick) ++got_tick;
|
|
}
|
|
|
|
# ifdef PRESET_TICK
|
|
if (!got_tick)
|
|
{
|
|
# if defined(HAVE_SYS_TIMEX_H) && defined(HAVE___ADJTIMEX)
|
|
# ifdef MOD_OFFSET
|
|
txc.modes = 0;
|
|
# else
|
|
txc.mode = 0;
|
|
# endif
|
|
__adjtimex(&txc);
|
|
# endif /* HAVE_SYS_TIMEX_H && HAVE___ADJTIMEX */
|
|
*ptick = (u_long) PRESET_TICK;
|
|
if (*ptick) ++got_tick;
|
|
}
|
|
# endif /* PRESET_TICK */
|
|
|
|
if (got_tick != 1)
|
|
{
|
|
msyslog(LOG_ERR, "Problem getting tick: %d != 1", got_tick);
|
|
exit(3);
|
|
}
|
|
|
|
tick = *ptick; /* This might be used by PRESET_TICKADJ */
|
|
}
|
|
|
|
/* Skippy says we need to know TICK before handling TICKADJ */
|
|
if (got_tickadj != 1)
|
|
{
|
|
# if !defined(NOKMEM) && defined(N_TICKADJ)
|
|
if (nl[N_TICKADJ].n_value == 0)
|
|
{
|
|
msyslog(LOG_ERR, "Unknown kernel variable <%s>",
|
|
nl[N_TICKADJ].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
# ifdef HAVE_K_OPEN
|
|
if (K_read(ptickadj, sizeof(*ptickadj), nl[N_TICKADJ].n_value) !=
|
|
sizeof(*ptickadj))
|
|
{
|
|
msyslog(LOG_ERR, "K_read tickadj failed");
|
|
}
|
|
else
|
|
{
|
|
if (*ptickadj) ++got_tickadj;
|
|
}
|
|
# else /* not HAVE_K_OPEN */
|
|
# ifdef HAVE_KVM_OPEN
|
|
if (kvm_read(kd, nl[N_TICKADJ].n_value, (char *)ptickadj, sizeof(*ptickadj)) !=
|
|
sizeof(*ptickadj))
|
|
{
|
|
msyslog(LOG_ERR, "kvm_read tickadj failed");
|
|
}
|
|
else
|
|
{
|
|
if (*ptickadj) ++got_tickadj;
|
|
}
|
|
# else /* not HAVE_KVM_OPEN */
|
|
if ((where = nl[N_TICKADJ].n_value) == 0)
|
|
{
|
|
msyslog(LOG_ERR, "Unknown kernel var <%s>",
|
|
nl[N_TICKADJ].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
if (lseek(kmem, where, SEEK_SET) == -1)
|
|
{
|
|
msyslog(LOG_ERR, "lseek for %s fails: %m",
|
|
nl[N_TICKADJ].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
if (read(kmem, ptickadj, sizeof(*ptickadj)) !=
|
|
sizeof(*ptickadj))
|
|
{
|
|
msyslog(LOG_ERR, "read for %s fails: %m",
|
|
nl[N_TICKADJ].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
# ifdef NLIST_EXTRA_INDIRECTION
|
|
/*
|
|
* Aix requires one more round of indirection
|
|
* if storage class a pointer.
|
|
*/
|
|
if ( nl[N_TICKADJ].n_sclass == 0x6b)
|
|
{
|
|
if (lseek(kmem, *ptickadj, SEEK_SET) == -1)
|
|
{
|
|
msyslog(LOG_ERR, "lseek2 for %s fails: %m",
|
|
nl[N_TICKADJ].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
if (read(kmem, ptickadj, sizeof(*ptickadj)) !=
|
|
sizeof(*ptickadj))
|
|
{
|
|
msyslog(LOG_ERR, "read2 for %s fails: %m",
|
|
nl[N_TICKADJ].N_NAME);
|
|
}
|
|
else
|
|
{
|
|
if (*ptickadj) ++got_tickadj;
|
|
}
|
|
}
|
|
}
|
|
# else /* not NLIST_EXTRA_INDIRECTION */
|
|
if (*ptickadj) ++got_tickadj;
|
|
# endif /* not NLIST_EXTRA_INDIRECTION */
|
|
}
|
|
}
|
|
}
|
|
# endif /* not HAVE_KVM_OPEN */
|
|
# endif /* not HAVE_K_OPEN */
|
|
}
|
|
|
|
# ifdef TICKADJ_NANO
|
|
if (got_tickadj)
|
|
{
|
|
*ptickadj /= 1000;
|
|
if (*ptickadj == 0)
|
|
{
|
|
*ptickadj = 1;
|
|
}
|
|
}
|
|
# endif /* TICKADJ_NANO */
|
|
# ifdef SCO5_TICKADJ
|
|
if (got_tickadj)
|
|
{
|
|
*ptickadj /= (1000 * hz);
|
|
}
|
|
# else /* not SCO5_TICKADJ */
|
|
# ifdef SCO3_TICKADJ
|
|
if (got_tickadj)
|
|
{
|
|
*ptickadj *= (10000 / hz);
|
|
}
|
|
# endif /* SCO3_TICKADJ */
|
|
# endif/* not SCO5_TICKADJ */
|
|
# endif /* not NOKMEM && N_TICKADJ */
|
|
|
|
if (!got_tickadj && default_tickadj)
|
|
{
|
|
*ptickadj = default_tickadj;
|
|
if (*ptickadj) ++got_tickadj;
|
|
}
|
|
|
|
# ifdef PRESET_TICKADJ
|
|
if (!got_tickadj)
|
|
{
|
|
*ptickadj = (u_long) ((PRESET_TICKADJ) ? PRESET_TICKADJ : 1);
|
|
if (*ptickadj) ++got_tickadj;
|
|
}
|
|
# endif /* PRESET_TICKADJ */
|
|
|
|
if (got_tickadj != 1)
|
|
{
|
|
msyslog(LOG_ERR, "Problem getting tickadj: %d != 1", got_tickadj);
|
|
exit(3);
|
|
}
|
|
}
|
|
|
|
# ifndef NOKMEM
|
|
# ifdef HAVE_K_OPEN
|
|
(void) K_close();
|
|
# else /* not HAVE_K_OPEN */
|
|
# ifdef HAVE_KVM_OPEN
|
|
if (kvm_close(kd) < 0)
|
|
{
|
|
msyslog(LOG_ERR, "kvm_close failed");
|
|
exit(3);
|
|
}
|
|
# else /* not HAVE_KVM_OPEN */
|
|
close(kmem);
|
|
# endif /* not HAVE_KVM_OPEN */
|
|
# endif /* not HAVE_K_OPEN */
|
|
# endif /* not NOKMEM */
|
|
|
|
# ifdef DEBUG
|
|
if (debug)
|
|
printf("tick = %ld, tickadj = %ld, hz = %d\n", *ptick, *ptickadj, hz);
|
|
# endif
|
|
}
|
|
#endif /* not VMS */
|