#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <err.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#ifndef NO_UTIL
#include <util.h>
#else
#define logwtmp(a,b,c)
#endif
void ntp_client(const char *, int, struct timeval *, struct timeval *, int);
extern char *__progname;
__dead void usage(void);
struct {
char message[2048];
struct timeval new;
struct timeval adjust;
} pdata;
__dead void
usage(void)
{
(void) fprintf(stderr, "usage: %s [-46acnpsv] host\n", __progname);
exit(1);
}
int
main(int argc, char **argv)
{
int pr = 0, silent = 0, verbose = 0;
int slidetime = 0, corrleaps = 0;
char *hname;
int c, p[2], pid;
int family = PF_UNSPEC;
while ((c = getopt(argc, argv, "46psanocv")) != -1) {
switch (c) {
case '4':
family = PF_INET;
break;
case '6':
family = PF_INET6;
break;
case 'p':
pr = 1;
break;
case 's':
silent = 1;
break;
case 'a':
slidetime = 1;
break;
case 'n':
break;
case 'c':
corrleaps = 1;
break;
case 'v':
verbose = 1;
break;
default:
usage();
}
}
if (argc - 1 != optind)
usage();
hname = argv[optind];
if (pipe(p) == -1)
err(1, "pipe");
switch ((pid = fork())) {
case -1:
err(1, "fork");
break;
case 0:
if (pledge("stdio inet dns", NULL) == -1)
err(1, "pledge");
close(p[0]);
dup2(p[1], STDIN_FILENO);
if (p[1] != STDIN_FILENO)
close(p[1]);
dup2(STDIN_FILENO, STDOUT_FILENO);
dup2(STDOUT_FILENO, STDERR_FILENO);
setvbuf(stdout, NULL, _IOFBF, 0);
setvbuf(stderr, NULL, _IOFBF, 0);
ntp_client(hname, family, &pdata.new,
&pdata.adjust, corrleaps);
if (write(STDOUT_FILENO, &pdata, sizeof pdata) != sizeof pdata)
exit(1);
exit(0);
}
if (pledge("stdio rpath wpath settime", NULL) == -1)
err(1, "pledge");
close(p[1]);
if (read(p[0], &pdata, sizeof pdata) < 1)
err(1, "child did not collect time");
if (waitpid(pid, NULL, 0) == -1)
err(1, "waitpid");
if (pdata.message[0]) {
pdata.message[sizeof(pdata.message)- 1] = '\0';
write(STDERR_FILENO, pdata.message, strlen(pdata.message));
exit(1);
}
if (!pr) {
if (!slidetime) {
logwtmp("|", "date", "");
if (settimeofday(&pdata.new, NULL) == -1)
err(1, "Could not set time of day");
logwtmp("{", "date", "");
} else {
if (adjtime(&pdata.adjust, NULL) == -1)
err(1, "Could not adjust time of day");
}
}
if (pledge("stdio rpath", NULL) == -1)
err(1, "pledge");
if (!silent) {
struct tm *ltm;
char buf[80];
time_t tim = pdata.new.tv_sec;
double adjsec;
ltm = localtime(&tim);
(void) strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y\n", ltm);
(void) fputs(buf, stdout);
adjsec = pdata.adjust.tv_sec + pdata.adjust.tv_usec / 1.0e6;
if (slidetime || verbose) {
(void) fprintf(stdout,
"%s: adjust local clock by %.6f seconds\n",
__progname, adjsec);
}
}
return 0;
}