#include "defaults.h"
struct path *
-store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
+store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice,
+ int flag)
{
struct path * pp;
+ const char * devname;
+
+ devname = udev_device_get_sysname(udevice);
+ if (!devname)
+ return NULL;
pp = alloc_path();
condlog(0, "pp->dev too small");
goto out;
}
+ pp->udev = udev_device_ref(udevice);
if (pathinfo(pp, hwtable, flag))
goto out;
pp = find_path_by_dev(pathvec, (char *)devname);
if (!pp) {
pp = store_pathinfo(pathvec, conf->hwtable,
- (char *)devname, flag);
+ udevice, flag);
return (pp ? 0 : 1);
}
return pathinfo(pp, conf->hwtable, flag);
return r;
}
-#define declare_sysfs_get_str(fname) \
-extern int \
-sysfs_get_##fname (const char * devpath, char * buff, size_t len) \
-{ \
- int size; \
- \
- size = sysfs_attr_get_value(devpath, #fname, buff, len); \
- if (!size) { \
+#define declare_sysfs_get_str(fname) \
+extern int \
+sysfs_get_##fname (struct udev_device * udev, char * buff, size_t len) \
+{ \
+ const char * attr; \
+ const char * devname; \
+ \
+ devname = udev_device_get_sysname(udev); \
+ \
+ attr = udev_device_get_sysattr_value(udev, #fname); \
+ if (!attr) { \
condlog(3, "%s: attribute %s not found in sysfs", \
- devpath, #fname); \
+ devname, #fname); \
return 1; \
} \
- if (size == len) { \
+ if (strlen(attr) > len) { \
condlog(3, "%s: overflow in attribute %s", \
- devpath, #fname); \
+ devname, #fname); \
return 2; \
} \
- strchop(buff); \
+ strlcpy(buff, attr, len); \
return 0; \
}
declare_sysfs_get_str(dev);
int
-sysfs_get_timeout(const char *devpath, unsigned int *timeout)
+sysfs_get_timeout(struct path *pp, unsigned int *timeout)
{
- char attr_path[SYSFS_PATH_SIZE], attr[NAME_SIZE];
- size_t len;
+ const char *attr = NULL;
+ const char *subsys;
+ struct udev_device *parent;
int r;
unsigned int t;
- if (!devpath)
- return 1;
-
- if (safe_sprintf(attr_path, "%s/device", devpath))
+ if (!pp->udev)
return 1;
- len = sysfs_attr_get_value(attr_path, "timeout", attr, NAME_SIZE);
- if (!len) {
- condlog(3, "%s: No timeout value in sysfs", devpath);
+ parent = pp->udev;
+ while (parent) {
+ subsys = udev_device_get_subsystem(parent);
+ attr = udev_device_get_sysattr_value(parent, "timeout");
+ if (subsys && attr)
+ break;
+ parent = udev_device_get_parent(parent);
+ }
+ if (!attr) {
+ condlog(3, "%s: No timeout value in sysfs", pp->dev);
return 1;
}
if (r != 1) {
condlog(3, "%s: Cannot parse timeout attribute '%s'",
- devpath, attr);
+ pp->dev, attr);
return 1;
}
}
int
-sysfs_get_size (const char * devpath, unsigned long long * size)
+sysfs_get_size (struct path *pp, unsigned long long * size)
{
- char attr[NAME_SIZE];
- size_t len;
+ const char * attr;
int r;
- len = sysfs_attr_get_value(devpath, "size", attr, NAME_SIZE);
- if (!len) {
- condlog(3, "%s: No size attribute in sysfs", devpath);
+ if (!pp->udev)
+ return 1;
+
+ attr = udev_device_get_sysattr_value(pp->udev, "size");
+ if (!attr) {
+ condlog(3, "%s: No size attribute in sysfs", pp->dev);
return 1;
}
if (r != 1) {
condlog(3, "%s: Cannot parse size attribute '%s'",
- devpath, attr);
+ pp->dev, attr);
return 1;
}
}
int
-sysfs_get_tgt_nodename (const char * devpath, char * node,
- unsigned int host, unsigned int channel,
- unsigned int target)
+sysfs_get_tgt_nodename (struct path *pp, char * node)
{
- unsigned int checkhost, session;
+ const char * targetid;
+ struct udev_device *parent;
char attr_path[SYSFS_PATH_SIZE];
size_t len;
+ parent = pp->udev;
+ while (parent) {
+ targetid = udev_device_get_sysname(parent);
+ if (!strncmp(targetid , "target", 6))
+ break;
+ parent = udev_device_get_parent(parent);
+ }
+ /* 'target' needs to exist */
+ if (!parent || !targetid)
+ return 1;
+ /* Check if it's FibreChannel */
if (safe_sprintf(attr_path,
- "/class/fc_transport/target%i:%i:%i",
- host, channel, target)) {
+ "/class/fc_transport/%s", targetid)) {
condlog(0, "attr_path too small");
return 1;
}
- len = sysfs_attr_get_value(attr_path, "node_name", node, NODE_NAME_SIZE);
+ len = sysfs_attr_get_value(attr_path, "node_name",
+ node, NODE_NAME_SIZE);
if (len)
return 0;
- if (sscanf(devpath, "/devices/platform/host%u/session%u/",
- &checkhost, &session) != 2)
- return 1;
- if (checkhost != host)
- return 1;
- if (safe_sprintf(attr_path, "/devices/platform/host%u/session%u/iscsi_session/session%u", host, session, session)) {
- condlog(0, "attr_path too small");
- return 1;
+ /* Check for iSCSI */
+ parent = pp->udev;
+ while (parent) {
+ targetid = udev_device_get_sysname(parent);
+ if (!strncmp(targetid , "session", 6))
+ break;
+ parent = udev_device_get_parent(parent);
+ }
+ if (parent) {
+ if (safe_sprintf(attr_path, "/class/iscsi_session/%s",
+ targetid)) {
+ condlog(0, "attr_path too small");
+ return 1;
+ }
+ len = sysfs_attr_get_value(attr_path, "targetname", node,
+ NODE_NAME_SIZE);
+ if (len)
+ return 0;
}
- len = sysfs_attr_get_value(attr_path, "targetname", node,
- NODE_NAME_SIZE);
- if (!len)
- return 1;
-
- return 0;
+ return 1;
}
static int
}
static int
-scsi_sysfs_pathinfo (struct path * pp, const char * parent)
+scsi_sysfs_pathinfo (struct path * pp)
{
- char attr_path[FILE_NAME_SIZE];
+ struct udev_device *parent;
+ const char *attr_path = NULL;
+
+ parent = pp->udev;
+ while (parent) {
+ if (!strncmp(udev_device_get_subsystem(parent), "scsi", 4)) {
+ attr_path = udev_device_get_sysname(parent);
+ if (!attr_path)
+ break;
+ if (sscanf(attr_path, "%i:%i:%i:%i",
+ &pp->sg_id.host_no,
+ &pp->sg_id.channel,
+ &pp->sg_id.scsi_id,
+ &pp->sg_id.lun) == 4)
+ break;
+ }
+ parent = udev_device_get_parent(parent);
+ }
+ if (!attr_path || pp->sg_id.host_no == -1)
+ return 1;
if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE))
return 1;
/*
* host / bus / target / lun
*/
- basenamecpy(parent, attr_path, FILE_NAME_SIZE);
-
- sscanf(attr_path, "%i:%i:%i:%i",
- &pp->sg_id.host_no,
- &pp->sg_id.channel,
- &pp->sg_id.scsi_id,
- &pp->sg_id.lun);
condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
pp->dev,
pp->sg_id.host_no,
/*
* target node name
*/
- if(!sysfs_get_tgt_nodename(parent, pp->tgt_node_name,
- pp->sg_id.host_no,
- pp->sg_id.channel,
- pp->sg_id.scsi_id)) {
+ if(!sysfs_get_tgt_nodename(pp, pp->tgt_node_name)) {
condlog(3, "%s: tgt_node_name = %s",
pp->dev, pp->tgt_node_name);
}
}
static int
-ccw_sysfs_pathinfo (struct path * pp, const char * parent)
+ccw_sysfs_pathinfo (struct path * pp)
{
- char attr_path[FILE_NAME_SIZE];
- char attr_buff[FILE_NAME_SIZE];
+ struct udev_device *parent;
+ char attr_buff[NAME_SIZE];
+ const char *attr_path;
+
+ parent = pp->udev;
+ while (parent) {
+ if (!strncmp(udev_device_get_subsystem(parent), "ccw", 3))
+ break;
+ parent = udev_device_get_parent(parent);
+ }
+ if (!parent)
+ return 1;
sprintf(pp->vendor_id, "IBM");
/*
* host / bus / target / lun
*/
- basenamecpy(parent, attr_path, FILE_NAME_SIZE);
+ attr_path = udev_device_get_sysname(parent);
pp->sg_id.lun = 0;
sscanf(attr_path, "%i.%i.%x",
&pp->sg_id.host_no,
}
static int
-cciss_sysfs_pathinfo (struct path * pp, const char * devpath)
+cciss_sysfs_pathinfo (struct path * pp)
{
- char attr_path[FILE_NAME_SIZE];
+ const char * attr_path;
/*
* host / bus / target / lun
*/
- basenamecpy(devpath, attr_path, FILE_NAME_SIZE);
+ attr_path = udev_device_get_devpath(pp->udev);
+ if (!attr_path)
+ return 1;
+
pp->sg_id.lun = 0;
pp->sg_id.channel = 0;
sscanf(attr_path, "cciss!c%id%i",
}
static int
-common_sysfs_pathinfo (struct path * pp, const char * devpath)
+common_sysfs_pathinfo (struct path * pp)
{
- size_t len;
-
- len = sysfs_attr_get_value(devpath, "dev",
- pp->dev_t, BLK_DEV_SIZE);
- if (!len) {
+ if (!pp->udev) {
+ condlog(4, "%s: udev not initialised", pp->dev);
+ return 1;
+ }
+ if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE)) {
condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev);
return 1;
}
condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t);
- if (sysfs_get_size(devpath, &pp->size))
+ if (sysfs_get_size(pp, &pp->size))
return 1;
condlog(3, "%s: size = %llu", pp->dev, pp->size);
return 0;
}
-struct sysfs_device *sysfs_device_from_path(struct path *pp)
-{
- char sysdev[FILE_NAME_SIZE];
-
- if (pp->sysdev && sysfs_device_verify(pp->sysdev))
- return pp->sysdev;
-
- strlcpy(sysdev,"/block/", FILE_NAME_SIZE);
- strlcat(sysdev,pp->dev, FILE_NAME_SIZE);
-
- return sysfs_device_get(sysdev);
-}
-
int
path_offline (struct path * pp)
{
- struct sysfs_device * parent;
+ struct udev_device * parent;
char buff[SCSI_STATE_SIZE];
if (pp->bus != SYSFS_BUS_SCSI)
return PATH_UP;
- pp->sysdev = sysfs_device_from_path(pp);
- if (!pp->sysdev) {
- condlog(1, "%s: failed to get sysfs information", pp->dev);
- return PATH_WILD;
+ parent = pp->udev;
+ while (parent) {
+ if (!strncmp(udev_device_get_subsystem(parent), "scsi", 4))
+ break;
+ parent = udev_device_get_parent(parent);
}
- parent = sysfs_device_get_parent(pp->sysdev);
- if (!parent)
- parent = pp->sysdev;
- if (parent && !strncmp(parent->kernel, "block",5))
- parent = sysfs_device_get_parent(parent);
if (!parent) {
- condlog(1, "%s: failed to get parent", pp->dev);
+ condlog(1, "%s: failed to get sysfs information", pp->dev);
return PATH_WILD;
}
- if (sysfs_get_state(parent->devpath, buff, SCSI_STATE_SIZE))
+ if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE))
return PATH_WILD;
condlog(3, "%s: path state = %s", pp->dev, buff);
extern int
sysfs_pathinfo(struct path * pp)
{
- struct sysfs_device *parent;
-
- pp->sysdev = sysfs_device_from_path(pp);
- if (!pp->sysdev) {
- condlog(1, "%s: failed to get sysfs information", pp->dev);
+ if (common_sysfs_pathinfo(pp))
return 1;
- }
-
- if (common_sysfs_pathinfo(pp, pp->sysdev->devpath))
- return 1;
-
- parent = sysfs_device_get_parent(pp->sysdev);
- if (!parent)
- parent = pp->sysdev;
- if (parent && !strncmp(parent->kernel, "block",5))
- parent = sysfs_device_get_parent(parent);
- if (!parent) {
- condlog(1, "%s: failed to get parent", pp->dev);
- return 1;
- }
pp->bus = SYSFS_BUS_UNDEF;
if (!strncmp(pp->dev,"cciss",5))
if (pp->bus == SYSFS_BUS_UNDEF)
return 0;
else if (pp->bus == SYSFS_BUS_SCSI) {
- if (scsi_sysfs_pathinfo(pp, parent->devpath))
+ if (scsi_sysfs_pathinfo(pp))
return 1;
} else if (pp->bus == SYSFS_BUS_CCW) {
- if (ccw_sysfs_pathinfo(pp, parent->devpath))
+ if (ccw_sysfs_pathinfo(pp))
return 1;
} else if (pp->bus == SYSFS_BUS_CCISS) {
- if (cciss_sysfs_pathinfo(pp, pp->sysdev->devpath))
+ if (cciss_sysfs_pathinfo(pp))
return 1;
}
return 0;
condlog(3, "%s: get_state", pp->dev);
if (!checker_selected(c)) {
- if (daemon || pp->sysdev == NULL) {
+ if (daemon) {
if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) {
condlog(3, "%s: couldn't get sysfs pathinfo",
pp->dev);
checker_clear_message(c);
if (daemon)
checker_set_async(c);
- if (!conf->checker_timeout && pp->sysdev)
- sysfs_get_timeout(pp->sysdev->devpath, &(c->timeout));
+ if (!conf->checker_timeout)
+ sysfs_get_timeout(pp, &(c->timeout));
state = checker_check(c);
condlog(3, "%s: state = %s", pp->dev, checker_state_name(state));
if (state == PATH_DOWN && strlen(checker_message(c)))
char sysfs_path[PATH_SIZE];
-/* list of sysfs devices */
-static LIST_HEAD(sysfs_dev_list);
-struct sysfs_dev {
- struct list_head node;
- struct sysfs_device dev;
- int refcount;
-};
-
int sysfs_init(char *path, size_t len)
{
if (path) {
strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
dbg("sysfs_path='%s'", sysfs_path);
- INIT_LIST_HEAD(&sysfs_dev_list);
return 0;
}
-void sysfs_cleanup(void)
-{
- struct sysfs_dev *sysdev_loop;
- struct sysfs_dev *sysdev_temp;
-
- list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) {
- list_del(&sysdev_loop->node);
- free(sysdev_loop);
- }
-}
-
-void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath)
-{
- char *pos;
-
- strlcpy(dev->devpath, devpath, sizeof(dev->devpath));
-
- /* set kernel name */
- pos = strrchr(dev->devpath, '/');
- if (pos == NULL)
- return;
- strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel));
- dbg("kernel='%s'", dev->kernel);
-
- /* some devices have '!' in their name, change that to '/' */
- pos = dev->kernel;
- while (pos[0] != '\0') {
- if (pos[0] == '!')
- pos[0] = '/';
- pos++;
- }
-}
-
int sysfs_resolve_link(char *devpath, size_t size)
{
char link_path[PATH_SIZE];
return 0;
}
-/*
- * Caution: this routine is called extremely often.
- * Should be as efficient as possible.
- */
-struct sysfs_device *sysfs_device_get(const char *devpath)
-{
- char path[PATH_SIZE];
- char devpath_real[PATH_SIZE];
- struct sysfs_device *dev = NULL;
- struct sysfs_dev *sysdev_loop, *sysdev;
- struct stat statbuf;
-
- dbg("open '%s'", devpath);
- strlcpy(devpath_real, devpath, sizeof(devpath_real));
- remove_trailing_chars(devpath_real, '/');
- if (devpath[0] == '\0' )
- return NULL;
-
- /* if we got a link, resolve it to the real device */
- strlcpy(path, sysfs_path, sizeof(path));
- strlcat(path, devpath_real, sizeof(path));
- if (lstat(path, &statbuf) != 0) {
- /* if stat fails look in the cache */
- dbg("stat '%s' failed: %s", path, strerror(errno));
- list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) {
- if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) {
- dbg("found vanished dev in cache '%s'",
- sysdev_loop->dev.devpath);
- sysdev_loop->refcount++;
- return &sysdev_loop->dev;
- }
- }
- return NULL;
- }
-
- if (S_ISLNK(statbuf.st_mode)) {
- if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0)
- return NULL;
- }
-
- list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) {
- if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) {
- dbg("found dev in cache '%s'", sysdev_loop->dev.devpath);
- dev = &sysdev_loop->dev;
- sysdev_loop->refcount++;
- }
- }
-
- if(!dev) {
- /* it is a new device */
- dbg("new device '%s'", devpath_real);
- sysdev = malloc(sizeof(struct sysfs_dev));
- if (sysdev == NULL)
- return NULL;
- memset(sysdev, 0x00, sizeof(struct sysfs_dev));
- sysdev->refcount = 1;
- list_add(&sysdev->node, &sysfs_dev_list);
- dev = &sysdev->dev;
- }
-
- sysfs_device_set_values(dev, devpath_real);
-
- return dev;
-}
-
-struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
-{
- char parent_devpath[PATH_SIZE];
- char *pos;
-
- dbg("open '%s'", dev->devpath);
-
- /* look if we already know the parent */
- if (dev->parent != NULL)
- return dev->parent;
-
- strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
- dbg("'%s'", parent_devpath);
-
- /* strip last element */
- pos = strrchr(parent_devpath, '/');
- if (pos == NULL || pos == parent_devpath)
- return NULL;
- pos[0] = '\0';
-
- if (strncmp(parent_devpath, "/class", 6) == 0) {
- pos = strrchr(parent_devpath, '/');
- if (pos == &parent_devpath[6] || pos == parent_devpath) {
- dbg("/class top level, look for device link");
- goto device_link;
- }
- }
- if (strcmp(parent_devpath, "/block") == 0) {
- dbg("/block top level, look for device link");
- goto device_link;
- }
-
- /* are we at the top level? */
- pos = strrchr(parent_devpath, '/');
- if (pos == NULL || pos == parent_devpath)
- return NULL;
-
- /* get parent and remember it */
- dev->parent = sysfs_device_get(parent_devpath);
- return dev->parent;
-
-device_link:
- strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
- strlcat(parent_devpath, "/device", sizeof(parent_devpath));
- if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0)
- return NULL;
-
- /* get parent and remember it */
- dev->parent = sysfs_device_get(parent_devpath);
- return dev->parent;
-}
-
-struct sysfs_device *sysfs_device_verify(struct sysfs_device *dev)
-{
- char path[PATH_SIZE];
- struct stat statbuf;
-
- if (!dev->devpath)
- return NULL;
- strlcpy(path, sysfs_path, sizeof(path));
- strlcat(path, dev->devpath, sizeof(path));
- if (stat(dev->devpath, &statbuf) == 0 &&
- S_ISDIR(statbuf.st_mode))
- return dev;
-
- return NULL;
-}
-
-void sysfs_device_put(struct sysfs_device *dev)
-{
- struct sysfs_dev *sysdev_loop;
-
- list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) {
- if (&sysdev_loop->dev == dev) {
- sysdev_loop->refcount--;
- if (!sysdev_loop->refcount) {
- dbg("removed dev '%s' from cache",
- sysdev_loop->dev.devpath);
- list_del(&sysdev_loop->node);
- free(sysdev_loop);
- } else {
- dbg("dev '%s' still in cache, refcount %d",
- sysdev_loop->dev.devpath,
- sysdev_loop->refcount);
- }
- return;
- }
- }
- dbg("dev '%s' not found in cache", dev->devpath);
-
- return;
-}
-
size_t sysfs_attr_get_value(const char *devpath, const char *attr_name,
char *attr_value, int attr_len)
{