client.c | 2 +- configure.ac | 5 ++ defines.h | 4 ++ ntp.c | 15 +++-- ntpd.8 | 2 +- ntpd.c | 18 +++++- openbsd-compat/Makefile.in | 2 +- openbsd-compat/openbsd-compat.h | 5 ++ openbsd-compat/port-linux.c | 124 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 167 insertions(+), 10 deletions(-) diff --git a/client.c b/client.c index 208672b..159a4cb 100644 --- a/client.c +++ b/client.c @@ -321,7 +321,7 @@ client_update(struct ntp_peer *p) priv_adjtime(); for (i = 0; i < OFFSET_ARRAY_SIZE; i++) - if (p->reply[i].rcvd <= p->reply[best].rcvd) + /* if (p->reply[i].rcvd <= p->reply[best].rcvd) */ p->reply[i].good = 0; return (0); diff --git a/configure.ac b/configure.ac index c476585..2c6ed17 100644 --- a/configure.ac +++ b/configure.ac @@ -583,6 +583,11 @@ AC_ARG_WITH(builtin-arc4random, [ builtin_arc4random=$withval ] ) +AC_ARG_WITH(adjtimex, + [ --with-adjtimex Use adjtimex to adjust kernel skew], + [ AC_DEFINE(USE_ADJTIMEX, [], [Use adjust skew with adjtimex (experimental)]) ] +) + AC_ARG_WITH(mantype, [ --with-mantype=man|cat|doc Set man page type], [ diff --git a/defines.h b/defines.h index 25a4cd1..272e299 100644 --- a/defines.h +++ b/defines.h @@ -20,6 +20,10 @@ # define setproctitle(x) #endif +#ifdef USE_ADJTIMEX +# define adjtime(a,b) (_compat_adjtime((a),(b))) +#endif + #if !defined(SA_LEN) # if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) # define SA_LEN(x) ((x)->sa_len) diff --git a/ntp.c b/ntp.c index ac94638..4cf620c 100644 --- a/ntp.c +++ b/ntp.c @@ -36,6 +36,9 @@ #include #include #include +#ifdef HAVE_SETPROCTITLE +# include +#endif #include "ntpd.h" #include "ntp.h" @@ -68,7 +71,7 @@ ntp_sighdlr(int sig) pid_t ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf) { - int a, b, nfds, i, j, idx_peers, timeout, nullfd; + int a, b, nfds, i, j, idx_peers, timeout, nullfd = -1; u_int pfd_elms = 0, idx2peer_elms = 0; u_int listener_cnt, new_cnt, sent_cnt, trial_cnt; pid_t pid; @@ -100,7 +103,7 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf) if ((pw = getpwnam(NTPD_USER)) == NULL) fatal("getpwnam"); - if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) + if (!nconf->debug && (nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) fatal(NULL); #ifdef NTPD_CHROOT_DIR @@ -121,9 +124,7 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf) if (!nconf->debug) { dup2(nullfd, STDIN_FILENO); dup2(nullfd, STDOUT_FILENO); - dup2(nullfd, STDERR_FILENO); } - close(nullfd); setproctitle("ntp engine"); @@ -137,6 +138,12 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf) endservent(); + if (!nconf->debug) { + dup2(nullfd, STDERR_FILENO); + if (nullfd > 2) + close(nullfd); + } + signal(SIGTERM, ntp_sighdlr); signal(SIGINT, ntp_sighdlr); signal(SIGPIPE, SIG_IGN); diff --git a/ntpd.8 b/ntpd.8 index 614e9a8..133e062 100644 --- a/ntpd.8 +++ b/ntpd.8 @@ -75,7 +75,6 @@ instead of the default .Pa /etc/ntpd.conf . .It Fl S Do not set the time immediately at startup. -This is the default. .It Fl s Set the time immediately at startup if the local clock is off by more than 180 seconds. @@ -84,6 +83,7 @@ eliminating the need to run .Xr rdate 8 before starting .Nm . +This is the default. .El .Sh FILES .Bl -tag -width "/etc/ntpd.confXXX" -compact diff --git a/ntpd.c b/ntpd.c index 66b236e..574b7fe 100644 --- a/ntpd.c +++ b/ntpd.c @@ -35,6 +35,9 @@ RCSID("$Release: OpenNTPD "OPENNTPD_VERSION" $"); #include #include #include +#ifdef HAVE_SETPROCTITLE +# include +#endif #include "ntpd.h" @@ -86,6 +89,7 @@ main(int argc, char *argv[]) struct ntpd_conf conf; struct pollfd pfd[POLL_MAX]; pid_t chld_pid = 0, pid; + int chld_rc = 0; const char *conffile; int ch, nfds, timeout = INFTIM; int pipe_chld[2]; @@ -96,6 +100,7 @@ main(int argc, char *argv[]) conffile = CONFFILE; bzero(&conf, sizeof(conf)); + conf.settime = 1; log_init(1); /* log to stderr until daemonized */ res_init(); /* XXX */ @@ -200,10 +205,11 @@ main(int argc, char *argv[]) quit = 1; } - if (sigchld) { + if (sigchld && chld_pid) { if (check_child(chld_pid, "child")) { quit = 1; chld_pid = 0; + chld_rc = 1; } sigchld = 0; } @@ -216,15 +222,21 @@ main(int argc, char *argv[]) kill(chld_pid, SIGTERM); do { - if ((pid = wait(NULL)) == -1 && + int status; + if ((pid = wait(&status)) == -1 && errno != EINTR && errno != ECHILD) fatal("wait"); + if (pid != -1) { + if ((WIFEXITED(status) && WEXITSTATUS(status)) || + (WIFSIGNALED(status) && WTERMSIG(status) != SIGTERM)) + chld_rc = 1; + } } while (pid != -1 || (pid == -1 && errno == EINTR)); msgbuf_clear(&ibuf->w); free(ibuf); log_info("Terminating"); - return (0); + return (chld_rc); } int diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in index 37670b6..c7b71c8 100644 --- a/openbsd-compat/Makefile.in +++ b/openbsd-compat/Makefile.in @@ -9,7 +9,7 @@ OPENBSD= asprintf.o daemon.o errx.o inet_pton.o strlcpy.o verrx.o COMPAT= atomicio.o bsd-arc4random.o bsd-misc.o bsd-poll.o \ bsd-snprintf.o bsd-getifaddrs.o bsd-setresuid.o \ bsd-setresgid.o fake-rfc2553.o -PORT= port-qnx.o +PORT= port-linux.o port-qnx.o VPATH=@srcdir@ CC=@CC@ diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index 4df29fc..9b91d5e 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -46,6 +46,11 @@ int asprintf(char **, const char *, ...) __attribute__((__format__ (printf, 2, 3))); #endif +#ifdef USE_ADJTIMEX +# include +int _compat_adjtime(const struct timeval *, struct timeval *); +#endif + #ifndef HAVE_INET_PTON int inet_pton(int, const char *, void *); #endif diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c new file mode 100644 index 0000000..70ecc6c --- /dev/null +++ b/openbsd-compat/port-linux.c @@ -0,0 +1,124 @@ +/* $Id$ */ + +/* + * Copyright (c) 2006 Grigory Batalov + * Copyright (c) 2004 Darren Tucker + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifdef USE_ADJTIMEX +#include +#include +#ifdef adjtime +# undef adjtime +#endif + +#include "ntpd.h" + +/* scale factor used by adjtimex freq param. 1 ppm = 65536 */ +#define ADJTIMEX_FREQ_SCALE 65536 + +int +_compat_adjtime(const struct timeval *delta, struct timeval *olddelta) +{ + static struct timeval tlast = {0,0}; + struct timeval tnow, tdelta; + double adjust, adjust_last, interval, error_ppm; + long freq_delta = 0, tick_delta = 0; + struct timex tmx; + int result, saved_errno; + /* Get system clock ticks per second */ + long hz = sysconf(_SC_CLK_TCK); + + gettimeofday(&tnow, NULL); + adjust = (double)delta->tv_sec; + adjust += (double)delta->tv_usec / 1000000; + + /* Even if the caller doesn't care about the olddelta, we do */ + if (olddelta == NULL) + olddelta = &tdelta; + + /* Adjust time in a simple way */ + result = adjtime(delta, olddelta); + saved_errno = errno; + + /* How much correction from last call */ + adjust_last = (double)olddelta->tv_sec; + adjust_last += (double)olddelta->tv_usec / 1000000; + + /* Get current adjtimex values */ + tmx.modes = 0; + if (adjtimex(&tmx) == -1) + log_warn("adjtimex get failed"); + + /* If we can calculate interval */ + if (tlast.tv_sec && tlast.tv_usec) { + interval = (double)(tnow.tv_sec - tlast.tv_sec); + interval += (double)(tnow.tv_usec - tlast.tv_usec) / 1000000; + + log_debug("interval %0.3lf olddelta %0.3lf (delta - olddelta) %0.3lf", + interval, adjust_last, adjust - adjust_last); + + if (interval != 0) { + /* Calculate error in "parts per million" */ + error_ppm = (adjust - adjust_last) * 1000000 / interval; + /* Half of error_ppm leads to less fluctiations */ + error_ppm /= 2; + /* Tick adjustment */ + tick_delta = error_ppm / hz; + /* Frequency adjustment */ + freq_delta = ADJTIMEX_FREQ_SCALE * (error_ppm - tick_delta * hz); + + log_debug("error_ppm %0.3lf freq_delta %ld tick_delta %ld", + error_ppm, freq_delta, tick_delta); + + /* Adjust the kernel skew. */ + tmx.freq += freq_delta; + tmx.tick += tick_delta; + /* Check frequency bounds: -tolerance <= tolerance */ + if (tmx.freq < -tmx.tolerance) { + tmx.tick--; + tmx.freq += ADJTIMEX_FREQ_SCALE * hz; + } + else if (tmx.freq > tmx.tolerance) { + tmx.tick++; + tmx.freq -= ADJTIMEX_FREQ_SCALE * hz; + } + /* Check tick bounds: 900000/hz <= 1100000/hz */ + if (tmx.tick < 900000/hz) + tmx.tick = 900000/hz; + else if (tmx.tick > 1100000/hz) + tmx.tick = 1100000/hz; + + tmx.modes = ADJ_FREQUENCY | ADJ_TICK; + + if (olddelta->tv_sec == 0 && olddelta->tv_usec == 0) { + tmx.maxerror = 0; + tmx.status &= ~STA_UNSYNC; + tmx.modes |= ADJ_MAXERROR | ADJ_STATUS; + } + if (adjtimex(&tmx) == -1) + log_warn("adjtimex set freq failed"); + } + + } + else + log_debug("skiping very first adjtimex"); + tlast = tnow; + errno = saved_errno; + return result; +} +#endif