1 /*- 2 * Copyright (c) 2003-2004 Sean M. Kelly <smkelly@FreeBSD.org> 3 * Copyright (c) 2013 iXsystems.com, 4 * author: Alfred Perlstein <alfred@freebsd.org> 5 * 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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 the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * Software watchdog daemon. 32 */ 33 34 #include <sys/types.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/mman.h> 38 #include <sys/param.h> 39 #include <sys/rtprio.h> 40 #include <sys/stat.h> 41 #include <sys/time.h> 42 #include <sys/sysctl.h> 43 #include <sys/watchdog.h> 44 45 #include <err.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <libutil.h> 49 #include <math.h> 50 #include <paths.h> 51 #include <signal.h> 52 #include <stdio.h> 53 #include <stdint.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <strings.h> 57 #include <sysexits.h> 58 #include <syslog.h> 59 #include <unistd.h> 60 61 #include <getopt.h> 62 63 static long fetchtimeout(int opt, 64 const char *longopt, const char *myoptarg, int zero_ok); 65 static void parseargs(int, char *[]); 66 static int seconds_to_pow2ns(int); 67 static void sighandler(int); 68 static void watchdog_loop(void); 69 static int watchdog_init(void); 70 static int watchdog_onoff(int onoff); 71 static int watchdog_patpat(u_int timeout); 72 static void usage(void); 73 static int tstotv(struct timeval *tv, struct timespec *ts); 74 static int tvtohz(struct timeval *tv); 75 76 static int debugging = 0; 77 static int end_program = 0; 78 static const char *pidfile = _PATH_VARRUN "watchdogd.pid"; 79 static u_int timeout = WD_TO_128SEC; 80 static u_int exit_timeout = WD_TO_NEVER; 81 static u_int pretimeout = 0; 82 static u_int timeout_sec; 83 static u_int passive = 0; 84 static int is_daemon = 0; 85 static int is_dry_run = 0; /* do not arm the watchdog, only 86 report on timing of the watch 87 program */ 88 static int do_timedog = 0; 89 static int do_syslog = 1; 90 static int fd = -1; 91 static int nap = 10; 92 static int carp_thresh_seconds = -1; 93 static char *test_cmd = NULL; 94 95 static const char *getopt_shortopts; 96 97 static int pretimeout_set; 98 static int pretimeout_act; 99 static int pretimeout_act_set; 100 101 static int softtimeout_set; 102 static int softtimeout_act; 103 static int softtimeout_act_set; 104 105 static struct option longopts[] = { 106 { "debug", no_argument, &debugging, 1 }, 107 { "pretimeout", required_argument, &pretimeout_set, 1 }, 108 { "pretimeout-action", required_argument, &pretimeout_act_set, 1 }, 109 { "softtimeout", no_argument, &softtimeout_set, 1 }, 110 { "softtimeout-action", required_argument, &softtimeout_act_set, 1 }, 111 { NULL, 0, NULL, 0} 112 }; 113 114 /* 115 * Ask malloc() to map minimum-sized chunks of virtual address space at a time, 116 * so that mlockall() won't needlessly wire megabytes of unused memory into the 117 * process. This must be done using the malloc_conf string so that it gets set 118 * up before the first allocation, which happens before entry to main(). 119 */ 120 const char * malloc_conf = "lg_chunk:0"; 121 122 /* 123 * Periodically pat the watchdog, preventing it from firing. 124 */ 125 int 126 main(int argc, char *argv[]) 127 { 128 struct rtprio rtp; 129 struct pidfh *pfh; 130 pid_t otherpid; 131 132 if (getuid() != 0) 133 errx(EX_SOFTWARE, "not super user"); 134 135 parseargs(argc, argv); 136 137 if (do_syslog) 138 openlog("watchdogd", LOG_CONS|LOG_NDELAY|LOG_PERROR, 139 LOG_DAEMON); 140 141 rtp.type = RTP_PRIO_REALTIME; 142 rtp.prio = 0; 143 if (rtprio(RTP_SET, 0, &rtp) == -1) 144 err(EX_OSERR, "rtprio"); 145 146 if (!is_dry_run && watchdog_init() == -1) 147 errx(EX_SOFTWARE, "unable to initialize watchdog"); 148 149 if (is_daemon) { 150 if (watchdog_onoff(1) == -1) 151 err(EX_OSERR, "patting the dog"); 152 153 pfh = pidfile_open(pidfile, 0600, &otherpid); 154 if (pfh == NULL) { 155 if (errno == EEXIST) { 156 watchdog_onoff(0); 157 errx(EX_SOFTWARE, "%s already running, pid: %d", 158 getprogname(), otherpid); 159 } 160 warn("Cannot open or create pidfile"); 161 } 162 163 if (debugging == 0 && daemon(0, 0) == -1) { 164 watchdog_onoff(0); 165 pidfile_remove(pfh); 166 err(EX_OSERR, "daemon"); 167 } 168 169 signal(SIGHUP, SIG_IGN); 170 signal(SIGINT, sighandler); 171 signal(SIGTERM, sighandler); 172 173 pidfile_write(pfh); 174 if (madvise(0, 0, MADV_PROTECT) != 0) 175 warn("madvise failed"); 176 if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) 177 warn("mlockall failed"); 178 179 watchdog_loop(); 180 181 /* exiting */ 182 pidfile_remove(pfh); 183 return (EX_OK); 184 } else { 185 if (passive) 186 timeout |= WD_PASSIVE; 187 else 188 timeout |= WD_ACTIVE; 189 if (watchdog_patpat(timeout) < 0) 190 err(EX_OSERR, "patting the dog"); 191 return (EX_OK); 192 } 193 } 194 195 static void 196 pow2ns_to_ts(int pow2ns, struct timespec *ts) 197 { 198 uint64_t ns; 199 200 ns = 1ULL << pow2ns; 201 ts->tv_sec = ns / 1000000000ULL; 202 ts->tv_nsec = ns % 1000000000ULL; 203 } 204 205 /* 206 * Convert a timeout in seconds to N where 2^N nanoseconds is close to 207 * "seconds". 208 * 209 * The kernel expects the timeouts for watchdogs in "2^N nanosecond format". 210 */ 211 static u_int 212 parse_timeout_to_pow2ns(char opt, const char *longopt, const char *myoptarg) 213 { 214 double a; 215 u_int rv; 216 struct timespec ts; 217 struct timeval tv; 218 int ticks; 219 char shortopt[] = "- "; 220 221 if (!longopt) 222 shortopt[1] = opt; 223 224 a = fetchtimeout(opt, longopt, myoptarg, 1); 225 226 if (a == 0) 227 rv = WD_TO_NEVER; 228 else 229 rv = seconds_to_pow2ns(a); 230 pow2ns_to_ts(rv, &ts); 231 tstotv(&tv, &ts); 232 ticks = tvtohz(&tv); 233 if (debugging) { 234 printf("Timeout for %s%s " 235 "is 2^%d nanoseconds " 236 "(in: %s sec -> out: %jd sec %ld ns -> %d ticks)\n", 237 longopt ? "-" : "", longopt ? longopt : shortopt, 238 rv, 239 myoptarg, (intmax_t)ts.tv_sec, ts.tv_nsec, ticks); 240 } 241 if (ticks <= 0) { 242 errx(1, "Timeout for %s%s is too small, please choose a higher timeout.", longopt ? "-" : "", longopt ? longopt : shortopt); 243 } 244 245 return (rv); 246 } 247 248 /* 249 * Catch signals and begin shutdown process. 250 */ 251 static void 252 sighandler(int signum) 253 { 254 255 if (signum == SIGINT || signum == SIGTERM) 256 end_program = 1; 257 } 258 259 /* 260 * Open the watchdog device. 261 */ 262 static int 263 watchdog_init(void) 264 { 265 266 if (is_dry_run) 267 return 0; 268 269 fd = open("/dev/" _PATH_WATCHDOG, O_RDWR); 270 if (fd >= 0) 271 return (0); 272 warn("Could not open watchdog device"); 273 return (-1); 274 } 275 276 /* 277 * If we are doing timing, then get the time. 278 */ 279 static int 280 watchdog_getuptime(struct timespec *tp) 281 { 282 int error; 283 284 if (!do_timedog) 285 return 0; 286 287 error = clock_gettime(CLOCK_UPTIME_FAST, tp); 288 if (error) 289 warn("clock_gettime"); 290 return (error); 291 } 292 293 static long 294 watchdog_check_dogfunction_time(struct timespec *tp_start, 295 struct timespec *tp_end) 296 { 297 struct timeval tv_start, tv_end, tv_now, tv; 298 const char *cmd_prefix, *cmd; 299 struct timespec tp_now; 300 int sec; 301 302 if (!do_timedog) 303 return (0); 304 305 TIMESPEC_TO_TIMEVAL(&tv_start, tp_start); 306 TIMESPEC_TO_TIMEVAL(&tv_end, tp_end); 307 timersub(&tv_end, &tv_start, &tv); 308 sec = tv.tv_sec; 309 if (sec < carp_thresh_seconds) 310 return (sec); 311 312 if (test_cmd) { 313 cmd_prefix = "Watchdog program"; 314 cmd = test_cmd; 315 } else { 316 cmd_prefix = "Watchdog operation"; 317 cmd = "stat(\"/etc\", &sb)"; 318 } 319 if (do_syslog) 320 syslog(LOG_CRIT, "%s: '%s' took too long: " 321 "%d.%06ld seconds >= %d seconds threshold", 322 cmd_prefix, cmd, sec, (long)tv.tv_usec, 323 carp_thresh_seconds); 324 else 325 warnx("%s: '%s' took too long: " 326 "%d.%06ld seconds >= %d seconds threshold", 327 cmd_prefix, cmd, sec, (long)tv.tv_usec, 328 carp_thresh_seconds); 329 330 /* 331 * Adjust the sleep interval again in case syslog(3) took a non-trivial 332 * amount of time to run. 333 */ 334 if (watchdog_getuptime(&tp_now)) 335 return (sec); 336 TIMESPEC_TO_TIMEVAL(&tv_now, &tp_now); 337 timersub(&tv_now, &tv_start, &tv); 338 sec = tv.tv_sec; 339 340 return (sec); 341 } 342 343 /* 344 * Main program loop which is iterated every second. 345 */ 346 static void 347 watchdog_loop(void) 348 { 349 struct timespec ts_start, ts_end; 350 struct stat sb; 351 long waited; 352 int error, failed; 353 354 while (end_program != 2) { 355 failed = 0; 356 357 error = watchdog_getuptime(&ts_start); 358 if (error) { 359 end_program = 1; 360 goto try_end; 361 } 362 363 if (test_cmd != NULL) 364 failed = system(test_cmd); 365 else 366 failed = stat("/etc", &sb); 367 368 error = watchdog_getuptime(&ts_end); 369 if (error) { 370 end_program = 1; 371 goto try_end; 372 } 373 374 if (failed == 0) 375 watchdog_patpat(timeout|WD_ACTIVE); 376 377 waited = watchdog_check_dogfunction_time(&ts_start, &ts_end); 378 if (nap - waited > 0) 379 sleep(nap - waited); 380 381 try_end: 382 if (end_program != 0) { 383 if (watchdog_onoff(0) == 0) { 384 end_program = 2; 385 } else { 386 warnx("Could not stop the watchdog, not exiting"); 387 end_program = 0; 388 } 389 } 390 } 391 } 392 393 /* 394 * Reset the watchdog timer. This function must be called periodically 395 * to keep the watchdog from firing. 396 */ 397 static int 398 watchdog_patpat(u_int t) 399 { 400 401 if (is_dry_run) 402 return 0; 403 404 return ioctl(fd, WDIOCPATPAT, &t); 405 } 406 407 /* 408 * Toggle the kernel's watchdog. This routine is used to enable and 409 * disable the watchdog. 410 */ 411 static int 412 watchdog_onoff(int onoff) 413 { 414 int error; 415 416 /* fake successful watchdog op if a dry run */ 417 if (is_dry_run) 418 return 0; 419 420 if (onoff) { 421 /* 422 * Call the WDIOC_SETSOFT regardless of softtimeout_set 423 * because we'll need to turn it off if someone had turned 424 * it on. 425 */ 426 error = ioctl(fd, WDIOC_SETSOFT, &softtimeout_set); 427 if (error) { 428 warn("setting WDIOC_SETSOFT %d", softtimeout_set); 429 return (error); 430 } 431 error = watchdog_patpat((timeout|WD_ACTIVE)); 432 if (error) { 433 warn("watchdog_patpat failed"); 434 goto failsafe; 435 } 436 if (softtimeout_act_set) { 437 error = ioctl(fd, WDIOC_SETSOFTTIMEOUTACT, 438 &softtimeout_act); 439 if (error) { 440 warn("setting WDIOC_SETSOFTTIMEOUTACT %d", 441 softtimeout_act); 442 goto failsafe; 443 } 444 } 445 if (pretimeout_set) { 446 error = ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout); 447 if (error) { 448 warn("setting WDIOC_SETPRETIMEOUT %d", 449 pretimeout); 450 goto failsafe; 451 } 452 } 453 if (pretimeout_act_set) { 454 error = ioctl(fd, WDIOC_SETPRETIMEOUTACT, 455 &pretimeout_act); 456 if (error) { 457 warn("setting WDIOC_SETPRETIMEOUTACT %d", 458 pretimeout_act); 459 goto failsafe; 460 } 461 } 462 /* pat one more time for good measure */ 463 return watchdog_patpat((timeout|WD_ACTIVE)); 464 } else { 465 return watchdog_patpat(exit_timeout); 466 } 467 failsafe: 468 watchdog_patpat(exit_timeout); 469 return (error); 470 } 471 472 /* 473 * Tell user how to use the program. 474 */ 475 static void 476 usage(void) 477 { 478 if (is_daemon) 479 fprintf(stderr, "usage:\n" 480 " watchdogd [-dnSw] [-e cmd] [-I pidfile] [-s sleep] [-t timeout]\n" 481 " [-T script_timeout] [-x exit_timeout]\n" 482 " [--debug]\n" 483 " [--pretimeout seconds] [-pretimeout-action action]\n" 484 " [--softtimeout] [-softtimeout-action action]\n" 485 ); 486 else 487 fprintf(stderr, "usage: watchdog [-d] [-t timeout]\n"); 488 exit(EX_USAGE); 489 } 490 491 static long 492 fetchtimeout(int opt, const char *longopt, const char *myoptarg, int zero_ok) 493 { 494 const char *errstr; 495 char *p; 496 long rv; 497 498 errstr = NULL; 499 p = NULL; 500 errno = 0; 501 rv = strtol(myoptarg, &p, 0); 502 if ((p != NULL && *p != '\0') || errno != 0) 503 errstr = "is not a number"; 504 if (rv < 0 || (!zero_ok && rv == 0)) 505 errstr = "must be greater than zero"; 506 if (errstr) { 507 if (longopt) 508 errx(EX_USAGE, "--%s argument %s", longopt, errstr); 509 else 510 errx(EX_USAGE, "-%c argument %s", opt, errstr); 511 } 512 return (rv); 513 } 514 515 struct act_tbl { 516 const char *at_act; 517 int at_value; 518 }; 519 520 static const struct act_tbl act_tbl[] = { 521 { "panic", WD_SOFT_PANIC }, 522 { "ddb", WD_SOFT_DDB }, 523 { "log", WD_SOFT_LOG }, 524 { "printf", WD_SOFT_PRINTF }, 525 { NULL, 0 } 526 }; 527 528 static void 529 timeout_act_error(const char *lopt, const char *badact) 530 { 531 char *opts, *oldopts; 532 int i; 533 534 opts = NULL; 535 for (i = 0; act_tbl[i].at_act != NULL; i++) { 536 oldopts = opts; 537 if (asprintf(&opts, "%s%s%s", 538 oldopts == NULL ? "" : oldopts, 539 oldopts == NULL ? "" : ", ", 540 act_tbl[i].at_act) == -1) 541 err(EX_OSERR, "malloc"); 542 free(oldopts); 543 } 544 warnx("bad --%s argument '%s' must be one of (%s).", 545 lopt, badact, opts); 546 usage(); 547 } 548 549 /* 550 * Take a comma separated list of actions and or the flags 551 * together for the ioctl. 552 */ 553 static int 554 timeout_act_str2int(const char *lopt, const char *acts) 555 { 556 int i; 557 char *dupacts, *tofree; 558 char *o; 559 int rv = 0; 560 561 tofree = dupacts = strdup(acts); 562 if (!tofree) 563 err(EX_OSERR, "malloc"); 564 while ((o = strsep(&dupacts, ",")) != NULL) { 565 for (i = 0; act_tbl[i].at_act != NULL; i++) { 566 if (!strcmp(o, act_tbl[i].at_act)) { 567 rv |= act_tbl[i].at_value; 568 break; 569 } 570 } 571 if (act_tbl[i].at_act == NULL) 572 timeout_act_error(lopt, o); 573 } 574 free(tofree); 575 return rv; 576 } 577 578 int 579 tstotv(struct timeval *tv, struct timespec *ts) 580 { 581 582 tv->tv_sec = ts->tv_sec; 583 tv->tv_usec = ts->tv_nsec / 1000; 584 return 0; 585 } 586 587 /* 588 * Convert a timeval to a number of ticks. 589 * Mostly copied from the kernel. 590 */ 591 int 592 tvtohz(struct timeval *tv) 593 { 594 register unsigned long ticks; 595 register long sec, usec; 596 int hz; 597 size_t hzsize; 598 int error; 599 int tick; 600 601 hzsize = sizeof(hz); 602 603 error = sysctlbyname("kern.hz", &hz, &hzsize, NULL, 0); 604 if (error) 605 err(1, "sysctlbyname kern.hz"); 606 607 tick = 1000000 / hz; 608 609 /* 610 * If the number of usecs in the whole seconds part of the time 611 * difference fits in a long, then the total number of usecs will 612 * fit in an unsigned long. Compute the total and convert it to 613 * ticks, rounding up and adding 1 to allow for the current tick 614 * to expire. Rounding also depends on unsigned long arithmetic 615 * to avoid overflow. 616 * 617 * Otherwise, if the number of ticks in the whole seconds part of 618 * the time difference fits in a long, then convert the parts to 619 * ticks separately and add, using similar rounding methods and 620 * overflow avoidance. This method would work in the previous 621 * case but it is slightly slower and assumes that hz is integral. 622 * 623 * Otherwise, round the time difference down to the maximum 624 * representable value. 625 * 626 * If ints have 32 bits, then the maximum value for any timeout in 627 * 10ms ticks is 248 days. 628 */ 629 sec = tv->tv_sec; 630 usec = tv->tv_usec; 631 if (usec < 0) { 632 sec--; 633 usec += 1000000; 634 } 635 if (sec < 0) { 636 #ifdef DIAGNOSTIC 637 if (usec > 0) { 638 sec++; 639 usec -= 1000000; 640 } 641 printf("tvotohz: negative time difference %ld sec %ld usec\n", 642 sec, usec); 643 #endif 644 ticks = 1; 645 } else if (sec <= LONG_MAX / 1000000) 646 ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1)) 647 / tick + 1; 648 else if (sec <= LONG_MAX / hz) 649 ticks = sec * hz 650 + ((unsigned long)usec + (tick - 1)) / tick + 1; 651 else 652 ticks = LONG_MAX; 653 if (ticks > INT_MAX) 654 ticks = INT_MAX; 655 return ((int)ticks); 656 } 657 658 static int 659 seconds_to_pow2ns(int seconds) 660 { 661 uint64_t power; 662 uint64_t ns; 663 uint64_t shifted; 664 665 if (seconds <= 0) 666 errx(1, "seconds %d < 0", seconds); 667 ns = ((uint64_t)seconds) * 1000000000ULL; 668 power = flsll(ns); 669 shifted = 1ULL << power; 670 if (shifted <= ns) { 671 power++; 672 } 673 if (debugging) { 674 printf("shifted %lld\n", (long long)shifted); 675 printf("seconds_to_pow2ns: seconds: %d, ns %lld, power %d\n", 676 seconds, (long long)ns, (int)power); 677 } 678 return (power); 679 } 680 681 682 /* 683 * Handle the few command line arguments supported. 684 */ 685 static void 686 parseargs(int argc, char *argv[]) 687 { 688 int longindex; 689 int c; 690 const char *lopt; 691 692 /* 693 * if we end with a 'd' aka 'watchdogd' then we are the daemon program, 694 * otherwise run as a command line utility. 695 */ 696 c = strlen(argv[0]); 697 if (argv[0][c - 1] == 'd') 698 is_daemon = 1; 699 700 if (is_daemon) 701 getopt_shortopts = "I:de:ns:t:ST:wx:?"; 702 else 703 getopt_shortopts = "dt:?"; 704 705 while ((c = getopt_long(argc, argv, getopt_shortopts, longopts, 706 &longindex)) != -1) { 707 switch (c) { 708 case 'I': 709 pidfile = optarg; 710 break; 711 case 'd': 712 debugging = 1; 713 break; 714 case 'e': 715 test_cmd = strdup(optarg); 716 break; 717 case 'n': 718 is_dry_run = 1; 719 break; 720 #ifdef notyet 721 case 'p': 722 passive = 1; 723 break; 724 #endif 725 case 's': 726 nap = fetchtimeout(c, NULL, optarg, 0); 727 break; 728 case 'S': 729 do_syslog = 0; 730 break; 731 case 't': 732 timeout_sec = atoi(optarg); 733 timeout = parse_timeout_to_pow2ns(c, NULL, optarg); 734 if (debugging) 735 printf("Timeout is 2^%d nanoseconds\n", 736 timeout); 737 break; 738 case 'T': 739 carp_thresh_seconds = 740 fetchtimeout(c, "NULL", optarg, 0); 741 break; 742 case 'w': 743 do_timedog = 1; 744 break; 745 case 'x': 746 exit_timeout = parse_timeout_to_pow2ns(c, NULL, optarg); 747 if (exit_timeout != 0) 748 exit_timeout |= WD_ACTIVE; 749 break; 750 case 0: 751 lopt = longopts[longindex].name; 752 if (!strcmp(lopt, "pretimeout")) { 753 pretimeout = fetchtimeout(0, lopt, optarg, 0); 754 } else if (!strcmp(lopt, "pretimeout-action")) { 755 pretimeout_act = timeout_act_str2int(lopt, 756 optarg); 757 } else if (!strcmp(lopt, "softtimeout-action")) { 758 softtimeout_act = timeout_act_str2int(lopt, 759 optarg); 760 } else { 761 /* warnx("bad option at index %d: %s", optind, 762 argv[optind]); 763 usage(); 764 */ 765 } 766 break; 767 case '?': 768 default: 769 usage(); 770 /* NOTREACHED */ 771 } 772 } 773 774 if (carp_thresh_seconds == -1) 775 carp_thresh_seconds = nap; 776 777 if (argc != optind) 778 errx(EX_USAGE, "extra arguments."); 779 if (is_daemon && timeout < WD_TO_1SEC) 780 errx(EX_USAGE, "-t argument is less than one second."); 781 if (pretimeout_set) { 782 struct timespec ts; 783 784 pow2ns_to_ts(timeout, &ts); 785 if (pretimeout >= (uintmax_t)ts.tv_sec) { 786 errx(EX_USAGE, 787 "pretimeout (%d) >= timeout (%d -> %ld)\n" 788 "see manual section TIMEOUT RESOLUTION", 789 pretimeout, timeout_sec, (long)ts.tv_sec); 790 } 791 } 792 } 793