]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/watchdog.c
2 This file is part of systemd.
4 Copyright 2012 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/ioctl.h>
25 #include <linux/watchdog.h>
29 #include "time-util.h"
32 static int watchdog_fd
= -1;
33 static usec_t watchdog_timeout
= USEC_INFINITY
;
35 static int update_timeout(void) {
41 if (watchdog_timeout
== USEC_INFINITY
)
43 else if (watchdog_timeout
== 0) {
46 flags
= WDIOS_DISABLECARD
;
47 r
= ioctl(watchdog_fd
, WDIOC_SETOPTIONS
, &flags
);
49 return log_warning_errno(errno
, "Failed to disable hardware watchdog: %m");
52 char buf
[FORMAT_TIMESPAN_MAX
];
54 sec
= (int) ((watchdog_timeout
+ USEC_PER_SEC
- 1) / USEC_PER_SEC
);
55 r
= ioctl(watchdog_fd
, WDIOC_SETTIMEOUT
, &sec
);
57 return log_warning_errno(errno
, "Failed to set timeout to %is: %m", sec
);
59 watchdog_timeout
= (usec_t
) sec
* USEC_PER_SEC
;
60 log_info("Set hardware watchdog to %s.", format_timespan(buf
, sizeof(buf
), watchdog_timeout
, 0));
62 flags
= WDIOS_ENABLECARD
;
63 r
= ioctl(watchdog_fd
, WDIOC_SETOPTIONS
, &flags
);
65 /* ENOTTY means the watchdog is always enabled so we're fine */
66 log_full(errno
== ENOTTY
? LOG_DEBUG
: LOG_WARNING
,
67 "Failed to enable hardware watchdog: %m");
72 r
= ioctl(watchdog_fd
, WDIOC_KEEPALIVE
, 0);
74 return log_warning_errno(errno
, "Failed to ping hardware watchdog: %m");
80 static int open_watchdog(void) {
81 struct watchdog_info ident
;
86 watchdog_fd
= open("/dev/watchdog", O_WRONLY
|O_CLOEXEC
);
90 if (ioctl(watchdog_fd
, WDIOC_GETSUPPORT
, &ident
) >= 0)
91 log_info("Hardware watchdog '%s', version %x",
93 ident
.firmware_version
);
95 return update_timeout();
98 int watchdog_set_timeout(usec_t
*usec
) {
101 watchdog_timeout
= *usec
;
103 /* If we didn't open the watchdog yet and didn't get any
104 * explicit timeout value set, don't do anything */
105 if (watchdog_fd
< 0 && watchdog_timeout
== USEC_INFINITY
)
111 r
= update_timeout();
113 *usec
= watchdog_timeout
;
118 int watchdog_ping(void) {
121 if (watchdog_fd
< 0) {
127 r
= ioctl(watchdog_fd
, WDIOC_KEEPALIVE
, 0);
129 return log_warning_errno(errno
, "Failed to ping hardware watchdog: %m");
134 void watchdog_close(bool disarm
) {
143 /* Explicitly disarm it */
144 flags
= WDIOS_DISABLECARD
;
145 r
= ioctl(watchdog_fd
, WDIOC_SETOPTIONS
, &flags
);
147 log_warning_errno(errno
, "Failed to disable hardware watchdog: %m");
149 /* To be sure, use magic close logic, too */
151 static const char v
= 'V';
153 if (write(watchdog_fd
, &v
, 1) > 0)
156 if (errno
!= EINTR
) {
157 log_error_errno(errno
, "Failed to disarm watchdog timer: %m");
163 watchdog_fd
= safe_close(watchdog_fd
);