watchdogd.c revision 117185
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: head/usr.sbin/watchdogd/watchdogd.c 117185 2003-07-03 03:37:04Z smkelly $"); 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 47static void parseargs(int, char *[]); 48static void sighandler(int); 49static void watchdog_loop(void); 50static int watchdog_init(void); 51static int watchdog_onoff(int onoff); 52static int watchdog_tickle(void); 53static void usage(void); 54 55int debugging = 0; 56int end_program = 0; 57const char *pidfile = _PATH_VARRUN "watchdogd.pid"; 58int reset_mib[3]; 59size_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 */ 65int 66main(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 */ 113static void 114sighandler(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 */ 125static int 126watchdog_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 */ 142static void 143watchdog_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 */ 163int 164watchdog_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 */ 174static int 175watchdog_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 */ 198static void 199usage() 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 */ 208static void 209parseargs(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