Blob Blame History Raw
From b154ab95212f2a882f9893000a184199baa8fb68 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Tue, 8 Jan 2013 14:23:14 -0600
Subject: [PATCH 6/6] wdmd: dynamically select working watchdog device

Some watchdog drivers enable both /dev/watchdog0 and
/dev/watchdog1.  Sometimes, only one of them works,
and the working one is not consistent.  So, we need
to test which works before deciding which to use.

Signed-off-by: David Teigland <teigland@redhat.com>
---
 wdmd/main.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 5 deletions(-)

diff --git a/wdmd/main.c b/wdmd/main.c
index 8a97f04..827d1bb 100644
--- a/wdmd/main.c
+++ b/wdmd/main.c
@@ -49,6 +49,8 @@
 #define DEFAULT_SOCKET_GID 0
 #define DEFAULT_SOCKET_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
 
+#define WDPATH_SIZE 64
+
 static int test_interval = DEFAULT_TEST_INTERVAL;
 static int fire_timeout = DEFAULT_FIRE_TIMEOUT;
 static int high_priority = DEFAULT_HIGH_PRIORITY;
@@ -64,7 +66,9 @@ static int shm_fd;
 static int allow_scripts;
 static int kill_script_sec;
 static const char *scripts_dir = "/etc/wdmd.d";
-static const char *watchdog_path = "/dev/watchdog";
+static char watchdog_path[WDPATH_SIZE];
+static char option_path[WDPATH_SIZE];
+static char saved_path[WDPATH_SIZE];
 
 struct script_status {
 	uint64_t start;
@@ -928,7 +932,7 @@ static int open_dev(void)
 
 	fd = open(watchdog_path, O_WRONLY | O_CLOEXEC);
 	if (fd < 0) {
-		log_error("no %s, load a watchdog driver", watchdog_path);
+		log_error("open %s error %d", watchdog_path, errno);
 		return fd;
 	}
 
@@ -969,10 +973,18 @@ static void close_watchdog(void)
 	dev_fd = -1;
 }
 
-static int setup_watchdog(void)
+static int _setup_watchdog(char *path)
 {
+	struct stat buf;
 	int rv, timeout;
 
+	strncpy(watchdog_path, path, WDPATH_SIZE);
+	watchdog_path[WDPATH_SIZE - 1] = '\0';
+
+	rv = stat(watchdog_path, &buf);
+	if (rv < 0)
+		return -1;
+
 	rv = open_dev();
 	if (rv < 0)
 		return -1;
@@ -1006,9 +1018,73 @@ static int setup_watchdog(void)
  out:
 	log_error("%s armed with fire_timeout %d", watchdog_path, fire_timeout);
 
+	/* TODO: save watchdog_path in /var/run/wdmd/saved_path,
+	 * and in startup read that file, copying it to saved_path */
+
 	return 0;
 }
 
+/*
+ * Order of preference:
+ * . saved path (path used before daemon restart)
+ * . command line option (-w)
+ * . /dev/watchdog0
+ * . /dev/watchdog1
+ * . /dev/watchdog
+ */
+
+static int setup_watchdog(void)
+{
+	int rv;
+
+	if (!saved_path[0])
+		goto opt;
+
+	rv = _setup_watchdog(saved_path);
+	if (!rv)
+		return 0;
+
+ opt:
+	if (!option_path[0] || !strcmp(saved_path, option_path))
+		goto zero;
+
+	rv = _setup_watchdog(option_path);
+	if (!rv)
+		return 0;
+
+ zero:
+	if (!strcmp(saved_path, "/dev/watchdog0") ||
+	    !strcmp(option_path, "/dev/watchdog0"))
+		goto one;
+
+	rv = _setup_watchdog((char *)"/dev/watchdog0");
+	if (!rv)
+		return 0;
+
+ one:
+	if (!strcmp(saved_path, "/dev/watchdog1") ||
+	    !strcmp(option_path, "/dev/watchdog1"))
+		goto old;
+
+	rv = _setup_watchdog((char *)"/dev/watchdog1");
+	if (!rv)
+		return 0;
+
+ old:
+	if (!strcmp(saved_path, "/dev/watchdog") ||
+	    !strcmp(option_path, "/dev/watchdog"))
+		goto out;
+
+	rv = _setup_watchdog((char *)"/dev/watchdog");
+	if (!rv)
+		return 0;
+
+ out:
+	log_error("no watchdog device, load a watchdog driver");
+	return -1;
+
+}
+
 static void pet_watchdog(void)
 {
 	int rv, unused;
@@ -1327,7 +1403,7 @@ static void print_usage_and_exit(int status)
 	printf("-s <path>             path to scripts dir (default %s)\n", scripts_dir);
 	printf("-k <num>              kill unfinished scripts after num seconds (default %d)\n",
 				      kill_script_sec);
-	printf("-w /dev/watchdog      path to the watchdog device (default %s)\n", watchdog_path);
+	printf("-w /dev/watchdog      path to the watchdog device to try first\n");
 	exit(status);
 }
 
@@ -1394,7 +1470,8 @@ int main(int argc, char *argv[])
 		    kill_script_sec = atoi(optarg);
 		    break;
 		case 'w':
-		    watchdog_path = strdup(optarg);
+		    snprintf(option_path, WDPATH_SIZE, "%s", optarg);
+		    option_path[WDPATH_SIZE - 1] = '\0';
 		    break;
 	    }
 	}
-- 
1.7.11.7