wdctl; read from /sys if necessary
The device can be inaccessible for non-root user or busy (already used by another process). In this case it seems better to read information from /sys. Note that /sys does not provide struct watchdog_info.options, so we cannot print list of supported watchdog features. Addresses: https://github.com/karelzak/util-linux/issues/804 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
e3188dd90a
commit
b3dd29d1b8
|
@ -104,6 +104,7 @@
|
|||
|
||||
#define _PATH_SYS_BLOCK "/sys/block"
|
||||
#define _PATH_SYS_DEVBLOCK "/sys/dev/block"
|
||||
#define _PATH_SYS_DEVCHAR "/sys/dev/char"
|
||||
#define _PATH_SYS_CLASS "/sys/class"
|
||||
#define _PATH_SYS_SCSI "/sys/bus/scsi"
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@ Show hardware watchdog status. The default device is
|
|||
If more than one device is specified then the output is separated by
|
||||
one blank line.
|
||||
.PP
|
||||
If the device is already used or user has no permissions to read from the device than
|
||||
.B wdctl
|
||||
reads data from sysfs. In this case information about supported features (flags) might be missing.
|
||||
.PP
|
||||
Note that the number of supported watchdog features is hardware specific.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libsmartcols.h>
|
||||
|
||||
|
@ -36,6 +39,7 @@
|
|||
#include "pathnames.h"
|
||||
#include "strutils.h"
|
||||
#include "carefulputc.h"
|
||||
#include "path.h"
|
||||
|
||||
/*
|
||||
* since 2.6.18
|
||||
|
@ -113,12 +117,14 @@ struct wd_device {
|
|||
|
||||
uint32_t status;
|
||||
uint32_t bstatus;
|
||||
int nowayout;
|
||||
|
||||
struct watchdog_info ident;
|
||||
|
||||
unsigned int has_timeout : 1,
|
||||
has_timeleft : 1,
|
||||
has_pretimeout : 1;
|
||||
has_pretimeout : 1,
|
||||
has_nowayout : 1;
|
||||
};
|
||||
|
||||
struct wd_control {
|
||||
|
@ -282,6 +288,10 @@ static int show_flags(struct wd_control *ctl, struct wd_device *wd, uint32_t wan
|
|||
struct libscols_table *table;
|
||||
uint32_t flags;
|
||||
|
||||
/* information about supported bits is probably missing in /sys */
|
||||
if (!wd->ident.options)
|
||||
return 0;
|
||||
|
||||
scols_init_debug(0);
|
||||
|
||||
/* create output table */
|
||||
|
@ -388,7 +398,7 @@ static int set_watchdog(struct wd_device *wd, int timeout)
|
|||
*
|
||||
* Don't use err() or exit() here!
|
||||
*/
|
||||
static int read_watchdog(struct wd_device *wd)
|
||||
static int read_watchdog_from_device(struct wd_device *wd)
|
||||
{
|
||||
int fd;
|
||||
sigset_t sigs, oldsigs;
|
||||
|
@ -401,13 +411,8 @@ static int read_watchdog(struct wd_device *wd)
|
|||
|
||||
fd = open(wd->devpath, O_WRONLY|O_CLOEXEC);
|
||||
|
||||
if (fd < 0) {
|
||||
if (errno == EBUSY)
|
||||
warnx(_("%s: watchdog already in use, terminating."),
|
||||
wd->devpath);
|
||||
warn(_("cannot open %s"), wd->devpath);
|
||||
return -1;
|
||||
}
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (ioctl(fd, WDIOC_GETSUPPORT, &wd->ident) < 0)
|
||||
warn(_("%s: failed to get information about watchdog"), wd->devpath);
|
||||
|
@ -445,6 +450,64 @@ static int read_watchdog(struct wd_device *wd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Returns: <0 error, 0 success, 1 unssuported */
|
||||
static int read_watchdog_from_sysfs(struct wd_device *wd)
|
||||
{
|
||||
struct path_cxt *sys;
|
||||
struct stat st;
|
||||
int rc;
|
||||
|
||||
rc = stat(wd->devpath, &st);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
sys = ul_new_path(_PATH_SYS_DEVCHAR "/%u:%u",
|
||||
major(st.st_rdev), minor(st.st_rdev));
|
||||
if (!sys)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ul_path_get_dirfd(sys) < 0)
|
||||
goto nosysfs; /* device not in /sys */
|
||||
|
||||
if (ul_path_access(sys, F_OK, "identity") != 0)
|
||||
goto nosysfs; /* no info in /sys (old miscdev?) */
|
||||
|
||||
ul_path_read_buffer(sys, (char *) wd->ident.identity, sizeof(wd->ident.identity), "identity");
|
||||
|
||||
ul_path_scanf(sys, "status", "%x", &wd->status);
|
||||
ul_path_read_u32(sys, &wd->bstatus, "bootstatus");
|
||||
|
||||
if (ul_path_read_s32(sys, &wd->nowayout, "nowayout") == 0)
|
||||
wd->has_nowayout = 1;
|
||||
if (ul_path_read_s32(sys, &wd->timeout, "timeout") == 0)
|
||||
wd->has_timeout = 1;
|
||||
if (ul_path_read_s32(sys, &wd->pretimeout, "pretimeout") == 0)
|
||||
wd->has_pretimeout = 1;
|
||||
if (ul_path_read_s32(sys, &wd->timeleft, "timeleft") == 0)
|
||||
wd->has_timeleft = 1;
|
||||
|
||||
ul_unref_path(sys);
|
||||
return 0;
|
||||
nosysfs:
|
||||
ul_unref_path(sys);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_watchdog(struct wd_device *wd)
|
||||
{
|
||||
int rc = read_watchdog_from_device(wd);
|
||||
|
||||
if (rc == -EBUSY || rc == -EACCES || rc == -EPERM)
|
||||
rc = read_watchdog_from_sysfs(wd);
|
||||
|
||||
if (rc) {
|
||||
warn(_("cannot read information about %s"), wd->devpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_timeouts(struct wd_device *wd)
|
||||
{
|
||||
if (wd->has_timeout)
|
||||
|
|
Loading…
Reference in New Issue