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
34 * $DragonFly: src/usr.sbin/dntpd/main.c,v 1.6 2005/04/26 00:56:54 dillon Exp $
39 static void usage(const char *av0);
40 static void dotest(const char *target);
41 static void add_server(const char *target);
42 static void process_config_file(const char *path);
43 static pid_t check_pid(void);
44 static void set_pid(const char *av0);
45 static void sigint_handler(int signo);
47 static struct server_info **servers;
49 static int maxservers;
53 int debug_level = -1; /* (set to default later) */
54 int quickset_opt = 0; /* immediate set time of day on startup */
55 int no_update_opt = 0; /* do not make any actual updates */
56 int min_sleep_opt = 5; /* 5 seconds minimum poll interval */
57 int nom_sleep_opt = 300; /* 5 minutes nominal poll interval */
58 int max_sleep_opt = 1800; /* 30 minutes maximum poll interval */
59 const char *config_opt; /* config file */
60 const char *pid_opt = "/var/run/dntpd.pid";
63 main(int ac, char **av)
80 while ((ch = getopt(ac, av, "df:l:np:qstFL:QST:")) != -1) {
87 if (config_opt == NULL)
88 config_opt = "/dev/null";
97 debug_level = strtol(optarg, NULL, 0);
107 fprintf(stderr, "%s: warning, -s not currently implemented\n",
119 if (config_opt == NULL)
120 config_opt = "/dev/null";
126 max_sleep_opt = strtol(optarg, NULL, 0);
129 nom_sleep_opt = strtol(optarg, NULL, 0);
130 if (nom_sleep_opt < 1) {
131 fprintf(stderr, "Warning: nominal poll interval too small, "
132 "limiting to 1 second\n");
135 if (nom_sleep_opt > 24 * 60 * 60) {
136 fprintf(stderr, "Warning: nominal poll interval too large, "
137 "limiting to 24 hours\n");
138 nom_sleep_opt = 24 * 60 * 60;
140 if (min_sleep_opt > nom_sleep_opt)
141 min_sleep_opt = nom_sleep_opt;
142 if (max_sleep_opt < nom_sleep_opt * 5)
143 max_sleep_opt = nom_sleep_opt * 5;
146 if ((pid = check_pid()) != 0) {
147 fprintf(stderr, "%s: killing old daemon\n", av[0]);
155 fprintf(stderr, "%s: Unable to kill running daemon.\n", av[0]);
157 fprintf(stderr, "%s: Running daemon has been terminated.\n", av[0]);
160 fprintf(stderr, "%s: There is no daemon running to kill.\n", av[0]);
170 if (config_opt == NULL) {
172 config_opt = "/dev/null";
174 config_opt = "/etc/dntpd.conf";
180 process_config_file(config_opt);
183 openlog("dntpd", LOG_CONS|LOG_PID, LOG_DAEMON);
186 if (optind != ac - 1)
193 * Add additional hosts.
195 for (i = optind; i < ac; ++i) {
204 * Do an initial course time setting if requested using the first
205 * host successfully polled.
210 * Daemonize, stop logging to stderr.
213 if ((pid = check_pid()) != 0) {
214 logerrstr("%s: NOTE: killing old daemon and starting a new one",
223 logerrstr("%s: Unable to kill running daemon, exiting", av[0]);
228 } else if (check_pid() != 0) {
229 logerrstr("%s: A background dntpd is running, you must kill it first",
233 if (debug_opt == 0) {
236 signal(SIGINT, sigint_handler);
237 logdebug(0, "dntpd version %s started\n", DNTPD_VERSION);
243 sysntp_clear_alternative_corrections();
245 rc = client_main(servers, nservers);
251 usage(const char *av0)
253 fprintf(stderr, "%s [-dqstFS] [-l log_level] [-T poll_interval] [-L poll_limit] [additional_targets]\n", av0);
255 "\t-d\tDebugging mode, implies -F, -l 99, and logs to stderr\n"
256 "\t-f file\tSpecify the config file (/etc/dntpd.conf)\n"
257 "\t-l int\tSet log level (0-4), default 1\n"
258 "\t-n\tNo-update mode. No offset or frequency corrections are made\n"
259 "\t-q\tQuiet-mode, same as -L 0\n"
260 "\t-s\tSet the time immediately on startup\n"
261 "\t-t\tTest mode, implies -F, -l 99, -n, logs to stderr\n"
262 "\t-F\tRun in foreground (log still goes to syslog)\n"
263 "\t-L int\tMaximum polling interval\n"
264 "\t-S\tDo not set the time immediately on startup\n"
265 "\t-T int\tNominal polling interval\n"
266 "\t-Q\tTerminate any running background daemon\n"
268 "\t\tNOTE: in debug and test modes -f must be specified if\n"
269 "\t\tyou want to use a config file.\n"
276 dotest(const char *target)
278 struct server_info info;
280 bzero(&info, sizeof(info));
281 info.fd = udp_socket(target, 123);
283 logerrstr("unable to create UDP socket for %s", target);
286 info.target = strdup(target);
290 "Will run %d-second polls until interrupted.\n", nom_sleep_opt);
293 client_poll(&info, nom_sleep_opt);
294 sleep(nom_sleep_opt);
300 add_server(const char *target)
304 if (nservers == maxservers) {
306 servers = realloc(servers, maxservers * sizeof(server_info_t));
307 assert(servers != NULL);
309 info = malloc(sizeof(struct server_info));
310 servers[nservers] = info;
311 bzero(info, sizeof(struct server_info));
312 info->fd = udp_socket(target, 123);
314 logerrstr("Unable to add server %s", target);
316 info->target = strdup(target);
322 process_config_file(const char *path)
324 const char *ws = " \t\r\n";
331 if ((fi = fopen(path, "r")) != NULL) {
333 while (fgets(buf, sizeof(buf), fi) != NULL) {
334 if (strchr(buf, '#'))
335 *strchr(buf, '#') = 0;
336 if ((keyword = strtok(buf, ws)) != NULL) {
337 data = strtok(NULL, ws);
338 if (strcmp(keyword, "server") == 0) {
340 logerr("%s:%d server missing host specification",
346 logerr("%s:%d unknown keyword %s", path, line, keyword);
353 logerr("Unable to open %s", path);
367 if ((fi = fopen(pid_opt, "r")) != NULL) {
368 if (fgets(buf, sizeof(buf), fi) != NULL) {
369 pid = strtol(buf, NULL, 0);
370 if (kill(pid, 0) != 0)
380 set_pid(const char *av0)
386 if ((fo = fopen(pid_opt, "w")) != NULL) {
387 fprintf(fo, "%d\n", (int)pid);
390 logerr("%s: Unable to create %s, continuing anyway.", av0, pid_opt);
396 sigint_handler(int signo)
399 /* dangerous, but we are exiting anyway so pray... */
400 logdebug(0, "dntpd version %s stopped\n", DNTPD_VERSION);