1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/ioctl.h>
26 #include <linux/watchdog.h>
31 static int watchdog_fd = -1;
32 static usec_t watchdog_timeout = (usec_t) -1;
34 static int update_timeout(void) {
40 if (watchdog_timeout == (usec_t) -1)
42 else if (watchdog_timeout == 0) {
45 flags = WDIOS_DISABLECARD;
46 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
48 log_warning("Failed to disable hardware watchdog: %m");
53 char buf[FORMAT_TIMESPAN_MAX];
55 sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
56 r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec);
58 log_warning("Failed to set timeout to %is: %m", sec);
62 watchdog_timeout = (usec_t) sec * USEC_PER_SEC;
63 log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout));
65 flags = WDIOS_ENABLECARD;
66 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
68 log_warning("Failed to enable hardware watchdog: %m");
72 r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
74 log_warning("Failed to ping hardware watchdog: %m");
82 static int open_watchdog(void) {
83 struct watchdog_info ident;
88 watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC);
92 if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) >= 0)
93 log_info("Hardware watchdog '%s', version %x",
95 ident.firmware_version);
97 return update_timeout();
100 int watchdog_set_timeout(usec_t *usec) {
102 watchdog_timeout = *usec;
104 /* If we didn't open the watchdog yet and didn't get any
105 * explicit timeout value set, don't do anything */
106 if (watchdog_fd < 0 && watchdog_timeout == (usec_t) -1)
110 return open_watchdog();
112 return update_timeout();
114 *usec = watchdog_timeout;
117 int watchdog_ping(void) {
120 if (watchdog_fd < 0) {
126 r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
128 log_warning("Failed to ping hardware watchdog: %m");
135 void watchdog_close(bool disarm) {
144 /* Explicitly disarm it */
145 flags = WDIOS_DISABLECARD;
146 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
148 log_warning("Failed to disable hardware watchdog: %m");
150 /* To be sure, use magic close logic, too */
152 static const char v = 'V';
154 if (write(watchdog_fd, &v, 1) > 0)
157 if (errno != EINTR) {
158 log_error("Failed to disarm watchdog timer: %m");
164 close_nointr_nofail(watchdog_fd);