diff --git a/build-aux/iso-grub-cfg.sh b/build-aux/iso-grub-cfg.sh index fc7a8ddd..054ae796 100755 --- a/build-aux/iso-grub-cfg.sh +++ b/build-aux/iso-grub-cfg.sh @@ -125,6 +125,7 @@ mkdir -p boot/grub/init echo "furthermore" > boot/grub/init/furthermore # TODO: Possibly use a 'try' feature to not warn in case it was already unset. echo "unset require dhclient" > boot/grub/init/network-no-dhclient +echo "require ntpd optional" > boot/grub/init/local-ntpd echo "require sshd optional" > boot/grub/init/local-sshd exec > boot/grub/grub.cfg @@ -194,6 +195,7 @@ fi set enable_src=true set enable_network_drivers= set enable_dhclient=true +set enable_ntpd=false set enable_sshd=false export version @@ -206,6 +208,7 @@ export no_random_seed export enable_src export enable_network_drivers export enable_dhclient +export enable_ntpd export enable_sshd EOF @@ -302,6 +305,13 @@ cat << EOF module /boot/grub/init/network-no-dhclient --append-to /etc/init/network echo done fi + if \$enable_ntpd; then + echo -n "Enabling ntpd ... " + module /boot/grub/init/local-ntpd --append-to /etc/init/local + module /boot/grub/init/furthermore --create-to /etc/init/time + module /boot/grub/init/local-ntpd --append-to /etc/init/time + echo done + fi if \$enable_sshd; then echo -n "Enabling sshd ... " module /boot/grub/init/local-sshd --append-to /etc/init/local @@ -466,6 +476,18 @@ else } fi +if \$enable_ntpd; then + menuentry "Disable NTP client" { + enable_ntpd=false + configfile /boot/grub/advanced.cfg + } +else + menuentry "Enable NTP client" { + enable_ntpd=true + configfile /boot/grub/advanced.cfg + } +fi + if \$enable_sshd; then menuentry "Disable SSH server" { enable_sshd=false diff --git a/build-aux/ports.conf b/build-aux/ports.conf index cf9a0ea8..10aa6179 100644 --- a/build-aux/ports.conf +++ b/build-aux/ports.conf @@ -1,3 +1,3 @@ set_minimal="cut dash e2fsprogs grep grub mdocml sed xargs" -set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip libcurl libcurses libssl libstdc++ nano make patch pkg-config python ssh tar vim wget xz xorriso" +set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip libcurl libcurses libssl libstdc++ nano ntpd make patch pkg-config python ssh tar vim wget xz xorriso" sets="basic minimal" diff --git a/ports/ntpd/ntpd.patch b/ports/ntpd/ntpd.patch new file mode 100644 index 00000000..ce02894c --- /dev/null +++ b/ports/ntpd/ntpd.patch @@ -0,0 +1,805 @@ +diff -Paur --no-dereference -- ntpd.upstream/compat/bsd-setresuid.c ntpd/compat/bsd-setresuid.c +--- ntpd.upstream/compat/bsd-setresuid.c ++++ ntpd/compat/bsd-setresuid.c +@@ -44,6 +44,7 @@ + return -1; + # endif + ++#if !defined(__sortix__) + /* + * When real, effective and saved uids are the same and we have + * changed uids, sanity check that we cannot restore the old uid. +@@ -62,6 +63,7 @@ + errno = EACCES; + return -1; + } ++#endif + + return ret; + } +diff -Paur --no-dereference -- ntpd.upstream/compat/imsg-buffer.c ntpd/compat/imsg-buffer.c +--- ntpd.upstream/compat/imsg-buffer.c ++++ ntpd/compat/imsg-buffer.c +@@ -27,6 +27,10 @@ + #include + #include + ++#if defined(__sortix__) && !defined(IOV_MAX) ++#include ++#endif ++ + #include "imsg.h" + + static int ibuf_realloc(struct ibuf *, size_t); +@@ -252,7 +256,7 @@ + msg.msg_iovlen = i; + + if (buf != NULL && buf->fd != -1) { +- msg.msg_control = (caddr_t)&cmsgbuf.buf; ++ msg.msg_control = (char*)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); +diff -Paur --no-dereference -- ntpd.upstream/include/imsg.h ntpd/include/imsg.h +--- ntpd.upstream/include/imsg.h ++++ ntpd/include/imsg.h +@@ -23,6 +23,8 @@ + + #include + ++typedef unsigned char u_char; ++ + #define IBUF_READ_SIZE 65535 + #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) + #define MAX_IMSGSIZE 16384 +diff -Paur --no-dereference -- ntpd.upstream/include/machine/endian.h ntpd/include/machine/endian.h +--- ntpd.upstream/include/machine/endian.h ++++ ntpd/include/machine/endian.h +@@ -32,7 +32,7 @@ + #include + + #else +-#include_next ++#include + + #endif + +diff -Paur --no-dereference -- ntpd.upstream/Makefile.in ntpd/Makefile.in +--- ntpd.upstream/Makefile.in ++++ ntpd/Makefile.in +@@ -824,17 +824,14 @@ + + + install-exec-hook: +- @if [ ! -f "$(DESTDIR)$(sysconfdir)/ntpd.conf" ]; then \ +- $(INSTALL) -m 644 "$(srcdir)/ntpd.conf" "$(DESTDIR)$(sysconfdir)/ntpd.conf"; \ +- else \ +- echo; \ +- echo " $(DESTDIR)$(sysconfdir)/ntpd.conf already exists, install will not overwrite"; \ +- fi ++ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)/default" ++ $(INSTALL) -m 644 "$(srcdir)/ntpd.conf" "$(DESTDIR)$(sysconfdir)/default/ntpd.conf" ++ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)/default/passwd.d" ++ echo "_ntp:x:101:101:_ntp:/var/empty:sh" > "$(DESTDIR)$(sysconfdir)/default/passwd.d/ntpd" ++ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)/default/group.d" ++ echo "_ntp::101:_ntp" > "$(DESTDIR)$(sysconfdir)/default/group.d/ntpd" + + uninstall-local: +- @if cmp -s "$(DESTDIR)$(sysconfdir)/ntpd.conf" "$(srcdir)/ntpd.conf"; then \ +- rm -f "$(DESTDIR)$(sysconfdir)/ntpd.conf"; \ +- fi + @rm -f "$(DESTDIR)$(sbindir)/ntpctl" + + # Tell versions [3.59,3.63) of GNU make to not export all variables. +diff -Paur --no-dereference -- ntpd.upstream/src/client.c ntpd/src/client.c +--- ntpd.upstream/src/client.c ++++ ntpd/src/client.c +@@ -128,7 +128,9 @@ + int + client_query(struct ntp_peer *p) + { ++#ifdef IPTOS_LOWDELAY + int val; ++#endif + + if (p->addr == NULL && client_nextaddr(p) == -1) { + if (conf->settime) +@@ -189,10 +191,12 @@ + } else + fatal("client_query connect"); + } ++#ifdef IPTOS_LOWDELAY + val = IPTOS_LOWDELAY; + if (p->addr->ss.ss_family == AF_INET && setsockopt(p->query->fd, + IPPROTO_IP, IP_TOS, &val, sizeof(val)) == -1) + log_warn("setsockopt IPTOS_LOWDELAY"); ++#endif + #ifdef SO_TIMESTAMP + val = 1; + if (setsockopt(p->query->fd, SOL_SOCKET, SO_TIMESTAMP, +@@ -307,7 +311,10 @@ + somsg.msg_controllen = sizeof(cmsgbuf.buf); + + if ((size = recvmsg(p->query->fd, &somsg, 0)) == -1) { +- if (errno == EHOSTUNREACH || errno == EHOSTDOWN || ++ if (errno == EHOSTUNREACH || ++#ifdef EHOSTDOWN ++ errno == EHOSTDOWN || ++#endif + errno == ENETUNREACH || errno == ENETDOWN || + errno == ECONNREFUSED || errno == EADDRNOTAVAIL || + errno == ENOPROTOOPT || errno == ENOENT) { +@@ -405,10 +412,11 @@ + if (p->reply[p->shift].delay < 0) { + interval = error_interval(); + set_next(p, interval); +- log_info("reply from %s: negative delay %fs, " ++ log_info("reply from %s: negative delay %llims, " + "next query %llds", + log_sockaddr((struct sockaddr *)&p->addr->ss), +- p->reply[p->shift].delay, (long long)interval); ++ (long long)(p->reply[p->shift].delay * 1000.0), ++ (long long)interval); + return (0); + } + p->reply[p->shift].error = (T2 - T1) - (T3 - T4); +@@ -470,10 +478,10 @@ + else + interval = scale_interval(INTERVAL_QUERY_NORMAL); + +- log_debug("reply from %s: offset %f delay %f, " ++ log_debug("reply from %s: offset %llims delay %llims, " + "next query %llds", + log_sockaddr((struct sockaddr *)&p->addr->ss), +- offset, delay, ++ (long long)(offset * 1000), (long long)(delay * 1000), + (long long)interval); + + set_next(p, interval); +diff -Paur --no-dereference -- ntpd.upstream/src/config.c ntpd/src/config.c +--- ntpd.upstream/src/config.c ++++ ntpd/src/config.c +@@ -25,7 +25,9 @@ + #include + #include + #include ++#if __has_include() + #include ++#endif + #include + + #include "ntpd.h" +diff -Paur --no-dereference -- ntpd.upstream/src/constraint.c ntpd/src/constraint.c +--- ntpd.upstream/src/constraint.c ++++ ntpd/src/constraint.c +@@ -48,6 +48,10 @@ + #define IMF_FIXDATE "%a, %d %h %Y %T GMT" + #define X509_DATE "%Y-%m-%d %T UTC" + ++#if defined(__sortix__) ++#define setgroups(a, b) ((void) (a), (void) (b), 0) ++#endif ++ + int constraint_addr_init(struct constraint *); + void constraint_addr_head_clear(struct constraint *); + struct constraint * +@@ -265,7 +269,8 @@ + constraint_add(cstr); + constraint_cnt++; + +- if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, ++ /* PATCH: AF_UNIX SOCK_DGRAM isn't implemented on Sortix. */ ++ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, AF_UNSPEC, + pipes) == -1) + fatal("%s pipes", __func__); + +@@ -683,9 +688,9 @@ + offset = gettime_from_timeval(&tv[0]) - + gettime_from_timeval(&tv[1]); + +- log_info("constraint reply from %s: offset %f", ++ log_info("constraint reply from %s: offset %lli ms", + log_sockaddr((struct sockaddr *)&cstr->addr->ss), +- offset); ++ (long long)(offset * 1000)); + + cstr->state = STATE_REPLY_RECEIVED; + cstr->last = getmonotime(); +diff -Paur --no-dereference -- ntpd.upstream/src/control.c ntpd/src/control.c +--- ntpd.upstream/src/control.c ++++ ntpd/src/control.c +@@ -42,7 +42,7 @@ + struct sockaddr_un saddr; + int fd; + +- bzero(&saddr, sizeof(saddr)); ++ memset(&saddr, 0, sizeof(saddr)); + saddr.sun_family = AF_UNIX; + strlcpy(saddr.sun_path, path, sizeof(saddr.sun_path)); + +@@ -97,10 +97,12 @@ + umask(old_umask); + + if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { ++#if !defined(__sortix__) + log_warn("control_init: chmod"); + close(fd); + (void)unlink(path); + return (-1); ++#endif + } + + session_socket_nonblockmode(fd); +diff -Paur --no-dereference -- ntpd.upstream/src/init/ntpd ntpd/src/init/ntpd +--- ntpd.upstream/src/init/ntpd ++++ ntpd/src/init/ntpd +@@ -0,0 +1,4 @@ ++require network ++#program=ntpd ++#exec $program -d ++exec ntpd -d +diff -Paur --no-dereference -- ntpd.upstream/src/Makefile.in ntpd/src/Makefile.in +--- ntpd.upstream/src/Makefile.in ++++ ntpd/src/Makefile.in +@@ -1003,6 +1003,8 @@ + info-am: + + install-data-am: install-man ++ mkdir -p $(DESTDIR)$(datadir)/init ++ cp init/ntpd $(DESTDIR)$(datadir)/init/ntpd + + install-dvi: install-dvi-am + +diff -Paur --no-dereference -- ntpd.upstream/src/ntp.c ntpd/src/ntp.c +--- ntpd.upstream/src/ntp.c ++++ ntpd/src/ntp.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -35,6 +36,10 @@ + + #include "ntpd.h" + ++#if defined(__sortix__) ++#define setgroups(a, b) ((void) (a), (void) (b), 0) ++#endif ++ + #define PFD_PIPE_MAIN 0 + #define PFD_PIPE_DNS 1 + #define PFD_SOCK_CTL 2 +@@ -79,7 +84,9 @@ + u_int listener_cnt, new_cnt, sent_cnt, trial_cnt; + u_int ctl_cnt; + struct pollfd *pfd = NULL; ++#if !defined(__sortix__) + struct servent *se; ++#endif + struct listen_addr *la; + struct ntp_peer *p; + struct ntp_peer **idx2peer = NULL; +@@ -96,7 +103,7 @@ + pipe_dns) == -1) + fatal("socketpair"); + +- start_child(NTPDNS_PROC_NAME, pipe_dns[1], argc, argv); ++ pid_t dns_pid = start_child(NTPDNS_PROC_NAME, pipe_dns[1], argc, argv); + + log_init(nconf->debug ? LOG_TO_STDERR : LOG_TO_SYSLOG, nconf->verbose, + LOG_DAEMON); +@@ -104,8 +111,10 @@ + fatal("setsid"); + log_procinit("ntp"); + ++#if !defined(__sortix__) + if ((se = getservbyname("ntp", "udp")) == NULL) + fatal("getservbyname"); ++#endif + + /* Start control socket. */ + if ((fd_ctl = control_init(CTLSOCKET)) == -1) +@@ -137,14 +146,20 @@ + setproctitle("ntp engine"); + + conf = nconf; ++#if defined(__sortix__) ++ setup_listeners(NULL, conf, &listener_cnt); ++#else + setup_listeners(se, conf, &listener_cnt); ++#endif + + if (setgroups(1, &pw->pw_gid) || + setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) + fatal("can't drop privileges"); + ++#if !defined(__sortix__) + endservent(); ++#endif + + /* The ntp process will want to open NTP client sockets -> "inet" */ + if (pledge("stdio inet", NULL) == -1) +@@ -464,6 +479,9 @@ + msgbuf_clear(&ibuf_dns->w); + free(ibuf_dns); + ++ kill(dns_pid, SIGTERM); ++ waitpid(dns_pid, NULL, 0); ++ + log_info("ntp engine exiting"); + exit(0); + } +diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c +--- ntpd.upstream/src/ntpd.c ++++ ntpd/src/ntpd.c +@@ -45,6 +45,107 @@ + + #include "ntpd.h" + ++#if defined(__sortix__) ++#include ++ ++int adjtime(const struct timeval *delta, struct timeval *olddelta) ++{ ++ if (delta) { ++ struct timespec deltats = { ++ .tv_sec = delta->tv_sec, ++ .tv_nsec = delta->tv_usec * 1000 ++ }; ++ struct timespec oldnow; ++ if (clock_gettime(CLOCK_REALTIME, &oldnow) < 0) ++ return -1; ++ struct timespec newnow = timespec_add(oldnow, deltats); ++ if (clock_settime(CLOCK_REALTIME, &newnow) < 0) ++ return -1; ++ } ++ if (olddelta) { ++ olddelta->tv_sec = 0; ++ olddelta->tv_usec = 0; ++ } ++ return 0; ++} ++ ++/* ++From musl: ++ ++Copyright © 2005-2014 Rich Felker, et al. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++*/ ++int daemon(int nochdir, int noclose) ++{ ++ if (!nochdir && chdir("/")) ++ return -1; ++ if (!noclose) { ++ int fd, failed = 0; ++ if ((fd = open("/dev/null", O_RDWR)) < 0) return -1; ++ if (dup2(fd, 0) < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) ++ failed++; ++ if (fd > 2) close(fd); ++ if (failed) return -1; ++ } ++ ++ switch(fork()) { ++ case 0: break; ++ case -1: return -1; ++ default: _exit(0); ++ } ++ ++ if (setsid() < 0) return -1; ++ ++ switch(fork()) { ++ case 0: break; ++ case -1: return -1; ++ default: _exit(0); ++ } ++ ++ return 0; ++} ++ ++int ++adjfreq(const int64_t *freq, int64_t *oldfreq) ++{ ++ (void) freq; ++ (void) oldfreq; ++ //log_warnx("adjfreq is not implemented"); ++ if (oldfreq) ++ *oldfreq = 0; ++ return 0; ++} ++ ++/* ++ * The RTC is only updated if the clock is not marked as unsynced. ++ */ ++ ++void ++update_time_sync_status(int synced) ++{ ++ (void) synced; ++ //log_warnx("update_time_sync_status is not implemented"); ++} ++#endif ++ + void sighdlr(int); + __dead void usage(void); + int auto_preconditions(const struct ntpd_conf *); +@@ -70,6 +171,7 @@ + volatile sig_atomic_t sigchld = 0; + struct imsgbuf *ibuf; + int timeout = INFTIM; ++int readyfd = -1; + + extern u_int constraint_cnt; + +@@ -108,6 +210,17 @@ + } + } + ++void ++ready(void) ++{ ++ if (0 <= readyfd) { ++ char c = '\n'; ++ write(readyfd, &c, 1); ++ close(readyfd); ++ readyfd = -1; ++ } ++} ++ + __dead void + usage(void) + { +@@ -176,7 +289,10 @@ + /* NOTREACHED */ + } + +- conffile = CONFFILE; ++ if (access(CONFFILE, F_OK) < 0 && access(DEFAULTCONFFILE, F_OK) == 0) ++ conffile = DEFAULTCONFFILE; ++ else ++ conffile = CONFFILE; + + memset(&lconf, 0, sizeof(lconf)); + +@@ -222,6 +338,12 @@ + } + } + ++ if (getenv("READYFD")) { ++ readyfd = atoi(getenv("READYFD")); ++ unsetenv("READYENV"); ++ fcntl(readyfd, F_SETFD, O_CLOEXEC | O_CLOFORK); ++ } ++ + /* log to stderr until daemonized */ + logdest = LOG_TO_STDERR; + if (!lconf.debug) +@@ -335,6 +457,10 @@ + if (pledge("stdio rpath inet settime proc exec id", NULL) == -1) + err(1, "pledge"); + ++ if (!lconf.settime) { ++ ready(); ++ } ++ + while (quit == 0) { + new_cnt = PFD_MAX + constraint_cnt; + if (new_cnt > pfd_elms) { +@@ -380,6 +506,7 @@ + fatal("daemon"); + writepid(&lconf); + } ++ ready(); + } + + if (nfds > 0 && (pfd[PFD_PIPE].revents & POLLOUT)) +@@ -487,6 +614,7 @@ + } + lconf->settime = 0; + timeout = INFTIM; ++ ready(); + break; + case IMSG_CONSTRAINT_QUERY: + priv_constraint_msg(imsg.hdr.peerid, +@@ -507,9 +635,8 @@ + void + reset_adjtime(void) + { +- struct timeval tv; ++ struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + +- timerclear(&tv); + if (adjtime(&tv, NULL) == -1) + log_warn("reset adjtime failed"); + } +@@ -523,9 +650,9 @@ + + d += getoffset(); + if (d >= threshold || d <= -1 * threshold) +- log_info("adjusting local clock by %fs", d); ++ log_info("adjusting local clock by %llims", (long long)(d * 1000)); + else +- log_debug("adjusting local clock by %fs", d); ++ log_debug("adjusting local clock by %llims", (long long)(d * 1000)); + + #ifdef HAVE_ADJTIMEX + int rc; +@@ -614,14 +741,26 @@ + curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000); + curtime.tv_usec %= 1000000; + ++#if defined(__sortix__) ++ struct timespec ts = ++ { ++ .tv_sec = curtime.tv_sec, ++ .tv_nsec = curtime.tv_usec * 1000 ++ }; ++ if (clock_settime(CLOCK_REALTIME, &ts) == -1) { ++ log_warn("settimeofday"); ++ return; ++ } ++#else + if (settimeofday(&curtime, NULL) == -1) { + log_warn("settimeofday"); + return; + } ++#endif + tval = curtime.tv_sec; + strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", + localtime(&tval)); +- log_info("set local clock to %s (offset %fs)", buf, d); ++ log_info("set local clock to %s (offset %llims)", buf, (long long)(d * 1000.0)); + } + + static FILE *freqfp; +@@ -632,6 +771,7 @@ + int64_t current; + int fd; + double d; ++ long long lli; + + fd = open(DRIFTFILE, O_RDWR); + if (fd == -1) { +@@ -649,7 +789,8 @@ + if (adjfreq(NULL, ¤t) == -1) + log_warn("adjfreq failed"); + else if (current == 0 && freqfp) { +- if (fscanf(freqfp, "%lf", &d) == 1) { ++ if (fscanf(freqfp, "%lli", &lli) == 1) { ++ d = (double)lli; + d /= 1e6; /* scale from ppm */ + ntpd_adjfreq(d, 0); + } else +@@ -667,7 +808,8 @@ + if (freqfp == NULL) + return 0; + rewind(freqfp); +- r = fprintf(freqfp, "%.3f\n", d * 1e6); /* scale to ppm */ ++ long long lli = (long long)(d * 1e6); ++ r = fprintf(freqfp, "%lli\n", lli); /* scale to ppm */ + if (r < 0 || fflush(freqfp) != 0) { + if (warnonce) { + log_warnx("can't write %s", DRIFTFILE); +diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.h ntpd/src/ntpd.h +--- ntpd.upstream/src/ntpd.h ++++ ntpd/src/ntpd.h +@@ -23,7 +23,9 @@ + #include + #include + #include ++#if __has_include() + #include ++#endif + #include + #include + #include +@@ -31,6 +33,11 @@ + #include + #include + ++typedef unsigned char u_char; ++typedef unsigned short u_short; ++typedef unsigned int u_int; ++typedef unsigned long u_long; ++ + #include "ntp.h" + #include "log.h" + +@@ -44,6 +51,7 @@ + #define SYSCONFDIR "/etc" + #endif + #define CONFFILE SYSCONFDIR "/ntpd.conf" ++#define DEFAULTCONFFILE SYSCONFDIR "/default/ntpd.conf" + + #ifndef LOCALSTATEDIR + #define LOCALSTATEDIR "/var" +diff -Paur --no-dereference -- ntpd.upstream/src/ntp_dns.c ntpd/src/ntp_dns.c +--- ntpd.upstream/src/ntp_dns.c ++++ ntpd/src/ntp_dns.c +@@ -20,8 +20,10 @@ + #include + #include + #include ++#ifndef __sortix__ + #include + #include ++#endif + + #include + +@@ -33,11 +35,17 @@ + #include + #include + #include ++#ifndef __sortix__ + #include ++#endif + #include + + #include "ntpd.h" + ++#ifdef __sortix__ ++#define setgroups(a, b) ((void) (a), (void) (b), 0) ++#endif ++ + volatile sig_atomic_t quit_dns = 0; + static struct imsgbuf *ibuf_dns; + extern int non_numeric; +@@ -64,7 +72,9 @@ + struct pollfd pfd[1]; + int nfds, nullfd; + ++#ifndef __sortix__ + res_init(); ++#endif + if (setpriority(PRIO_PROCESS, 0, 0) == -1) + log_warn("could not set priority"); + +@@ -214,6 +224,9 @@ + return (0); + } + ++/* PATCH: Sortix doesn't have res_qury but it's only used to check if the DNS ++ is online, but init(8) already ensures that's the case. */ ++#ifndef __sortix__ + int + probe_root_ns(void) + { +@@ -238,18 +251,21 @@ + + return ret; + } ++#endif + + void + probe_root(void) + { + int n; + ++#ifndef __sortix__ + n = probe_root_ns(); + if (n < 0) { + /* give programs like unwind a second chance */ + sleep(1); + n = probe_root_ns(); + } ++#endif + if (imsg_compose(ibuf_dns, IMSG_PROBE_ROOT, 0, 0, -1, &n, + sizeof(int)) == -1) + fatalx("probe_root"); +diff -Paur --no-dereference -- ntpd.upstream/src/ntp_msg.c ntpd/src/ntp_msg.c +--- ntpd.upstream/src/ntp_msg.c ++++ ntpd/src/ntp_msg.c +@@ -53,7 +53,11 @@ + n = sendto(fd, msg, sizeof(*msg), 0, sa, sa_len); + if (n == -1) { + if (errno == ENOBUFS || errno == EHOSTUNREACH || +- errno == ENETDOWN || errno == EHOSTDOWN) { ++ errno == ENETDOWN ++#ifdef EHOSTDOWN ++ || errno == EHOSTDOWN ++#endif ++ ) { + /* logging is futile */ + return (-1); + } +diff -Paur --no-dereference -- ntpd.upstream/src/server.c ntpd/src/server.c +--- ntpd.upstream/src/server.c ++++ ntpd/src/server.c +@@ -41,7 +41,9 @@ + u_int8_t *a6; + size_t sa6len = sizeof(struct in6_addr); + u_int new_cnt = 0; ++#ifdef IPTOS_LOWDELAY + int tos = IPTOS_LOWDELAY; ++#endif + #ifdef IPV6_V6ONLY + int on = 1; + #endif +@@ -109,12 +111,20 @@ + case AF_INET: + if (((struct sockaddr_in *)&la->sa)->sin_port == 0) + ((struct sockaddr_in *)&la->sa)->sin_port = ++#if defined(__sortix__) ++ 123; ++#else + se->s_port; ++#endif + break; + case AF_INET6: + if (((struct sockaddr_in6 *)&la->sa)->sin6_port == 0) + ((struct sockaddr_in6 *)&la->sa)->sin6_port = ++#if defined(__sortix__) ++ 123; ++#else + se->s_port; ++#endif + break; + case AF_UNSPEC: + nla = TAILQ_NEXT(la, entry); +@@ -133,9 +143,11 @@ + if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1) + fatal("socket"); + ++#ifdef IPTOS_LOWDELAY + if (la->sa.ss_family == AF_INET && setsockopt(la->fd, + IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) + log_warn("setsockopt IPTOS_LOWDELAY"); ++#endif + + #ifdef IPV6_V6ONLY + if (la->sa.ss_family == AF_INET6 && setsockopt(la->fd, +@@ -183,7 +195,10 @@ + fsa_len = sizeof(fsa); + if ((size = recvfrom(fd, &buf, sizeof(buf), 0, + (struct sockaddr *)&fsa, &fsa_len)) == -1) { +- if (errno == EHOSTUNREACH || errno == EHOSTDOWN || ++ if (errno == EHOSTUNREACH || ++#ifdef EHOSTDOWN ++ errno == EHOSTDOWN || ++#endif + errno == ENETUNREACH || errno == ENETDOWN) { + log_warn("recvfrom %s", + log_sockaddr((struct sockaddr *)&fsa)); +diff -Paur --no-dereference -- ntpd.upstream/src/util.c ntpd/src/util.c +--- ntpd.upstream/src/util.c ++++ ntpd/src/util.c +@@ -25,6 +25,8 @@ + + #include "ntpd.h" + ++int adjtime(const struct timeval *delta, struct timeval *olddelta); ++ + double + gettime_corrected(void) + { +diff -Paur --no-dereference -- ntpd.upstream/TODO.sortix ntpd/TODO.sortix +--- ntpd.upstream/TODO.sortix ++++ ntpd/TODO.sortix +@@ -0,0 +1,5 @@ ++- nptd is unaware of leap seconds but Sortix is aware of them to the clock doesn't actually get synced correctly. ++- Sortix needs `adjtime` or the time adjustments can be jarring. ++- Sortix needs `strptime`. ++- Sortix needs `getservbyname` but worked around by hard-coding the ntp port. ++- The dns process wasn't being properly killed and awaited when exiting. diff --git a/ports/ntpd/ntpd.port b/ports/ntpd/ntpd.port new file mode 100644 index 00000000..7abb98ad --- /dev/null +++ b/ports/ntpd/ntpd.port @@ -0,0 +1,13 @@ +NAME=ntpd +BUILD_LIBRARIES=libssl? +VERSION=6.8p1 +DISTNAME=openntpd-$VERSION +COMPRESSION=tar.gz +ARCHIVE=$DISTNAME.$COMPRESSION +SHA256SUM=8582db838a399153d4a17f2a76518b638cc3020f58028575bf54127518f55a46 +UPSTREAM_SITE=https://ftp.openbsd.org/pub/OpenBSD/OpenNTPD +UPSTREAM_ARCHIVE=$ARCHIVE +BUILD_SYSTEM=configure +MAKE_VARS='V=1' +POST_INSTALL=tix-eradicate-libtool-la +VERSION_REGEX='([0-9]+\.[0-9]+p[0-9]+)' diff --git a/ports/ntpd/ntpd.rmpatch b/ports/ntpd/ntpd.rmpatch new file mode 100644 index 00000000..7f54501f --- /dev/null +++ b/ports/ntpd/ntpd.rmpatch @@ -0,0 +1 @@ +rm -rf -- 'src/parse.c' diff --git a/share/man/man5/init.5 b/share/man/man5/init.5 index c3046b22..512ff5db 100644 --- a/share/man/man5/init.5 +++ b/share/man/man5/init.5 @@ -180,8 +180,9 @@ The system provides a default implementation that does nothing, as the base system does not contain a daemon that obtains the current date and time. The system administrator is meant to override the daemon in .Pa /etc/init/time -by depending on a daemon that obtains the current date and time and sets the -system time. +by depending on a daemon such as +.Xr ntpd 8 +that obtains the current date and time and sets the system time. Daemons can depend on this daemon if they need the current date and time to have been established before they start. .El diff --git a/share/man/man7/installation.7 b/share/man/man7/installation.7 index 3e7c5b07..4bbe6547 100644 --- a/share/man/man7/installation.7 +++ b/share/man/man7/installation.7 @@ -385,6 +385,22 @@ and .Pp Please note that Sortix is not currently secure as a multi-user system and filesystem permissions are not enforced. +.Ss Network Time +You will be asked if you want to enable the Network Time Protocol client +.Xr ntpd 8 , +which will automatically synchronize the current time with the internet. +Although it's recommended to use network time to avoid clock drift, it does come +with potential privacy implications. +.Pp +Privacy notice: If enabled, the default configuration will obtain time from +various internet servers and the installer will inform you which ones they are. +You are encouraged to answer +.Sy man +to read the +.Xr ntpd.conf 5 +manual and then answer +.Sy edit +to edit the configuration with your preferences. .Ss SSH Server You will be asked if you want to enable a .Xr sshd 8 diff --git a/share/man/man7/release-iso-bootconfig.7 b/share/man/man7/release-iso-bootconfig.7 index ce1db588..c472fa10 100644 --- a/share/man/man7/release-iso-bootconfig.7 +++ b/share/man/man7/release-iso-bootconfig.7 @@ -274,6 +274,11 @@ command line parameter that controls whether network drivers are enabled. Either set to the empty string (network drivers are enabled) or .Sy --disable-network-drivers . (Default: The empty string). +.It Sy enable_ntpd +Whether to start the +.Xr ntpd 8 +daemon. +(Default: false) .It Sy enable_src Whether to load the source code initrd containing .Pa /src . diff --git a/sysinstall/sysinstall.c b/sysinstall/sysinstall.c index eec58e7e..0e7a8a77 100644 --- a/sysinstall/sysinstall.c +++ b/sysinstall/sysinstall.c @@ -1199,6 +1199,65 @@ int main(void) // TODO: Ask if networking should be disabled / enabled. + if ( !access_or_die("/tix/tixinfo/ntpd", F_OK) ) + { + text("A Network Time Protocol client (ntpd) has been installed that " + "can automatically synchronize the current time with the internet." + "\n\n"); + text("Privacy notice: If enabled, the default configuration will " + "obtain time from pool.ntp.org and time.cloudflare.com; and " + "compare with HTTPS timestamps from quad9 and www.google.com. " + "You are encouraged to edit /etc/ntpd.conf per the ntpd.conf(5) " + "manual with your preferences.\n\n"); + bool copied = false; + while ( true ) + { + prompt(input, sizeof(input), "enable_ntpd", + "Automatically get time from the network? (yes/no/edit/man)", + copied ? "yes" : "no"); + if ( strcasecmp(input, "no") == 0 ) + break; + if ( strcasecmp(input, "man") == 0 ) + { + execute((const char*[]) {"man", "5", "ntpd.conf", NULL}, "fi"); + continue; + } + if ( strcasecmp(input, "edit") == 0 ) + { + if ( !copied ) + { + execute((const char*[]) {"cp", "etc/default/ntpd.conf", + "etc/ntpd.conf", NULL}, "f"); + copied = true; + } + const char* editor = + getenv("EDITOR") ? getenv("EDITOR") : "editor"; + execute((const char*[]) {editor, "etc/ntpd.conf", NULL}, "f"); + text("Created /etc/ntpd.conf from /etc/default/ntpd.conf\n"); + continue; + } + if ( strcasecmp(input, "yes") != 0 ) + continue; + if ( !install_configurationf("etc/init/local", "a", + "require ntpd optional\n") ) + { + warn("etc/init/local"); + continue; + } + if ( !install_configurationf("etc/init/time", "a", + "furthermore\n" + "require ntpd optional\n") ) + { + warn("etc/init/time"); + continue; + } + text("Added 'require ntpd optional' to /etc/init/local\n"); + text("Added 'require ntpd optional' to /etc/init/time\n"); + break; + } + text("\n"); + } + struct sshd_key_file { const char* pri; diff --git a/tix/tix-iso-bootconfig b/tix/tix-iso-bootconfig index 9303317a..5ee14d01 100755 --- a/tix/tix-iso-bootconfig +++ b/tix/tix-iso-bootconfig @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2017, 2018, 2022 Jonas 'Sortie' Termansen. +# Copyright (c) 2017, 2018, 2022, 2023 Jonas 'Sortie' Termansen. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -24,6 +24,7 @@ directory= enable_append_title=true enable_dhclient= enable_network_drivers= +enable_ntpd= enable_src= enable_sshd= init_target= @@ -56,11 +57,13 @@ for argument do --disable-append-title) enable_append_title=false ;; --disable-dhclient) enable_dhclient=false ;; --disable-network-drivers) enable_network_drivers=false ;; + --disable-ntpd) enable_ntpd=false ;; --disable-src) enable_src=false ;; --disable-sshd) enable_sshd=false ;; --enable-append-title) enable_append_title=true ;; --enable-dhclient) enable_dhclient=true ;; --enable-network-drivers) enable_network_drivers=true ;; + --enable-ntpd) enable_ntpd=true ;; --enable-src) enable_src=true ;; --enable-sshd) enable_sshd=true ;; --init-target=*) init_target=$parameter ;; @@ -148,6 +151,7 @@ mkdir -p -- "$directory/boot/grub" print_enable_default "$enable_network_drivers" network_drivers network-drivers print_enable_default_bool "$enable_src" src src print_enable_default_bool "$enable_sshd" sshd sshd + print_enable_default_bool "$enable_ntpd" ntpd ntpd if $enable_append_title; then printf "base_menu_title=\"\$base_menu_title - \"'%s'\n" \ "$(printf '%s\n' "$append_title" | sed "s/'/'\\\\''/g")" diff --git a/tix/tix-iso-bootconfig.8 b/tix/tix-iso-bootconfig.8 index 882e37ba..9ab7481d 100644 --- a/tix/tix-iso-bootconfig.8 +++ b/tix/tix-iso-bootconfig.8 @@ -11,11 +11,13 @@ .Op Fl \-disable-append-title .Op Fl \-disable-dhclient .Op Fl \-disable-network-drivers +.Op Fl \-disable-ntpd .Op Fl \-disable-src .Op Fl \-disable-sshd .Op Fl \-enable-append-title .Op Fl \-enable-dhclient .Op Fl \-enable-network-drivers +.Op Fl \-enable-ntpd .Op Fl \-enable-src .Op Fl \-enable-sshd .Op Fl \-init-target Ns = Ns Ar target @@ -111,6 +113,14 @@ GRUB variable to the option which will be passed on the .Xr kernel 7 command line. +.It Fl \-disable-ntpd +Disable automatically starting the ntp client by setting the +.Sy enable_ntpd +GRUB variable to +.Sy false , +selecting the default behavior of not starting the +.Xr ntpd 8 +daemon. .It Fl \-disable-src Disable loading the source code in .Pa /src @@ -150,6 +160,14 @@ GRUB variable to the option which will be passed on the .Xr kernel 7 command line. +.It Fl \-enable-ntpd +Enable automatically starting the ntp client by setting the +.Sy enable_ntpd +GRUB variable to +.Sy true , +causing the bootloader to load additional configuration that turns on the +.Xr ntpd 8 +daemon on boot. .It Fl \-enable-src Enable loading the source code in .Pa /src