1 /* 2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org> 3 * Copyright (C) 2013 John Crispin <blogic@openwrt.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU Lesser General Public License version 2.1 7 * as published by the Free Software Foundation 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15 #include <linux/watchdog.h> 16 17 #include <sys/ioctl.h> 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <fcntl.h> 21 22 #include <unistd.h> 23 24 #include <libubox/uloop.h> 25 26 #include "procd.h" 27 #include "watchdog.h" 28 29 #define WDT_PATH "/dev/watchdog" 30 31 static struct uloop_timeout wdt_timeout; 32 static int wdt_fd = -1; 33 static int wdt_drv_timeout = 30; 34 static int wdt_frequency = 5; 35 static bool wdt_magicclose = false; 36 37 void watchdog_ping(void) 38 { 39 DEBUG(4, "Ping\n"); 40 if (wdt_fd >= 0 && write(wdt_fd, "X", 1) < 0) 41 ERROR("WDT failed to write: %m\n"); 42 } 43 44 static void watchdog_timeout_cb(struct uloop_timeout *t) 45 { 46 watchdog_ping(); 47 uloop_timeout_set(t, wdt_frequency * 1000); 48 } 49 50 static int watchdog_open(bool cloexec) 51 { 52 char *env = getenv("WDTFD"); 53 54 if (wdt_fd >= 0) 55 return wdt_fd; 56 57 if (env) { 58 DEBUG(2, "Watchdog handover: fd=%s\n", env); 59 wdt_fd = atoi(env); 60 unsetenv("WDTFD"); 61 } else { 62 wdt_fd = open(WDT_PATH, O_WRONLY); 63 } 64 65 if (wdt_fd < 0) 66 return wdt_fd; 67 68 if (cloexec) 69 fcntl(wdt_fd, F_SETFD, fcntl(wdt_fd, F_GETFD) | FD_CLOEXEC); 70 71 return wdt_fd; 72 } 73 74 static void watchdog_close(void) 75 { 76 if (wdt_fd < 0) 77 return; 78 79 if (write(wdt_fd, "V", 1) < 0) 80 ERROR("WDT failed to write release: %m\n"); 81 82 if (close(wdt_fd) == -1) 83 ERROR("WDT failed to close watchdog: %m\n"); 84 85 wdt_fd = -1; 86 } 87 88 static int watchdog_set_drv_timeout(void) 89 { 90 if (wdt_fd < 0) 91 return -1; 92 93 return ioctl(wdt_fd, WDIOC_SETTIMEOUT, &wdt_drv_timeout); 94 } 95 96 static void watchdog_print_status(void) 97 { 98 struct watchdog_info wdt_info; 99 int bootstatus; 100 101 if (wdt_fd < 0) 102 return; 103 104 if (ioctl(wdt_fd, WDIOC_GETSUPPORT, &wdt_info)) { 105 DEBUG(2, "Watchdog GETSUPPORT failed\n"); 106 return; 107 } 108 109 if (!(wdt_info.options & WDIOF_CARDRESET)) { 110 DEBUG(2, "Watchdog does not have CARDRESET support\n"); 111 return; 112 } 113 114 if (ioctl(wdt_fd, WDIOC_GETBOOTSTATUS, &bootstatus)) { 115 DEBUG(2, "Watchdog GETBOOTSTATUS failed\n"); 116 return; 117 } 118 119 if (bootstatus & WDIOF_CARDRESET) 120 LOG("Watchdog has previously reset the system\n"); 121 else 122 DEBUG(2, "Watchdog did not previously reset the system\n"); 123 } 124 125 void watchdog_set_magicclose(bool val) 126 { 127 wdt_magicclose = val; 128 } 129 130 bool watchdog_get_magicclose(void) 131 { 132 return wdt_magicclose; 133 } 134 135 void watchdog_set_stopped(bool val) 136 { 137 if (val) { 138 uloop_timeout_cancel(&wdt_timeout); 139 140 if (wdt_magicclose) 141 watchdog_close(); 142 } 143 else { 144 watchdog_open(true); 145 watchdog_set_drv_timeout(); 146 watchdog_timeout_cb(&wdt_timeout); 147 } 148 } 149 150 bool watchdog_get_stopped(void) 151 { 152 return !wdt_timeout.pending; 153 } 154 155 int watchdog_timeout(int timeout) 156 { 157 if (timeout) { 158 DEBUG(4, "Set watchdog timeout: %ds\n", timeout); 159 wdt_drv_timeout = timeout; 160 161 if (wdt_fd >= 0) 162 watchdog_set_drv_timeout(); 163 } 164 165 return wdt_drv_timeout; 166 } 167 168 int watchdog_frequency(int frequency) 169 { 170 if (frequency) { 171 DEBUG(4, "Set watchdog frequency: %ds\n", frequency); 172 wdt_frequency = frequency; 173 } 174 175 return wdt_frequency; 176 } 177 178 char* watchdog_fd(void) 179 { 180 static char fd_buf[12]; 181 182 if (wdt_fd < 0) 183 return NULL; 184 185 snprintf(fd_buf, sizeof(fd_buf), "%d", wdt_fd); 186 187 return fd_buf; 188 } 189 190 void watchdog_init(int preinit) 191 { 192 wdt_timeout.cb = watchdog_timeout_cb; 193 194 if (watchdog_open(!preinit) < 0) 195 return; 196 197 LOG("- watchdog -\n"); 198 watchdog_set_drv_timeout(); 199 watchdog_timeout_cb(&wdt_timeout); 200 201 DEBUG(4, "Opened watchdog with timeout %ds\n", watchdog_timeout(0)); 202 203 watchdog_print_status(); 204 } 205 206 207 void watchdog_set_cloexec(bool val) 208 { 209 if (wdt_fd < 0) 210 return; 211 212 int flags = fcntl(wdt_fd, F_GETFD); 213 if (val) 214 flags |= FD_CLOEXEC; 215 else 216 flags &= ~FD_CLOEXEC; 217 fcntl(wdt_fd, F_SETFD, flags); 218 } 219
This page was automatically generated by LXR 0.3.1. • OpenWrt