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.9 2005/04/27 00:42:13 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 const char *config_opt; /* config file */ 60 const char *pid_opt = "/var/run/dntpd.pid"; 61 62 int 63 main(int ac, char **av) 64 { 65 int test_opt = 0; 66 pid_t pid; 67 int rc; 68 int ch; 69 int i; 70 71 /* 72 * Really randomize 73 */ 74 srandomdev(); 75 rc = 0; 76 77 /* 78 * Process Options 79 */ 80 while ((ch = getopt(ac, av, "df:l:np:qstFL:QST:")) != -1) { 81 switch(ch) { 82 case 'd': 83 debug_opt = 1; 84 daemon_opt = 0; 85 if (debug_level < 0) 86 debug_level = 99; 87 if (config_opt == NULL) 88 config_opt = "/dev/null"; 89 break; 90 case 'p': 91 pid_opt = optarg; 92 break; 93 case 'f': 94 config_opt = optarg; 95 break; 96 case 'l': 97 debug_level = strtol(optarg, NULL, 0); 98 break; 99 case 'n': 100 no_update_opt = 1; 101 break; 102 case 'q': 103 debug_level = 0; 104 break; 105 case 's': 106 quickset_opt = 1; 107 break; 108 case 'S': 109 quickset_opt = 0; 110 break; 111 case 't': 112 test_opt = 1; 113 debug_opt = 1; 114 daemon_opt = 0; 115 if (debug_level < 0) 116 debug_level = 99; 117 if (config_opt == NULL) 118 config_opt = "/dev/null"; 119 break; 120 case 'F': 121 daemon_opt = 0; 122 break; 123 case 'L': 124 max_sleep_opt = strtol(optarg, NULL, 0); 125 break; 126 case 'T': 127 nom_sleep_opt = strtol(optarg, NULL, 0); 128 if (nom_sleep_opt < 1) { 129 fprintf(stderr, "Warning: nominal poll interval too small, " 130 "limiting to 1 second\n"); 131 nom_sleep_opt = 1; 132 } 133 if (nom_sleep_opt > 24 * 60 * 60) { 134 fprintf(stderr, "Warning: nominal poll interval too large, " 135 "limiting to 24 hours\n"); 136 nom_sleep_opt = 24 * 60 * 60; 137 } 138 if (min_sleep_opt > nom_sleep_opt) 139 min_sleep_opt = nom_sleep_opt; 140 if (max_sleep_opt < nom_sleep_opt * 5) 141 max_sleep_opt = nom_sleep_opt * 5; 142 break; 143 case 'Q': 144 if ((pid = check_pid()) != 0) { 145 fprintf(stderr, "%s: killing old daemon\n", av[0]); 146 kill(pid, SIGINT); 147 usleep(100000); 148 if (check_pid()) 149 sleep(1); 150 if (check_pid()) 151 sleep(9); 152 if (check_pid()) { 153 fprintf(stderr, "%s: Unable to kill running daemon.\n", av[0]); 154 } else { 155 fprintf(stderr, "%s: Running daemon has been terminated.\n", av[0]); 156 } 157 } else { 158 fprintf(stderr, "%s: There is no daemon running to kill.\n", av[0]); 159 } 160 exit(0); 161 break; 162 case 'h': 163 default: 164 usage(av[0]); 165 /* not reached */ 166 } 167 } 168 if (config_opt == NULL) { 169 if (optind != ac) 170 config_opt = "/dev/null"; 171 else 172 config_opt = "/etc/dntpd.conf"; 173 } 174 175 if (debug_level < 0) 176 debug_level = 1; 177 178 process_config_file(config_opt); 179 180 if (debug_opt == 0) 181 openlog("dntpd", LOG_CONS|LOG_PID, LOG_DAEMON); 182 183 if (test_opt) { 184 if (optind != ac - 1) 185 usage(av[0]); 186 dotest(av[optind]); 187 /* not reached */ 188 } 189 190 /* 191 * Add additional hosts. 192 */ 193 for (i = optind; i < ac; ++i) { 194 add_server(av[i]); 195 } 196 if (nservers == 0) { 197 usage(av[0]); 198 /* not reached */ 199 } 200 201 /* 202 * Do an initial course time setting if requested using the first 203 * host successfully polled. 204 */ 205 /* XXX */ 206 207 /* 208 * Daemonize, stop logging to stderr. 209 */ 210 if (daemon_opt) { 211 if ((pid = check_pid()) != 0) { 212 logerrstr("%s: NOTE: killing old daemon and starting a new one", 213 av[0]); 214 kill(pid, SIGINT); 215 usleep(100000); 216 if (check_pid()) 217 sleep(1); 218 if (check_pid()) 219 sleep(9); 220 if (check_pid()) { 221 logerrstr("%s: Unable to kill running daemon, exiting", av[0]); 222 exit(1); 223 } 224 } 225 daemon(0, 0); 226 } else if (check_pid() != 0) { 227 logerrstr("%s: A background dntpd is running, you must kill it first", 228 av[0]); 229 exit(1); 230 } 231 if (debug_opt == 0) { 232 log_stderr = 0; 233 set_pid(av[0]); 234 signal(SIGINT, sigint_handler); 235 logdebug(0, "dntpd version %s started\n", DNTPD_VERSION); 236 } 237 238 /* 239 * And go. 240 */ 241 sysntp_clear_alternative_corrections(); 242 client_init(); 243 rc = client_main(servers, nservers); 244 return(rc); 245 } 246 247 static 248 void 249 usage(const char *av0) 250 { 251 fprintf(stderr, "%s [-dnqstFSQ] [-f config_file] [-l log_level] [-T poll_interval] [-L poll_limit] [additional_targets]\n", av0); 252 fprintf(stderr, 253 "\t-d\tDebugging mode, implies -F, -l 99, and logs to stderr\n" 254 "\t-f file\tSpecify the config file (/etc/dntpd.conf)\n" 255 "\t-l int\tSet log level (0-4), default 1\n" 256 "\t-n\tNo-update mode. No offset or frequency corrections are made\n" 257 "\t-q\tQuiet-mode, same as -L 0\n" 258 "\t-s\tSet the time immediately on startup\n" 259 "\t-t\tTest mode, implies -F, -l 99, -n, logs to stderr\n" 260 "\t-F\tRun in foreground (log still goes to syslog)\n" 261 "\t-L int\tMaximum polling interval\n" 262 "\t-S\tDo not set the time immediately on startup\n" 263 "\t-T int\tNominal polling interval\n" 264 "\t-Q\tTerminate any running background daemon\n" 265 "\n" 266 "\t\tNOTE: in debug and test modes -f must be specified if\n" 267 "\t\tyou want to use a config file.\n" 268 ); 269 exit(1); 270 } 271 272 static 273 void 274 dotest(const char *target) 275 { 276 struct server_info info; 277 278 bzero(&info, sizeof(info)); 279 info.fd = udp_socket(target, 123); 280 if (info.fd < 0) { 281 logerrstr("unable to create UDP socket for %s", target); 282 return; 283 } 284 info.target = strdup(target); 285 client_init(); 286 287 fprintf(stderr, 288 "Will run %d-second polls until interrupted.\n", nom_sleep_opt); 289 290 for (;;) { 291 client_poll(&info, nom_sleep_opt, 1); 292 sleep(nom_sleep_opt); 293 } 294 /* not reached */ 295 } 296 297 static void 298 add_server(const char *target) 299 { 300 server_info_t info; 301 302 if (nservers == maxservers) { 303 maxservers += 16; 304 servers = realloc(servers, maxservers * sizeof(server_info_t)); 305 assert(servers != NULL); 306 } 307 info = malloc(sizeof(struct server_info)); 308 servers[nservers] = info; 309 bzero(info, sizeof(struct server_info)); 310 info->fd = udp_socket(target, 123); 311 if (info->fd < 0) { 312 logerrstr("Unable to add server %s", target); 313 } else { 314 info->target = strdup(target); 315 ++nservers; 316 } 317 } 318 319 static void 320 process_config_file(const char *path) 321 { 322 const char *ws = " \t\r\n"; 323 char buf[1024]; 324 char *keyword; 325 char *data; 326 int line; 327 FILE *fi; 328 329 if ((fi = fopen(path, "r")) != NULL) { 330 line = 1; 331 while (fgets(buf, sizeof(buf), fi) != NULL) { 332 if (strchr(buf, '#')) 333 *strchr(buf, '#') = 0; 334 if ((keyword = strtok(buf, ws)) != NULL) { 335 data = strtok(NULL, ws); 336 if (strcmp(keyword, "server") == 0) { 337 if (data == NULL) { 338 logerr("%s:%d server missing host specification", 339 path, line); 340 } else { 341 add_server(data); 342 } 343 } else { 344 logerr("%s:%d unknown keyword %s", path, line, keyword); 345 } 346 } 347 ++line; 348 } 349 fclose(fi); 350 } else { 351 logerr("Unable to open %s", path); 352 exit(1); 353 } 354 } 355 356 static 357 pid_t 358 check_pid(void) 359 { 360 char buf[32]; 361 pid_t pid; 362 FILE *fi; 363 364 pid = 0; 365 if ((fi = fopen(pid_opt, "r")) != NULL) { 366 if (fgets(buf, sizeof(buf), fi) != NULL) { 367 pid = strtol(buf, NULL, 0); 368 if (kill(pid, 0) != 0) 369 pid = 0; 370 } 371 fclose(fi); 372 } 373 return(pid); 374 } 375 376 static 377 void 378 set_pid(const char *av0) 379 { 380 pid_t pid; 381 FILE *fo; 382 383 pid = getpid(); 384 if ((fo = fopen(pid_opt, "w")) != NULL) { 385 fprintf(fo, "%d\n", (int)pid); 386 fclose(fo); 387 } else { 388 logerr("%s: Unable to create %s, continuing anyway.", av0, pid_opt); 389 } 390 } 391 392 static 393 void 394 sigint_handler(int signo __unused) 395 { 396 remove(pid_opt); 397 /* dangerous, but we are exiting anyway so pray... */ 398 logdebug(0, "dntpd version %s stopped\n", DNTPD_VERSION); 399 exit(0); 400 } 401 402