1 /* 2 * Copyright (c) 2003 Sean M. Kelly <smkelly@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * Software watchdog daemon. 29 */ 30 31 #include <sys/types.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/rtprio.h> 35 #include <sys/stat.h> 36 #include <sys/sysctl.h> 37 #include <sys/time.h> 38 39 #include <err.h> 40 #include <paths.h> 41 #include <signal.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <sysexits.h> 45 #include <unistd.h> 46 47 static void parseargs(int, char *[]); 48 static void sighandler(int); 49 static void watchdog_loop(void); 50 static int watchdog_init(void); 51 static int watchdog_onoff(int onoff); 52 static int watchdog_tickle(void); 53 static void usage(void); 54 55 int debugging = 0; 56 int end_program = 0; 57 const char *pidfile = _PATH_VARRUN "watchdogd.pid"; 58 int reset_mib[3]; 59 size_t reset_miblen = 3; 60 61 /* 62 * Periodically write to the debug.watchdog.reset sysctl OID 63 * to keep the software watchdog from firing. 64 */ 65 int 66 main(int argc, char *argv[]) 67 { 68 struct rtprio rtp; 69 FILE *fp; 70 71 if (getuid() != 0) 72 errx(EX_SOFTWARE, "not super user"); 73 74 parseargs(argc, argv); 75 76 rtp.type = RTP_PRIO_REALTIME; 77 rtp.prio = 0; 78 if (rtprio(RTP_SET, 0, &rtp) == -1) 79 err(EX_OSERR, "rtprio"); 80 81 if (watchdog_init() == -1) 82 errx(EX_SOFTWARE, "unable to initialize watchdog"); 83 84 if (watchdog_onoff(1) == -1) 85 exit(EX_SOFTWARE); 86 87 if (debugging == 0 && daemon(0, 0) == -1) { 88 watchdog_onoff(0); 89 err(EX_OSERR, "daemon"); 90 } 91 92 signal(SIGHUP, SIG_IGN); 93 signal(SIGINT, sighandler); 94 signal(SIGTERM, sighandler); 95 96 fp = fopen(pidfile, "w"); 97 if (fp != NULL) { 98 fprintf(fp, "%d\n", getpid()); 99 fclose(fp); 100 } 101 102 watchdog_loop(); 103 104 /* exiting */ 105 watchdog_onoff(0); 106 unlink(pidfile); 107 return (EX_OK); 108 } 109 110 /* 111 * Catch signals and begin shutdown process. 112 */ 113 static void 114 sighandler(int signum) 115 { 116 117 if (signum == SIGINT || signum == SIGTERM) 118 end_program = 1; 119 } 120 121 /* 122 * Locate the OID for the 'debug.watchdog.reset' sysctl setting. 123 * Upon finding it, do an initial reset on the watchdog. 124 */ 125 static int 126 watchdog_init() 127 { 128 int error; 129 130 error = sysctlnametomib("debug.watchdog.reset", reset_mib, 131 &reset_miblen); 132 if (error == -1) { 133 warn("could not find reset OID"); 134 return (error); 135 } 136 return watchdog_tickle(); 137 } 138 139 /* 140 * Main program loop which is iterated every second. 141 */ 142 static void 143 watchdog_loop(void) 144 { 145 struct stat sb; 146 int failed; 147 148 while (end_program == 0) { 149 failed = 0; 150 151 failed = stat("/etc", &sb); 152 153 if (failed == 0) 154 watchdog_tickle(); 155 sleep(1); 156 } 157 } 158 159 /* 160 * Reset the watchdog timer. This function must be called periodically 161 * to keep the watchdog from firing. 162 */ 163 int 164 watchdog_tickle(void) 165 { 166 167 return sysctl(reset_mib, reset_miblen, NULL, NULL, NULL, 0); 168 } 169 170 /* 171 * Toggle the kernel's watchdog. This routine is used to enable and 172 * disable the watchdog. 173 */ 174 static int 175 watchdog_onoff(int onoff) 176 { 177 int mib[3]; 178 int error; 179 size_t len; 180 181 len = 3; 182 183 error = sysctlnametomib("debug.watchdog.enabled", mib, &len); 184 if (error == 0) 185 error = sysctl(mib, len, NULL, NULL, &onoff, sizeof(onoff)); 186 187 if (error == -1) { 188 warn("could not %s watchdog", 189 (onoff > 0) ? "enable" : "disable"); 190 return (error); 191 } 192 return (0); 193 } 194 195 /* 196 * Tell user how to use the program. 197 */ 198 static void 199 usage() 200 { 201 fprintf(stderr, "usage: watchdogd [-d] [-I file]\n"); 202 exit(EX_USAGE); 203 } 204 205 /* 206 * Handle the few command line arguments supported. 207 */ 208 static void 209 parseargs(int argc, char *argv[]) 210 { 211 int c; 212 213 while ((c = getopt(argc, argv, "I:d?")) != -1) { 214 switch (c) { 215 case 'I': 216 pidfile = optarg; 217 break; 218 case 'd': 219 debugging = 1; 220 break; 221 case '?': 222 default: 223 usage(); 224 /* NOTREACHED */ 225 } 226 } 227 } 228