907 lines
16 KiB
C
907 lines
16 KiB
C
/* $NetBSD: tickadj.c,v 1.2 2001/04/06 11:13:55 wiz Exp $ */
|
|
|
|
/*
|
|
* tickadj - read, and possibly modify, the kernel `tick' and
|
|
* `tickadj' variables, as well as `dosynctodr'. Note that
|
|
* this operates on the running kernel only. I'd like to be
|
|
* able to read and write the binary as well, but haven't
|
|
* mastered this yet.
|
|
*
|
|
* HMS: The #includes here are different from those in xntpd/ntp_unixclock.c
|
|
* These seem "worse".
|
|
*/
|
|
|
|
#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 */
|
|
|
|
#include "ntp_types.h"
|
|
#include "l_stdlib.h"
|
|
|
|
#ifdef HAVE___ADJTIMEX /* Linux */
|
|
|
|
#include <sys/timex.h>
|
|
struct timex txc;
|
|
|
|
#if 0
|
|
int
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
int c, i;
|
|
int quiet = 0;
|
|
int errflg = 0;
|
|
char *progname;
|
|
extern int ntp_optind;
|
|
extern char *ntp_optarg;
|
|
|
|
progname = argv[0];
|
|
if (argc==2 && argv[1][0] != '-') { /* old Linux format, for compatability */
|
|
if ((i = atoi(argv[1])) > 0) {
|
|
txc.time_tick = i;
|
|
txc.modes = ADJ_TIMETICK;
|
|
} else {
|
|
fprintf(stderr, "Silly value for tick: %s\n", argv[1]);
|
|
errflg++;
|
|
}
|
|
} else {
|
|
while ((c = ntp_getopt(argc, argv, "a:qt:")) != EOF) {
|
|
switch (c) {
|
|
case 'a':
|
|
if ((i=atoi(ntp_optarg)) > 0) {
|
|
txc.tickadj = i;
|
|
txc.modes |= ADJ_TICKADJ;
|
|
} else {
|
|
(void) fprintf(stderr,
|
|
"%s: unlikely value for tickadj: %s\n",
|
|
progname, ntp_optarg);
|
|
errflg++;
|
|
}
|
|
break;
|
|
|
|
case 'q':
|
|
quiet = 1;
|
|
break;
|
|
|
|
case 't':
|
|
if ((i=atoi(ntp_optarg)) > 0) {
|
|
txc.time_tick = i;
|
|
txc.modes |= ADJ_TIMETICK;
|
|
} else {
|
|
(void) fprintf(stderr,
|
|
"%s: unlikely value for tick: %s\n",
|
|
progname, ntp_optarg);
|
|
errflg++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr,
|
|
"Usage: %s [tick_value]\n-or- %s [ -q ] [ -t tick ] [ -a tickadj ]\n",
|
|
progname, progname);
|
|
errflg++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!errflg) {
|
|
if (__adjtimex(&txc) < 0)
|
|
perror("adjtimex");
|
|
else if (!quiet)
|
|
printf("tick = %ld\ntick_adj = %d\n",
|
|
txc.time_tick, txc.tickadj);
|
|
}
|
|
|
|
exit(errflg ? 1 : 0);
|
|
}
|
|
#else
|
|
int
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
if (argc > 2)
|
|
{
|
|
fprintf(stderr, "Usage: %s [tick_value]\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
else if (argc == 2)
|
|
{
|
|
#ifdef ADJ_TIMETICK
|
|
if ( (txc.time_tick = atoi(argv[1])) < 1 )
|
|
#else
|
|
if ( (txc.tick = atoi(argv[1])) < 1 )
|
|
#endif
|
|
{
|
|
fprintf(stderr, "Silly value for tick: %s\n", argv[1]);
|
|
exit(1);
|
|
}
|
|
#ifdef ADJ_TIMETICK
|
|
txc.modes = ADJ_TIMETICK;
|
|
#else
|
|
#ifdef MOD_OFFSET
|
|
txc.modes = ADJ_TICK;
|
|
#else
|
|
txc.mode = ADJ_TICK;
|
|
#endif
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef ADJ_TIMETICK
|
|
txc.modes = 0;
|
|
#else
|
|
#ifdef MOD_OFFSET
|
|
txc.modes = 0;
|
|
#else
|
|
txc.mode = 0;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
if (__adjtimex(&txc) < 0)
|
|
{
|
|
perror("adjtimex");
|
|
}
|
|
else
|
|
{
|
|
#ifdef ADJ_TIMETICK
|
|
printf("tick = %ld\ntick_adj = %ld\n", txc.time_tick, txc.tickadj);
|
|
#else
|
|
printf("tick = %ld\n", txc.tick);
|
|
#endif
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
#endif
|
|
|
|
#else /* not Linux... kmem tweaking: */
|
|
|
|
#ifdef HAVE_SYS_FILE_H
|
|
# include <sys/file.h>
|
|
#endif
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef HAVE_SYS_PARAM_H
|
|
# include <sys/param.h>
|
|
#endif
|
|
|
|
#ifdef NLIST_STRUCT
|
|
# include <nlist.h>
|
|
#else /* not NLIST_STRUCT */ /* was defined(SYS_AUX3) || defined(SYS_AUX2) */
|
|
# include <sys/time.h>
|
|
# include <sys/resource.h>
|
|
# include <sys/file.h>
|
|
# include <a.out.h>
|
|
# include <sys/var.h>
|
|
#endif
|
|
|
|
#include "ntp_io.h"
|
|
#include "ntp_stdlib.h"
|
|
|
|
#ifdef hz /* Was: RS6000 */
|
|
# undef hz
|
|
#endif /* hz */
|
|
|
|
#ifdef HAVE_KVM_OPEN
|
|
# include <kvm.h>
|
|
#endif
|
|
|
|
#ifdef SYS_VXWORKS
|
|
/* vxWorks needs mode flag -casey*/
|
|
#define open(name, flags) open(name, flags, 0777)
|
|
#endif
|
|
|
|
#ifndef L_SET /* Was: defined(SYS_PTX) || defined(SYS_IX86OSF1) */
|
|
# define L_SET SEEK_SET
|
|
#endif
|
|
|
|
#ifndef HZ
|
|
# define HZ DEFAULT_HZ
|
|
#endif
|
|
|
|
#define KMEM "/dev/kmem"
|
|
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
|
|
|
|
char *progname;
|
|
volatile int debug;
|
|
|
|
int dokmem = 1;
|
|
int writetickadj = 0;
|
|
int writeopttickadj = 0;
|
|
int unsetdosync = 0;
|
|
int writetick = 0;
|
|
int quiet = 0;
|
|
int setnoprintf = 0;
|
|
|
|
const char *kmem = KMEM;
|
|
const char *file = NULL;
|
|
int fd = -1;
|
|
|
|
static void getoffsets P((off_t *, off_t *, off_t *, off_t *));
|
|
static int openfile P((const char *, int));
|
|
static void writevar P((int, off_t, int));
|
|
static void readvar P((int, off_t, int *));
|
|
|
|
/*
|
|
* main - parse arguments and handle options
|
|
*/
|
|
int
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
int c;
|
|
int errflg = 0;
|
|
off_t tickadj_offset;
|
|
off_t tick_offset;
|
|
off_t dosync_offset;
|
|
off_t noprintf_offset;
|
|
int tickadj, ktickadj; /* HMS: Why isn't this u_long? */
|
|
int tick, ktick; /* HMS: Why isn't this u_long? */
|
|
int dosynctodr;
|
|
int noprintf;
|
|
int hz;
|
|
int hz_int, hz_hundredths;
|
|
int recommend_tickadj;
|
|
long tmp;
|
|
|
|
progname = argv[0];
|
|
while ((c = ntp_getopt(argc, argv, "a:Adkpqst:")) != EOF)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'a':
|
|
writetickadj = atoi(ntp_optarg);
|
|
if (writetickadj <= 0)
|
|
{
|
|
(void) fprintf(stderr,
|
|
"%s: unlikely value for tickadj: %s\n",
|
|
progname, ntp_optarg);
|
|
errflg++;
|
|
}
|
|
|
|
#if defined SCO5_CLOCK
|
|
if (writetickadj % HZ)
|
|
{
|
|
writetickadj = (writetickadj / HZ) * HZ;
|
|
(void) fprintf(stderr,
|
|
"tickadj truncated to: %d\n", writetickadj);
|
|
}
|
|
#endif /* SCO5_CLOCK */
|
|
|
|
break;
|
|
case 'A':
|
|
writeopttickadj = 1;
|
|
break;
|
|
case 'd':
|
|
++debug;
|
|
break;
|
|
case 'k':
|
|
dokmem = 1;
|
|
break;
|
|
case 'p':
|
|
setnoprintf = 1;
|
|
break;
|
|
case 'q':
|
|
quiet = 1;
|
|
break;
|
|
case 's':
|
|
unsetdosync = 1;
|
|
break;
|
|
case 't':
|
|
writetick = atoi(ntp_optarg);
|
|
if (writetick <= 0)
|
|
{
|
|
(void) fprintf(stderr,
|
|
"%s: unlikely value for tick: %s\n",
|
|
progname, ntp_optarg);
|
|
errflg++;
|
|
}
|
|
break;
|
|
default:
|
|
errflg++;
|
|
break;
|
|
}
|
|
}
|
|
if (errflg || ntp_optind != argc)
|
|
{
|
|
(void) fprintf(stderr,
|
|
"usage: %s [-Adkpqs] [-a newadj] [-t newtick]\n", progname);
|
|
exit(2);
|
|
}
|
|
|
|
getoffsets(&tick_offset, &tickadj_offset, &dosync_offset, &noprintf_offset);
|
|
|
|
if (debug)
|
|
{
|
|
(void) printf("tick offset = %lu\n", (unsigned long)tick_offset);
|
|
(void) printf("tickadj offset = %lu\n", (unsigned long)tickadj_offset);
|
|
(void) printf("dosynctodr offset = %lu\n", (unsigned long)dosync_offset);
|
|
(void) printf("noprintf offset = %lu\n", (unsigned long)noprintf_offset);
|
|
}
|
|
|
|
if (writetick && (tick_offset == 0))
|
|
{
|
|
(void) fprintf(stderr,
|
|
"No tick kernel variable\n");
|
|
errflg++;
|
|
}
|
|
|
|
if (writeopttickadj && (tickadj_offset == 0))
|
|
{
|
|
(void) fprintf(stderr,
|
|
"No tickadj kernel variable\n");
|
|
errflg++;
|
|
}
|
|
|
|
if (unsetdosync && (dosync_offset == 0))
|
|
{
|
|
(void) fprintf(stderr,
|
|
"No dosynctodr kernel variable\n");
|
|
errflg++;
|
|
}
|
|
|
|
if (setnoprintf && (noprintf_offset == 0))
|
|
{
|
|
(void) fprintf(stderr,
|
|
"No noprintf kernel variable\n");
|
|
errflg++;
|
|
}
|
|
|
|
if (tick_offset != 0)
|
|
{
|
|
readvar(fd, tick_offset, &tick);
|
|
#if defined(TICK_NANO) && defined(K_TICK_NAME)
|
|
if (!quiet)
|
|
(void) printf("KERNEL %s = %d nsec\n", K_TICK_NAME, tick);
|
|
#endif /* TICK_NANO && K_TICK_NAME */
|
|
|
|
#ifdef TICK_NANO
|
|
tick /= 1000;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
tick = 0;
|
|
}
|
|
|
|
if (tickadj_offset != 0)
|
|
{
|
|
readvar(fd, tickadj_offset, &tickadj);
|
|
|
|
#ifdef SCO5_CLOCK
|
|
/* scale from nsec/sec to usec/tick */
|
|
tickadj /= (1000L * HZ);
|
|
#endif /*SCO5_CLOCK */
|
|
|
|
#if defined(TICKADJ_NANO) && defined(K_TICKADJ_NAME)
|
|
if (!quiet)
|
|
(void) printf("KERNEL %s = %d nsec\n", K_TICKADJ_NAME, tickadj);
|
|
#endif /* TICKADJ_NANO && K_TICKADJ_NAME */
|
|
|
|
#ifdef TICKADJ_NANO
|
|
tickadj += 999;
|
|
tickadj /= 1000;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
tickadj = 0;
|
|
}
|
|
|
|
if (dosync_offset != 0)
|
|
{
|
|
readvar(fd, dosync_offset, &dosynctodr);
|
|
}
|
|
|
|
if (noprintf_offset != 0)
|
|
{
|
|
readvar(fd, noprintf_offset, &noprintf);
|
|
}
|
|
|
|
(void) close(fd);
|
|
|
|
if (unsetdosync && dosync_offset == 0)
|
|
{
|
|
(void) fprintf(stderr,
|
|
"%s: can't find %s in namelist\n",
|
|
progname,
|
|
#ifdef K_DOSYNCTODR_NAME
|
|
K_DOSYNCTODR_NAME
|
|
#else /* not K_DOSYNCTODR_NAME */
|
|
"dosynctodr"
|
|
#endif /* not K_DOSYNCTODR_NAME */
|
|
);
|
|
exit(1);
|
|
}
|
|
|
|
hz = HZ;
|
|
#if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
|
|
hz = (int) sysconf (_SC_CLK_TCK);
|
|
#endif /* not HAVE_SYSCONF && _SC_CLK_TCK */
|
|
#ifdef OVERRIDE_HZ
|
|
hz = DEFAULT_HZ;
|
|
#endif
|
|
ktick = tick;
|
|
#ifdef PRESET_TICK
|
|
tick = PRESET_TICK;
|
|
#endif /* PRESET_TICK */
|
|
#ifdef TICKADJ_NANO
|
|
tickadj /= 1000;
|
|
if (tickadj == 0)
|
|
tickadj = 1;
|
|
#endif
|
|
ktickadj = tickadj;
|
|
#ifdef PRESET_TICKADJ
|
|
tickadj = (PRESET_TICKADJ) ? PRESET_TICKADJ : 1;
|
|
#endif /* PRESET_TICKADJ */
|
|
|
|
if (!quiet)
|
|
{
|
|
if (tick_offset != 0)
|
|
{
|
|
(void) printf("KERNEL tick = %d usec (from %s kernel variable)\n",
|
|
ktick,
|
|
#ifdef K_TICK_NAME
|
|
K_TICK_NAME
|
|
#else
|
|
"<this can't happen>"
|
|
#endif
|
|
);
|
|
}
|
|
#ifdef PRESET_TICK
|
|
(void) printf("PRESET tick = %d usec\n", tick);
|
|
#endif /* PRESET_TICK */
|
|
if (tickadj_offset != 0)
|
|
{
|
|
(void) printf("KERNEL tickadj = %d usec (from %s kernel variable)\n",
|
|
ktickadj,
|
|
#ifdef K_TICKADJ_NAME
|
|
K_TICKADJ_NAME
|
|
#else
|
|
"<this can't happen>"
|
|
#endif
|
|
);
|
|
}
|
|
#ifdef PRESET_TICKADJ
|
|
(void) printf("PRESET tickadj = %d usec\n", tickadj);
|
|
#endif /* PRESET_TICKADJ */
|
|
if (dosync_offset != 0)
|
|
{
|
|
(void) printf("dosynctodr is %s\n", dosynctodr ? "on" : "off");
|
|
}
|
|
if (noprintf_offset != 0)
|
|
{
|
|
(void) printf("kernel level printf's: %s\n",
|
|
noprintf ? "off" : "on");
|
|
}
|
|
}
|
|
|
|
if (tick <= 0)
|
|
{
|
|
(void) fprintf(stderr, "%s: the value of tick is silly!\n",
|
|
progname);
|
|
exit(1);
|
|
}
|
|
|
|
hz_int = (int)(1000000L / (long)tick);
|
|
hz_hundredths = (int)((100000000L / (long)tick) - ((long)hz_int * 100L));
|
|
if (!quiet)
|
|
{
|
|
(void) printf("KERNEL hz = %d\n", hz);
|
|
(void) printf("calculated hz = %d.%02d Hz\n", hz_int,
|
|
hz_hundredths);
|
|
}
|
|
|
|
#if defined SCO5_CLOCK
|
|
recommend_tickadj = 100;
|
|
#else /* SCO5_CLOCK */
|
|
tmp = (long) tick * 500L;
|
|
recommend_tickadj = (int)(tmp / 1000000L);
|
|
if (tmp % 1000000L > 0)
|
|
{
|
|
recommend_tickadj++;
|
|
}
|
|
|
|
#ifdef MIN_REC_TICKADJ
|
|
if (recommend_tickadj < MIN_REC_TICKADJ)
|
|
{
|
|
recommend_tickadj = MIN_REC_TICKADJ;
|
|
}
|
|
#endif /* MIN_REC_TICKADJ */
|
|
#endif /* SCO5_CLOCK */
|
|
|
|
|
|
if ((!quiet) && (tickadj_offset != 0))
|
|
{
|
|
(void) printf("recommended value of tickadj = %d us\n",
|
|
recommend_tickadj);
|
|
}
|
|
|
|
if ( writetickadj == 0
|
|
&& !writeopttickadj
|
|
&& !unsetdosync
|
|
&& writetick == 0
|
|
&& !setnoprintf)
|
|
{
|
|
exit(errflg ? 1 : 0);
|
|
}
|
|
|
|
if (writetickadj == 0 && writeopttickadj)
|
|
{
|
|
writetickadj = recommend_tickadj;
|
|
}
|
|
|
|
fd = openfile(file, O_WRONLY);
|
|
|
|
if (setnoprintf && (noprintf_offset != 0))
|
|
{
|
|
if (!quiet)
|
|
{
|
|
(void) fprintf(stderr, "setting noprintf: ");
|
|
(void) fflush(stderr);
|
|
}
|
|
writevar(fd, noprintf_offset, 1);
|
|
if (!quiet)
|
|
{
|
|
(void) fprintf(stderr, "done!\n");
|
|
}
|
|
}
|
|
|
|
if ((writetick > 0) && (tick_offset != 0))
|
|
{
|
|
if (!quiet)
|
|
{
|
|
(void) fprintf(stderr, "writing tick, value %d: ",
|
|
writetick);
|
|
(void) fflush(stderr);
|
|
}
|
|
writevar(fd, tick_offset, writetick);
|
|
if (!quiet)
|
|
{
|
|
(void) fprintf(stderr, "done!\n");
|
|
}
|
|
}
|
|
|
|
if ((writetickadj > 0) && (tickadj_offset != 0))
|
|
{
|
|
if (!quiet)
|
|
{
|
|
(void) fprintf(stderr, "writing tickadj, value %d: ",
|
|
writetickadj);
|
|
(void) fflush(stderr);
|
|
}
|
|
|
|
#ifdef SCO5_CLOCK
|
|
/* scale from usec/tick to nsec/sec */
|
|
writetickadj *= (1000L * HZ);
|
|
#endif /* SCO5_CLOCK */
|
|
|
|
writevar(fd, tickadj_offset, writetickadj);
|
|
if (!quiet)
|
|
{
|
|
(void) fprintf(stderr, "done!\n");
|
|
}
|
|
}
|
|
|
|
if (unsetdosync && (dosync_offset != 0))
|
|
{
|
|
if (!quiet)
|
|
{
|
|
(void) fprintf(stderr, "zeroing dosynctodr: ");
|
|
(void) fflush(stderr);
|
|
}
|
|
writevar(fd, dosync_offset, 0);
|
|
if (!quiet)
|
|
{
|
|
(void) fprintf(stderr, "done!\n");
|
|
}
|
|
}
|
|
(void) close(fd);
|
|
return(errflg ? 1 : 0);
|
|
}
|
|
|
|
/*
|
|
* getoffsets - read the magic offsets from the specified file
|
|
*/
|
|
static void
|
|
getoffsets(
|
|
off_t *tick_off,
|
|
off_t *tickadj_off,
|
|
off_t *dosync_off,
|
|
off_t *noprintf_off
|
|
)
|
|
{
|
|
|
|
#ifndef NOKMEM
|
|
# ifndef HAVE_KVM_OPEN
|
|
const char **kname;
|
|
# endif
|
|
#endif
|
|
|
|
#ifndef NOKMEM
|
|
# ifdef NLIST_NAME_UNION
|
|
# define NL_B {{
|
|
# define NL_E }}
|
|
# else
|
|
# define NL_B {
|
|
# define NL_E }
|
|
# endif
|
|
#endif
|
|
|
|
#define K_FILLER_NAME "DavidLetterman"
|
|
|
|
#ifdef NLIST_EXTRA_INDIRECTION
|
|
int i;
|
|
#endif
|
|
|
|
#ifndef NOKMEM
|
|
static struct nlist nl[] =
|
|
{
|
|
NL_B
|
|
#ifdef K_TICKADJ_NAME
|
|
#define N_TICKADJ 0
|
|
K_TICKADJ_NAME
|
|
#else
|
|
K_FILLER_NAME
|
|
#endif
|
|
NL_E,
|
|
NL_B
|
|
#ifdef K_TICK_NAME
|
|
#define N_TICK 1
|
|
K_TICK_NAME
|
|
#else
|
|
K_FILLER_NAME
|
|
#endif
|
|
NL_E,
|
|
NL_B
|
|
#ifdef K_DOSYNCTODR_NAME
|
|
#define N_DOSYNC 2
|
|
K_DOSYNCTODR_NAME
|
|
#else
|
|
K_FILLER_NAME
|
|
#endif
|
|
NL_E,
|
|
NL_B
|
|
#ifdef K_NOPRINTF_NAME
|
|
#define N_NOPRINTF 3
|
|
K_NOPRINTF_NAME
|
|
#else
|
|
K_FILLER_NAME
|
|
#endif
|
|
NL_E,
|
|
NL_B "" NL_E,
|
|
};
|
|
|
|
#ifndef HAVE_KVM_OPEN
|
|
static const char *kernels[] =
|
|
{
|
|
#ifdef HAVE_GETBOOTFILE
|
|
NULL, /* *** SEE BELOW! *** */
|
|
#endif
|
|
"/kernel/unix",
|
|
"/kernel",
|
|
"/vmunix",
|
|
"/unix",
|
|
"/mach",
|
|
"/hp-ux",
|
|
"/386bsd",
|
|
"/netbsd",
|
|
"/stand/vmunix",
|
|
"/bsd",
|
|
NULL
|
|
};
|
|
#endif /* not HAVE_KVM_OPEN */
|
|
|
|
#ifdef HAVE_KVM_OPEN
|
|
/*
|
|
* Solaris > 2.5 doesn't have a kernel file. Use the kvm_* interface
|
|
* to read the kernel name list. -- stolcke 3/4/96
|
|
*/
|
|
kvm_t *kvm_handle = kvm_open(NULL, NULL, NULL, O_RDONLY, progname);
|
|
|
|
if (kvm_handle == NULL)
|
|
{
|
|
(void) fprintf(stderr,
|
|
"%s: kvm_open failed\n",
|
|
progname);
|
|
exit(1);
|
|
}
|
|
if (kvm_nlist(kvm_handle, nl) == -1)
|
|
{
|
|
(void) fprintf(stderr,
|
|
"%s: kvm_nlist failed\n",
|
|
progname);
|
|
exit(1);
|
|
}
|
|
kvm_close(kvm_handle);
|
|
#else /* not HAVE_KVM_OPEN */
|
|
#ifdef HAVE_GETBOOTFILE /* *** SEE HERE! *** */
|
|
if (kernels[0] == NULL)
|
|
{
|
|
char * cp = (char *)getbootfile();
|
|
|
|
if (cp)
|
|
{
|
|
kernels[0] = cp;
|
|
}
|
|
else
|
|
{
|
|
kernels[0] = "/Placeholder";
|
|
}
|
|
}
|
|
#endif /* HAVE_GETBOOTFILE */
|
|
for (kname = kernels; *kname != NULL; kname++)
|
|
{
|
|
struct stat stbuf;
|
|
|
|
if (stat(*kname, &stbuf) == -1)
|
|
{
|
|
continue;
|
|
}
|
|
if (nlist(*kname, nl) >= 0)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
(void) fprintf(stderr,
|
|
"%s: nlist didn't find needed symbols from <%s>: %m\n",
|
|
progname, *kname);
|
|
}
|
|
}
|
|
if (*kname == NULL)
|
|
{
|
|
(void) fprintf(stderr,
|
|
"%s: Couldn't find the kernel\n",
|
|
progname);
|
|
exit(1);
|
|
}
|
|
#endif /* HAVE_KVM_OPEN */
|
|
|
|
if (dokmem)
|
|
{
|
|
file = kmem;
|
|
|
|
fd = openfile(file, O_RDONLY);
|
|
#ifdef NLIST_EXTRA_INDIRECTION
|
|
/*
|
|
* Go one more round of indirection.
|
|
*/
|
|
for (i = 0; i < (sizeof(nl) / sizeof(struct nlist)); i++)
|
|
{
|
|
if ((nl[i].n_value) && (nl[i].n_sclass == 0x6b))
|
|
{
|
|
readvar(fd, nl[i].n_value, &nl[i].n_value);
|
|
}
|
|
}
|
|
#endif /* NLIST_EXTRA_INDIRECTION */
|
|
}
|
|
#endif /* not NOKMEM */
|
|
|
|
*tickadj_off = 0;
|
|
*tick_off = 0;
|
|
*dosync_off = 0;
|
|
*noprintf_off = 0;
|
|
|
|
#if defined(N_TICKADJ)
|
|
*tickadj_off = nl[N_TICKADJ].n_value;
|
|
#endif
|
|
|
|
#if defined(N_TICK)
|
|
*tick_off = nl[N_TICK].n_value;
|
|
#endif
|
|
|
|
#if defined(N_DOSYNC)
|
|
*dosync_off = nl[N_DOSYNC].n_value;
|
|
#endif
|
|
|
|
#if defined(N_NOPRINTF)
|
|
*noprintf_off = nl[N_NOPRINTF].n_value;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#undef N_TICKADJ
|
|
#undef N_TICK
|
|
#undef N_DOSYNC
|
|
#undef N_NOPRINTF
|
|
|
|
|
|
/*
|
|
* openfile - open the file, check for errors
|
|
*/
|
|
static int
|
|
openfile(
|
|
const char *name,
|
|
int mode
|
|
)
|
|
{
|
|
int ifd;
|
|
|
|
ifd = open(name, mode);
|
|
if (ifd < 0)
|
|
{
|
|
(void) fprintf(stderr, "%s: open %s: ", progname, name);
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
return ifd;
|
|
}
|
|
|
|
|
|
/*
|
|
* writevar - write a variable into the file
|
|
*/
|
|
static void
|
|
writevar(
|
|
int ofd,
|
|
off_t off,
|
|
int var
|
|
)
|
|
{
|
|
|
|
if (lseek(ofd, off, L_SET) == -1)
|
|
{
|
|
(void) fprintf(stderr, "%s: lseek fails: ", progname);
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
if (write(ofd, (char *)&var, sizeof(int)) != sizeof(int))
|
|
{
|
|
(void) fprintf(stderr, "%s: write fails: ", progname);
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* readvar - read a variable from the file
|
|
*/
|
|
static void
|
|
readvar(
|
|
int ifd,
|
|
off_t off,
|
|
int *var
|
|
)
|
|
{
|
|
int i;
|
|
|
|
if (lseek(ifd, off, L_SET) == -1)
|
|
{
|
|
(void) fprintf(stderr, "%s: lseek fails: ", progname);
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
i = read(ifd, (char *)var, sizeof(int));
|
|
if (i < 0)
|
|
{
|
|
(void) fprintf(stderr, "%s: read fails: ", progname);
|
|
perror("");
|
|
exit(1);
|
|
}
|
|
if (i != sizeof(int))
|
|
{
|
|
(void) fprintf(stderr, "%s: read expected %d, got %d\n",
|
|
progname, (int)sizeof(int), i);
|
|
exit(1);
|
|
}
|
|
return;
|
|
}
|
|
#endif /* not Linux */
|