]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/watchdog.c
tree-wide: sort includes
[thirdparty/systemd.git] / src / shared / watchdog.c
CommitLineData
e96d6be7
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
e96d6be7
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
e96d6be7 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
e96d6be7
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
e96d6be7
LP
22#include <errno.h>
23#include <fcntl.h>
cf0fbc49 24#include <sys/ioctl.h>
e96d6be7
LP
25#include <unistd.h>
26#include <linux/watchdog.h>
27
3ffd4af2 28#include "fd-util.h"
cf0fbc49
TA
29#include "log.h"
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}