watchdogd.c revision 116880
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/cdefs.h> 32__FBSDID("$FreeBSD: head/usr.sbin/watchdogd/watchdogd.c 116880 2003-06-26 11:24:10Z maxim $"); 33 34#include <sys/types.h> 35#include <sys/errno.h> 36#include <sys/sysctl.h> 37#include <sys/time.h> 38#include <sys/rtprio.h> 39#include <sys/stat.h> 40 41#include <err.h> 42#include <paths.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <sysexits.h> 47#include <unistd.h> 48#include <signal.h> 49 50static void parseargs(int, char *[]); 51static void sighandler(int); 52static void watchdog_loop(void); 53static int watchdog_init(void); 54static int watchdog_onoff(int onoff); 55static int watchdog_tickle(void); 56static void usage(void); 57 58int debugging = 0; 59int end_program = 0; 60const char *pidfile = _PATH_VARRUN "watchdogd.pid"; 61int reset_mib[3]; 62int reset_miblen = 3; 63 64/* 65 * Periodically write to the debug.watchdog.reset sysctl OID 66 * to keep the software watchdog from firing. 67 */ 68int 69main(int argc, char *argv[]) 70{ 71 struct rtprio rtp; 72 FILE *fp; 73 74 if (getuid() != 0) 75 errx(EX_SOFTWARE, "not super user"); 76 77 parseargs(argc, argv); 78 79 rtp.type = RTP_PRIO_REALTIME; 80 rtp.prio = 0; 81 if (rtprio(RTP_SET, 0, &rtp) == -1) 82 err(EX_OSERR, "rtprio"); 83 84 if (watchdog_init() == -1) 85 exit(EX_SOFTWARE); 86 87 if (watchdog_onoff(1) == -1) 88 exit(EX_SOFTWARE); 89 90 if (debugging == 0 && daemon(0, 0) == -1) { 91 watchdog_onoff(0); 92 err(EX_OSERR, "daemon"); 93 } 94 95 signal(SIGHUP, SIG_IGN); 96 signal(SIGINT, sighandler); 97 signal(SIGTERM, sighandler); 98 99 fp = fopen(pidfile, "w"); 100 if (fp != NULL) { 101 fprintf(fp, "%d\n", getpid()); 102 fclose(fp); 103 } 104 105 watchdog_loop(); 106 107 /* exiting */ 108 watchdog_onoff(0); 109 unlink(pidfile); 110 return (EX_OK); 111} 112 113/* 114 * Catch signals and begin shutdown process. 115 */ 116static void 117sighandler(int signum) 118{ 119 120 if (signum == SIGINT || signum == SIGTERM) 121 end_program = 1; 122} 123 124/* 125 * Locate the OID for the 'debug.watchdog.reset' sysctl setting. 126 * Upon finding it, do an initial reset on the watchdog. 127 */ 128static int 129watchdog_init() 130{ 131 int error; 132 133 error = sysctlnametomib("debug.watchdog.reset", reset_mib, 134 &reset_miblen); 135 if (error == -1) { 136 fprintf(stderr, "Could not find reset OID: %s\n", 137 strerror(errno)); 138 return (error); 139 } 140 return watchdog_tickle(); 141} 142 143/* 144 * Main program loop which is iterated every second. 145 */ 146static void 147watchdog_loop(void) 148{ 149 struct stat sb; 150 int failed; 151 152 while (end_program == 0) { 153 failed = 0; 154 155 failed = stat("/etc", &sb); 156 157 if (failed == 0) 158 watchdog_tickle(); 159 sleep(1); 160 } 161} 162 163/* 164 * Reset the watchdog timer. This function must be called periodically 165 * to keep the watchdog from firing. 166 */ 167int 168watchdog_tickle(void) 169{ 170 171 return sysctl(reset_mib, reset_miblen, NULL, NULL, NULL, 0); 172} 173 174/* 175 * Toggle the kernel's watchdog. This routine is used to enable and 176 * disable the watchdog. 177 */ 178static int 179watchdog_onoff(int onoff) 180{ 181 int mib[3]; 182 int error; 183 int len; 184 185 len = 3; 186 187 error = sysctlnametomib("debug.watchdog.enabled", mib, &len); 188 if (error == 0) 189 error = sysctl(mib, len, NULL, NULL, &onoff, sizeof(onoff)); 190 191 if (error == -1) { 192 fprintf(stderr, "Could not %s watchdog: %s\n", 193 (onoff > 0) ? "enable" : "disable", 194 strerror(errno)); 195 return (error); 196 } 197 return (0); 198} 199 200/* 201 * Tell user how to use the program. 202 */ 203static void 204usage() 205{ 206 fprintf(stderr, "usage: watchdogd [-d] [-I file]\n"); 207 exit(EX_USAGE); 208} 209 210/* 211 * Handle the few command line arguments supported. 212 */ 213static void 214parseargs(int argc, char *argv[]) 215{ 216 int c; 217 218 while ((c = getopt(argc, argv, "I:d?")) != -1) { 219 switch (c) { 220 case 'I': 221 pidfile = optarg; 222 break; 223 case 'd': 224 debugging = 1; 225 break; 226 case '?': 227 default: 228 usage(); 229 /* NOTREACHED */ 230 } 231 } 232} 233