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); 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 const char *ipstr; 348 349 if (nservers == maxservers) { 350 maxservers += 16; 351 servers = realloc(servers, maxservers * sizeof(server_info_t)); 352 assert(servers != NULL); 353 } 354 info = malloc(sizeof(struct server_info)); 355 servers[nservers] = info; 356 bzero(info, sizeof(struct server_info)); 357 info->sam = (struct sockaddr *)&info->sam_st; 358 info->fd = udp_socket(target, 123, info->sam); 359 info->target = strdup(target); 360 if (info->fd >= 0) { 361 ipstr = myaddr2ascii(info->sam); 362 info->ipstr = strdup(ipstr); 363 } else { 364 client_setserverstate(info, -1, "DNS or IP lookup failure"); 365 } 366 ++nservers; 367 } 368 369 void 370 disconnect_server(server_info_t info) 371 { 372 if (info->fd >= 0) 373 close(info->fd); 374 info->fd = -1; 375 if (info->ipstr) { 376 free(info->ipstr); 377 info->ipstr = NULL; 378 } 379 } 380 381 void 382 reconnect_server(server_info_t info) 383 { 384 const char *ipstr; 385 386 if (info->fd >= 0) 387 close(info->fd); 388 if (info->ipstr) { 389 free(info->ipstr); 390 info->ipstr = NULL; 391 } 392 info->sam = (struct sockaddr *)&info->sam_st; 393 info->fd = udp_socket(info->target, 123, info->sam); 394 if (info->fd >= 0) { 395 ipstr = myaddr2ascii(info->sam); 396 info->ipstr = strdup(ipstr); 397 } 398 } 399 400 static void 401 process_config_file(const char *path) 402 { 403 const char *ws = " \t\r\n"; 404 char buf[1024]; 405 char *keyword; 406 char *data; 407 int line; 408 FILE *fi; 409 410 if ((fi = fopen(path, "r")) != NULL) { 411 line = 1; 412 while (fgets(buf, sizeof(buf), fi) != NULL) { 413 if (strchr(buf, '#')) 414 *strchr(buf, '#') = 0; 415 if ((keyword = strtok(buf, ws)) != NULL) { 416 data = strtok(NULL, ws); 417 if (strcmp(keyword, "server") == 0) { 418 if (data == NULL) { 419 logerr("%s:%d server missing host specification", 420 path, line); 421 } else { 422 add_server(data); 423 } 424 } else { 425 logerr("%s:%d unknown keyword %s", path, line, keyword); 426 } 427 } 428 ++line; 429 } 430 fclose(fi); 431 } else { 432 logerr("Unable to open %s", path); 433 exit(1); 434 } 435 } 436 437 static 438 pid_t 439 check_pid(void) 440 { 441 char buf[32]; 442 pid_t pid; 443 FILE *fi; 444 445 pid = 0; 446 if ((fi = fopen(pid_opt, "r")) != NULL) { 447 if (fgets(buf, sizeof(buf), fi) != NULL) { 448 pid = strtol(buf, NULL, 0); 449 if (kill(pid, 0) != 0) 450 pid = 0; 451 } 452 fclose(fi); 453 } 454 return(pid); 455 } 456 457 static 458 void 459 set_pid(const char *av0) 460 { 461 pid_t pid; 462 FILE *fo; 463 464 pid = getpid(); 465 if ((fo = fopen(pid_opt, "w")) != NULL) { 466 fprintf(fo, "%d\n", (int)pid); 467 fclose(fo); 468 } else { 469 logerr("%s: Unable to create %s, continuing anyway.", av0, pid_opt); 470 } 471 } 472 473 static 474 void 475 sigint_handler(int signo __unused) 476 { 477 remove(pid_opt); 478 /* dangerous, but we are exiting anyway so pray... */ 479 logdebug(0, "dntpd version %s stopped\n", DNTPD_VERSION); 480 exit(0); 481 } 482 483