2 * Copyright (c) 2005 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 static void usage(const char *av0
);
38 static void dotest(const char *target
);
39 static void add_server(const char *target
);
40 static void process_config_file(const char *path
);
41 static pid_t
check_pid(void);
42 static void set_pid(const char *av0
);
43 static void sigint_handler(int signo __unused
);
45 static struct server_info
**servers
;
47 static int maxservers
;
51 int debug_level
= -1; /* (set to default later) */
52 int quickset_opt
= 0; /* immediately set time of day on startup */
53 int no_update_opt
= 0; /* do not make any actual updates */
54 int min_sleep_opt
= 5; /* 5 seconds minimum poll interval */
55 int nom_sleep_opt
= 300; /* 5 minutes nominal poll interval */
56 int max_sleep_opt
= 1800; /* 30 minutes maximum poll interval */
57 int family
= PF_UNSPEC
; /* Address family */
58 double insane_deviation
= 0.5; /* 0.5 seconds of deviation == insane */
59 const char *config_opt
; /* config file */
60 const char *pid_opt
= "/var/run/dntpd.pid";
63 main(int ac
, char **av
)
78 while ((ch
= getopt(ac
, av
, "46df:i:l:np:qstFL:QST:")) != -1) {
91 if (config_opt
== NULL
)
92 config_opt
= "/dev/null";
101 insane_deviation
= strtod(optarg
, NULL
);
104 debug_level
= strtol(optarg
, NULL
, 0);
124 if (config_opt
== NULL
)
125 config_opt
= "/dev/null";
131 max_sleep_opt
= strtol(optarg
, NULL
, 0);
134 nom_sleep_opt
= strtol(optarg
, NULL
, 0);
135 if (nom_sleep_opt
< 1) {
136 fprintf(stderr
, "Warning: nominal poll interval too small, "
137 "limiting to 1 second\n");
140 if (nom_sleep_opt
> 24 * 60 * 60) {
141 fprintf(stderr
, "Warning: nominal poll interval too large, "
142 "limiting to 24 hours\n");
143 nom_sleep_opt
= 24 * 60 * 60;
145 if (min_sleep_opt
> nom_sleep_opt
)
146 min_sleep_opt
= nom_sleep_opt
;
147 if (max_sleep_opt
< nom_sleep_opt
* 5)
148 max_sleep_opt
= nom_sleep_opt
* 5;
151 if ((pid
= check_pid()) != 0) {
152 fprintf(stderr
, "%s: killing old daemon\n", av
[0]);
160 fprintf(stderr
, "%s: Unable to kill running daemon.\n", av
[0]);
162 fprintf(stderr
, "%s: Running daemon has been terminated.\n", av
[0]);
165 fprintf(stderr
, "%s: There is no daemon running to kill.\n", av
[0]);
177 * Make sure min and nom intervals are less then or equal to the maximum
180 if (min_sleep_opt
> max_sleep_opt
)
181 min_sleep_opt
= max_sleep_opt
;
182 if (nom_sleep_opt
> max_sleep_opt
)
183 nom_sleep_opt
= max_sleep_opt
;
186 * Set default config file
188 if (config_opt
== NULL
) {
190 config_opt
= "/dev/null";
192 config_opt
= "/etc/dntpd.conf";
198 process_config_file(config_opt
);
201 openlog("dntpd", LOG_CONS
|LOG_PID
, LOG_DAEMON
);
204 if (optind
!= ac
- 1)
211 * Add additional hosts.
213 for (i
= optind
; i
< ac
; ++i
) {
222 * Do an initial course time setting if requested using the first
223 * host successfully polled.
228 * Daemonize, stop logging to stderr.
231 if ((pid
= check_pid()) != 0) {
232 logerrstr("%s: NOTE: killing old daemon and starting a new one",
241 logerrstr("%s: Unable to kill running daemon, exiting", av
[0]);
246 } else if (check_pid() != 0) {
247 logerrstr("%s: A background dntpd is running, you must kill it first",
251 if (debug_opt
== 0) {
254 signal(SIGINT
, sigint_handler
);
255 logdebug(0, "dntpd version %s started\n", DNTPD_VERSION
);
261 sysntp_clear_alternative_corrections();
263 client_check_duplicate_ips(servers
, nservers
);
264 client_main(servers
, nservers
);
270 usage(const char *av0
)
272 fprintf(stderr
, "%s [-dnqstFSQ] [-f config_file] [-l log_level] [-T poll_interval] [-L poll_limit] [additional_targets]\n", av0
);
274 "\t-d\tDebugging mode, implies -F, -l 99, and logs to stderr\n"
275 "\t-f file\tSpecify the config file (/etc/dntpd.conf)\n"
276 "\t-l int\tSet log level (0-4), default 1\n"
277 "\t-n\tNo-update mode. No offset or frequency corrections are made\n"
278 "\t-q\tQuiet-mode, same as -L 0\n"
279 "\t-s\tSet the time immediately on startup\n"
280 "\t-t\tTest mode, implies -F, -l 99, -n, logs to stderr\n"
281 "\t-F\tRun in foreground (log still goes to syslog)\n"
282 "\t-L int\tMaximum polling interval\n"
283 "\t-S\tDo not set the time immediately on startup\n"
284 "\t-T int\tNominal polling interval\n"
285 "\t-Q\tTerminate any running background daemon\n"
287 "\t\tNOTE: in debug and test modes -f must be specified if\n"
288 "\t\tyou want to use a config file.\n"
295 dotest(const char *target
)
297 struct server_info info
;
299 bzero(&info
, sizeof(info
));
300 info
.sam
= (struct sockaddr
*)&info
.sam_st
;
301 info
.fd
= udp_socket(target
, 123, info
.sam
, LOG_DNS_ERROR
);
303 logerrstr("unable to create UDP socket for %s", target
);
306 info
.target
= strdup(target
);
310 "Will run %d-second polls until interrupted.\n", nom_sleep_opt
);
313 client_poll(&info
, nom_sleep_opt
, 1);
314 sleep(nom_sleep_opt
);
320 myaddr2ascii(struct sockaddr
*sa
)
322 static char str
[INET6_ADDRSTRLEN
];
323 struct sockaddr_in
*soin
;
324 struct sockaddr_in6
*sin6
;
326 switch (sa
->sa_family
) {
328 soin
= (struct sockaddr_in
*) sa
;
329 inet_ntop(AF_INET
, &soin
->sin_addr
, str
, sizeof(str
));
332 sin6
= (struct sockaddr_in6
*) sa
;
333 inet_ntop(AF_INET6
, &sin6
->sin6_addr
, str
, sizeof(str
));
340 add_server(const char *target
)
344 if (nservers
== maxservers
) {
346 servers
= realloc(servers
, maxservers
* sizeof(server_info_t
));
347 assert(servers
!= NULL
);
349 info
= malloc(sizeof(struct server_info
));
350 servers
[nservers
] = info
;
351 bzero(info
, sizeof(struct server_info
));
352 info
->sam
= (struct sockaddr
*)&info
->sam_st
;
353 info
->target
= strdup(target
);
355 * Postpone socket opening and server name resolution until we are in main
356 * loop to avoid hang during init if network down.
359 info
->server_state
= -1;
364 disconnect_server(server_info_t info
)
376 reconnect_server(server_info_t info
)
379 dns_error_policy_t policy
;
382 * Ignore DNS errors if never connected before to handle the case where
383 * we're started before network up.
385 policy
= IGNORE_DNS_ERROR
;
388 policy
= LOG_DNS_ERROR
;
394 info
->sam
= (struct sockaddr
*)&info
->sam_st
;
395 info
->fd
= udp_socket(info
->target
, 123, info
->sam
, policy
);
397 ipstr
= myaddr2ascii(info
->sam
);
398 info
->ipstr
= strdup(ipstr
);
403 process_config_file(const char *path
)
405 const char *ws
= " \t\r\n";
412 if ((fi
= fopen(path
, "r")) != NULL
) {
414 while (fgets(buf
, sizeof(buf
), fi
) != NULL
) {
415 if (strchr(buf
, '#'))
416 *strchr(buf
, '#') = 0;
417 if ((keyword
= strtok(buf
, ws
)) != NULL
) {
418 data
= strtok(NULL
, ws
);
419 if (strcmp(keyword
, "server") == 0) {
421 logerr("%s:%d server missing host specification",
427 logerr("%s:%d unknown keyword %s", path
, line
, keyword
);
434 logerr("Unable to open %s", path
);
448 if ((fi
= fopen(pid_opt
, "r")) != NULL
) {
449 if (fgets(buf
, sizeof(buf
), fi
) != NULL
) {
450 pid
= strtol(buf
, NULL
, 0);
451 if (kill(pid
, 0) != 0)
461 set_pid(const char *av0
)
467 if ((fo
= fopen(pid_opt
, "w")) != NULL
) {
468 fprintf(fo
, "%d\n", (int)pid
);
471 logerr("%s: Unable to create %s, continuing anyway.", av0
, pid_opt
);
477 sigint_handler(int signo __unused
)
480 /* dangerous, but we are exiting anyway so pray... */
481 logdebug(0, "dntpd version %s stopped\n", DNTPD_VERSION
);