Kernel part of bluetooth stack ported by Dmitry Komissaroff. Very much work
[dragonfly.git] / contrib / ntpd / ntpd.c
blob32ccfd3e4e0472dae034866029e6ee27865192af
1 /* $OpenBSD: src/usr.sbin/ntpd/ntpd.c,v 1.35 2005/04/18 20:46:02 henning Exp $ */
3 /*
4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/wait.h>
22 #include <netinet/in.h>
23 #include <errno.h>
24 #include <poll.h>
25 #include <pwd.h>
26 #include <resolv.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
33 #include "ntpd.h"
35 void sighdlr(int);
36 __dead void usage(void);
37 int main(int, char *[]);
38 int check_child(pid_t, const char *);
39 int dispatch_imsg(struct ntpd_conf *);
40 void ntpd_adjtime(double);
41 void ntpd_settime(double);
43 volatile sig_atomic_t quit = 0;
44 volatile sig_atomic_t reconfig = 0;
45 volatile sig_atomic_t sigchld = 0;
46 struct imsgbuf *ibuf;
48 void
49 sighdlr(int sig)
51 switch (sig) {
52 case SIGTERM:
53 case SIGINT:
54 quit = 1;
55 break;
56 case SIGCHLD:
57 sigchld = 1;
58 break;
59 case SIGHUP:
60 reconfig = 1;
61 break;
65 __dead void
66 usage(void)
68 extern char *__progname;
70 fprintf(stderr, "usage: %s [-dSs] [-f file]\n", __progname);
71 exit(1);
74 #define POLL_MAX 8
75 #define PFD_PIPE 0
77 int
78 main(int argc, char *argv[])
80 struct ntpd_conf conf;
81 struct pollfd pfd[POLL_MAX];
82 pid_t chld_pid = 0, pid;
83 const char *conffile;
84 int ch, nfds, timeout = INFTIM;
85 int pipe_chld[2];
87 conffile = CONFFILE;
89 bzero(&conf, sizeof(conf));
91 log_init(1); /* log to stderr until daemonized */
92 res_init(); /* XXX */
94 while ((ch = getopt(argc, argv, "df:sS")) != -1) {
95 switch (ch) {
96 case 'd':
97 conf.debug = 1;
98 break;
99 case 'f':
100 conffile = optarg;
101 break;
102 case 's':
103 conf.settime = 1;
104 break;
105 case 'S':
106 conf.settime = 0;
107 break;
108 default:
109 usage();
110 /* NOTREACHED */
114 if (parse_config(conffile, &conf))
115 exit(1);
117 if (geteuid()) {
118 fprintf(stderr, "ntpd: need root privileges\n");
119 exit(1);
122 if (getpwnam(NTPD_USER) == NULL) {
123 fprintf(stderr, "ntpd: unknown user %s\n", NTPD_USER);
124 exit(1);
126 endpwent();
128 if (!conf.settime) {
129 log_init(conf.debug);
130 if (!conf.debug)
131 if (daemon(1, 0))
132 fatal("daemon");
133 } else
134 timeout = 15 * 1000;
136 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_chld) == -1)
137 fatal("socketpair");
139 /* fork child process */
140 chld_pid = ntp_main(pipe_chld, &conf);
142 setproctitle("[priv]");
144 signal(SIGTERM, sighdlr);
145 signal(SIGINT, sighdlr);
146 signal(SIGCHLD, sighdlr);
147 signal(SIGHUP, sighdlr);
149 close(pipe_chld[1]);
151 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
152 fatal(NULL);
153 imsg_init(ibuf, pipe_chld[0]);
155 while (quit == 0) {
156 pfd[PFD_PIPE].fd = ibuf->fd;
157 pfd[PFD_PIPE].events = POLLIN;
158 if (ibuf->w.queued)
159 pfd[PFD_PIPE].events |= POLLOUT;
161 if ((nfds = poll(pfd, 1, timeout)) == -1)
162 if (errno != EINTR) {
163 log_warn("poll error");
164 quit = 1;
167 if (nfds == 0 && conf.settime) {
168 conf.settime = 0;
169 timeout = INFTIM;
170 log_init(conf.debug);
171 log_debug("no reply received, skipping initial time "
172 "setting");
173 if (!conf.debug)
174 if (daemon(1, 0))
175 fatal("daemon");
178 if (nfds > 0 && (pfd[PFD_PIPE].revents & POLLOUT))
179 if (msgbuf_write(&ibuf->w) < 0) {
180 log_warn("pipe write error (to child)");
181 quit = 1;
184 if (nfds > 0 && pfd[PFD_PIPE].revents & POLLIN) {
185 nfds--;
186 if (dispatch_imsg(&conf) == -1)
187 quit = 1;
190 if (sigchld) {
191 if (check_child(chld_pid, "child")) {
192 quit = 1;
193 chld_pid = 0;
195 sigchld = 0;
200 signal(SIGCHLD, SIG_DFL);
202 if (chld_pid)
203 kill(chld_pid, SIGTERM);
205 do {
206 if ((pid = wait(NULL)) == -1 &&
207 errno != EINTR && errno != ECHILD)
208 fatal("wait");
209 } while (pid != -1 || (pid == -1 && errno == EINTR));
211 msgbuf_clear(&ibuf->w);
212 free(ibuf);
213 log_info("Terminating");
214 return (0);
218 check_child(pid_t pid, const char *pname)
220 int status;
222 if (waitpid(pid, &status, WNOHANG) > 0) {
223 if (WIFEXITED(status)) {
224 log_warnx("Lost child: %s exited", pname);
225 return (1);
227 if (WIFSIGNALED(status)) {
228 log_warnx("Lost child: %s terminated; signal %d",
229 pname, WTERMSIG(status));
230 return (1);
234 return (0);
238 dispatch_imsg(struct ntpd_conf *conf)
240 struct imsg imsg;
241 int n, cnt;
242 double d;
243 char *name;
244 struct ntp_addr *h, *hn;
245 struct buf *buf;
247 if ((n = imsg_read(ibuf)) == -1)
248 return (-1);
250 if (n == 0) { /* connection closed */
251 log_warnx("dispatch_imsg in main: pipe closed");
252 return (-1);
255 for (;;) {
256 if ((n = imsg_get(ibuf, &imsg)) == -1)
257 return (-1);
259 if (n == 0)
260 break;
262 switch (imsg.hdr.type) {
263 case IMSG_ADJTIME:
264 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
265 fatalx("invalid IMSG_ADJTIME received");
266 memcpy(&d, imsg.data, sizeof(d));
267 ntpd_adjtime(d);
268 break;
269 case IMSG_SETTIME:
270 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
271 fatalx("invalid IMSG_SETTIME received");
272 if (!conf->settime)
273 break;
274 memcpy(&d, imsg.data, sizeof(d));
275 ntpd_settime(d);
276 /* daemonize now */
277 log_init(conf->debug);
278 if (!conf->debug)
279 if (daemon(1, 0))
280 fatal("daemon");
281 conf->settime = 0;
282 break;
283 case IMSG_HOST_DNS:
284 name = imsg.data;
285 if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
286 fatalx("invalid IMSG_HOST_DNS received");
287 imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
288 if (name[imsg.hdr.len] != '\0' ||
289 strlen(name) != imsg.hdr.len)
290 fatalx("invalid IMSG_HOST_DNS received");
291 if ((cnt = host_dns(name, &hn)) > 0) {
292 buf = imsg_create(ibuf, IMSG_HOST_DNS,
293 imsg.hdr.peerid, 0,
294 cnt * sizeof(struct sockaddr_storage));
295 if (buf == NULL)
296 break;
297 for (h = hn; h != NULL; h = h->next) {
298 imsg_add(buf, &h->ss, sizeof(h->ss));
300 imsg_close(ibuf, buf);
302 break;
303 default:
304 break;
306 imsg_free(&imsg);
308 return (0);
311 void
312 ntpd_adjtime(double d)
314 struct timeval tv;
316 if (d >= (double)LOG_NEGLIGEE / 1000 ||
317 d <= -1 * (double)LOG_NEGLIGEE / 1000)
318 log_info("adjusting local clock by %fs", d);
319 else
320 log_debug("adjusting local clock by %fs", d);
321 d_to_tv(d, &tv);
322 if (adjtime(&tv, NULL) == -1)
323 log_warn("adjtime failed");
326 void
327 ntpd_settime(double d)
329 struct timeval tv, curtime;
330 char buf[80];
331 time_t tval;
333 /* if the offset is small, don't call settimeofday */
334 if (d < SETTIME_MIN_OFFSET && d > -SETTIME_MIN_OFFSET)
335 return;
337 if (gettimeofday(&curtime, NULL) == -1) {
338 log_warn("gettimeofday");
339 return;
341 d_to_tv(d, &tv);
342 curtime.tv_usec += tv.tv_usec + 1000000;
343 curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000);
344 curtime.tv_usec %= 1000000;
346 if (settimeofday(&curtime, NULL) == -1) {
347 log_warn("settimeofday");
348 return;
350 tval = curtime.tv_sec;
351 strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y",
352 localtime(&tval));
353 log_info("set local clock to %s (offset %fs)", buf, d);