X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=watchdog.c;h=9d770b4470a946ec37cc65d5769445ecd544997b;hb=4625350465744c2446ac0b0dc821699fa1695c81;hp=780b321196def0adcca35ba7de2cdf938d265d98;hpb=056d8ddda8d5236ac94d6897b674291679c05e91;p=project%2Fprocd.git diff --git a/watchdog.c b/watchdog.c index 780b321..9d770b4 100644 --- a/watchdog.c +++ b/watchdog.c @@ -30,13 +30,15 @@ static struct uloop_timeout wdt_timeout; static int wdt_fd = -1; +static int wdt_drv_timeout = 30; static int wdt_frequency = 5; +static bool wdt_magicclose = false; void watchdog_ping(void) { DEBUG(4, "Ping\n"); if (wdt_fd >= 0 && write(wdt_fd, "X", 1) < 0) - ERROR("WDT failed to write: %s\n", strerror(errno)); + ERROR("WDT failed to write: %m\n"); } static void watchdog_timeout_cb(struct uloop_timeout *t) @@ -45,12 +47,75 @@ static void watchdog_timeout_cb(struct uloop_timeout *t) uloop_timeout_set(t, wdt_frequency * 1000); } +static int watchdog_open(bool cloexec) +{ + char *env = getenv("WDTFD"); + + if (wdt_fd >= 0) + return wdt_fd; + + if (env) { + DEBUG(2, "Watchdog handover: fd=%s\n", env); + wdt_fd = atoi(env); + unsetenv("WDTFD"); + } else { + wdt_fd = open(WDT_PATH, O_WRONLY); + } + + if (wdt_fd < 0) + return wdt_fd; + + if (cloexec) + fcntl(wdt_fd, F_SETFD, fcntl(wdt_fd, F_GETFD) | FD_CLOEXEC); + + return wdt_fd; +} + +static void watchdog_close(void) +{ + if (wdt_fd < 0) + return; + + if (write(wdt_fd, "V", 1) < 0) + ERROR("WDT failed to write release: %m\n"); + + if (close(wdt_fd) == -1) + ERROR("WDT failed to close watchdog: %m\n"); + + wdt_fd = -1; +} + +static int watchdog_set_drv_timeout(void) +{ + if (wdt_fd < 0) + return -1; + + return ioctl(wdt_fd, WDIOC_SETTIMEOUT, &wdt_drv_timeout); +} + +void watchdog_set_magicclose(bool val) +{ + wdt_magicclose = val; +} + +bool watchdog_get_magicclose(void) +{ + return wdt_magicclose; +} + void watchdog_set_stopped(bool val) { - if (val) + if (val) { uloop_timeout_cancel(&wdt_timeout); - else + + if (wdt_magicclose) + watchdog_close(); + } + else { + watchdog_open(true); + watchdog_set_drv_timeout(); watchdog_timeout_cb(&wdt_timeout); + } } bool watchdog_get_stopped(void) @@ -60,23 +125,19 @@ bool watchdog_get_stopped(void) int watchdog_timeout(int timeout) { - if (wdt_fd < 0) - return 0; - if (timeout) { DEBUG(4, "Set watchdog timeout: %ds\n", timeout); - ioctl(wdt_fd, WDIOC_SETTIMEOUT, &timeout); + wdt_drv_timeout = timeout; + + if (wdt_fd >= 0) + watchdog_set_drv_timeout(); } - ioctl(wdt_fd, WDIOC_GETTIMEOUT, &timeout); - return timeout; + return wdt_drv_timeout; } int watchdog_frequency(int frequency) { - if (wdt_fd < 0) - return 0; - if (frequency) { DEBUG(4, "Set watchdog frequency: %ds\n", frequency); wdt_frequency = frequency; @@ -87,10 +148,11 @@ int watchdog_frequency(int frequency) char* watchdog_fd(void) { - static char fd_buf[3]; + static char fd_buf[12]; if (wdt_fd < 0) return NULL; + snprintf(fd_buf, sizeof(fd_buf), "%d", wdt_fd); return fd_buf; @@ -98,28 +160,13 @@ char* watchdog_fd(void) void watchdog_init(int preinit) { - char *env = getenv("WDTFD"); - - if (wdt_fd >= 0) - return; - wdt_timeout.cb = watchdog_timeout_cb; - if (env) { - DEBUG(2, "Watchdog handover: fd=%s\n", env); - wdt_fd = atoi(env); - unsetenv("WDTFD"); - } else { - wdt_fd = open("/dev/watchdog", O_WRONLY); - } - if (wdt_fd < 0) + if (watchdog_open(!preinit) < 0) return; - if (!preinit) - fcntl(wdt_fd, F_SETFD, fcntl(wdt_fd, F_GETFD) | FD_CLOEXEC); - LOG("- watchdog -\n"); - watchdog_timeout(30); + watchdog_set_drv_timeout(); watchdog_timeout_cb(&wdt_timeout); DEBUG(4, "Opened watchdog with timeout %ds\n", watchdog_timeout(0));