xref: /dragonfly/usr.sbin/dntpd/main.c (revision 1d9b37b0)
1e0163549SMatthew Dillon /*
2e0163549SMatthew Dillon  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3e0163549SMatthew Dillon  *
4e0163549SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5e0163549SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6e0163549SMatthew Dillon  *
7e0163549SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8e0163549SMatthew Dillon  * modification, are permitted provided that the following conditions
9e0163549SMatthew Dillon  * are met:
10e0163549SMatthew Dillon  *
11e0163549SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12e0163549SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13e0163549SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14e0163549SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15e0163549SMatthew Dillon  *    the documentation and/or other materials provided with the
16e0163549SMatthew Dillon  *    distribution.
17e0163549SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18e0163549SMatthew Dillon  *    contributors may be used to endorse or promote products derived
19e0163549SMatthew Dillon  *    from this software without specific, prior written permission.
20e0163549SMatthew Dillon  *
21e0163549SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22e0163549SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23e0163549SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24e0163549SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25e0163549SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26e0163549SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27e0163549SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28e0163549SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29e0163549SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30e0163549SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31e0163549SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e0163549SMatthew Dillon  * SUCH DAMAGE.
33e0163549SMatthew Dillon  */
34e0163549SMatthew Dillon 
35e0163549SMatthew Dillon #include "defs.h"
36e0163549SMatthew Dillon 
37e0163549SMatthew Dillon static void usage(const char *av0);
38e0163549SMatthew Dillon static void dotest(const char *target);
39e0163549SMatthew Dillon static void add_server(const char *target);
4097c30a15SMatthew Dillon static void process_config_file(const char *path);
4197c30a15SMatthew Dillon static pid_t check_pid(void);
4297c30a15SMatthew Dillon static void set_pid(const char *av0);
43c32f1362SMatthew Dillon static void sigint_handler(int signo __unused);
44e0163549SMatthew Dillon 
45e0163549SMatthew Dillon static struct server_info **servers;
46e0163549SMatthew Dillon static int nservers;
47e0163549SMatthew Dillon static int maxservers;
48e0163549SMatthew Dillon 
4997c30a15SMatthew Dillon int daemon_opt = 1;
50c44548fcSMatthew Dillon int debug_opt = 0;
513d15852bSMatthew Dillon int debug_level = -1;		/* (set to default later) */
5275349a56SMatthew Dillon int quickset_opt = 0;		/* immediately set time of day on startup */
53c44548fcSMatthew Dillon int no_update_opt = 0;		/* do not make any actual updates */
54fdd4337fSMatthew Dillon int min_sleep_opt = 5;		/* 5 seconds minimum poll interval */
55fdd4337fSMatthew Dillon int nom_sleep_opt = 300;	/* 5 minutes nominal poll interval */
56fdd4337fSMatthew Dillon int max_sleep_opt = 1800;	/* 30 minutes maximum poll interval */
574d1d74baSMatthias Schmidt int family = PF_UNSPEC;		/* Address family */
585e13edd7SMatthew Dillon double insane_deviation = 0.5;	/* 0.5 seconds of deviation == insane */
5997c30a15SMatthew Dillon const char *config_opt;		/* config file */
6097c30a15SMatthew Dillon const char *pid_opt = "/var/run/dntpd.pid";
61e0163549SMatthew Dillon 
62e0163549SMatthew Dillon int
main(int ac,char ** av)63e0163549SMatthew Dillon main(int ac, char **av)
64e0163549SMatthew Dillon {
659b724d8cSMatthew Dillon     int test_opt = 0;
6697c30a15SMatthew Dillon     pid_t pid;
67e0163549SMatthew Dillon     int ch;
68e0163549SMatthew Dillon     int i;
69e0163549SMatthew Dillon 
70e0163549SMatthew Dillon     /*
71e0163549SMatthew Dillon      * Really randomize
72e0163549SMatthew Dillon      */
73e0163549SMatthew Dillon     srandomdev();
74e0163549SMatthew Dillon 
75e0163549SMatthew Dillon     /*
76e0163549SMatthew Dillon      * Process Options
77e0163549SMatthew Dillon      */
784d1d74baSMatthias Schmidt     while ((ch = getopt(ac, av, "46df:i:l:np:qstFL:QST:")) != -1) {
79e0163549SMatthew Dillon 	switch(ch) {
804d1d74baSMatthias Schmidt 	case '4':
814d1d74baSMatthias Schmidt 	    family = PF_INET;
824d1d74baSMatthias Schmidt 	    break;
834d1d74baSMatthias Schmidt 	case '6':
844d1d74baSMatthias Schmidt 	    family = PF_INET6;
854d1d74baSMatthias Schmidt 	    break;
8697c30a15SMatthew Dillon 	case 'd':
8797c30a15SMatthew Dillon 	    debug_opt = 1;
8897c30a15SMatthew Dillon 	    daemon_opt = 0;
8997c30a15SMatthew Dillon 	    if (debug_level < 0)
9097c30a15SMatthew Dillon 		debug_level = 99;
9197c30a15SMatthew Dillon 	    if (config_opt == NULL)
9297c30a15SMatthew Dillon 		config_opt = "/dev/null";
9397c30a15SMatthew Dillon 	    break;
9497c30a15SMatthew Dillon 	case 'p':
9597c30a15SMatthew Dillon 	    pid_opt = optarg;
9697c30a15SMatthew Dillon 	    break;
9797c30a15SMatthew Dillon 	case 'f':
9897c30a15SMatthew Dillon 	    config_opt = optarg;
9997c30a15SMatthew Dillon 	    break;
1005e13edd7SMatthew Dillon 	case 'i':
1015e13edd7SMatthew Dillon 	    insane_deviation = strtod(optarg, NULL);
1025e13edd7SMatthew Dillon 	    break;
10397c30a15SMatthew Dillon 	case 'l':
10497c30a15SMatthew Dillon 	    debug_level = strtol(optarg, NULL, 0);
10597c30a15SMatthew Dillon 	    break;
106c44548fcSMatthew Dillon 	case 'n':
107c44548fcSMatthew Dillon 	    no_update_opt = 1;
108c44548fcSMatthew Dillon 	    break;
10997c30a15SMatthew Dillon 	case 'q':
11097c30a15SMatthew Dillon 	    debug_level = 0;
11197c30a15SMatthew Dillon 	    break;
11297c30a15SMatthew Dillon 	case 's':
11397c30a15SMatthew Dillon 	    quickset_opt = 1;
11497c30a15SMatthew Dillon 	    break;
11597c30a15SMatthew Dillon 	case 'S':
11697c30a15SMatthew Dillon 	    quickset_opt = 0;
11797c30a15SMatthew Dillon 	    break;
11897c30a15SMatthew Dillon 	case 't':
11997c30a15SMatthew Dillon 	    test_opt = 1;
12097c30a15SMatthew Dillon 	    debug_opt = 1;
12197c30a15SMatthew Dillon 	    daemon_opt = 0;
12297c30a15SMatthew Dillon 	    if (debug_level < 0)
12397c30a15SMatthew Dillon 		debug_level = 99;
12497c30a15SMatthew Dillon 	    if (config_opt == NULL)
12597c30a15SMatthew Dillon 		config_opt = "/dev/null";
12697c30a15SMatthew Dillon 	    break;
12797c30a15SMatthew Dillon 	case 'F':
12897c30a15SMatthew Dillon 	    daemon_opt = 0;
12997c30a15SMatthew Dillon 	    break;
13097c30a15SMatthew Dillon 	case 'L':
13197c30a15SMatthew Dillon 	    max_sleep_opt = strtol(optarg, NULL, 0);
13297c30a15SMatthew Dillon 	    break;
1339b724d8cSMatthew Dillon 	case 'T':
134fdd4337fSMatthew Dillon 	    nom_sleep_opt = strtol(optarg, NULL, 0);
135fdd4337fSMatthew Dillon 	    if (nom_sleep_opt < 1) {
136fdd4337fSMatthew Dillon 		fprintf(stderr, "Warning: nominal poll interval too small, "
137fdd4337fSMatthew Dillon 				"limiting to 1 second\n");
138fdd4337fSMatthew Dillon 		nom_sleep_opt = 1;
139fdd4337fSMatthew Dillon 	    }
140fdd4337fSMatthew Dillon 	    if (nom_sleep_opt > 24 * 60 * 60) {
141fdd4337fSMatthew Dillon 		fprintf(stderr, "Warning: nominal poll interval too large, "
142fdd4337fSMatthew Dillon 				"limiting to 24 hours\n");
143fdd4337fSMatthew Dillon 		nom_sleep_opt = 24 * 60 * 60;
144fdd4337fSMatthew Dillon 	    }
145fdd4337fSMatthew Dillon 	    if (min_sleep_opt > nom_sleep_opt)
146fdd4337fSMatthew Dillon 		min_sleep_opt = nom_sleep_opt;
147fdd4337fSMatthew Dillon 	    if (max_sleep_opt < nom_sleep_opt * 5)
148fdd4337fSMatthew Dillon 		max_sleep_opt = nom_sleep_opt * 5;
149fdd4337fSMatthew Dillon 	    break;
15097c30a15SMatthew Dillon 	case 'Q':
15197c30a15SMatthew Dillon 	    if ((pid = check_pid()) != 0) {
15297c30a15SMatthew Dillon 		fprintf(stderr, "%s: killing old daemon\n", av[0]);
15397c30a15SMatthew Dillon 		kill(pid, SIGINT);
15497c30a15SMatthew Dillon 		usleep(100000);
15597c30a15SMatthew Dillon 		if (check_pid())
15697c30a15SMatthew Dillon 		    sleep(1);
15797c30a15SMatthew Dillon 		if (check_pid())
15897c30a15SMatthew Dillon 		    sleep(9);
15997c30a15SMatthew Dillon 		if (check_pid()) {
160c44548fcSMatthew Dillon 		    fprintf(stderr, "%s: Unable to kill running daemon.\n", av[0]);
16197c30a15SMatthew Dillon 		} else {
162c44548fcSMatthew Dillon 		    fprintf(stderr, "%s: Running daemon has been terminated.\n", av[0]);
16397c30a15SMatthew Dillon 		}
16497c30a15SMatthew Dillon 	    } else {
165c44548fcSMatthew Dillon 		fprintf(stderr, "%s: There is no daemon running to kill.\n", av[0]);
16697c30a15SMatthew Dillon 	    }
16797c30a15SMatthew Dillon 	    exit(0);
1689b724d8cSMatthew Dillon 	    break;
169e0163549SMatthew Dillon 	case 'h':
170e0163549SMatthew Dillon 	default:
171e0163549SMatthew Dillon 	    usage(av[0]);
172e0163549SMatthew Dillon 	    /* not reached */
173e0163549SMatthew Dillon 	}
174e0163549SMatthew Dillon     }
1752408d859SMatthew Dillon 
1762408d859SMatthew Dillon     /*
1772408d859SMatthew Dillon      * Make sure min and nom intervals are less then or equal to the maximum
1782408d859SMatthew Dillon      * interval.
1792408d859SMatthew Dillon      */
1802408d859SMatthew Dillon     if (min_sleep_opt > max_sleep_opt)
1812408d859SMatthew Dillon 	min_sleep_opt = max_sleep_opt;
1822408d859SMatthew Dillon     if (nom_sleep_opt > max_sleep_opt)
1832408d859SMatthew Dillon 	nom_sleep_opt = max_sleep_opt;
1842408d859SMatthew Dillon 
1852408d859SMatthew Dillon     /*
1862408d859SMatthew Dillon      * Set default config file
1872408d859SMatthew Dillon      */
18897c30a15SMatthew Dillon     if (config_opt == NULL) {
18997c30a15SMatthew Dillon 	if (optind != ac)
19097c30a15SMatthew Dillon 	    config_opt = "/dev/null";
19197c30a15SMatthew Dillon 	else
19297c30a15SMatthew Dillon 	    config_opt = "/etc/dntpd.conf";
19397c30a15SMatthew Dillon     }
194e0163549SMatthew Dillon 
1953d15852bSMatthew Dillon     if (debug_level < 0)
1963d15852bSMatthew Dillon 	debug_level = 1;
1973d15852bSMatthew Dillon 
19897c30a15SMatthew Dillon     process_config_file(config_opt);
19997c30a15SMatthew Dillon 
2003d15852bSMatthew Dillon     if (debug_opt == 0)
2013d15852bSMatthew Dillon 	openlog("dntpd", LOG_CONS|LOG_PID, LOG_DAEMON);
2023d15852bSMatthew Dillon 
2039b724d8cSMatthew Dillon     if (test_opt) {
2049b724d8cSMatthew Dillon 	if (optind != ac - 1)
2059b724d8cSMatthew Dillon 	    usage(av[0]);
2069b724d8cSMatthew Dillon 	dotest(av[optind]);
2079b724d8cSMatthew Dillon 	/* not reached */
2089b724d8cSMatthew Dillon     }
2099b724d8cSMatthew Dillon 
210e0163549SMatthew Dillon     /*
211e0163549SMatthew Dillon      * Add additional hosts.
212e0163549SMatthew Dillon      */
213e0163549SMatthew Dillon     for (i = optind; i < ac; ++i) {
214e0163549SMatthew Dillon 	add_server(av[i]);
215e0163549SMatthew Dillon     }
216e0163549SMatthew Dillon     if (nservers == 0) {
217e0163549SMatthew Dillon 	usage(av[0]);
218e0163549SMatthew Dillon 	/* not reached */
219e0163549SMatthew Dillon     }
220e0163549SMatthew Dillon 
221e0163549SMatthew Dillon     /*
22297c30a15SMatthew Dillon      * Do an initial course time setting if requested using the first
22397c30a15SMatthew Dillon      * host successfully polled.
22497c30a15SMatthew Dillon      */
22597c30a15SMatthew Dillon     /* XXX */
22697c30a15SMatthew Dillon 
22797c30a15SMatthew Dillon     /*
22897c30a15SMatthew Dillon      * Daemonize, stop logging to stderr.
22997c30a15SMatthew Dillon      */
23097c30a15SMatthew Dillon     if (daemon_opt) {
23197c30a15SMatthew Dillon 	if ((pid = check_pid()) != 0) {
23297c30a15SMatthew Dillon 	    logerrstr("%s: NOTE: killing old daemon and starting a new one",
23397c30a15SMatthew Dillon 			av[0]);
23497c30a15SMatthew Dillon 	    kill(pid, SIGINT);
23597c30a15SMatthew Dillon 	    usleep(100000);
23697c30a15SMatthew Dillon 	    if (check_pid())
23797c30a15SMatthew Dillon 		sleep(1);
23897c30a15SMatthew Dillon 	    if (check_pid())
23997c30a15SMatthew Dillon 		sleep(9);
24097c30a15SMatthew Dillon 	    if (check_pid()) {
24197c30a15SMatthew Dillon 		logerrstr("%s: Unable to kill running daemon, exiting", av[0]);
24297c30a15SMatthew Dillon 		exit(1);
24397c30a15SMatthew Dillon 	    }
24497c30a15SMatthew Dillon 	}
24597c30a15SMatthew Dillon 	daemon(0, 0);
24697c30a15SMatthew Dillon     } else if (check_pid() != 0) {
24797c30a15SMatthew Dillon 	logerrstr("%s: A background dntpd is running, you must kill it first",
24897c30a15SMatthew Dillon 		av[0]);
24997c30a15SMatthew Dillon 	exit(1);
25097c30a15SMatthew Dillon     }
25197c30a15SMatthew Dillon     if (debug_opt == 0) {
25297c30a15SMatthew Dillon 	log_stderr = 0;
25397c30a15SMatthew Dillon 	set_pid(av[0]);
25497c30a15SMatthew Dillon 	signal(SIGINT, sigint_handler);
25597c30a15SMatthew Dillon 	logdebug(0, "dntpd version %s started\n", DNTPD_VERSION);
25697c30a15SMatthew Dillon     }
25797c30a15SMatthew Dillon 
25897c30a15SMatthew Dillon     /*
259e0163549SMatthew Dillon      * And go.
260e0163549SMatthew Dillon      */
261c44548fcSMatthew Dillon     sysntp_clear_alternative_corrections();
262e0163549SMatthew Dillon     client_init();
2632408d859SMatthew Dillon     client_check_duplicate_ips(servers, nservers);
264*1d9b37b0SSascha Wildner     client_main(servers, nservers);
265*1d9b37b0SSascha Wildner     return(0);
266e0163549SMatthew Dillon }
267e0163549SMatthew Dillon 
268e0163549SMatthew Dillon static
269e0163549SMatthew Dillon void
usage(const char * av0)270e0163549SMatthew Dillon usage(const char *av0)
271e0163549SMatthew Dillon {
272d399b893SMatthew Dillon     fprintf(stderr, "%s [-dnqstFSQ] [-f config_file] [-l log_level] [-T poll_interval] [-L poll_limit] [additional_targets]\n", av0);
27397c30a15SMatthew Dillon     fprintf(stderr,
27497c30a15SMatthew Dillon 	"\t-d\tDebugging mode, implies -F, -l 99, and logs to stderr\n"
27597c30a15SMatthew Dillon 	"\t-f file\tSpecify the config file (/etc/dntpd.conf)\n"
27697c30a15SMatthew Dillon 	"\t-l int\tSet log level (0-4), default 1\n"
277c44548fcSMatthew Dillon 	"\t-n\tNo-update mode.  No offset or frequency corrections are made\n"
27897c30a15SMatthew Dillon 	"\t-q\tQuiet-mode, same as -L 0\n"
27997c30a15SMatthew Dillon 	"\t-s\tSet the time immediately on startup\n"
280c44548fcSMatthew Dillon 	"\t-t\tTest mode, implies -F, -l 99, -n, logs to stderr\n"
281c44548fcSMatthew Dillon 	"\t-F\tRun in foreground (log still goes to syslog)\n"
28297c30a15SMatthew Dillon 	"\t-L int\tMaximum polling interval\n"
28397c30a15SMatthew Dillon 	"\t-S\tDo not set the time immediately on startup\n"
28497c30a15SMatthew Dillon 	"\t-T int\tNominal polling interval\n"
28597c30a15SMatthew Dillon 	"\t-Q\tTerminate any running background daemon\n"
286c44548fcSMatthew Dillon 	"\n"
287c44548fcSMatthew Dillon 	"\t\tNOTE: in debug and test modes -f must be specified if\n"
288c44548fcSMatthew Dillon 	"\t\tyou want to use a config file.\n"
28997c30a15SMatthew Dillon     );
290e0163549SMatthew Dillon     exit(1);
291e0163549SMatthew Dillon }
292e0163549SMatthew Dillon 
293e0163549SMatthew Dillon static
294e0163549SMatthew Dillon void
dotest(const char * target)295e0163549SMatthew Dillon dotest(const char *target)
296e0163549SMatthew Dillon {
297e0163549SMatthew Dillon     struct server_info info;
298e0163549SMatthew Dillon 
299e0163549SMatthew Dillon     bzero(&info, sizeof(info));
3004d1d74baSMatthias Schmidt     info.sam = (struct sockaddr *)&info.sam_st;
30185ecde19SNicolas Thery     info.fd = udp_socket(target, 123, info.sam, LOG_DNS_ERROR);
302e0163549SMatthew Dillon     if (info.fd < 0) {
303e0163549SMatthew Dillon 	logerrstr("unable to create UDP socket for %s", target);
304e0163549SMatthew Dillon 	return;
305e0163549SMatthew Dillon     }
306e0163549SMatthew Dillon     info.target = strdup(target);
307e0163549SMatthew Dillon     client_init();
308e0163549SMatthew Dillon 
3099b724d8cSMatthew Dillon     fprintf(stderr,
310fdd4337fSMatthew Dillon 	    "Will run %d-second polls until interrupted.\n", nom_sleep_opt);
3119b724d8cSMatthew Dillon 
312e0163549SMatthew Dillon     for (;;) {
313c32f1362SMatthew Dillon 	client_poll(&info, nom_sleep_opt, 1);
314fdd4337fSMatthew Dillon 	sleep(nom_sleep_opt);
315e0163549SMatthew Dillon     }
3169b724d8cSMatthew Dillon     /* not reached */
317e0163549SMatthew Dillon }
318e0163549SMatthew Dillon 
3194d1d74baSMatthias Schmidt static char *
myaddr2ascii(struct sockaddr * sa)3204d1d74baSMatthias Schmidt myaddr2ascii(struct sockaddr *sa)
3214d1d74baSMatthias Schmidt {
3224d1d74baSMatthias Schmidt 	static char str[INET6_ADDRSTRLEN];
3234d1d74baSMatthias Schmidt 	struct sockaddr_in *soin;
3244d1d74baSMatthias Schmidt 	struct sockaddr_in6 *sin6;
3254d1d74baSMatthias Schmidt 
3264d1d74baSMatthias Schmidt 	switch (sa->sa_family) {
3274d1d74baSMatthias Schmidt 	case AF_INET:
3284d1d74baSMatthias Schmidt 		soin = (struct sockaddr_in *) sa;
3294d1d74baSMatthias Schmidt 		inet_ntop(AF_INET, &soin->sin_addr, str, sizeof(str));
3304d1d74baSMatthias Schmidt 		break;
3314d1d74baSMatthias Schmidt 	case AF_INET6:
3324d1d74baSMatthias Schmidt 		sin6 = (struct sockaddr_in6 *) sa;
3334d1d74baSMatthias Schmidt 		inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
3344d1d74baSMatthias Schmidt 		break;
3354d1d74baSMatthias Schmidt 	}
3364d1d74baSMatthias Schmidt 	return (str);
3374d1d74baSMatthias Schmidt }
3384d1d74baSMatthias Schmidt 
339e0163549SMatthew Dillon static void
add_server(const char * target)340e0163549SMatthew Dillon add_server(const char *target)
341e0163549SMatthew Dillon {
342e0163549SMatthew Dillon     server_info_t info;
343e0163549SMatthew Dillon 
344e0163549SMatthew Dillon     if (nservers == maxservers) {
345e0163549SMatthew Dillon 	maxservers += 16;
346e0163549SMatthew Dillon 	servers = realloc(servers, maxservers * sizeof(server_info_t));
347e0163549SMatthew Dillon 	assert(servers != NULL);
348e0163549SMatthew Dillon     }
349e0163549SMatthew Dillon     info = malloc(sizeof(struct server_info));
350e0163549SMatthew Dillon     servers[nservers] = info;
351e0163549SMatthew Dillon     bzero(info, sizeof(struct server_info));
3524d1d74baSMatthias Schmidt     info->sam = (struct sockaddr *)&info->sam_st;
353e0163549SMatthew Dillon     info->target = strdup(target);
35485ecde19SNicolas Thery     /*
35585ecde19SNicolas Thery      * Postpone socket opening and server name resolution until we are in main
35685ecde19SNicolas Thery      * loop to avoid hang during init if network down.
35785ecde19SNicolas Thery      */
35885ecde19SNicolas Thery     info->fd = -1;
35985ecde19SNicolas Thery     info->server_state = -1;
360e0163549SMatthew Dillon     ++nservers;
361e0163549SMatthew Dillon }
3622408d859SMatthew Dillon 
3632408d859SMatthew Dillon void
disconnect_server(server_info_t info)3642408d859SMatthew Dillon disconnect_server(server_info_t info)
3652408d859SMatthew Dillon {
3662408d859SMatthew Dillon     if (info->fd >= 0)
3672408d859SMatthew Dillon 	close(info->fd);
3682408d859SMatthew Dillon     info->fd = -1;
3692408d859SMatthew Dillon     if (info->ipstr) {
3702408d859SMatthew Dillon 	free(info->ipstr);
3712408d859SMatthew Dillon 	info->ipstr = NULL;
3722408d859SMatthew Dillon     }
3732408d859SMatthew Dillon }
3742408d859SMatthew Dillon 
3752408d859SMatthew Dillon void
reconnect_server(server_info_t info)3762408d859SMatthew Dillon reconnect_server(server_info_t info)
3772408d859SMatthew Dillon {
3782408d859SMatthew Dillon     const char *ipstr;
37985ecde19SNicolas Thery     dns_error_policy_t policy;
3802408d859SMatthew Dillon 
38185ecde19SNicolas Thery     /*
38285ecde19SNicolas Thery      * Ignore DNS errors if never connected before to handle the case where
38385ecde19SNicolas Thery      * we're started before network up.
38485ecde19SNicolas Thery      */
38585ecde19SNicolas Thery     policy = IGNORE_DNS_ERROR;
38685ecde19SNicolas Thery     if (info->fd >= 0) {
3872408d859SMatthew Dillon 	close(info->fd);
38885ecde19SNicolas Thery 	policy = LOG_DNS_ERROR;
38985ecde19SNicolas Thery     }
3902408d859SMatthew Dillon     if (info->ipstr) {
3912408d859SMatthew Dillon 	free(info->ipstr);
3922408d859SMatthew Dillon 	info->ipstr = NULL;
3932408d859SMatthew Dillon     }
3944d1d74baSMatthias Schmidt     info->sam = (struct sockaddr *)&info->sam_st;
39585ecde19SNicolas Thery     info->fd = udp_socket(info->target, 123, info->sam, policy);
3962408d859SMatthew Dillon     if (info->fd >= 0) {
3974d1d74baSMatthias Schmidt 	ipstr = myaddr2ascii(info->sam);
3982408d859SMatthew Dillon 	info->ipstr = strdup(ipstr);
3992408d859SMatthew Dillon     }
400e0163549SMatthew Dillon }
401e0163549SMatthew Dillon 
40297c30a15SMatthew Dillon static void
process_config_file(const char * path)40397c30a15SMatthew Dillon process_config_file(const char *path)
40497c30a15SMatthew Dillon {
40597c30a15SMatthew Dillon     const char *ws = " \t\r\n";
40697c30a15SMatthew Dillon     char buf[1024];
40797c30a15SMatthew Dillon     char *keyword;
40897c30a15SMatthew Dillon     char *data;
40997c30a15SMatthew Dillon     int line;
41097c30a15SMatthew Dillon     FILE *fi;
41197c30a15SMatthew Dillon 
41297c30a15SMatthew Dillon     if ((fi = fopen(path, "r")) != NULL) {
41397c30a15SMatthew Dillon 	line = 1;
41497c30a15SMatthew Dillon 	while (fgets(buf, sizeof(buf), fi) != NULL) {
41597c30a15SMatthew Dillon 	    if (strchr(buf, '#'))
41697c30a15SMatthew Dillon 		*strchr(buf, '#') = 0;
41797c30a15SMatthew Dillon 	    if ((keyword = strtok(buf, ws)) != NULL) {
41897c30a15SMatthew Dillon 		data = strtok(NULL, ws);
41997c30a15SMatthew Dillon 		if (strcmp(keyword, "server") == 0) {
42097c30a15SMatthew Dillon 		    if (data == NULL) {
42197c30a15SMatthew Dillon 			logerr("%s:%d server missing host specification",
42297c30a15SMatthew Dillon 				path, line);
42397c30a15SMatthew Dillon 		    } else {
42497c30a15SMatthew Dillon 			add_server(data);
42597c30a15SMatthew Dillon 		    }
42697c30a15SMatthew Dillon 		} else {
42797c30a15SMatthew Dillon 		    logerr("%s:%d unknown keyword %s", path, line, keyword);
42897c30a15SMatthew Dillon 		}
42997c30a15SMatthew Dillon 	    }
43097c30a15SMatthew Dillon 	    ++line;
43197c30a15SMatthew Dillon 	}
43297c30a15SMatthew Dillon 	fclose(fi);
43397c30a15SMatthew Dillon     } else {
43497c30a15SMatthew Dillon 	logerr("Unable to open %s", path);
43597c30a15SMatthew Dillon 	exit(1);
43697c30a15SMatthew Dillon     }
43797c30a15SMatthew Dillon }
43897c30a15SMatthew Dillon 
43997c30a15SMatthew Dillon static
44097c30a15SMatthew Dillon pid_t
check_pid(void)44197c30a15SMatthew Dillon check_pid(void)
44297c30a15SMatthew Dillon {
44397c30a15SMatthew Dillon     char buf[32];
44497c30a15SMatthew Dillon     pid_t pid;
44597c30a15SMatthew Dillon     FILE *fi;
44697c30a15SMatthew Dillon 
44797c30a15SMatthew Dillon     pid = 0;
44897c30a15SMatthew Dillon     if ((fi = fopen(pid_opt, "r")) != NULL) {
44997c30a15SMatthew Dillon 	if (fgets(buf, sizeof(buf), fi) != NULL) {
45097c30a15SMatthew Dillon 	    pid = strtol(buf, NULL, 0);
45197c30a15SMatthew Dillon 	    if (kill(pid, 0) != 0)
45297c30a15SMatthew Dillon 		pid = 0;
45397c30a15SMatthew Dillon 	}
45497c30a15SMatthew Dillon 	fclose(fi);
45597c30a15SMatthew Dillon     }
45697c30a15SMatthew Dillon     return(pid);
45797c30a15SMatthew Dillon }
45897c30a15SMatthew Dillon 
45997c30a15SMatthew Dillon static
46097c30a15SMatthew Dillon void
set_pid(const char * av0)46197c30a15SMatthew Dillon set_pid(const char *av0)
46297c30a15SMatthew Dillon {
46397c30a15SMatthew Dillon     pid_t pid;
46497c30a15SMatthew Dillon     FILE *fo;
46597c30a15SMatthew Dillon 
46697c30a15SMatthew Dillon     pid = getpid();
46797c30a15SMatthew Dillon     if ((fo = fopen(pid_opt, "w")) != NULL) {
46897c30a15SMatthew Dillon 	fprintf(fo, "%d\n", (int)pid);
46997c30a15SMatthew Dillon 	fclose(fo);
47097c30a15SMatthew Dillon     } else {
47197c30a15SMatthew Dillon 	logerr("%s: Unable to create %s, continuing anyway.", av0, pid_opt);
47297c30a15SMatthew Dillon     }
47397c30a15SMatthew Dillon }
47497c30a15SMatthew Dillon 
47597c30a15SMatthew Dillon static
47697c30a15SMatthew Dillon void
sigint_handler(int signo __unused)477c32f1362SMatthew Dillon sigint_handler(int signo __unused)
47897c30a15SMatthew Dillon {
47997c30a15SMatthew Dillon     remove(pid_opt);
48097c30a15SMatthew Dillon     /* dangerous, but we are exiting anyway so pray... */
48197c30a15SMatthew Dillon     logdebug(0, "dntpd version %s stopped\n", DNTPD_VERSION);
48297c30a15SMatthew Dillon     exit(0);
48397c30a15SMatthew Dillon }
48497c30a15SMatthew Dillon 
485