1 /* $OpenBSD: watchdogd.c,v 1.12 2008/05/12 19:15:02 pyr Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Marc Balmer <mbalmer@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/sysctl.h> 21 #include <sys/mman.h> 22 23 #include <err.h> 24 #include <errno.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <unistd.h> 28 29 volatile sig_atomic_t quit = 0; 30 31 __dead void usage(void); 32 void sighdlr(int); 33 int main(int, char *[]); 34 35 __dead void 36 usage(void) 37 { 38 extern char *__progname; 39 40 fprintf(stderr, "usage: %s [-dnq] [-i interval] [-p period]\n", 41 __progname); 42 exit(1); 43 } 44 45 /* ARGSUSED */ 46 void 47 sighdlr(int signum) 48 { 49 quit = 1; 50 } 51 52 int 53 main(int argc, char *argv[]) 54 { 55 const char *errstr; 56 size_t len; 57 u_int interval = 0, period = 30, nperiod; 58 int ch, trigauto, sauto, speriod; 59 int quiet = 0, daemonize = 1, retval = 1, do_restore = 1; 60 int mib[3]; 61 62 while ((ch = getopt(argc, argv, "di:np:q")) != -1) { 63 switch (ch) { 64 case 'd': 65 daemonize = 0; 66 break; 67 case 'i': 68 interval = (u_int)strtonum(optarg, 1LL, 86400LL, 69 &errstr); 70 if (errstr) 71 errx(1, "interval is %s: %s", errstr, optarg); 72 break; 73 case 'n': 74 do_restore = 0; 75 break; 76 case 'p': 77 period = (u_int)strtonum(optarg, 2LL, 86400LL, &errstr); 78 if (errstr) 79 errx(1, "period is %s: %s", errstr, optarg); 80 break; 81 case 'q': 82 quiet = 1; 83 break; 84 default: 85 usage(); 86 } 87 } 88 89 argc -= optind; 90 argv += optind; 91 if (argc > 0) 92 usage(); 93 94 if (interval == 0 && (interval = period / 3) == 0) 95 interval = 1; 96 97 if (period <= interval) 98 errx(1, "retrigger interval too long"); 99 100 /* save kern.watchdog.period and kern.watchdog.auto for restore */ 101 mib[0] = CTL_KERN; 102 mib[1] = KERN_WATCHDOG; 103 mib[2] = KERN_WATCHDOG_PERIOD; 104 105 len = sizeof(speriod); 106 if (sysctl(mib, 3, &speriod, &len, &period, sizeof(period)) == -1) { 107 if (errno == EOPNOTSUPP) 108 errx(1, "no watchdog timer available"); 109 else 110 err(1, "can't access kern.watchdog.period"); 111 } 112 113 mib[2] = KERN_WATCHDOG_AUTO; 114 len = sizeof(sauto); 115 trigauto = 0; 116 117 if (sysctl(mib, 3, &sauto, &len, &trigauto, sizeof(trigauto)) == -1) 118 err(1, "can't access kern.watchdog.auto"); 119 120 /* Double check the timeout period, some devices change the value */ 121 mib[2] = KERN_WATCHDOG_PERIOD; 122 len = sizeof(nperiod); 123 if (sysctl(mib, 3, &nperiod, &len, NULL, 0) == -1) { 124 warnx("can't read back kern.watchdog.period, " 125 "restoring original values"); 126 goto restore; 127 } 128 129 if (nperiod != period && !quiet) 130 warnx("period adjusted to %d by device", nperiod); 131 132 if (nperiod <= interval) { 133 warnx("retrigger interval %d too long, " 134 "restoring original values", interval); 135 goto restore; 136 } 137 138 if (daemonize && daemon(0, 0)) { 139 warn("can't daemonize, restoring original values"); 140 goto restore; 141 } 142 143 (void)mlockall(MCL_CURRENT | MCL_FUTURE); 144 setpriority(PRIO_PROCESS, getpid(), -5); 145 146 signal(SIGTERM, sighdlr); 147 148 retval = 0; 149 while (!quit) { 150 if (sysctl(mib, 3, NULL, 0, &period, sizeof(period)) == -1) 151 quit = retval = 1; 152 sleep(interval); 153 } 154 155 if (do_restore) { 156 restore: sysctl(mib, 3, NULL, 0, &speriod, sizeof(speriod)); 157 mib[2] = KERN_WATCHDOG_AUTO; 158 sysctl(mib, 3, NULL, 0, &sauto, sizeof(sauto)); 159 } 160 161 return retval; 162 } 163