• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/watchdog.c

  1 /*
  2  * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  3  * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU Lesser General Public License version 2.1
  7  * as published by the Free Software Foundation
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  */
 14 
 15 #include <linux/watchdog.h>
 16 
 17 #include <sys/ioctl.h>
 18 #include <sys/types.h>
 19 #include <sys/stat.h>
 20 #include <fcntl.h>
 21 
 22 #include <unistd.h>
 23 
 24 #include <libubox/uloop.h>
 25 
 26 #include "procd.h"
 27 #include "watchdog.h"
 28 
 29 #define WDT_PATH        "/dev/watchdog"
 30 
 31 static struct uloop_timeout wdt_timeout;
 32 static int wdt_fd = -1;
 33 static int wdt_drv_timeout = 30;
 34 static int wdt_frequency = 5;
 35 static bool wdt_magicclose = false;
 36 
 37 void watchdog_ping(void)
 38 {
 39         DEBUG(4, "Ping\n");
 40         if (wdt_fd >= 0 && write(wdt_fd, "X", 1) < 0)
 41                 ERROR("WDT failed to write: %m\n");
 42 }
 43 
 44 static void watchdog_timeout_cb(struct uloop_timeout *t)
 45 {
 46         watchdog_ping();
 47         uloop_timeout_set(t, wdt_frequency * 1000);
 48 }
 49 
 50 static int watchdog_open(bool cloexec)
 51 {
 52         char *env = getenv("WDTFD");
 53 
 54         if (wdt_fd >= 0)
 55                 return wdt_fd;
 56 
 57         if (env) {
 58                 DEBUG(2, "Watchdog handover: fd=%s\n", env);
 59                 wdt_fd = atoi(env);
 60                 unsetenv("WDTFD");
 61         } else {
 62                 wdt_fd = open(WDT_PATH, O_WRONLY);
 63         }
 64 
 65         if (wdt_fd < 0)
 66                 return wdt_fd;
 67 
 68         if (cloexec)
 69                 fcntl(wdt_fd, F_SETFD, fcntl(wdt_fd, F_GETFD) | FD_CLOEXEC);
 70 
 71         return wdt_fd;
 72 }
 73 
 74 static void watchdog_close(bool with_release)
 75 {
 76         if (wdt_fd < 0)
 77                 return;
 78 
 79         if (with_release) {
 80                 if (write(wdt_fd, "V", 1) < 0)
 81                         ERROR("WDT failed to write release: %m\n");
 82         }
 83 
 84         if (close(wdt_fd) == -1)
 85                 ERROR("WDT failed to close watchdog: %m\n");
 86 
 87         wdt_fd = -1;
 88 }
 89 
 90 static int watchdog_set_drv_timeout(void)
 91 {
 92         if (wdt_fd < 0)
 93                 return -1;
 94 
 95         return ioctl(wdt_fd, WDIOC_SETTIMEOUT, &wdt_drv_timeout);
 96 }
 97 
 98 static void watchdog_print_status(void)
 99 {
100         struct watchdog_info wdt_info;
101         int bootstatus;
102 
103         if (wdt_fd < 0)
104                 return;
105 
106         if (ioctl(wdt_fd, WDIOC_GETSUPPORT, &wdt_info)) {
107                 DEBUG(2, "Watchdog GETSUPPORT failed\n");
108                 return;
109         }
110 
111         if (!(wdt_info.options & WDIOF_CARDRESET)) {
112                 DEBUG(2, "Watchdog does not have CARDRESET support\n");
113                 return;
114         }
115 
116         if (ioctl(wdt_fd, WDIOC_GETBOOTSTATUS, &bootstatus)) {
117                 DEBUG(2, "Watchdog GETBOOTSTATUS failed\n");
118                 return;
119         }
120 
121         if (bootstatus & WDIOF_CARDRESET)
122                 LOG("Watchdog has previously reset the system\n");
123         else
124                 DEBUG(2, "Watchdog did not previously reset the system\n");
125 }
126 
127 void watchdog_set_magicclose(bool val)
128 {
129         wdt_magicclose = val;
130 }
131 
132 bool watchdog_get_magicclose(void)
133 {
134         return wdt_magicclose;
135 }
136 
137 void watchdog_set_stopped(bool val)
138 {
139         if (val) {
140                 uloop_timeout_cancel(&wdt_timeout);
141 
142                 watchdog_close(wdt_magicclose);
143         }
144         else {
145                 watchdog_open(true);
146                 watchdog_set_drv_timeout();
147                 watchdog_timeout_cb(&wdt_timeout);
148         }
149 }
150 
151 bool watchdog_get_stopped(void)
152 {
153         return !wdt_timeout.pending;
154 }
155 
156 int watchdog_timeout(int timeout)
157 {
158         if (timeout) {
159                 DEBUG(4, "Set watchdog timeout: %ds\n", timeout);
160                 wdt_drv_timeout = timeout;
161 
162                 if (wdt_fd >= 0)
163                         watchdog_set_drv_timeout();
164         }
165 
166         return wdt_drv_timeout;
167 }
168 
169 int watchdog_frequency(int frequency)
170 {
171         if (frequency) {
172                 DEBUG(4, "Set watchdog frequency: %ds\n", frequency);
173                 wdt_frequency = frequency;
174         }
175 
176         return wdt_frequency;
177 }
178 
179 char* watchdog_fd(void)
180 {
181         static char fd_buf[12];
182 
183         if (wdt_fd < 0)
184                 return NULL;
185 
186         snprintf(fd_buf, sizeof(fd_buf), "%d", wdt_fd);
187 
188         return fd_buf;
189 }
190 
191 void watchdog_init(int preinit)
192 {
193         wdt_timeout.cb = watchdog_timeout_cb;
194 
195         if (watchdog_open(!preinit) < 0)
196                 return;
197 
198         LOG("- watchdog -\n");
199         watchdog_set_drv_timeout();
200         watchdog_timeout_cb(&wdt_timeout);
201 
202         DEBUG(4, "Opened watchdog with timeout %ds\n", watchdog_timeout(0));
203 
204         watchdog_print_status();
205 }
206 
207 
208 void watchdog_set_cloexec(bool val)
209 {
210         if (wdt_fd < 0)
211                 return;
212 
213         int flags = fcntl(wdt_fd, F_GETFD);
214         if (val)
215                 flags |= FD_CLOEXEC;
216         else
217                 flags &= ~FD_CLOEXEC;
218         fcntl(wdt_fd, F_SETFD,  flags);
219 }
220 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt