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>