Blame SOURCES/0001-Fix-Be-a-bit-more-descriptive-on-issues-opening-watc.patch

266f16
From 230586043d9efd3a431b64427b0760b3ffbd6b58 Mon Sep 17 00:00:00 2001
266f16
From: Klaus Wenninger <klaus.wenninger@aon.at>
266f16
Date: Wed, 13 Jul 2022 14:46:38 +0200
266f16
Subject: [PATCH] Fix: Be a bit more descriptive on issues opening
266f16
 watchdog-devices
266f16
266f16
Both when running as daemon and with 'test/query-watchdog'
266f16
---
266f16
 src/sbd-common.c | 495 +++++++++++++++++++++++++++++++++----------------------
266f16
 1 file changed, 302 insertions(+), 193 deletions(-)
266f16
266f16
diff --git a/src/sbd-common.c b/src/sbd-common.c
266f16
index b14575f..f3f226a 100644
266f16
--- a/src/sbd-common.c
266f16
+++ b/src/sbd-common.c
266f16
@@ -118,6 +118,62 @@ usage(void)
266f16
                 , cmdname);
266f16
 }
266f16
 
266f16
+#define MAX_WATCHDOGS 64
266f16
+#define SYS_CLASS_WATCHDOG "/sys/class/watchdog"
266f16
+#define SYS_CHAR_DEV_DIR "/sys/dev/char"
266f16
+#define WATCHDOG_NODEDIR "/dev/"
266f16
+
266f16
+static bool
266f16
+is_watchdog(dev_t device)
266f16
+{
266f16
+    static int num_watchdog_devs = 0;
266f16
+    static dev_t watchdog_devs[MAX_WATCHDOGS];
266f16
+    struct dirent *entry;
266f16
+    int i;
266f16
+
266f16
+    /* populate on first call */
266f16
+    if (num_watchdog_devs == 0) {
266f16
+        DIR *dp;
266f16
+
266f16
+        watchdog_devs[0] = makedev(10,130);
266f16
+        num_watchdog_devs = 1;
266f16
+
266f16
+        /* get additional devices from /sys/class/watchdog */
266f16
+        dp = opendir(SYS_CLASS_WATCHDOG);
266f16
+        if (dp) {
266f16
+            while ((entry = readdir(dp))) {
266f16
+                if (entry->d_type == DT_LNK) {
266f16
+                    FILE *file;
266f16
+                    char entry_name[NAME_MAX+sizeof(SYS_CLASS_WATCHDOG)+5];
266f16
+
266f16
+                    snprintf(entry_name, sizeof(entry_name),
266f16
+                        SYS_CLASS_WATCHDOG "/%s/dev", entry->d_name);
266f16
+                    file = fopen(entry_name, "r");
266f16
+                    if (file) {
266f16
+                        int major, minor;
266f16
+
266f16
+                        if (fscanf(file, "%d:%d", &major, &minor) == 2) {
266f16
+                            watchdog_devs[num_watchdog_devs++] = makedev(major, minor);
266f16
+                        }
266f16
+                        fclose(file);
266f16
+                        if (num_watchdog_devs == MAX_WATCHDOGS) {
266f16
+                            break;
266f16
+                        }
266f16
+                    }
266f16
+                }
266f16
+            }
266f16
+            closedir(dp);
266f16
+        }
266f16
+    }
266f16
+
266f16
+    for (i=0; i < num_watchdog_devs; i++) {
266f16
+        if (device == watchdog_devs[i]) {
266f16
+            return true;
266f16
+        }
266f16
+    }
266f16
+    return false;
266f16
+}
266f16
+
266f16
 static int
266f16
 watchdog_init_interval_fd(int wdfd, int timeout)
266f16
 {
266f16
@@ -173,20 +229,27 @@ watchdog_tickle(void)
266f16
 static int
266f16
 watchdog_init_fd(char *wddev, int timeout)
266f16
 {
266f16
-	int wdfd;
266f16
+    int wdfd;
266f16
+
266f16
+    wdfd = open(wddev, O_WRONLY);
266f16
+    if (wdfd >= 0) {
266f16
+        if (((timeout >= 0) && (watchdog_init_interval_fd(wdfd, timeout) < 0)) ||
266f16
+            (watchdog_tickle_fd(wdfd, wddev) < 0)) {
266f16
+            close(wdfd);
266f16
+            return -1;
266f16
+        }
266f16
+    } else {
266f16
+        struct stat statbuf;
266f16
 
266f16
-	wdfd = open(wddev, O_WRONLY);
266f16
-	if (wdfd >= 0) {
266f16
-		if (((timeout >= 0) && (watchdog_init_interval_fd(wdfd, timeout) < 0))
266f16
-					|| (watchdog_tickle_fd(wdfd, wddev) < 0)) {
266f16
-			close(wdfd);
266f16
-			return -1;
266f16
-		}
266f16
-	} else {
266f16
-		cl_perror("Cannot open watchdog device '%s'", wddev);
266f16
-		return -1;
266f16
-	}
266f16
-	return wdfd;
266f16
+        if(!stat(wddev, &statbuf) && S_ISCHR(statbuf.st_mode) &&
266f16
+           is_watchdog(statbuf.st_rdev)) {
266f16
+            cl_perror("Cannot open watchdog device '%s'", wddev);
266f16
+        } else {
266f16
+            cl_perror("Seems as if '%s' isn't a valid watchdog-device", wddev);
266f16
+        }
266f16
+        return -1;
266f16
+    }
266f16
+    return wdfd;
266f16
 }
266f16
 
266f16
 int
266f16
@@ -250,17 +313,13 @@ watchdog_close(bool disarm)
266f16
     watchdogfd = -1;
266f16
 }
266f16
 
266f16
-#define MAX_WATCHDOGS 64
266f16
-#define SYS_CLASS_WATCHDOG "/sys/class/watchdog"
266f16
-#define SYS_CHAR_DEV_DIR "/sys/dev/char"
266f16
-#define WATCHDOG_NODEDIR "/dev/"
266f16
-#define WATCHDOG_NODEDIR_LEN 5
266f16
-
266f16
 struct watchdog_list_item {
266f16
 	dev_t dev;
266f16
 	char *dev_node;
266f16
 	char *dev_ident;
266f16
 	char *dev_driver;
266f16
+	pid_t busy_pid;
266f16
+	char *busy_name;
266f16
 	struct watchdog_list_item *next;
266f16
 };
266f16
 
266f16
@@ -276,184 +335,223 @@ static int watchdog_list_items = 0;
266f16
 static void
266f16
 watchdog_populate_list(void)
266f16
 {
266f16
-	dev_t watchdogs[MAX_WATCHDOGS + 1] =
266f16
-		{makedev(10,130), 0};
266f16
-	int num_watchdogs = 1;
266f16
-	struct dirent *entry;
266f16
-	char entry_name[280];
266f16
-	DIR *dp;
266f16
-	char buf[280] = "";
266f16
-	struct link_list_item *link_list = NULL;
266f16
-
266f16
-	if (watchdog_list != NULL) {
266f16
-		return;
266f16
-	}
266f16
+    struct dirent *entry;
266f16
+    char entry_name[sizeof(WATCHDOG_NODEDIR)+NAME_MAX];
266f16
+    DIR *dp;
266f16
+    char buf[NAME_MAX+sizeof(WATCHDOG_NODEDIR)] = "";
266f16
+    struct link_list_item *link_list = NULL;
266f16
 
266f16
-	/* get additional devices from /sys/class/watchdog */
266f16
-	dp = opendir(SYS_CLASS_WATCHDOG);
266f16
-	if (dp) {
266f16
-		while ((entry = readdir(dp))) {
266f16
-			if (entry->d_type == DT_LNK) {
266f16
-				FILE *file;
266f16
-
266f16
-				snprintf(entry_name, sizeof(entry_name),
266f16
-						 SYS_CLASS_WATCHDOG "/%s/dev", entry->d_name);
266f16
-				file = fopen(entry_name, "r");
266f16
-				if (file) {
266f16
-					int major, minor;
266f16
-
266f16
-					if (fscanf(file, "%d:%d", &major, &minor) == 2) {
266f16
-						watchdogs[num_watchdogs++] = makedev(major, minor);
266f16
-					}
266f16
-					fclose(file);
266f16
-					if (num_watchdogs == MAX_WATCHDOGS) {
266f16
-						break;
266f16
-					}
266f16
-				}
266f16
-			}
266f16
-		}
266f16
-		closedir(dp);
266f16
-	}
266f16
+    if (watchdog_list != NULL) {
266f16
+        return;
266f16
+    }
266f16
 
266f16
-	/* search for watchdog nodes in /dev */
266f16
-	dp = opendir(WATCHDOG_NODEDIR);
266f16
-	if (dp) {
266f16
-		/* first go for links and memorize them */
266f16
-		while ((entry = readdir(dp))) {
266f16
-			if (entry->d_type == DT_LNK) {
266f16
-				int len;
266f16
-
266f16
-				snprintf(entry_name, sizeof(entry_name),
266f16
-				         WATCHDOG_NODEDIR "%s", entry->d_name);
266f16
-
266f16
-				/* !realpath(entry_name, buf) unfortunately does a stat on
266f16
-				 * target so we can't really use it to check if links stay
266f16
-				 * within /dev without triggering e.g. AVC-logs (with
266f16
-				 * SELinux policy that just allows stat within /dev).
266f16
-				 * Without canonicalization that doesn't actually touch the
266f16
-				 * filesystem easily available introduce some limitations
266f16
-				 * for simplicity:
266f16
-				 * - just simple path without '..'
266f16
-				 * - just one level of symlinks (avoid e.g. loop-checking)
266f16
-				 */
266f16
-				len = readlink(entry_name, buf, sizeof(buf) - 1);
266f16
-				if ((len < 1) ||
266f16
-				    (len > sizeof(buf) - WATCHDOG_NODEDIR_LEN - 1)) {
266f16
-					continue;
266f16
-				}
266f16
-				buf[len] = '\0';
266f16
-				if (buf[0] != '/') {
266f16
-					memmove(&buf[WATCHDOG_NODEDIR_LEN], buf, len+1);
266f16
-					memcpy(buf, WATCHDOG_NODEDIR, WATCHDOG_NODEDIR_LEN);
266f16
-					len += WATCHDOG_NODEDIR_LEN;
266f16
-				}
266f16
-				if (strstr(buf, "/../") ||
266f16
-				    strncmp(WATCHDOG_NODEDIR, buf, WATCHDOG_NODEDIR_LEN)) {
266f16
-					continue;
266f16
-				} else {
266f16
-					/* just memorize to avoid statting the target - SELinux */
266f16
-					struct link_list_item *lli =
266f16
-						calloc(1, sizeof(struct link_list_item));
266f16
-
266f16
-					lli->dev_node = strdup(buf);
266f16
-					lli->link_name = strdup(entry_name);
266f16
-					lli->next = link_list;
266f16
-					link_list = lli;
266f16
-				}
266f16
-			}
266f16
-		}
266f16
+    /* search for watchdog nodes in /dev */
266f16
+    dp = opendir(WATCHDOG_NODEDIR);
266f16
+    if (dp) {
266f16
+        /* first go for links and memorize them */
266f16
+        while ((entry = readdir(dp))) {
266f16
+            if (entry->d_type == DT_LNK) {
266f16
+                int len;
266f16
+
266f16
+                snprintf(entry_name, sizeof(entry_name),
266f16
+                         WATCHDOG_NODEDIR "%s", entry->d_name);
266f16
+
266f16
+                /* realpath(entry_name, buf) unfortunately does a stat on
266f16
+                 * target so we can't really use it to check if links stay
266f16
+                 * within /dev without triggering e.g. AVC-logs (with
266f16
+                 * SELinux policy that just allows stat within /dev).
266f16
+                 * Without canonicalization that doesn't actually touch the
266f16
+                 * filesystem easily available introduce some limitations
266f16
+                 * for simplicity:
266f16
+                 * - just simple path without '..'
266f16
+                 * - just one level of symlinks (avoid e.g. loop-checking)
266f16
+                 */
266f16
+                len = readlink(entry_name, buf, sizeof(buf) - 1);
266f16
+                if ((len < 1) ||
266f16
+                    (len > sizeof(buf) - sizeof(WATCHDOG_NODEDIR) -1 - 1)) {
266f16
+                    continue;
266f16
+                }
266f16
+                buf[len] = '\0';
266f16
+                if (buf[0] != '/') {
266f16
+                    memmove(&buf[sizeof(WATCHDOG_NODEDIR)-1], buf, len+1);
266f16
+                    memcpy(buf, WATCHDOG_NODEDIR, sizeof(WATCHDOG_NODEDIR)-1);
266f16
+                    len += sizeof(WATCHDOG_NODEDIR)-1;
266f16
+                }
266f16
+                if (strstr(buf, "/../") ||
266f16
+                    strncmp(WATCHDOG_NODEDIR, buf, sizeof(WATCHDOG_NODEDIR)-1)) {
266f16
+                    continue;
266f16
+                } else {
266f16
+                    /* just memorize to avoid statting the target - SELinux */
266f16
+                    struct link_list_item *lli =
266f16
+                        calloc(1, sizeof(struct link_list_item));
266f16
+
266f16
+                    lli->dev_node = strdup(buf);
266f16
+                    lli->link_name = strdup(entry_name);
266f16
+                    lli->next = link_list;
266f16
+                    link_list = lli;
266f16
+                }
266f16
+            }
266f16
+        }
266f16
 
266f16
-		rewinddir(dp);
266f16
-
266f16
-		while ((entry = readdir(dp))) {
266f16
-			if (entry->d_type == DT_CHR) {
266f16
-				struct stat statbuf;
266f16
-
266f16
-				snprintf(entry_name, sizeof(entry_name),
266f16
-				         WATCHDOG_NODEDIR "%s", entry->d_name);
266f16
-				if(!stat(entry_name, &statbuf) && S_ISCHR(statbuf.st_mode)) {
266f16
-					int i;
266f16
-
266f16
-					for (i=0; i
266f16
-						if (statbuf.st_rdev == watchdogs[i]) {
266f16
-							int wdfd = watchdog_init_fd(entry_name, -1);
266f16
-							struct watchdog_list_item *wdg =
266f16
-								calloc(1, sizeof(struct watchdog_list_item));
266f16
-							int len;
266f16
-							struct link_list_item *tmp_list = NULL;
266f16
-
266f16
-							wdg->dev = watchdogs[i];
266f16
-							wdg->dev_node = strdup(entry_name);
266f16
-							wdg->next = watchdog_list;
266f16
-							watchdog_list = wdg;
266f16
-							watchdog_list_items++;
266f16
-
266f16
-							if (wdfd >= 0) {
266f16
-								struct watchdog_info ident;
266f16
-
266f16
-								ident.identity[0] = '\0';
266f16
-								ioctl(wdfd, WDIOC_GETSUPPORT, &ident);
266f16
-								watchdog_close_fd(wdfd, entry_name, true);
266f16
-								if (ident.identity[0]) {
266f16
-									wdg->dev_ident = strdup((char *) ident.identity);
266f16
-								}
266f16
-							}
266f16
-
266f16
-							snprintf(entry_name, sizeof(entry_name),
266f16
-							         SYS_CHAR_DEV_DIR "/%d:%d/device/driver",
266f16
-							         major(watchdogs[i]), minor(watchdogs[i]));
266f16
-							len = readlink(entry_name, buf, sizeof(buf) - 1);
266f16
-							if (len > 0) {
266f16
-								buf[len] = '\0';
266f16
-								wdg->dev_driver = strdup(basename(buf));
266f16
-							} else if ((wdg->dev_ident) &&
266f16
-							           (strcmp(wdg->dev_ident,
266f16
-							                   "Software Watchdog") == 0)) {
266f16
-								wdg->dev_driver = strdup("softdog");
266f16
-							}
266f16
-
266f16
-							/* create dupes if we have memorized links
266f16
-							 * to this node
266f16
-							 */
266f16
-							for (tmp_list = link_list; tmp_list;
266f16
-							     tmp_list = tmp_list->next) {
266f16
-								if (!strcmp(tmp_list->dev_node,
266f16
-								            wdg->dev_node)) {
266f16
-									struct watchdog_list_item *dupe_wdg =
266f16
-										calloc(1, sizeof(struct watchdog_list_item));
266f16
-
266f16
-									/* as long as we never purge watchdog_list
266f16
-									 * there is no need to dupe strings
266f16
-									 */
266f16
-									*dupe_wdg = *wdg;
266f16
-									dupe_wdg->dev_node = strdup(tmp_list->link_name);
266f16
-									dupe_wdg->next = watchdog_list;
266f16
-									watchdog_list = dupe_wdg;
266f16
-									watchdog_list_items++;
266f16
-								}
266f16
-								/* for performance reasons we could remove
266f16
-								 * the link_list entry
266f16
-								 */
266f16
-							}
266f16
-							break;
266f16
-						}
266f16
-					}
266f16
-				}
266f16
-			}
266f16
-		}
266f16
+        rewinddir(dp);
266f16
+
266f16
+        while ((entry = readdir(dp))) {
266f16
+            if (entry->d_type == DT_CHR) {
266f16
+                struct stat statbuf;
266f16
+
266f16
+                snprintf(entry_name, sizeof(entry_name),
266f16
+                            WATCHDOG_NODEDIR "%s", entry->d_name);
266f16
+                if(!stat(entry_name, &statbuf) && S_ISCHR(statbuf.st_mode) &&
266f16
+                   is_watchdog(statbuf.st_rdev)) {
266f16
+
266f16
+                    int wdfd = watchdog_init_fd(entry_name, -1);
266f16
+                    struct watchdog_list_item *wdg =
266f16
+                        calloc(1, sizeof(struct watchdog_list_item));
266f16
+                    int len;
266f16
+                    struct link_list_item *tmp_list = NULL;
266f16
+
266f16
+                    wdg->dev = statbuf.st_rdev;
266f16
+                    wdg->dev_node = strdup(entry_name);
266f16
+                    wdg->next = watchdog_list;
266f16
+                    watchdog_list = wdg;
266f16
+                    watchdog_list_items++;
266f16
+
266f16
+                    if (wdfd >= 0) {
266f16
+                        struct watchdog_info ident;
266f16
+
266f16
+                        ident.identity[0] = '\0';
266f16
+                        ioctl(wdfd, WDIOC_GETSUPPORT, &ident);
266f16
+                        watchdog_close_fd(wdfd, entry_name, true);
266f16
+                        if (ident.identity[0]) {
266f16
+                            wdg->dev_ident = strdup((char *) ident.identity);
266f16
+                        }
266f16
+                    }
266f16
+
266f16
+                    snprintf(entry_name, sizeof(entry_name),
266f16
+                                SYS_CHAR_DEV_DIR "/%d:%d/device/driver",
266f16
+                                major(wdg->dev), minor(wdg->dev));
266f16
+                    len = readlink(entry_name, buf, sizeof(buf) - 1);
266f16
+                    if (len > 0) {
266f16
+                        buf[len] = '\0';
266f16
+                        wdg->dev_driver = strdup(basename(buf));
266f16
+                    } else if ((wdg->dev_ident) &&
266f16
+                               (strcmp(wdg->dev_ident,
266f16
+                                       "Software Watchdog") == 0)) {
266f16
+                        wdg->dev_driver = strdup("softdog");
266f16
+                    }
266f16
+
266f16
+                    /* create dupes if we have memorized links
266f16
+                     * to this node
266f16
+                     */
266f16
+                    for (tmp_list = link_list; tmp_list;
266f16
+                            tmp_list = tmp_list->next) {
266f16
+                        if (!strcmp(tmp_list->dev_node,
266f16
+                                    wdg->dev_node)) {
266f16
+                            struct watchdog_list_item *dupe_wdg =
266f16
+                                calloc(1, sizeof(struct watchdog_list_item));
266f16
+
266f16
+                            /* as long as we never purge watchdog_list
266f16
+                             * there is no need to dupe strings
266f16
+                             */
266f16
+                            *dupe_wdg = *wdg;
266f16
+                            dupe_wdg->dev_node = strdup(tmp_list->link_name);
266f16
+                            dupe_wdg->next = watchdog_list;
266f16
+                            watchdog_list = dupe_wdg;
266f16
+                            watchdog_list_items++;
266f16
+                        }
266f16
+                        /* for performance reasons we could remove
266f16
+                         * the link_list entry
266f16
+                         */
266f16
+                    }
266f16
+                }
266f16
+            }
266f16
+        }
266f16
 
266f16
-		closedir(dp);
266f16
-	}
266f16
+        closedir(dp);
266f16
+    }
266f16
 
266f16
-	/* cleanup link list */
266f16
-	while (link_list) {
266f16
-		struct link_list_item *tmp_list = link_list;
266f16
+    /* cleanup link list */
266f16
+    while (link_list) {
266f16
+        struct link_list_item *tmp_list = link_list;
266f16
 
266f16
-		link_list = link_list->next;
266f16
-		free(tmp_list->dev_node);
266f16
-		free(tmp_list->link_name);
266f16
-		free(tmp_list);
266f16
-	}
266f16
+        link_list = link_list->next;
266f16
+        free(tmp_list->dev_node);
266f16
+        free(tmp_list->link_name);
266f16
+        free(tmp_list);
266f16
+    }
266f16
+}
266f16
+
266f16
+static void
266f16
+watchdog_checkbusy()
266f16
+{
266f16
+    DIR *dproc;
266f16
+    struct dirent *entry;
266f16
+
266f16
+    dproc = opendir("/proc");
266f16
+    if (!dproc) {
266f16
+        /* no proc directory to search through */
266f16
+        return;
266f16
+    }
266f16
+
266f16
+    while ((entry = readdir(dproc)) != NULL) {
266f16
+        pid_t local_pid;
266f16
+        char *leftover;
266f16
+        DIR *dpid;
266f16
+        char procpath[NAME_MAX+10] = { 0 };
266f16
+
266f16
+        if (entry->d_name[0] == '.') {
266f16
+            continue;
266f16
+        }
266f16
+
266f16
+        local_pid = strtol(entry->d_name, &leftover, 10);
266f16
+        if (leftover[0] != '\0')
266f16
+            continue;
266f16
+
266f16
+        snprintf(procpath, sizeof(procpath), "/proc/%s/fd", entry->d_name);
266f16
+        dpid = opendir(procpath);
266f16
+        if (!dpid) {
266f16
+            /* silently continue - might be just a race */
266f16
+            continue;
266f16
+        }
266f16
+        while ((entry = readdir(dpid)) != NULL) {
266f16
+            struct watchdog_list_item *wdg;
266f16
+            char entry_name[sizeof(procpath)+NAME_MAX+1] = { 0 };
266f16
+            char buf[NAME_MAX+1] = { 0 };
266f16
+            int len;
266f16
+
266f16
+            if (entry->d_type != DT_LNK) {
266f16
+                continue;
266f16
+            }
266f16
+            snprintf(entry_name, sizeof(entry_name),
266f16
+                     "%s/%s", procpath, entry->d_name);
266f16
+            len = readlink(entry_name, buf, sizeof(buf) - 1);
266f16
+            if (len < 1) {
266f16
+                continue;
266f16
+            }
266f16
+            buf[len] = '\0';
266f16
+            for (wdg = watchdog_list; wdg != NULL; wdg = wdg->next) {
266f16
+                if (!strcmp(buf, wdg->dev_node)) {
266f16
+                    char name[16];
266f16
+                    FILE *file;
266f16
+
266f16
+                    wdg->busy_pid = local_pid;
266f16
+                    snprintf(procpath, sizeof(procpath), "/proc/%d/status", local_pid);
266f16
+                    file = fopen(procpath, "r");
266f16
+                    if (file) {
266f16
+                        if (fscanf(file, "Name:\t%15[a-zA-Z0-9 _-]", name) == 1) {
266f16
+                            wdg->busy_name = strdup(name);
266f16
+                        }
266f16
+                        fclose(file);
266f16
+                    }
266f16
+                }
266f16
+            }
266f16
+        }
266f16
+        closedir(dpid);
266f16
+    }
266f16
+
266f16
+    closedir(dproc);
266f16
+
266f16
+    return;
266f16
 }
266f16
 
266f16
 int watchdog_info(void)
266f16
@@ -462,13 +560,23 @@ int watchdog_info(void)
266f16
 	int wdg_cnt = 0;
266f16
 
266f16
 	watchdog_populate_list();
266f16
+	watchdog_checkbusy();
266f16
 	printf("\nDiscovered %d watchdog devices:\n", watchdog_list_items);
266f16
 	for (wdg = watchdog_list; wdg != NULL; wdg = wdg->next) {
266f16
 		wdg_cnt++;
266f16
-		printf("\n[%d] %s\nIdentity: %s\nDriver: %s\n",
266f16
+		if (wdg->busy_pid) {
266f16
+			printf("\n[%d] %s\nIdentity: Busy: PID %d (%s)\nDriver: %s\n",
266f16
 				wdg_cnt, wdg->dev_node,
266f16
-				wdg->dev_ident?wdg->dev_ident:"Error: Check if hogged by e.g. sbd-daemon!",
266f16
+				wdg->busy_pid,
266f16
+				wdg->busy_name?wdg->busy_name:"<unknown>",
266f16
 				wdg->dev_driver?wdg->dev_driver:"<unknown>");
266f16
+		} else {
266f16
+			printf("\n[%d] %s\nIdentity: %s\nDriver: %s\n",
266f16
+				wdg_cnt, wdg->dev_node,
266f16
+				wdg->dev_ident?wdg->dev_ident:
266f16
+					"Error: device hogged via alias major/minor?",
266f16
+				wdg->dev_driver?wdg->dev_driver:"<unknown>");
266f16
+		}
266f16
 		if ((wdg->dev_driver) && (strcmp(wdg->dev_driver, "softdog") == 0)) {
266f16
 			printf("CAUTION: Not recommended for use with sbd.\n"); 
266f16
 		}
266f16
@@ -512,6 +620,7 @@ int watchdog_test(void)
266f16
 		watchdogdev, (int) timeout_watchdog);
266f16
 	if ((watchdog_init() < 0) || (watchdog_init_interval() < 0)) {
266f16
 		printf("Failed to initialize watchdog!!!\n");
266f16
+		watchdog_info();
266f16
 		return -1;
266f16
 	}
266f16
 	printf("\n");
266f16
-- 
266f16
1.8.3.1
266f16