Annotation of embedaddon/ntp/adjtimed/adjtimed.c, revision 1.1.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>