File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / adjtimed / adjtimed.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:37 2012 UTC (12 years, 10 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>