]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/watchdog.c
Merge pull request #2495 from heftig/master
[thirdparty/systemd.git] / src / shared / watchdog.c
CommitLineData
e96d6be7
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2012 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
e96d6be7
LP
9 (at your option) any later version.
10
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
5430f7f2 14 Lesser General Public License for more details.
e96d6be7 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
e96d6be7
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
e96d6be7
LP
20#include <errno.h>
21#include <fcntl.h>
cf0fbc49 22#include <sys/ioctl.h>
a8fbdf54 23#include <syslog.h>
e96d6be7
LP
24#include <unistd.h>
25#include <linux/watchdog.h>
26
3ffd4af2 27#include "fd-util.h"
cf0fbc49 28#include "log.h"
a8fbdf54 29#include "time-util.h"
cf0fbc49 30#include "watchdog.h"
e96d6be7
LP
31
32static int watchdog_fd = -1;
3a43da28 33static usec_t watchdog_timeout = USEC_INFINITY;
e96d6be7
LP
34
35static int update_timeout(void) {
36 int r;
37
38 if (watchdog_fd < 0)
39 return 0;
40
3a43da28 41 if (watchdog_timeout == USEC_INFINITY)
e96d6be7
LP
42 return 0;
43 else if (watchdog_timeout == 0) {
44 int flags;
45
46 flags = WDIOS_DISABLECARD;
47 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
4a62c710
MS
48 if (r < 0)
49 return log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
e96d6be7
LP
50 } else {
51 int sec, flags;
52 char buf[FORMAT_TIMESPAN_MAX];
53
54 sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
55 r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec);
4a62c710
MS
56 if (r < 0)
57 return log_warning_errno(errno, "Failed to set timeout to %is: %m", sec);
e96d6be7
LP
58
59 watchdog_timeout = (usec_t) sec * USEC_PER_SEC;
2fa4092c 60 log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout, 0));
e96d6be7
LP
61
62 flags = WDIOS_ENABLECARD;
63 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
14f494c7
JD
64 if (r < 0) {
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");
68 if (errno != ENOTTY)
69 return -errno;
70 }
e96d6be7
LP
71
72 r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
4a62c710
MS
73 if (r < 0)
74 return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
e96d6be7
LP
75 }
76
77 return 0;
78}
79
80static int open_watchdog(void) {
81 struct watchdog_info ident;
82
83 if (watchdog_fd >= 0)
84 return 0;
85
86 watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC);
87 if (watchdog_fd < 0)
88 return -errno;
89
90 if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) >= 0)
91 log_info("Hardware watchdog '%s', version %x",
92 ident.identity,
93 ident.firmware_version);
94
95 return update_timeout();
96}
97
98int watchdog_set_timeout(usec_t *usec) {
56bcbfa5 99 int r;
e96d6be7
LP
100
101 watchdog_timeout = *usec;
102
103 /* If we didn't open the watchdog yet and didn't get any
104 * explicit timeout value set, don't do anything */
3a43da28 105 if (watchdog_fd < 0 && watchdog_timeout == USEC_INFINITY)
e96d6be7
LP
106 return 0;
107
108 if (watchdog_fd < 0)
56bcbfa5 109 r = open_watchdog();
e96d6be7 110 else
56bcbfa5 111 r = update_timeout();
e96d6be7
LP
112
113 *usec = watchdog_timeout;
56bcbfa5
MO
114
115 return r;
e96d6be7
LP
116}
117
118int watchdog_ping(void) {
119 int r;
120
121 if (watchdog_fd < 0) {
122 r = open_watchdog();
123 if (r < 0)
124 return r;
125 }
126
127 r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
4a62c710
MS
128 if (r < 0)
129 return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
e96d6be7
LP
130
131 return 0;
132}
133
134void watchdog_close(bool disarm) {
135 int r;
136
137 if (watchdog_fd < 0)
138 return;
139
140 if (disarm) {
141 int flags;
142
143 /* Explicitly disarm it */
144 flags = WDIOS_DISABLECARD;
145 r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
146 if (r < 0)
56f64d95 147 log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
e96d6be7
LP
148
149 /* To be sure, use magic close logic, too */
150 for (;;) {
151 static const char v = 'V';
152
153 if (write(watchdog_fd, &v, 1) > 0)
154 break;
155
156 if (errno != EINTR) {
56f64d95 157 log_error_errno(errno, "Failed to disarm watchdog timer: %m");
e96d6be7
LP
158 break;
159 }
160 }
161 }
162
03e334a1 163 watchdog_fd = safe_close(watchdog_fd);
e96d6be7 164}