1 /* 2 * Copyright (c) 2005 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 16 * distribution. 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. 20 * 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 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/usr.sbin/dntpd/main.c,v 1.11 2007/06/26 02:40:20 dillon Exp $ 35 */ 36 37 #include "defs.h" 38 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 __unused); 46 47 static struct server_info **servers; 48 static int nservers; 49 static int maxservers; 50 51 int daemon_opt = 1; 52 int debug_opt = 0; 53 int debug_level = -1; /* (set to default later) */ 54 int quickset_opt = 0; /* immediately 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 int family = PF_UNSPEC; /* Address family */ 60 double insane_deviation = 0.5; /* 0.5 seconds of deviation == insane */ 61 const char *config_opt; /* config file */ 62 const char *pid_opt = "/var/run/dntpd.pid"; 63 64 int 65 main(int ac, char **av) 66 { 67 int test_opt = 0; 68 pid_t pid; 69 int rc; 70 int ch; 71 int i; 72 73 /* 74 * Really randomize 75 */ 76 srandomdev(); 77 rc = 0; 78 79 /* 80 * Process Options 81 */ 82 while ((ch = getopt(ac, av, "46df:i:l:np:qstFL:QST:")) != -1) { 83 switch(ch) { 84 case '4': 85 family = PF_INET; 86 break; 87 case '6': 88 family = PF_INET6; 89 break; 90 case 'd': 91 debug_opt = 1; 92 daemon_opt = 0; 93 if (debug_level < 0) 94 debug_level = 99; 95 if (config_opt == NULL) 96 config_opt = "/dev/null"; 97 break; 98 case 'p': 99 pid_opt = optarg; 100 break; 101 case 'f': 102 config_opt = optarg; 103 break; 104 case 'i': 105 insane_deviation = strtod(optarg, NULL); 106 break; 107 case 'l': 108 debug_level = strtol(optarg, NULL, 0); 109 break; 110 case 'n': 111 no_update_opt = 1; 112 break; 113 case 'q': 114 debug_level = 0; 115 break; 116 case 's': 117 quickset_opt = 1; 118 break; 119 case 'S': 120 quickset_opt = 0; 121 break; 122 case 't': 123 test_opt = 1; 124 debug_opt = 1; 125 daemon_opt = 0; 126 if (debug_level < 0) 127 debug_level = 99; 128 if (config_opt == NULL) 129 config_opt = "/dev/null"; 130 break; 131 case 'F': 132 daemon_opt = 0; 133 break; 134 case 'L': 135 max_sleep_opt = strtol(optarg, NULL, 0); 136 break; 137 case 'T': 138 nom_sleep_opt = strtol(optarg, NULL, 0); 139 if (nom_sleep_opt < 1) { 140 fprintf(stderr, "Warning: nominal poll interval too small, " 141 "limiting to 1 second\n"); 142 nom_sleep_opt = 1; 143 } 144 if (nom_sleep_opt > 24 * 60 * 60) { 145 fprintf(stderr, "Warning: nominal poll interval too large, " 146 "limiting to 24 hours\n"); 147 nom_sleep_opt = 24 * 60 * 60; 148 } 149 if (min_sleep_opt > nom_sleep_opt) 150 min_sleep_opt = nom_sleep_opt; 151 if (max_sleep_opt < nom_sleep_opt * 5) 152 max_sleep_opt = nom_sleep_opt * 5; 153 break; 154 case 'Q': 155 if ((pid = check_pid()) != 0) { 156 fprintf(stderr, "%s: killing old daemon\n", av[0]); 157 kill(pid, SIGINT); 158 usleep(100000); 159 if (check_pid()) 160 sleep(1); 161 if (check_pid()) 162 sleep(9); 163 if (check_pid()) { 164 fprintf(stderr, "%s: Unable to kill running daemon.\n", av[0]); 165 } else { 166 fprintf(stderr, "%s: Running daemon has been terminated.\n", av[0]); 167 } 168 } else { 169 fprintf(stderr, "%s: There is no daemon running to kill.\n", av[0]); 170 } 171 exit(0); 172 break; 173 case 'h': 174 default: 175 usage(av[0]); 176 /* not reached */ 177 } 178 } 179 180 /* 181 * Make sure min and nom intervals are less then or equal to the maximum 182 * interval. 183 */ 184 if (min_sleep_opt > max_sleep_opt) 185 min_sleep_opt = max_sleep_opt; 186 if (nom_sleep_opt > max_sleep_opt) 187 nom_sleep_opt = max_sleep_opt; 188 189 /* 190 * Set default config file 191 */ 192 if (config_opt == NULL) { 193 if (optind != ac) 194 config_opt = "/dev/null"; 195 else 196 config_opt = "/etc/dntpd.conf"; 197 } 198 199 if (debug_level < 0) 200 debug_level = 1; 201 202 process_config_file(config_opt); 203 204 if (debug_opt == 0) 205 openlog("dntpd", LOG_CONS|LOG_PID, LOG_DAEMON); 206 207 if (test_opt) { 208 if (optind != ac - 1) 209 usage(av[0]); 210 dotest(av[optind]); 211 /* not reached */ 212 } 213 214 /* 215 * Add additional hosts. 216 */ 217 for (i = optind; i < ac; ++i) { 218 add_server(av[i]); 219 } 220 if (nservers == 0) { 221 usage(av[0]); 222 /* not reached */ 223 } 224 225 /* 226 * Do an initial course time setting if requested using the first 227 * host successfully polled. 228 */ 229 /* XXX */ 230 231 /* 232 * Daemonize, stop logging to stderr. 233 */ 234 if (daemon_opt) { 235 if ((pid = check_pid()) != 0) { 236 logerrstr("%s: NOTE: killing old daemon and starting a new one", 237 av[0]); 238 kill(pid, SIGINT); 239 usleep(100000); 240 if (check_pid()) 241 sleep(1); 242 if (check_pid()) 243 sleep(9); 244 if (check_pid()) { 245 logerrstr("%s: Unable to kill running daemon, exiting", av[0]); 246 exit(1); 247 } 248 } 249 daemon(0, 0); 250 } else if (check_pid() != 0) { 251 logerrstr("%s: A background dntpd is running, you must kill it first", 252 av[0]); 253 exit(1); 254 } 255 if (debug_opt == 0) { 256 log_stderr = 0; 257 set_pid(av[0]); 258 signal(SIGINT, sigint_handler); 259 logdebug(0, "dntpd version %s started\n", DNTPD_VERSION); 260 } 261 262 /* 263 * And go. 264 */ 265 sysntp_clear_alternative_corrections(); 266 client_init(); 267 client_check_duplicate_ips(servers, nservers); 268 rc = client_main(servers, nservers); 269 return(rc); 270 } 271 272 static 273 void 274 usage(const char *av0) 275 { 276 fprintf(stderr, "%s [-dnqstFSQ] [-f config_file] [-l log_level] [-T poll_interval] [-L poll_limit] [additional_targets]\n", av0); 277 fprintf(stderr, 278 "\t-d\tDebugging mode, implies -F, -l 99, and logs to stderr\n" 279 "\t-f file\tSpecify the config file (/etc/dntpd.conf)\n" 280 "\t-l int\tSet log level (0-4), default 1\n" 281 "\t-n\tNo-update mode. No offset or frequency corrections are made\n" 282 "\t-q\tQuiet-mode, same as -L 0\n" 283 "\t-s\tSet the time immediately on startup\n" 284 "\t-t\tTest mode, implies -F, -l 99, -n, logs to stderr\n" 285 "\t-F\tRun in foreground (log still goes to syslog)\n" 286 "\t-L int\tMaximum polling interval\n" 287 "\t-S\tDo not set the time immediately on startup\n" 288 "\t-T int\tNominal polling interval\n" 289 "\t-Q\tTerminate any running background daemon\n" 290 "\n" 291 "\t\tNOTE: in debug and test modes -f must be specified if\n" 292 "\t\tyou want to use a config file.\n" 293 ); 294 exit(1); 295 } 296 297 static 298 void 299 dotest(const char *target) 300 { 301 struct server_info info; 302 303 bzero(&info, sizeof(info)); 304 info.sam = (struct sockaddr *)&info.sam_st; 305 info.fd = udp_socket(target, 123, info.sam, LOG_DNS_ERROR); 306 if (info.fd < 0) { 307 logerrstr("unable to create UDP socket for %s", target); 308 return; 309 } 310 info.target = strdup(target); 311 client_init(); 312 313 fprintf(stderr, 314 "Will run %d-second polls until interrupted.\n", nom_sleep_opt); 315 316 for (;;) { 317 client_poll(&info, nom_sleep_opt, 1); 318 sleep(nom_sleep_opt); 319 } 320 /* not reached */ 321 } 322 323 static char * 324 myaddr2ascii(struct sockaddr *sa) 325 { 326 static char str[INET6_ADDRSTRLEN]; 327 struct sockaddr_in *soin; 328 struct sockaddr_in6 *sin6; 329 330 switch (sa->sa_family) { 331 case AF_INET: 332 soin = (struct sockaddr_in *) sa; 333 inet_ntop(AF_INET, &soin->sin_addr, str, sizeof(str)); 334 break; 335 case AF_INET6: 336 sin6 = (struct sockaddr_in6 *) sa; 337 inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)); 338 break; 339 } 340 return (str); 341 } 342 343 static void 344 add_server(const char *target) 345 { 346 server_info_t info; 347 348 if (nservers == maxservers) { 349 maxservers += 16; 350 servers = realloc(servers, maxservers * sizeof(server_info_t)); 351 assert(servers != NULL); 352 } 353 info = malloc(sizeof(struct server_info)); 354 servers[nservers] = info; 355 bzero(info, sizeof(struct server_info)); 356 info->sam = (struct sockaddr *)&info->sam_st; 357 info->target = strdup(target); 358 /* 359 * Postpone socket opening and server name resolution until we are in main 360 * loop to avoid hang during init if network down. 361 */ 362 info->fd = -1; 363 info->server_state = -1; 364 ++nservers; 365 } 366 367 void 368 disconnect_server(server_info_t info) 369 { 370 if (info->fd >= 0) 371 close(info->fd); 372 info->fd = -1; 373 if (info->ipstr) { 374 free(info->ipstr); 375 info->ipstr = NULL; 376 } 377 } 378 379 void 380 reconnect_server(server_info_t info) 381 { 382 const char *ipstr; 383 dns_error_policy_t policy; 384 385 /* 386 * Ignore DNS errors if never connected before to handle the case where 387 * we're started before network up. 388 */ 389 policy = IGNORE_DNS_ERROR; 390 if (info->fd >= 0) { 391 close(info->fd); 392 policy = LOG_DNS_ERROR; 393 } 394 if (info->ipstr) { 395 free(info->ipstr); 396 info->ipstr = NULL; 397 } 398 info->sam = (struct sockaddr *)&info->sam_st; 399 info->fd = udp_socket(info->target, 123, info->sam, policy); 400 if (info->fd >= 0) { 401 ipstr = myaddr2ascii(info->sam); 402 info->ipstr = strdup(ipstr); 403 } 404 } 405 406 static void 407 process_config_file(const char *path) 408 { 409 const char *ws = " \t\r\n"; 410 char buf[1024]; 411 char *keyword; 412 char *data; 413 int line; 414 FILE *fi; 415 416 if ((fi = fopen(path, "r")) != NULL) { 417 line = 1; 418 while (fgets(buf, sizeof(buf), fi) != NULL) { 419 if (strchr(buf, '#')) 420 *strchr(buf, '#') = 0; 421 if ((keyword = strtok(buf, ws)) != NULL) { 422 data = strtok(NULL, ws); 423 if (strcmp(keyword, "server") == 0) { 424 if (data == NULL) { 425 logerr("%s:%d server missing host specification", 426 path, line); 427 } else { 428 add_server(data); 429 } 430 } else { 431 logerr("%s:%d unknown keyword %s", path, line, keyword); 432 } 433 } 434 ++line; 435 } 436 fclose(fi); 437 } else { 438 logerr("Unable to open %s", path); 439 exit(1); 440 } 441 } 442 443 static 444 pid_t 445 check_pid(void) 446 { 447 char buf[32]; 448 pid_t pid; 449 FILE *fi; 450 451 pid = 0; 452 if ((fi = fopen(pid_opt, "r")) != NULL) { 453 if (fgets(buf, sizeof(buf), fi) != NULL) { 454 pid = strtol(buf, NULL, 0); 455 if (kill(pid, 0) != 0) 456 pid = 0; 457 } 458 fclose(fi); 459 } 460 return(pid); 461 } 462 463 static 464 void 465 set_pid(const char *av0) 466 { 467 pid_t pid; 468 FILE *fo; 469 470 pid = getpid(); 471 if ((fo = fopen(pid_opt, "w")) != NULL) { 472 fprintf(fo, "%d\n", (int)pid); 473 fclose(fo); 474 } else { 475 logerr("%s: Unable to create %s, continuing anyway.", av0, pid_opt); 476 } 477 } 478 479 static 480 void 481 sigint_handler(int signo __unused) 482 { 483 remove(pid_opt); 484 /* dangerous, but we are exiting anyway so pray... */ 485 logdebug(0, "dntpd version %s stopped\n", DNTPD_VERSION); 486 exit(0); 487 } 488 489