diff options
Diffstat (limited to 'util/tickadj.c')
-rw-r--r-- | util/tickadj.c | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/util/tickadj.c b/util/tickadj.c new file mode 100644 index 0000000..4a7f2c4 --- /dev/null +++ b/util/tickadj.c @@ -0,0 +1,902 @@ +/* + * 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 "ntp_types.h" +#include "l_stdlib.h" + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif /* HAVE_UNISTD_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/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>: %s\n", + progname, *kname, strerror(errno)); + } + } + 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 */ |