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