Annotation of embedaddon/ntp/adjtimed/adjtimed.c, revision 1.1
1.1 ! misho 1: /*************************************************************************/
! 2: /* (c) Copyright Tai Jin, 1988. All Rights Reserved. */
! 3: /* Hewlett-Packard Laboratories. */
! 4: /* */
! 5: /* Permission is hereby granted for unlimited modification, use, and */
! 6: /* distribution. This software is made available with no warranty of */
! 7: /* any kind, express or implied. This copyright notice must remain */
! 8: /* intact in all versions of this software. */
! 9: /* */
! 10: /* The author would appreciate it if any bug fixes and enhancements were */
! 11: /* to be sent back to him for incorporation into future versions of this */
! 12: /* software. Please send changes to tai@iag.hp.com or ken@sdd.hp.com. */
! 13: /*************************************************************************/
! 14:
! 15: #ifndef lint
! 16: static char RCSid[] = "adjtimed.c,v 3.1 1993/07/06 01:04:45 jbj Exp";
! 17: #endif
! 18:
! 19: /*
! 20: * Adjust time daemon.
! 21: * This daemon adjusts the rate of the system clock a la BSD's adjtime().
! 22: * The adjtime() routine uses SYSV messages to communicate with this daemon.
! 23: *
! 24: * Caveat: This emulation uses an undocumented kernel variable. As such, it
! 25: * cannot be guaranteed to work in future HP-UX releases. Fortunately,
! 26: * it will no longer be needed in HPUX 10.01 and later.
! 27: */
! 28:
! 29: #include <sys/param.h>
! 30: #include <sys/types.h>
! 31: #include <sys/ipc.h>
! 32: #include <sys/msg.h>
! 33: #include <sys/lock.h>
! 34: #include <time.h>
! 35: #include <signal.h>
! 36: #include <nlist.h>
! 37: #include <fcntl.h>
! 38: #include <stdio.h>
! 39: #include <unistd.h>
! 40:
! 41: #include "ntp_syslog.h"
! 42: #include "ntp_stdlib.h"
! 43:
! 44: #include "adjtime.h"
! 45:
! 46: double atof (const char *);
! 47:
! 48: int InitClockRate (void);
! 49: int AdjustClockRate (register struct timeval *delta, register struct timeval *olddelta);
! 50: long GetClockRate (void);
! 51: int SetClockRate (long);
! 52: void ResetClockRate (void);
! 53: void Cleanup (void);
! 54: void Exit (int);
! 55:
! 56: #define MILLION 1000000L
! 57:
! 58: /* emacs cc-mode goes nuts if we split the next line... */
! 59: #define tvtod(tv) ((double)tv.tv_sec + ((double)tv.tv_usec / (double)MILLION))
! 60:
! 61: char *progname = NULL;
! 62: int verbose = 0;
! 63: int sysdebug = 0;
! 64: static int mqid;
! 65: static double oldrate = 0.0;
! 66:
! 67: int
! 68: main(
! 69: int argc,
! 70: char *argv[]
! 71: )
! 72: {
! 73: struct timeval remains;
! 74: struct sigvec vec;
! 75: MsgBuf msg;
! 76: char ch;
! 77: int nofork = 0;
! 78: int fd;
! 79:
! 80: progname = argv[0];
! 81:
! 82: #ifdef LOG_LOCAL6
! 83: openlog("adjtimed", LOG_PID, LOG_LOCAL6);
! 84: #else
! 85: openlog("adjtimed", LOG_PID);
! 86: #endif
! 87:
! 88: while ((ch = ntp_getopt(argc, argv, "hkrvdfp:")) != EOF) {
! 89: switch (ch) {
! 90: case 'k':
! 91: case 'r':
! 92: if ((mqid = msgget(KEY, 0)) != -1) {
! 93: if (msgctl(mqid, IPC_RMID, (struct msqid_ds *)0) == -1) {
! 94: msyslog(LOG_ERR, "remove old message queue: %m");
! 95: perror("adjtimed: remove old message queue");
! 96: exit(1);
! 97: }
! 98: }
! 99:
! 100: if (ch == 'k')
! 101: exit(0);
! 102:
! 103: break;
! 104:
! 105: case 'v':
! 106: ++verbose, nofork = 1;
! 107: break;
! 108:
! 109: case 'd':
! 110: ++sysdebug;
! 111: break;
! 112:
! 113: case 'f':
! 114: nofork = 1;
! 115: break;
! 116:
! 117: case 'p':
! 118: fputs("adjtimed: -p option ignored\n", stderr);
! 119: break;
! 120:
! 121: default:
! 122: puts("usage: adjtimed -hkrvdf");
! 123: puts("-h\thelp");
! 124: puts("-k\tkill existing adjtimed, if any");
! 125: puts("-r\trestart (kills existing adjtimed, if any)");
! 126: puts("-v\tdebug output (repeat for more output)");
! 127: puts("-d\tsyslog output (repeat for more output)");
! 128: puts("-f\tno fork");
! 129: msyslog(LOG_ERR, "usage error");
! 130: exit(1);
! 131: } /* switch */
! 132: } /* while */
! 133:
! 134: if (!nofork) {
! 135: switch (fork()) {
! 136: case 0:
! 137: close(fileno(stdin));
! 138: close(fileno(stdout));
! 139: close(fileno(stderr));
! 140:
! 141: #ifdef TIOCNOTTY
! 142: if ((fd = open("/dev/tty")) != -1) {
! 143: ioctl(fd, TIOCNOTTY, 0);
! 144: close(fd);
! 145: }
! 146: #else
! 147: setpgrp();
! 148: #endif
! 149: break;
! 150:
! 151: case -1:
! 152: msyslog(LOG_ERR, "fork: %m");
! 153: perror("adjtimed: fork");
! 154: exit(1);
! 155:
! 156: default:
! 157: exit(0);
! 158: } /* switch */
! 159: } /* if */
! 160:
! 161: if (nofork) {
! 162: setvbuf(stdout, NULL, _IONBF, BUFSIZ);
! 163: setvbuf(stderr, NULL, _IONBF, BUFSIZ);
! 164: }
! 165:
! 166: msyslog(LOG_INFO, "started");
! 167: if (verbose) printf("adjtimed: started\n");
! 168:
! 169: if (InitClockRate() == -1)
! 170: Exit(2);
! 171:
! 172: (void)signal(SIGHUP, SIG_IGN);
! 173: (void)signal(SIGINT, SIG_IGN);
! 174: (void)signal(SIGQUIT, SIG_IGN);
! 175: (void)signal(SIGTERM, Cleanup);
! 176:
! 177: vec.sv_handler = ResetClockRate;
! 178: vec.sv_flags = 0;
! 179: vec.sv_mask = ~0;
! 180: sigvector(SIGALRM, &vec, (struct sigvec *)0);
! 181:
! 182: if (msgget(KEY, IPC_CREAT|IPC_EXCL) == -1) {
! 183: if (errno == EEXIST) {
! 184: msyslog(LOG_ERR, "message queue already exists, use -r to remove it");
! 185: fputs("adjtimed: message queue already exists, use -r to remove it\n",
! 186: stderr);
! 187: Exit(1);
! 188: }
! 189:
! 190: msyslog(LOG_ERR, "create message queue: %m");
! 191: perror("adjtimed: create message queue");
! 192: Exit(1);
! 193: }
! 194:
! 195: if ((mqid = msgget(KEY, 0)) == -1) {
! 196: msyslog(LOG_ERR, "get message queue id: %m");
! 197: perror("adjtimed: get message queue id");
! 198: Exit(1);
! 199: }
! 200:
! 201: /* Lock process in memory to improve response time */
! 202: if (plock(PROCLOCK)) {
! 203: msyslog(LOG_ERR, "plock: %m");
! 204: perror("adjtimed: plock");
! 205: Cleanup();
! 206: }
! 207:
! 208: /* Also raise process priority.
! 209: * If we do not get run when we want, this leads to bad timekeeping
! 210: * and "Previous time adjustment didn't complete" gripes from xntpd.
! 211: */
! 212: if (nice(-10) == -1) {
! 213: msyslog(LOG_ERR, "nice: %m");
! 214: perror("adjtimed: nice");
! 215: Cleanup();
! 216: }
! 217:
! 218: for (;;) {
! 219: if (msgrcv(mqid, &msg.msgp, MSGSIZE, CLIENT, 0) == -1) {
! 220: if (errno == EINTR) continue;
! 221: msyslog(LOG_ERR, "read message: %m");
! 222: perror("adjtimed: read message");
! 223: Cleanup();
! 224: }
! 225:
! 226: switch (msg.msgb.code) {
! 227: case DELTA1:
! 228: case DELTA2:
! 229: AdjustClockRate(&msg.msgb.tv, &remains);
! 230:
! 231: if (msg.msgb.code == DELTA2) {
! 232: msg.msgb.tv = remains;
! 233: msg.msgb.mtype = SERVER;
! 234:
! 235: while (msgsnd(mqid, &msg.msgp, MSGSIZE, 0) == -1) {
! 236: if (errno == EINTR) continue;
! 237: msyslog(LOG_ERR, "send message: %m");
! 238: perror("adjtimed: send message");
! 239: Cleanup();
! 240: }
! 241: }
! 242:
! 243: if (remains.tv_sec + remains.tv_usec != 0L) {
! 244: if (verbose) {
! 245: printf("adjtimed: previous correction remaining %.6fs\n",
! 246: tvtod(remains));
! 247: }
! 248: if (sysdebug) {
! 249: msyslog(LOG_INFO, "previous correction remaining %.6fs",
! 250: tvtod(remains));
! 251: }
! 252: }
! 253: break;
! 254:
! 255: default:
! 256: fprintf(stderr, "adjtimed: unknown message code %d\n", msg.msgb.code);
! 257: msyslog(LOG_ERR, "unknown message code %d", msg.msgb.code);
! 258: } /* switch */
! 259: } /* loop */
! 260: } /* main */
! 261:
! 262: /*
! 263: * Default clock rate (old_tick).
! 264: */
! 265: #define DEFAULT_RATE (MILLION / HZ)
! 266: #define UNKNOWN_RATE 0L
! 267: #define TICK_ADJ 5 /* standard adjustment rate, microsec/tick */
! 268:
! 269: static long default_rate = DEFAULT_RATE;
! 270: static long tick_rate = HZ; /* ticks per sec */
! 271: static long slew_rate = TICK_ADJ * HZ; /* in microsec/sec */
! 272:
! 273: int
! 274: AdjustClockRate(
! 275: register struct timeval *delta,
! 276: register struct timeval *olddelta
! 277: )
! 278: {
! 279: register long rate, dt, leftover;
! 280: struct itimerval period, remains;
! 281:
! 282: dt = (delta->tv_sec * MILLION) + delta->tv_usec;
! 283:
! 284: if (verbose)
! 285: printf("adjtimed: new correction %.6fs\n", (double)dt / (double)MILLION);
! 286: if (sysdebug)
! 287: msyslog(LOG_INFO, "new correction %.6fs", (double)dt / (double)MILLION);
! 288: if (verbose > 2) printf("adjtimed: leftover %ldus\n", leftover);
! 289: if (sysdebug > 2) msyslog(LOG_INFO, "leftover %ldus", leftover);
! 290: rate = dt;
! 291:
! 292: /*
! 293: * Apply a slew rate of slew_rate over a period of dt/slew_rate seconds.
! 294: */
! 295: if (dt > 0) {
! 296: rate = slew_rate;
! 297: } else {
! 298: rate = -slew_rate;
! 299: dt = -dt;
! 300: }
! 301: period.it_value.tv_sec = dt / slew_rate;
! 302: period.it_value.tv_usec = (dt % slew_rate) * (MILLION / slew_rate);
! 303: /*
! 304: * Note: we assume the kernel will convert the specified period into ticks
! 305: * using the modified clock rate rather than an assumed nominal clock rate,
! 306: * and therefore will generate the timer interrupt after the specified
! 307: * number of true seconds, not skewed seconds.
! 308: */
! 309:
! 310: if (verbose > 1)
! 311: printf("adjtimed: will be complete in %lds %ldus\n",
! 312: period.it_value.tv_sec, period.it_value.tv_usec);
! 313: if (sysdebug > 1)
! 314: msyslog(LOG_INFO, "will be complete in %lds %ldus",
! 315: period.it_value.tv_sec, period.it_value.tv_usec);
! 316: /*
! 317: * adjust the clock rate
! 318: */
! 319: if (dt) {
! 320: if (SetClockRate((rate / tick_rate) + default_rate) == -1) {
! 321: msyslog(LOG_ERR, "set clock rate: %m");
! 322: perror("adjtimed: set clock rate");
! 323: }
! 324: }
! 325: /*
! 326: * start the timer
! 327: * (do this after changing the rate because the period has been rounded down)
! 328: */
! 329: period.it_interval.tv_sec = period.it_interval.tv_usec = 0L;
! 330: setitimer(ITIMER_REAL, &period, &remains);
! 331: /*
! 332: * return old delta
! 333: */
! 334: if (olddelta) {
! 335: dt = ((remains.it_value.tv_sec * MILLION) + remains.it_value.tv_usec) *
! 336: oldrate;
! 337: olddelta->tv_sec = dt / MILLION;
! 338: olddelta->tv_usec = dt - (olddelta->tv_sec * MILLION);
! 339: }
! 340:
! 341: oldrate = (double)rate / (double)MILLION;
! 342: return(0);
! 343: } /* AdjustClockRate */
! 344:
! 345: static struct nlist nl[] = {
! 346: #ifdef __hp9000s800
! 347: #ifdef PRE7_0
! 348: { "tick" },
! 349: #else
! 350: { "old_tick" },
! 351: #endif
! 352: #else
! 353: { "_old_tick" },
! 354: #endif
! 355: { "" }
! 356: };
! 357:
! 358: static int kmem;
! 359:
! 360: /*
! 361: * The return value is the clock rate in old_tick units or -1 if error.
! 362: */
! 363: long
! 364: GetClockRate(void)
! 365: {
! 366: long rate, mask;
! 367:
! 368: if (lseek(kmem, (off_t)nl[0].n_value, 0) == -1L)
! 369: return (-1L);
! 370:
! 371: mask = sigblock(sigmask(SIGALRM));
! 372:
! 373: if (read(kmem, (caddr_t)&rate, sizeof(rate)) != sizeof(rate))
! 374: rate = UNKNOWN_RATE;
! 375:
! 376: sigsetmask(mask);
! 377: return (rate);
! 378: } /* GetClockRate */
! 379:
! 380: /*
! 381: * The argument is the new rate in old_tick units.
! 382: */
! 383: int
! 384: SetClockRate(
! 385: long rate
! 386: )
! 387: {
! 388: long mask;
! 389:
! 390: if (lseek(kmem, (off_t)nl[0].n_value, 0) == -1L)
! 391: return (-1);
! 392:
! 393: mask = sigblock(sigmask(SIGALRM));
! 394:
! 395: if (write(kmem, (caddr_t)&rate, sizeof(rate)) != sizeof(rate)) {
! 396: sigsetmask(mask);
! 397: return (-1);
! 398: }
! 399:
! 400: sigsetmask(mask);
! 401:
! 402: if (rate != default_rate) {
! 403: if (verbose > 3) {
! 404: printf("adjtimed: clock rate (%lu) %ldus/s\n", rate,
! 405: (rate - default_rate) * tick_rate);
! 406: }
! 407: if (sysdebug > 3) {
! 408: msyslog(LOG_INFO, "clock rate (%lu) %ldus/s", rate,
! 409: (rate - default_rate) * tick_rate);
! 410: }
! 411: }
! 412:
! 413: return (0);
! 414: } /* SetClockRate */
! 415:
! 416: int
! 417: InitClockRate(void)
! 418: {
! 419: if ((kmem = open("/dev/kmem", O_RDWR)) == -1) {
! 420: msyslog(LOG_ERR, "open(/dev/kmem): %m");
! 421: perror("adjtimed: open(/dev/kmem)");
! 422: return (-1);
! 423: }
! 424:
! 425: nlist("/hp-ux", nl);
! 426:
! 427: if (nl[0].n_type == 0) {
! 428: fputs("adjtimed: /hp-ux has no symbol table\n", stderr);
! 429: msyslog(LOG_ERR, "/hp-ux has no symbol table");
! 430: return (-1);
! 431: }
! 432: /*
! 433: * Set the default to the system's original value
! 434: */
! 435: default_rate = GetClockRate();
! 436: if (default_rate == UNKNOWN_RATE) default_rate = DEFAULT_RATE;
! 437: tick_rate = (MILLION / default_rate);
! 438: slew_rate = TICK_ADJ * tick_rate;
! 439: fprintf(stderr,"default_rate=%ld, tick_rate=%ld, slew_rate=%ld\n",default_rate,tick_rate,slew_rate);
! 440:
! 441: return (0);
! 442: } /* InitClockRate */
! 443:
! 444: /*
! 445: * Reset the clock rate to the default value.
! 446: */
! 447: void
! 448: ResetClockRate(void)
! 449: {
! 450: struct itimerval it;
! 451:
! 452: it.it_value.tv_sec = it.it_value.tv_usec = 0L;
! 453: setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
! 454:
! 455: if (verbose > 2) puts("adjtimed: resetting the clock");
! 456: if (sysdebug > 2) msyslog(LOG_INFO, "resetting the clock");
! 457:
! 458: if (GetClockRate() != default_rate) {
! 459: if (SetClockRate(default_rate) == -1) {
! 460: msyslog(LOG_ERR, "set clock rate: %m");
! 461: perror("adjtimed: set clock rate");
! 462: }
! 463: }
! 464:
! 465: oldrate = 0.0;
! 466: } /* ResetClockRate */
! 467:
! 468: void
! 469: Cleanup(void)
! 470: {
! 471: ResetClockRate();
! 472:
! 473: if (msgctl(mqid, IPC_RMID, (struct msqid_ds *)0) == -1) {
! 474: if (errno != EINVAL) {
! 475: msyslog(LOG_ERR, "remove message queue: %m");
! 476: perror("adjtimed: remove message queue");
! 477: }
! 478: }
! 479:
! 480: Exit(2);
! 481: } /* Cleanup */
! 482:
! 483: void
! 484: Exit(status)
! 485: int status;
! 486: {
! 487: msyslog(LOG_ERR, "terminated");
! 488: closelog();
! 489: if (kmem != -1) close(kmem);
! 490: exit(status);
! 491: } /* Exit */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>