static int pow2ns_to_ticks(int pow2ns) { struct timeval tv; struct timespec ts; pow2ns_to_ts(pow2ns, &ts); TIMESPEC_TO_TIMEVAL(&tv, &ts); return (tvtohz(&tv)); }
/* * Called to manage timeouts. * newtimeout needs to be in the range of 0 to actual watchdog timeout. * if 0, we disable the pre-timeout. * otherwise we set the pre-timeout provided it's not greater than the * current actual watchdog timeout. */ static int wd_set_pretimeout(int newtimeout, int disableiftoolong) { u_int utime; struct timespec utime_ts; int timeout_ticks; utime = wdog_kern_last_timeout(); pow2ns_to_ts(utime, &utime_ts); /* do not permit a pre-timeout >= than the timeout. */ if (newtimeout >= utime_ts.tv_sec) { /* * If 'disableiftoolong' then just fall through * so as to disable the pre-watchdog */ if (disableiftoolong) newtimeout = 0; else return EINVAL; } /* disable the pre-timeout */ if (newtimeout == 0) { wd_pretimeout = 0; callout_stop(&wd_pretimeo_handle); return 0; } timeout_ticks = pow2ns_to_ticks(utime) - (hz*newtimeout); #if 0 printf("wd_set_pretimeout: " "newtimeout: %d, " "utime: %d -> utime_ticks: %d, " "hz*newtimeout: %d, " "timeout_ticks: %d -> sec: %d\n", newtimeout, utime, pow2ns_to_ticks(utime), hz*newtimeout, timeout_ticks, timeout_ticks / hz); #endif /* We determined the value is sane, so reset the callout */ (void) callout_reset(&wd_pretimeo_handle, timeout_ticks, wd_timeout_cb, "pre-timeout"); wd_pretimeout = newtimeout; return 0; }
/* * Convert a timeout in seconds to N where 2^N nanoseconds is close to * "seconds". * * The kernel expects the timeouts for watchdogs in "2^N nanosecond format". */ static u_int parse_timeout_to_pow2ns(char opt, const char *longopt, const char *myoptarg) { double a; u_int rv; struct timespec ts; struct timeval tv; int ticks; char shortopt[] = "- "; if (!longopt) shortopt[1] = opt; a = fetchtimeout(opt, longopt, myoptarg, 1); if (a == 0) rv = WD_TO_NEVER; else rv = seconds_to_pow2ns(a); pow2ns_to_ts(rv, &ts); tstotv(&tv, &ts); ticks = tvtohz(&tv); if (debugging) { printf("Timeout for %s%s " "is 2^%d nanoseconds " "(in: %s sec -> out: %jd sec %ld ns -> %d ticks)\n", longopt ? "-" : "", longopt ? longopt : shortopt, rv, myoptarg, (intmax_t)ts.tv_sec, ts.tv_nsec, ticks); } if (ticks <= 0) { errx(1, "Timeout for %s%s is too small, please choose a higher timeout.", longopt ? "-" : "", longopt ? longopt : shortopt); } return (rv); }
/* * Handle the few command line arguments supported. */ static void parseargs(int argc, char *argv[]) { struct timespec ts; int longindex; int c; const char *lopt; /* Get the default value of timeout_sec from the default timeout. */ pow2ns_to_ts(timeout, &ts); timeout_sec = ts.tv_sec; /* * if we end with a 'd' aka 'watchdogd' then we are the daemon program, * otherwise run as a command line utility. */ c = strlen(argv[0]); if (argv[0][c - 1] == 'd') is_daemon = 1; if (is_daemon) getopt_shortopts = "I:de:ns:t:ST:wx:?"; else getopt_shortopts = "dt:?"; while ((c = getopt_long(argc, argv, getopt_shortopts, longopts, &longindex)) != -1) { switch (c) { case 'I': pidfile = optarg; break; case 'd': debugging = 1; break; case 'e': test_cmd = strdup(optarg); break; case 'n': is_dry_run = 1; break; #ifdef notyet case 'p': passive = 1; break; #endif case 's': nap = fetchtimeout(c, NULL, optarg, 0); break; case 'S': do_syslog = 0; break; case 't': timeout_sec = atoi(optarg); timeout = parse_timeout_to_pow2ns(c, NULL, optarg); if (debugging) printf("Timeout is 2^%d nanoseconds\n", timeout); break; case 'T': carp_thresh_seconds = fetchtimeout(c, "NULL", optarg, 0); break; case 'w': do_timedog = 1; break; case 'x': exit_timeout = parse_timeout_to_pow2ns(c, NULL, optarg); if (exit_timeout != 0) exit_timeout |= WD_ACTIVE; break; case 0: lopt = longopts[longindex].name; if (!strcmp(lopt, "pretimeout")) { pretimeout = fetchtimeout(0, lopt, optarg, 0); } else if (!strcmp(lopt, "pretimeout-action")) { pretimeout_act = timeout_act_str2int(lopt, optarg); } else if (!strcmp(lopt, "softtimeout-action")) { softtimeout_act = timeout_act_str2int(lopt, optarg); } else { /* warnx("bad option at index %d: %s", optind, argv[optind]); usage(); */ } break; case '?': default: usage(); /* NOTREACHED */ } } if (nap > timeout_sec / 2) nap = timeout_sec / 2; if (carp_thresh_seconds == -1) carp_thresh_seconds = nap; if (argc != optind) errx(EX_USAGE, "extra arguments."); if (is_daemon && timeout < WD_TO_1SEC) errx(EX_USAGE, "-t argument is less than one second."); if (pretimeout_set) { if (pretimeout >= timeout_sec) { errx(EX_USAGE, "pretimeout (%d) >= timeout (%d -> %ld)\n" "see manual section TIMEOUT RESOLUTION", pretimeout, timeout_sec, (long)ts.tv_sec); } } }