diff --git a/src/usr.sbin/ntpd/Makefile b/src/usr.sbin/ntpd/Makefile index 2557960d..e77935f8 100644 --- a/src/usr.sbin/ntpd/Makefile +++ b/src/usr.sbin/ntpd/Makefile @@ -1,8 +1,9 @@ -# $OpenBSD: Makefile,v 1.11 2010/05/26 16:44:32 nicm Exp $ +# $OpenBSD: Makefile,v 1.12 2013/10/04 14:28:15 phessler Exp $ PROG= ntpd SRCS= ntpd.c log.c ntp.c ntp_msg.c parse.y config.c \ - server.c client.c sensors.c util.c ntp_dns.c + server.c client.c sensors.c util.c ntp_dns.c \ + control.c CFLAGS+= -Wall -I${.CURDIR} CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations @@ -11,6 +12,7 @@ CFLAGS+= -Wsign-compare YFLAGS= LDADD+= -lutil DPADD+= ${LIBUTIL} -MAN= ntpd.8 ntpd.conf.5 +LINKS= ${BINDIR}/ntpd ${BINDIR}/ntpctl +MAN= ntpd.8 ntpd.conf.5 ntpctl.8 .include diff --git a/src/usr.sbin/ntpd/client.c b/src/usr.sbin/ntpd/client.c index 0b59427b..65957691 100644 --- a/src/usr.sbin/ntpd/client.c +++ b/src/usr.sbin/ntpd/client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: client.c,v 1.90 2013/04/30 11:42:56 mglocker Exp $ */ +/* $OpenBSD: client.c,v 1.91 2013/10/04 14:28:16 phessler Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -36,6 +36,7 @@ set_next(struct ntp_peer *p, time_t t) { p->next = getmonotime() + t; p->deadline = 0; + p->poll = t; } void @@ -328,6 +329,7 @@ client_dispatch(struct ntp_peer *p, u_int8_t settime) p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2; p->reply[p->shift].delay = (T4 - T1) - (T3 - T2); + p->reply[p->shift].status.stratum = msg.stratum; if (p->reply[p->shift].delay < 0) { interval = error_interval(); set_next(p, interval); @@ -348,7 +350,6 @@ client_dispatch(struct ntp_peer *p, u_int8_t settime) p->reply[p->shift].status.refid = msg.refid; p->reply[p->shift].status.reftime = lfp_to_d(msg.reftime); p->reply[p->shift].status.poll = msg.ppoll; - p->reply[p->shift].status.stratum = msg.stratum; if (p->addr->ss.ss_family == AF_INET) { p->reply[p->shift].status.send_refid = diff --git a/src/usr.sbin/ntpd/control.c b/src/usr.sbin/ntpd/control.c new file mode 100644 index 00000000..121e5a47 --- /dev/null +++ b/src/usr.sbin/ntpd/control.c @@ -0,0 +1,427 @@ +/* $OpenBSD: control.c,v 1.1 2013/10/04 14:28:16 phessler Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2012 Mike Miller + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ntpd.h" + +#define CONTROL_BACKLOG 5 + +int +control_init(char *path) +{ + struct sockaddr_un sun; + int fd; + mode_t old_umask; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + log_warn("control_init: socket"); + return (-1); + } + + bzero(&sun, sizeof(sun)); + sun.sun_family = AF_UNIX; + if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) + errx(1, "ctl socket name too long"); + + if (unlink(path) == -1) + if (errno != ENOENT) { + log_warn("control_init: unlink %s", path); + close(fd); + return (-1); + } + + old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + log_warn("control_init: bind: %s", path); + close(fd); + umask(old_umask); + return (-1); + } + umask(old_umask); + + if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { + log_warn("control_init: chmod"); + close(fd); + (void)unlink(path); + return (-1); + } + + session_socket_blockmode(fd, BM_NONBLOCK); + + return (fd); +} + +int +control_listen(int fd) +{ + if (fd != -1 && listen(fd, CONTROL_BACKLOG) == -1) { + log_warn("control_listen: listen"); + return (-1); + } + + return (0); +} + +void +control_shutdown(int fd) +{ + close(fd); +} + +void +control_cleanup(const char *path) +{ + if (path) + unlink(path); +} + +int +control_accept(int listenfd) +{ + int connfd; + socklen_t len; + struct sockaddr_un sun; + struct ctl_conn *ctl_conn; + + len = sizeof(sun); + if ((connfd = accept(listenfd, + (struct sockaddr *)&sun, &len)) == -1) { + if (errno != EWOULDBLOCK && errno != EINTR) + log_warn("control_accept: accept"); + return (0); + } + + session_socket_blockmode(connfd, BM_NONBLOCK); + + if ((ctl_conn = calloc(1, sizeof(struct ctl_conn))) == NULL) { + log_warn("control_accept"); + close(connfd); + return (0); + } + + imsg_init(&ctl_conn->ibuf, connfd); + + TAILQ_INSERT_TAIL(&ctl_conns, ctl_conn, entry); + + return (1); +} + +struct ctl_conn * +control_connbyfd(int fd) +{ + struct ctl_conn *c; + + for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->ibuf.fd != fd; + c = TAILQ_NEXT(c, entry)) + ; /* nothing */ + + return (c); +} + +int +control_close(int fd) +{ + struct ctl_conn *c; + + if ((c = control_connbyfd(fd)) == NULL) { + log_warn("control_close: fd %d: not found", fd); + return (0); + } + + msgbuf_clear(&c->ibuf.w); + TAILQ_REMOVE(&ctl_conns, c, entry); + + close(c->ibuf.fd); + free(c); + + return (1); +} + +int +control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) +{ + struct imsg imsg; + struct ctl_conn *c; + struct ntp_peer *p; + struct ntp_sensor *s; + struct ctl_show_status c_status; + struct ctl_show_peer c_peer; + struct ctl_show_sensor c_sensor; + int cnt; + ssize_t n; + + if ((c = control_connbyfd(pfd->fd)) == NULL) { + log_warn("control_dispatch_msg: fd %d: not found", pfd->fd); + return (0); + } + + if (pfd->revents & POLLOUT) + if (msgbuf_write(&c->ibuf.w) < 0) { + *ctl_cnt -= control_close(pfd->fd); + return (1); + } + + if (!(pfd->revents & POLLIN)) + return (0); + + if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) { + *ctl_cnt -= control_close(pfd->fd); + return (1); + } + + for (;;) { + if ((n = imsg_get(&c->ibuf, &imsg)) == -1) { + *ctl_cnt -= control_close(pfd->fd); + return (1); + } + if (n == 0) + break; + + switch (imsg.hdr.type) { + case IMSG_CTL_SHOW_STATUS: + build_show_status(&c_status); + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_STATUS, 0, 0, -1, + &c_status, sizeof (c_status)); + break; + case IMSG_CTL_SHOW_PEERS: + cnt = 0; + TAILQ_FOREACH(p, &conf->ntp_peers, entry) { + build_show_peer(&c_peer, p); + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS, + 0, 0, -1, &c_peer, sizeof(c_peer)); + cnt++; + } + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS_END, + 0, 0, -1, &cnt, sizeof(cnt)); + break; + case IMSG_CTL_SHOW_SENSORS: + cnt = 0; + TAILQ_FOREACH(s, &conf->ntp_sensors, entry) { + build_show_sensor(&c_sensor, s); + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS, + 0, 0, -1, &c_sensor, sizeof(c_sensor)); + cnt++; + } + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS_END, + 0, 0, -1, &cnt, sizeof(cnt)); + break; + case IMSG_CTL_SHOW_ALL: + build_show_status(&c_status); + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_STATUS, 0, 0, -1, + &c_status, sizeof (c_status)); + + cnt = 0; + TAILQ_FOREACH(p, &conf->ntp_peers, entry) { + build_show_peer(&c_peer, p); + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS, + 0, 0, -1, &c_peer, sizeof(c_peer)); + cnt++; + } + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_PEERS_END, + 0, 0, -1, &cnt, sizeof(cnt)); + + cnt = 0; + TAILQ_FOREACH(s, &conf->ntp_sensors, entry) { + build_show_sensor(&c_sensor, s); + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS, + 0, 0, -1, &c_sensor, sizeof(c_sensor)); + cnt++; + } + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_SENSORS_END, + 0, 0, -1, &cnt, sizeof(cnt)); + + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_ALL_END, + 0, 0, -1, NULL, 0); + break; + default: + break; + } + imsg_free(&imsg); + } + return (0); +} + +void +session_socket_blockmode(int fd, enum blockmodes bm) +{ + int flags; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + fatal("fcntl F_GETFL"); + + if (bm == BM_NONBLOCK) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + + if ((flags = fcntl(fd, F_SETFL, flags)) == -1) + fatal("fcntl F_SETFL"); +} + +void +build_show_status(struct ctl_show_status *cs) +{ + struct ntp_peer *p; + struct ntp_sensor *s; + + cs->peercnt = cs->valid_peers = 0; + cs->sensorcnt = cs->valid_sensors = 0; + + TAILQ_FOREACH(p, &conf->ntp_peers, entry) { + cs->peercnt++; + if (p->trustlevel >= TRUSTLEVEL_BADPEER) + cs->valid_peers++; + } + TAILQ_FOREACH(s, &conf->ntp_sensors, entry) { + cs->sensorcnt++; + if (s->update.good) + cs->valid_sensors++; + } + + cs->synced = conf->status.synced; + cs->stratum = conf->status.stratum; + cs->clock_offset = getoffset() * 1000.0; +} + +void +build_show_peer(struct ctl_show_peer *cp, struct ntp_peer *p) +{ + const char *a = "not resolved"; + const char *pool = "", *addr_head_name = ""; + u_int8_t shift, best, validdelaycnt, jittercnt; + time_t now; + + now = getmonotime(); + + if (p->addr) + a = log_sockaddr((struct sockaddr *)&p->addr->ss); + if (p->addr_head.pool) + pool = "from pool "; + + if (0 != strcmp(a, p->addr_head.name)) + addr_head_name = p->addr_head.name; + + snprintf(cp->peer_desc, sizeof(cp->peer_desc), + "%s %s%s %s", a, pool, addr_head_name, + print_rtable(p->rtable) ); + + validdelaycnt = best = 0; + cp->offset = cp->delay = 0.0; + for (shift = 0; shift < OFFSET_ARRAY_SIZE; shift++) { + if (p->reply[shift].delay > 0.0) { + cp->offset += p->reply[shift].offset; + cp->delay += p->reply[shift].delay; + + if (p->reply[shift].delay < p->reply[best].delay) + best = shift; + + validdelaycnt++; + } + } + + if (validdelaycnt > 1) { + cp->offset /= validdelaycnt; + cp->delay /= validdelaycnt; + } + + /* + * use simple average for jitter calculation, as the + * RFC5905-recommended RMS average needs the math library + */ + jittercnt = 0; + cp->jitter = 0.0; + for (shift = 0; shift < OFFSET_ARRAY_SIZE; shift++) { + if (p->reply[shift].delay > 0.0 && shift != best) { + cp->jitter += p->reply[shift].delay - + p->reply[best].delay; + jittercnt++; + } + } + if (jittercnt > 1) + cp->jitter /= jittercnt; + + if (p->shift == 0) + shift = OFFSET_ARRAY_SIZE - 1; + else + shift = p->shift - 1; + + if (conf->status.synced == 1 && + p->reply[shift].status.send_refid == conf->status.refid) + cp->syncedto = 1; + else + cp->syncedto = 0; + + /* milliseconds to reduce number of leading zeroes */ + cp->offset *= 1000.0; + cp->delay *= 1000.0; + cp->jitter *= 1000.0; + + cp->weight = p->weight; + cp->trustlevel = p->trustlevel; + cp->stratum = p->reply[shift].status.stratum; + cp->next = p->next - now < 0 ? 0 : p->next - now; + cp->poll = p->poll; +} + +void +build_show_sensor(struct ctl_show_sensor *cs, struct ntp_sensor *s) +{ + time_t now; + u_int8_t shift; + u_int32_t refid; + + now = getmonotime(); + + memcpy(&refid, SENSOR_DEFAULT_REFID, sizeof(refid)); + refid = refid == s->refid ? 0 : s->refid; + + snprintf(cs->sensor_desc, sizeof(cs->sensor_desc), + "%s %.4s", s->device, (char *)&refid); + + if (s->shift == 0) + shift = SENSOR_OFFSETS - 1; + else + shift = s->shift - 1; + + if (conf->status.synced == 1 && + s->offsets[shift].status.send_refid == conf->status.refid) + cs->syncedto = 1; + else + cs->syncedto = 0; + + cs->weight = s->weight; + cs->good = s->update.good; + cs->stratum = s->offsets[shift].status.stratum; + cs->next = s->next - now < 0 ? 0 : s->next - now; + cs->poll = SENSOR_QUERY_INTERVAL; + cs->offset = s->offsets[shift].offset * 1000.0; + cs->correction = (double)s->correction / 1000.0; +} diff --git a/src/usr.sbin/ntpd/ntp.c b/src/usr.sbin/ntpd/ntp.c index 3f85e252..a91dabb2 100644 --- a/src/usr.sbin/ntpd/ntp.c +++ b/src/usr.sbin/ntpd/ntp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ntp.c,v 1.118 2013/09/28 12:18:05 phessler Exp $ */ +/* $OpenBSD: ntp.c,v 1.119 2013/10/04 14:28:16 phessler Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -36,13 +36,15 @@ #define PFD_PIPE_MAIN 0 #define PFD_HOTPLUG 1 #define PFD_PIPE_DNS 2 -#define PFD_MAX 3 +#define PFD_SOCK_CTL 3 +#define PFD_MAX 4 volatile sig_atomic_t ntp_quit = 0; volatile sig_atomic_t ntp_report = 0; struct imsgbuf *ibuf_main; struct imsgbuf *ibuf_dns; struct ntpd_conf *conf; +struct ctl_conns ctl_conns; u_int peer_cnt; u_int sensors_cnt; time_t lastreport; @@ -69,12 +71,14 @@ ntp_sighdlr(int sig) } pid_t -ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) +ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf, + struct passwd *pw) { int a, b, nfds, i, j, idx_peers, timeout; - int hotplugfd, nullfd, pipe_dns[2]; + int hotplugfd, nullfd, pipe_dns[2], idx_clients; u_int pfd_elms = 0, idx2peer_elms = 0; u_int listener_cnt, new_cnt, sent_cnt, trial_cnt; + u_int ctl_cnt; pid_t pid, dns_pid; struct pollfd *pfd = NULL; struct servent *se; @@ -84,6 +88,7 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) struct ntp_sensor *s, *next_s; struct timespec tp; struct stat stb; + struct ctl_conn *cc; time_t nextaction, last_sensor_scan = 0; void *newp; @@ -179,10 +184,12 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) conf->status.precision = a; conf->scale = 1; + TAILQ_INIT(&ctl_conns); sensor_init(); log_info("ntp engine ready"); + ctl_cnt = 0; peer_cnt = 0; TAILQ_FOREACH(p, &conf->ntp_peers, entry) peer_cnt++; @@ -203,7 +210,7 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) idx2peer_elms = peer_cnt; } - new_cnt = PFD_MAX + peer_cnt + listener_cnt; + new_cnt = PFD_MAX + peer_cnt + listener_cnt + ctl_cnt; if (new_cnt > pfd_elms) { if ((newp = realloc(pfd, sizeof(struct pollfd) * new_cnt)) == NULL) { @@ -225,6 +232,8 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) pfd[PFD_HOTPLUG].events = POLLIN; pfd[PFD_PIPE_DNS].fd = ibuf_dns->fd; pfd[PFD_PIPE_DNS].events = POLLIN; + pfd[PFD_SOCK_CTL].fd = fd_ctl; + pfd[PFD_SOCK_CTL].events = POLLIN; i = PFD_MAX; TAILQ_FOREACH(la, &conf->listen_addrs, entry) { @@ -278,6 +287,7 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) i++; } } + idx_clients = i; if (last_sensor_scan == 0 || last_sensor_scan + SENSOR_SCAN_INTERVAL < getmonotime()) { @@ -306,6 +316,14 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) if (ibuf_dns->w.queued > 0) pfd[PFD_PIPE_DNS].events |= POLLOUT; + TAILQ_FOREACH(cc, &ctl_conns, entry) { + pfd[i].fd = cc->ibuf.fd; + pfd[i].events = POLLIN; + if (cc->ibuf.w.queued > 0) + pfd[i].events |= POLLOUT; + i++; + } + timeout = nextaction - getmonotime(); if (timeout < 0) timeout = 0; @@ -340,6 +358,11 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) ntp_quit = 1; } + if (nfds > 0 && pfd[PFD_SOCK_CTL].revents & (POLLIN|POLLERR)) { + nfds--; + ctl_cnt += control_accept(fd_ctl); + } + if (nfds > 0 && pfd[PFD_HOTPLUG].revents & (POLLIN|POLLERR)) { nfds--; sensor_hotplugevent(hotplugfd); @@ -352,13 +375,17 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) ntp_quit = 1; } - for (; nfds > 0 && j < i; j++) + for (; nfds > 0 && j < idx_clients; j++) { if (pfd[j].revents & (POLLIN|POLLERR)) { nfds--; if (client_dispatch(idx2peer[j - idx_peers], conf->settime) == -1) ntp_quit = 1; } + } + + for (; nfds > 0 && j < i; j++) + nfds -= control_dispatch_msg(&pfd[j], &ctl_cnt); for (s = TAILQ_FIRST(&conf->ntp_sensors); s != NULL; s = next_s) { diff --git a/src/usr.sbin/ntpd/ntpctl.8 b/src/usr.sbin/ntpd/ntpctl.8 new file mode 100644 index 00000000..1c60233e --- /dev/null +++ b/src/usr.sbin/ntpd/ntpctl.8 @@ -0,0 +1,81 @@ +.\" $OpenBSD: ntpctl.8,v 1.1 2013/10/04 14:28:16 phessler Exp $ +.\" +.\" Copyright (c) 2012 Mike Miller +.\" +.\" 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 MIND, 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. +.\" +.Dd $Mdocdate: October 4 2013 $ +.Dt NTPCTL 8 +.Os +.Sh NAME +.Nm ntpctl +.Nd "control program for the Network Time Protocol daemon" +.Sh SYNOPSIS +.Nm ntpctl +.Bk -words +.Op Fl s Ar modifier +.Ek +.Sh DESCRIPTION +The +.Nm +program displays information about the running +.Xr ntpd 8 +daemon. +.Pp +The options are as follows: +.Bl -tag -width "-s modifierX" +.It Fl s Ar modifier +Show the data specified by +.Ar modifier : +.Bl -tag -width XXXXXXXXXX -compact +.Pp +.It Fl s Cm status +Show the status of peers and sensors, and whether the system clock is +synced. When the system clock is synced, the stratum is displayed. +When the system clock is not synced, the offset of the system clock, +as reported by the +.Xr adjtime 2 +system call, is displayed. +.Pp +.It Fl s Cm peers +Shows the following information about each peer: weight, trustlevel, +stratum, number of seconds until the next poll, polling interval +in seconds, and offset, network delay and network jitter in +milliseconds. When the system clock is synced to a peer, an asterisk +is displayed to the left of the weight column for that peer. +.Pp +.It Fl s Cm sensors +Shows the following information about each sensor: weight, sensor "good" +status, stratum, and offset and the configured correction in +milliseconds. +When the system clock is synced to a sensor, an asterisk +is displayed to the left of the weight column for that sensor. +.Pp +.It Fl s Cm all +Shows all of the above. +.El +.Sh FILES +.Bl -tag -width "/var/db/ntpd.driftXXX" -compact +.It Pa /var/run/ntpd.sock +Socket file for communication with +.Xr ntpd 8 . +.El +.Sh SEE ALSO +.Xr adjtime 2 , +.Xr ntpd 8 , +.Xr ntpd.conf 5 +.Sh HISTORY +The +.Nm +program first appeared in +.Ox 5.3 . diff --git a/src/usr.sbin/ntpd/ntpd.8 b/src/usr.sbin/ntpd/ntpd.8 index 7c18a0f9..17f4e291 100644 --- a/src/usr.sbin/ntpd/ntpd.8 +++ b/src/usr.sbin/ntpd/ntpd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ntpd.8,v 1.35 2013/08/14 06:32:37 jmc Exp $ +.\" $OpenBSD: ntpd.8,v 1.36 2013/10/04 14:28:16 phessler Exp $ .\" .\" Copyright (c) 2003, 2004, 2006 Henning Brauer .\" @@ -14,7 +14,7 @@ .\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 14 2013 $ +.Dd $Mdocdate: October 4 2013 $ .Dt NTPD 8 .Os .Sh NAME @@ -130,12 +130,16 @@ signal, it writes its peer and sensor status to Default configuration file. .It Pa /var/db/ntpd.drift Drift file. +.It Pa /var/run/ntpd.sock +Socket file for communication with +.Xr ntpctl 8 . .El .Sh SEE ALSO .Xr date 1 , .Xr adjfreq 2 , .Xr adjtime 2 , .Xr ntpd.conf 5 , +.Xr ntpctl 8 , .Xr rc 8 , .Xr rc.conf 8 , .Xr rdate 8 diff --git a/src/usr.sbin/ntpd/ntpd.c b/src/usr.sbin/ntpd/ntpd.c index 02a5e52c..5a4fb446 100644 --- a/src/usr.sbin/ntpd/ntpd.c +++ b/src/usr.sbin/ntpd/ntpd.c @@ -1,7 +1,8 @@ -/* $OpenBSD: ntpd.c,v 1.69 2011/03/19 23:40:11 okan Exp $ */ +/* $OpenBSD: ntpd.c,v 1.70 2013/10/04 14:28:16 phessler Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2012 Mike Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -37,12 +39,17 @@ __dead void usage(void); int main(int, char *[]); int check_child(pid_t, const char *); int dispatch_imsg(struct ntpd_conf *); +int dispatch_imsg_ctl(struct ntpd_conf *); void reset_adjtime(void); int ntpd_adjtime(double); void ntpd_adjfreq(double, int); void ntpd_settime(double); void readfreq(void); int writefreq(double); +void ctl_main(int, char*[]); +void show_status_msg(struct imsg *); +void show_peer_msg(struct imsg *, int); +void show_sensor_msg(struct imsg *, int); volatile sig_atomic_t quit = 0; volatile sig_atomic_t reconfig = 0; @@ -73,7 +80,13 @@ usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-dnSsv] [-f file]\n", __progname); + if (strcmp(__progname, "ntpd") == 0) + fprintf(stderr, "usage: %s [-dnSsv] [-f file]\n", + __progname); + else if (strcmp(__progname, "ntpctl") == 0) + fprintf(stderr, "usage: %s [-s modifier]\n", __progname); + else + fprintf(stderr, "Invalid program name: %s\n", __progname); exit(1); } @@ -87,9 +100,15 @@ main(int argc, char *argv[]) struct pollfd pfd[POLL_MAX]; pid_t chld_pid = 0, pid; const char *conffile; - int ch, nfds; + int fd_ctl, ch, nfds; int pipe_chld[2]; struct passwd *pw; + extern char *__progname; + + if (strcmp(__progname, "ntpctl") == 0) { + ctl_main (argc, argv); + /* NOTREACHED */ + } conffile = CONFFILE; @@ -154,9 +173,14 @@ main(int argc, char *argv[]) if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_chld) == -1) fatal("socketpair"); + if ((fd_ctl = control_init(CTLSOCKET)) == -1) + fatalx("control socket init failed"); + if (control_listen(fd_ctl) == -1) + fatalx("control socket listen failed"); + signal(SIGCHLD, sighdlr); /* fork child process */ - chld_pid = ntp_main(pipe_chld, &lconf, pw); + chld_pid = ntp_main(pipe_chld, fd_ctl, &lconf, pw); setproctitle("[priv]"); readfreq(); @@ -489,3 +513,287 @@ writefreq(double d) } return 1; } + +void +ctl_main(int argc, char *argv[]) +{ + struct sockaddr_un sun; + struct imsg imsg; + struct imsgbuf *ibuf_ctl; + int fd, n, done, ch; + int do_what, action; + char *sockname, *show_what; + + sockname = CTLSOCKET; + + if (argc < 2) { + usage(); + /* NOTREACHED */ + } + + do_what = -1; + while ((ch = getopt(argc, argv, "s:")) != -1) { + switch (ch) { + case 's': + do_what = CTL_SHOW; + break; + default: + usage(); + /* NOTREACHED */ + } + } + + action = -1; + if (do_what == CTL_SHOW) { + show_what = argv[argc - 1]; + if (strcmp(show_what, "peers") == 0) + action = CTL_SHOW_PEERS; + else if (strcmp(show_what, "sensors") == 0) + action = CTL_SHOW_SENSORS; + else if (strcmp(show_what, "status") == 0) + action = CTL_SHOW_STATUS; + else if (strcmp(show_what, "all") == 0) + action = CTL_SHOW_ALL; + else { + usage(); + /* NOTREACHED */ + } + } + else + errx (1, "invalid do_what"); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + err(1, "ntpctl: socket"); + + bzero(&sun, sizeof(sun)); + sun.sun_family = AF_UNIX; + if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) + errx(1, "ctl socket name too long"); + if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) + err(1, "connect: %s", sockname); + + if ((ibuf_ctl = malloc(sizeof(struct imsgbuf))) == NULL) + err(1, NULL); + imsg_init(ibuf_ctl, fd); + + switch (action) { + case CTL_SHOW_STATUS: + imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_STATUS, + 0, 0, -1, NULL, 0); + break; + case CTL_SHOW_PEERS: + imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_PEERS, + 0, 0, -1, NULL, 0); + break; + case CTL_SHOW_SENSORS: + imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_SENSORS, + 0, 0, -1, NULL, 0); + break; + case CTL_SHOW_ALL: + imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_ALL, + 0, 0, -1, NULL, 0); + break; + default: + errx(1, "invalid action"); + break; /* NOTREACHED */ + } + + while (ibuf_ctl->w.queued) + if (msgbuf_write(&ibuf_ctl->w) < 0) + err(1, "ibuf_ctl: msgbuf_write error"); + + done = 0; + while (!done) { + if ((n = imsg_read(ibuf_ctl)) == -1) + err(1, "ibuf_ctl: imsg_read error"); + if (n == 0) + errx(1, "ntpctl: pipe closed"); + + while (!done) { + if ((n = imsg_get(ibuf_ctl, &imsg)) == -1) + err(1, "ibuf_ctl: imsg_get error"); + if (n == 0) + break; + + switch (action) { + case CTL_SHOW_STATUS: + show_status_msg(&imsg); + done = 1; + break; + case CTL_SHOW_PEERS: + show_peer_msg(&imsg, 0); + if (imsg.hdr.type == + IMSG_CTL_SHOW_PEERS_END) + done = 1; + break; + case CTL_SHOW_SENSORS: + show_sensor_msg(&imsg, 0); + if (imsg.hdr.type == + IMSG_CTL_SHOW_SENSORS_END) + done = 1; + break; + case CTL_SHOW_ALL: + switch (imsg.hdr.type) { + case IMSG_CTL_SHOW_STATUS: + show_status_msg(&imsg); + break; + case IMSG_CTL_SHOW_PEERS: + show_peer_msg(&imsg, 1); + break; + case IMSG_CTL_SHOW_SENSORS: + show_sensor_msg(&imsg, 1); + break; + case IMSG_CTL_SHOW_PEERS_END: + case IMSG_CTL_SHOW_SENSORS_END: + /* do nothing */ + break; + case IMSG_CTL_SHOW_ALL_END: + done=1; + break; + default: + /* no action taken */ + break; + } + default: + /* no action taken */ + break; + } + imsg_free(&imsg); + } + } + close(fd); + free(ibuf_ctl); + exit (0); +} + +void +show_status_msg(struct imsg *imsg) +{ + struct ctl_show_status *cstatus; + double clock_offset; + + if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_status)) + fatalx("invalid IMSG_CTL_SHOW_STATUS received"); + + cstatus = (struct ctl_show_status *)imsg->data; + + if (cstatus->peercnt > 0) + printf("%d of %d peers valid\n", + cstatus->valid_peers, cstatus->peercnt); + + if (cstatus->sensorcnt > 0) + printf("%d of %d sensors valid\n", + cstatus->valid_sensors, cstatus->sensorcnt); + + if (cstatus->peercnt + cstatus->sensorcnt == 0) + printf("no peers and no sensors configured\n"); + + if (cstatus->synced == 1) + printf("clock is synced, stratum %u\n", cstatus->stratum); + else { + printf("clock is unsynced"); + clock_offset = cstatus->clock_offset < 0 ? + -1.0 * cstatus->clock_offset : cstatus->clock_offset; + if (clock_offset > 5e-7) + printf(", clock offset is %.3fms\n", + cstatus->clock_offset); + else + printf("\n"); + } +} + +void +show_peer_msg(struct imsg *imsg, int calledfromshowall) +{ + struct ctl_show_peer *cpeer; + int cnt; + char stratum[3]; + static int firsttime = 1; + + if (imsg->hdr.type == IMSG_CTL_SHOW_PEERS_END) { + if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(cnt)) + fatalx("invalid IMSG_CTL_SHOW_PEERS_END received"); + memcpy(&cnt, imsg->data, sizeof(cnt)); + if (cnt == 0) + printf("no peers configured\n"); + return; + } + + if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_peer)) + fatalx("invalid IMSG_CTL_SHOW_PEERS received"); + + cpeer = (struct ctl_show_peer *)imsg->data; + + if (strlen(cpeer->peer_desc) > MAX_DISPLAY_WIDTH - 1) + fatalx("peer_desc is too long"); + + if (firsttime) { + firsttime = 0; + if (calledfromshowall) + printf("\n"); + printf("peer\n wt tl st next poll " + "offset delay jitter\n"); + } + + if (cpeer->stratum > 0) + snprintf(stratum, sizeof(stratum), "%2u", cpeer->stratum); + else + strlcpy (stratum, " -", sizeof (stratum)); + + printf("%s\n %1s %2u %2u %2s %4ds %4ds", + cpeer->peer_desc, cpeer->syncedto == 1 ? "*" : " ", + cpeer->weight, cpeer->trustlevel, stratum, cpeer->next, + cpeer->poll); + + if (cpeer->trustlevel >= TRUSTLEVEL_BADPEER) + printf(" %12.3fms %9.3fms %8.3fms\n", cpeer->offset, + cpeer->delay, cpeer->jitter); + else + printf(" ---- peer not valid ----\n"); + +} + +void +show_sensor_msg(struct imsg *imsg, int calledfromshowall) +{ + struct ctl_show_sensor *csensor; + int cnt; + static int firsttime = 1; + + if (imsg->hdr.type == IMSG_CTL_SHOW_SENSORS_END) { + if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(cnt)) + fatalx("invalid IMSG_CTL_SHOW_SENSORS_END received"); + memcpy(&cnt, imsg->data, sizeof(cnt)); + if (cnt == 0) + printf("no sensors configured\n"); + return; + } + + if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_sensor)) + fatalx("invalid IMSG_CTL_SHOW_SENSORS received"); + + csensor = (struct ctl_show_sensor *)imsg->data; + + if (strlen(csensor->sensor_desc) > MAX_DISPLAY_WIDTH - 1) + fatalx("sensor_desc is too long"); + + if (firsttime) { + firsttime = 0; + if (calledfromshowall) + printf("\n"); + printf("sensor\n wt gd st next poll " + "offset correction\n"); + } + + printf("%s\n %1s %2u %2u %2u %4ds %4ds", csensor->sensor_desc, + csensor->syncedto == 1 ? "*" : " ", csensor->weight, csensor->good, + csensor->stratum, csensor->next, csensor->poll); + + if (csensor->good == 1) + printf(" %11.3fms %9.3fms\n", + csensor->offset, csensor->correction); + else + printf(" - sensor not valid -\n"); + +} diff --git a/src/usr.sbin/ntpd/ntpd.h b/src/usr.sbin/ntpd/ntpd.h index 5cce7dd0..8d86d696 100644 --- a/src/usr.sbin/ntpd/ntpd.h +++ b/src/usr.sbin/ntpd/ntpd.h @@ -1,7 +1,8 @@ -/* $OpenBSD: ntpd.h,v 1.107 2013/04/30 11:42:56 mglocker Exp $ */ +/* $OpenBSD: ntpd.h,v 1.108 2013/10/04 14:28:16 phessler Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer + * Copyright (c) 2012 Mike Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -28,6 +29,8 @@ #include #include #include +#include +#include #include "ntp.h" #include @@ -35,6 +38,7 @@ #define NTPD_USER "_ntp" #define CONFFILE "/etc/ntpd.conf" #define DRIFTFILE "/var/db/ntpd.drift" +#define CTLSOCKET "/var/run/ntpd.sock" #define INTERVAL_QUERY_NORMAL 30 /* sync to peers every n secs */ #define INTERVAL_QUERY_PATHETIC 60 @@ -60,6 +64,7 @@ #define MAX_FREQUENCY_ADJUST 128e-5 /* max correction per iteration */ #define REPORT_INTERVAL (24*60*60) /* interval between status reports */ #define MAX_SEND_ERRORS 3 /* max send errors before reconnect */ +#define MAX_DISPLAY_WIDTH 80 /* max chars in ctl_show report line */ #define FILTER_ADJFREQ 0x01 /* set after doing adjfreq */ @@ -67,6 +72,7 @@ #define SENSOR_QUERY_INTERVAL 15 #define SENSOR_QUERY_INTERVAL_SETTIME (SETTIME_TIMEOUT/3) #define SENSOR_SCAN_INTERVAL (5*60) +#define SENSOR_DEFAULT_REFID "HARD" enum client_state { STATE_NONE, @@ -128,6 +134,7 @@ struct ntp_peer { enum client_state state; time_t next; time_t deadline; + time_t poll; u_int32_t id; u_int8_t shift; u_int8_t trustlevel; @@ -184,12 +191,83 @@ struct ntpd_conf { u_int8_t filters; }; +struct imsgev { + struct imsgbuf ibuf; + void (*handler)(int, short, void *); + struct event ev; + void *data; + short events; +}; + +struct ctl_show_status { + u_int peercnt; + u_int sensorcnt; + u_int valid_peers; + u_int valid_sensors; + u_int8_t synced; + u_int8_t stratum; + double clock_offset; +}; + +struct ctl_show_peer { + char peer_desc[MAX_DISPLAY_WIDTH]; + u_int8_t syncedto; + u_int8_t weight; + u_int8_t trustlevel; + u_int8_t stratum; + time_t next; + time_t poll; + double offset; + double delay; + double jitter; +}; + +struct ctl_show_sensor { + char sensor_desc[MAX_DISPLAY_WIDTH]; + u_int8_t syncedto; + u_int8_t weight; + u_int8_t good; + u_int8_t stratum; + time_t next; + time_t poll; + double offset; + double correction; +}; + +enum blockmodes { + BM_NORMAL, + BM_NONBLOCK +}; + +struct ctl_conn { + TAILQ_ENTRY(ctl_conn) entry; + struct imsgev iev; + struct imsgbuf ibuf; +}; + +TAILQ_HEAD(ctl_conns, ctl_conn) ; + enum imsg_type { IMSG_NONE, IMSG_ADJTIME, IMSG_ADJFREQ, IMSG_SETTIME, - IMSG_HOST_DNS + IMSG_HOST_DNS, + IMSG_CTL_SHOW_STATUS, + IMSG_CTL_SHOW_PEERS, + IMSG_CTL_SHOW_PEERS_END, + IMSG_CTL_SHOW_SENSORS, + IMSG_CTL_SHOW_SENSORS_END, + IMSG_CTL_SHOW_ALL, + IMSG_CTL_SHOW_ALL_END +}; + +enum ctl_actions { + CTL_SHOW, + CTL_SHOW_STATUS, + CTL_SHOW_PEERS, + CTL_SHOW_SENSORS, + CTL_SHOW_ALL }; /* prototypes */ @@ -205,7 +283,7 @@ void fatalx(const char *); const char *log_sockaddr(struct sockaddr *); /* ntp.c */ -pid_t ntp_main(int[2], struct ntpd_conf *, struct passwd *); +pid_t ntp_main(int[2], int, struct ntpd_conf *, struct passwd *); int priv_adjtime(void); void priv_settime(double); void priv_host_dns(char *, u_int32_t); @@ -214,6 +292,7 @@ void update_scale(double); time_t scale_interval(time_t); time_t error_interval(void); extern struct ntpd_conf *conf; +extern struct ctl_conns ctl_conns; /* parse.y */ int parse_config(const char *, struct ntpd_conf *); @@ -263,3 +342,19 @@ void sensor_hotplugevent(int); /* ntp_dns.c */ pid_t ntp_dns(int[2], struct ntpd_conf *, struct passwd *); + +/* control.c */ +int control_init(char *); +int control_listen(int); +void control_shutdown(int); +void control_cleanup(const char *); +int control_accept(int); +struct ctl_conn *control_connbyfd(int); +int control_close(int); +int control_dispatch_msg(struct pollfd *, u_int *); +void session_socket_blockmode(int, enum blockmodes); +void build_show_status(struct ctl_show_status *); +void build_show_peer(struct ctl_show_peer *, + struct ntp_peer *); +void build_show_sensor(struct ctl_show_sensor *, + struct ntp_sensor *); diff --git a/src/usr.sbin/ntpd/sensors.c b/src/usr.sbin/ntpd/sensors.c index 571b0c9e..f3b39ca1 100644 --- a/src/usr.sbin/ntpd/sensors.c +++ b/src/usr.sbin/ntpd/sensors.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sensors.c,v 1.46 2012/09/20 12:43:16 patrick Exp $ */ +/* $OpenBSD: sensors.c,v 1.47 2013/10/04 14:28:16 phessler Exp $ */ /* * Copyright (c) 2006 Henning Brauer @@ -140,7 +140,7 @@ sensor_add(int sensordev, char *dxname) s->sensordevid = sensordev; if (cs->refstr == NULL) - memcpy(&s->refid, "HARD", sizeof(s->refid)); + memcpy(&s->refid, SENSOR_DEFAULT_REFID, sizeof(s->refid)); else { s->refid = 0; strncpy((char *)&s->refid, cs->refstr, sizeof(s->refid));