1 /* $OpenBSD: src/usr.sbin/ntpd/ntpd.c,v 1.35 2005/04/18 20:46:02 henning Exp $ */
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>
22 #include <netinet/in.h>
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;
68 extern char *__progname
;
70 fprintf(stderr
, "usage: %s [-dSs] [-f file]\n", __progname
);
78 main(int argc
, char *argv
[])
80 struct ntpd_conf conf
;
81 struct pollfd pfd
[POLL_MAX
];
82 pid_t chld_pid
= 0, pid
;
84 int ch
, nfds
, timeout
= INFTIM
;
89 bzero(&conf
, sizeof(conf
));
91 log_init(1); /* log to stderr until daemonized */
94 while ((ch
= getopt(argc
, argv
, "df:sS")) != -1) {
114 if (parse_config(conffile
, &conf
))
118 fprintf(stderr
, "ntpd: need root privileges\n");
122 if (getpwnam(NTPD_USER
) == NULL
) {
123 fprintf(stderr
, "ntpd: unknown user %s\n", NTPD_USER
);
129 log_init(conf
.debug
);
136 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, pipe_chld
) == -1)
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
);
151 if ((ibuf
= malloc(sizeof(struct imsgbuf
))) == NULL
)
153 imsg_init(ibuf
, pipe_chld
[0]);
156 pfd
[PFD_PIPE
].fd
= ibuf
->fd
;
157 pfd
[PFD_PIPE
].events
= POLLIN
;
159 pfd
[PFD_PIPE
].events
|= POLLOUT
;
161 if ((nfds
= poll(pfd
, 1, timeout
)) == -1)
162 if (errno
!= EINTR
) {
163 log_warn("poll error");
167 if (nfds
== 0 && conf
.settime
) {
170 log_init(conf
.debug
);
171 log_debug("no reply received, skipping initial time "
178 if (nfds
> 0 && (pfd
[PFD_PIPE
].revents
& POLLOUT
))
179 if (msgbuf_write(&ibuf
->w
) < 0) {
180 log_warn("pipe write error (to child)");
184 if (nfds
> 0 && pfd
[PFD_PIPE
].revents
& POLLIN
) {
186 if (dispatch_imsg(&conf
) == -1)
191 if (check_child(chld_pid
, "child")) {
200 signal(SIGCHLD
, SIG_DFL
);
203 kill(chld_pid
, SIGTERM
);
206 if ((pid
= wait(NULL
)) == -1 &&
207 errno
!= EINTR
&& errno
!= ECHILD
)
209 } while (pid
!= -1 || (pid
== -1 && errno
== EINTR
));
211 msgbuf_clear(&ibuf
->w
);
213 log_info("Terminating");
218 check_child(pid_t pid
, const char *pname
)
222 if (waitpid(pid
, &status
, WNOHANG
) > 0) {
223 if (WIFEXITED(status
)) {
224 log_warnx("Lost child: %s exited", pname
);
227 if (WIFSIGNALED(status
)) {
228 log_warnx("Lost child: %s terminated; signal %d",
229 pname
, WTERMSIG(status
));
238 dispatch_imsg(struct ntpd_conf
*conf
)
244 struct ntp_addr
*h
, *hn
;
247 if ((n
= imsg_read(ibuf
)) == -1)
250 if (n
== 0) { /* connection closed */
251 log_warnx("dispatch_imsg in main: pipe closed");
256 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
262 switch (imsg
.hdr
.type
) {
264 if (imsg
.hdr
.len
!= IMSG_HEADER_SIZE
+ sizeof(d
))
265 fatalx("invalid IMSG_ADJTIME received");
266 memcpy(&d
, imsg
.data
, sizeof(d
));
270 if (imsg
.hdr
.len
!= IMSG_HEADER_SIZE
+ sizeof(d
))
271 fatalx("invalid IMSG_SETTIME received");
274 memcpy(&d
, imsg
.data
, sizeof(d
));
277 log_init(conf
->debug
);
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
,
294 cnt
* sizeof(struct sockaddr_storage
));
297 for (h
= hn
; h
!= NULL
; h
= h
->next
) {
298 imsg_add(buf
, &h
->ss
, sizeof(h
->ss
));
300 imsg_close(ibuf
, buf
);
312 ntpd_adjtime(double d
)
316 if (d
>= (double)LOG_NEGLIGEE
/ 1000 ||
317 d
<= -1 * (double)LOG_NEGLIGEE
/ 1000)
318 log_info("adjusting local clock by %fs", d
);
320 log_debug("adjusting local clock by %fs", d
);
322 if (adjtime(&tv
, NULL
) == -1)
323 log_warn("adjtime failed");
327 ntpd_settime(double d
)
329 struct timeval tv
, curtime
;
333 /* if the offset is small, don't call settimeofday */
334 if (d
< SETTIME_MIN_OFFSET
&& d
> -SETTIME_MIN_OFFSET
)
337 if (gettimeofday(&curtime
, NULL
) == -1) {
338 log_warn("gettimeofday");
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");
350 tval
= curtime
.tv_sec
;
351 strftime(buf
, sizeof(buf
), "%a %b %e %H:%M:%S %Z %Y",
353 log_info("set local clock to %s (offset %fs)", buf
, d
);