/*
- * compose persisistent device path
+ * compose persistent device path
*
* Copyright (C) 2009 Kay Sievers <kay.sievers@vrfy.org>
*
static int path_prepend(char **path, const char *fmt, ...)
{
va_list va;
- char *old;
char *pre;
- int err;
-
- old = *path;
+ int err = 0;
va_start(va, fmt);
err = vasprintf(&pre, fmt, va);
va_end(va);
if (err < 0)
- return err;
+ goto out;
- if (old != NULL) {
- err = asprintf(path, "%s-%s", pre, old);
- if (err < 0)
- return err;
+ if (*path != NULL) {
+ char *new;
+
+ err = asprintf(&new, "%s-%s", pre, *path);
free(pre);
+ if (err < 0)
+ goto out;
+ free(*path);
+ *path = new;
} else {
*path = pre;
}
+out:
+ return err;
+}
+
+/*
+** Linux only supports 32 bit luns.
+** See drivers/scsi/scsi_scan.c::scsilun_to_int() for more details.
+*/
+static int format_lun_number(struct udev_device *dev, char **path)
+{
+ unsigned long lun = strtoul(udev_device_get_sysnum(dev), NULL, 10);
- free(old);
- return 0;
+ /* address method 0, peripheral device addressing with bus id of zero */
+ if (lun < 256)
+ return path_prepend(path, "lun-%d", lun);
+ /* handle all other lun addressing methods by using a variant of the original lun format */
+ return path_prepend(path, "lun-0x%04x%04x00000000", (lun & 0xffff), (lun >> 16) & 0xffff);
}
static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys)
struct udev_device *targetdev;
struct udev_device *fcdev = NULL;
const char *port;
- unsigned int lun;
+ char *lun = NULL;;
targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
if (targetdev == NULL)
goto out;
}
- lun = strtoul(udev_device_get_sysnum(parent), NULL, 10);
- path_prepend(path, "fc-%s:0x%04x%04x00000000", port, lun & 0xffff, (lun >> 16) & 0xffff);
+ format_lun_number(parent, &lun);
+ path_prepend(path, "fc-%s-%s", port, lun);
+ if (lun)
+ free(lun);
out:
udev_device_unref(fcdev);
return parent;
static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path)
{
- return NULL;
+ struct udev *udev = udev_device_get_udev(parent);
+ struct udev_device *targetdev;
+ struct udev_device *target_parent;
+ struct udev_device *sasdev;
+ const char *sas_address;
+ char *lun = NULL;
+
+ targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
+ if (targetdev == NULL)
+ return NULL;
+
+ target_parent = udev_device_get_parent(targetdev);
+ if (target_parent == NULL)
+ return NULL;
+
+ sasdev = udev_device_new_from_subsystem_sysname(udev, "sas_device",
+ udev_device_get_sysname(target_parent));
+ if (sasdev == NULL)
+ return NULL;
+
+ sas_address = udev_device_get_sysattr_value(sasdev, "sas_address");
+ if (sas_address == NULL) {
+ parent = NULL;
+ goto out;
+ }
+
+ format_lun_number(parent, &lun);
+ path_prepend(path, "sas-%s-%s", sas_address, lun);
+ if (lun)
+ free(lun);
+out:
+ udev_device_unref(sasdev);
+ return parent;
}
static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path)
struct udev_device *conndev = NULL;
const char *addr;
const char *port;
+ char *lun = NULL;
/* find iscsi session */
transportdev = parent;
- while (1) {
+ for (;;) {
transportdev = udev_device_get_parent(transportdev);
if (transportdev == NULL)
return NULL;
if (strncmp(udev_device_get_sysname(transportdev), "session", 7) == 0)
break;
}
- if (transportdev == NULL)
- return NULL;
/* find iscsi session device */
sessiondev = udev_device_new_from_subsystem_sysname(udev, "iscsi_session", udev_device_get_sysname(transportdev));
goto out;
}
- path_prepend(path, "ip-%s:%s-iscsi-%s-lun-%s", addr, port, target, udev_device_get_sysnum(parent));
+ format_lun_number(parent, &lun);
+ path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun);
+ if (lun)
+ free(lun);
out:
udev_device_unref(sessiondev);
udev_device_unref(conndev);
return parent;
}
-static void handle_scsi_tape(struct udev_device *dev, char **suffix)
+static void handle_scsi_tape(struct udev_device *dev, char **path)
{
const char *name;
+ /* must be the last device in the syspath */
+ if (*path != NULL)
+ return;
+
name = udev_device_get_sysname(dev);
if (strncmp(name, "nst", 3) == 0 && strchr("lma", name[3]) != NULL)
- asprintf(suffix, "nst%c", name[3]);
+ path_prepend(path, "nst%c", name[3]);
else if (strncmp(name, "st", 2) == 0 && strchr("lma", name[2]) != NULL)
- asprintf(suffix, "st%c", name[2]);
+ path_prepend(path, "st%c", name[2]);
}
static struct udev_device *handle_usb(struct udev_device *parent, char **path)
const char *port;
devtype = udev_device_get_devtype(parent);
- if (devtype == NULL || strcmp(devtype, "usb_interface") != 0)
+ if (devtype == NULL)
+ return parent;
+ if (strcmp(devtype, "usb_interface") != 0 && strcmp(devtype, "usb_device") != 0)
return parent;
str = udev_device_get_sysname(parent);
struct udev_device *parent;
char syspath[UTIL_PATH_SIZE];
const char *devpath;
- char *path;
- char *path_suffix;
- int rc = 1;
+ char *path = NULL;
+ int rc = EXIT_FAILURE;
udev = udev_new();
if (udev == NULL)
printf("Usage: path_id [--debug] [--help] <devpath>\n"
" --debug print debug information\n"
" --help print this help text\n\n");
- default:
- rc = 1;
goto exit;
}
}
goto exit;
}
- path = NULL;
- path_suffix = NULL;
-
/* S390 ccw bus */
parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL);
if (parent != NULL) {
if (subsys == NULL) {
;
} else if (strcmp(subsys, "scsi_tape") == 0) {
- handle_scsi_tape(parent, &path_suffix);
+ handle_scsi_tape(parent, &path);
} else if (strcmp(subsys, "scsi") == 0) {
parent = handle_scsi(parent, &path);
} else if (strcmp(subsys, "cciss") == 0) {
} else if (strcmp(subsys, "xen") == 0) {
path_prepend(&path, "xen-%s", udev_device_get_sysname(parent));
parent = skip_subsystem(parent, "xen");
+ } else if (strcmp(subsys, "virtio") == 0) {
+ path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent));
+ parent = skip_subsystem(parent, "virtio");
}
parent = udev_device_get_parent(parent);
}
out:
if (path != NULL) {
- if (path_suffix != NULL) {
- printf("ID_PATH=%s%s\n", path, path_suffix);
- free(path_suffix);
- } else {
- printf("ID_PATH=%s\n", path);
- }
+ printf("ID_PATH=%s\n", path);
free(path);
- rc = 0;
+ rc = EXIT_SUCCESS;
}
udev_device_unref(dev);