X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fudev%2Fudev-builtin-path_id.c;h=d540ba8392b11debb5a8a5d49dccfe84fb71c777;hb=baade8cc237c37bd8905d86ec6e9c7872d4abe03;hp=0659967c686818970a33d22f8f4eefc25fdbdd85;hpb=dd8b2bf433a42683380b6fa041660dd92f91b6a9;p=elogind.git diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 0659967c6..d540ba839 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -32,8 +32,8 @@ #include "udev.h" -static int path_prepend(char **path, const char *fmt, ...) -{ +_printf_(2,3) +static int path_prepend(char **path, const char *fmt, ...) { va_list va; char *pre; int err = 0; @@ -64,19 +64,17 @@ out: ** 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) -{ +static int format_lun_number(struct udev_device *dev, char **path) { unsigned long lun = strtoul(udev_device_get_sysnum(dev), NULL, 10); /* address method 0, peripheral device addressing with bus id of zero */ if (lun < 256) - return path_prepend(path, "lun-%d", lun); + return path_prepend(path, "lun-%lu", 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); + return path_prepend(path, "lun-0x%04lx%04lx00000000", lun & 0xffff, (lun >> 16) & 0xffff); } -static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys) -{ +static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys) { struct udev_device *parent = dev; while (parent != NULL) { @@ -91,8 +89,7 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s return dev; } -static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) -{ +static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { struct udev *udev = udev_device_get_udev(parent); struct udev_device *targetdev; struct udev_device *fcdev = NULL; @@ -121,8 +118,7 @@ out: return parent; } -static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path) -{ +static struct udev_device *handle_scsi_sas_wide_port(struct udev_device *parent, char **path) { struct udev *udev = udev_device_get_udev(parent); struct udev_device *targetdev; struct udev_device *target_parent; @@ -158,8 +154,101 @@ out: return parent; } -static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path) +static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path) { + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; + struct udev_device *target_parent; + struct udev_device *port; + struct udev_device *expander; + struct udev_device *target_sasdev = NULL; + struct udev_device *expander_sasdev = NULL; + struct udev_device *port_sasdev = NULL; + const char *sas_address = NULL; + const char *phy_id; + const char *phy_count; + 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; + + /* Get sas device */ + target_sasdev = udev_device_new_from_subsystem_sysname(udev, + "sas_device", udev_device_get_sysname(target_parent)); + if (target_sasdev == NULL) + return NULL; + + /* The next parent is sas port */ + port = udev_device_get_parent(target_parent); + if (port == NULL) { + parent = NULL; + goto out; + } + + /* Get port device */ + port_sasdev = udev_device_new_from_subsystem_sysname(udev, + "sas_port", udev_device_get_sysname(port)); + + phy_count = udev_device_get_sysattr_value(port_sasdev, "num_phys"); + if (phy_count == NULL) { + parent = NULL; + goto out; + } + + /* Check if we are simple disk */ + if (strncmp(phy_count, "1", 2) != 0) { + parent = handle_scsi_sas_wide_port(parent, path); + goto out; + } + + /* Get connected phy */ + phy_id = udev_device_get_sysattr_value(target_sasdev, "phy_identifier"); + if (phy_id == NULL) { + parent = NULL; + goto out; + } + + /* The port's parent is either hba or expander */ + expander = udev_device_get_parent(port); + if (expander == NULL) { + parent = NULL; + goto out; + } + + /* Get expander device */ + expander_sasdev = udev_device_new_from_subsystem_sysname(udev, + "sas_device", udev_device_get_sysname(expander)); + if (expander_sasdev != NULL) { + /* Get expander's address */ + sas_address = udev_device_get_sysattr_value(expander_sasdev, + "sas_address"); + if (sas_address == NULL) { + parent = NULL; + goto out; + } + } + + format_lun_number(parent, &lun); + if (sas_address) + path_prepend(path, "sas-exp%s-phy%s-%s", sas_address, phy_id, lun); + else + path_prepend(path, "sas-phy%s-%s", phy_id, lun); + + if (lun) + free(lun); +out: + udev_device_unref(target_sasdev); + udev_device_unref(expander_sasdev); + udev_device_unref(port_sasdev); + return parent; +} + +static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path) { struct udev *udev = udev_device_get_udev(parent); struct udev_device *transportdev; struct udev_device *sessiondev = NULL; @@ -217,8 +306,7 @@ out: return parent; } -static struct udev_device *handle_scsi_default(struct udev_device *parent, char **path) -{ +static struct udev_device *handle_scsi_default(struct udev_device *parent, char **path) { struct udev_device *hostdev; int host, bus, target, lun; const char *name; @@ -338,8 +426,7 @@ static struct udev_device *handle_scsi_hyperv(struct udev_device *parent, char * return parent; } -static struct udev_device *handle_scsi(struct udev_device *parent, char **path) -{ +static struct udev_device *handle_scsi(struct udev_device *parent, char **path, bool *supported_parent) { const char *devtype; const char *name; const char *id; @@ -353,6 +440,7 @@ static struct udev_device *handle_scsi(struct udev_device *parent, char **path) if (id != NULL) { parent = skip_subsystem(parent, "scsi"); path_prepend(path, "ieee1394-0x%s", id); + *supported_parent = true; goto out; } @@ -361,16 +449,19 @@ static struct udev_device *handle_scsi(struct udev_device *parent, char **path) if (strstr(name, "/rport-") != NULL) { parent = handle_scsi_fibre_channel(parent, path); + *supported_parent = true; goto out; } if (strstr(name, "/end_device-") != NULL) { parent = handle_scsi_sas(parent, path); + *supported_parent = true; goto out; } if (strstr(name, "/session") != NULL) { parent = handle_scsi_iscsi(parent, path); + *supported_parent = true; goto out; } @@ -400,8 +491,7 @@ out: return parent; } -static struct udev_device *handle_cciss(struct udev_device *parent, char **path) -{ +static struct udev_device *handle_cciss(struct udev_device *parent, char **path) { const char *str; unsigned int controller, disk; @@ -414,8 +504,7 @@ static struct udev_device *handle_cciss(struct udev_device *parent, char **path) return parent; } -static void handle_scsi_tape(struct udev_device *dev, char **path) -{ +static void handle_scsi_tape(struct udev_device *dev, char **path) { const char *name; /* must be the last device in the syspath */ @@ -429,8 +518,7 @@ static void handle_scsi_tape(struct udev_device *dev, char **path) path_prepend(path, "st%c", name[2]); } -static struct udev_device *handle_usb(struct udev_device *parent, char **path) -{ +static struct udev_device *handle_usb(struct udev_device *parent, char **path) { const char *devtype; const char *str; const char *port; @@ -452,8 +540,19 @@ static struct udev_device *handle_usb(struct udev_device *parent, char **path) return parent; } -static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) -{ +static struct udev_device *handle_bcma(struct udev_device *parent, char **path) { + const char *sysname; + unsigned int core; + + sysname = udev_device_get_sysname(parent); + if (sscanf(sysname, "bcma%*u:%u", &core) != 1) + return NULL; + + path_prepend(path, "bcma-%u", core); + return parent; +} + +static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) { struct udev_device *scsi_dev; scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device"); @@ -477,11 +576,11 @@ out: return parent; } -static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool test) -{ +static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool test) { struct udev_device *parent; char *path = NULL; - bool some_transport = false; + bool supported_transport = false; + bool supported_parent = false; /* S390 ccw bus */ parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL); @@ -501,48 +600,63 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool } else if (streq(subsys, "scsi_tape")) { handle_scsi_tape(parent, &path); } else if (streq(subsys, "scsi")) { - parent = handle_scsi(parent, &path); - some_transport = true; + parent = handle_scsi(parent, &path, &supported_parent); + supported_transport = true; } else if (streq(subsys, "cciss")) { parent = handle_cciss(parent, &path); - some_transport = true; + supported_transport = true; } else if (streq(subsys, "usb")) { parent = handle_usb(parent, &path); - some_transport = true; + supported_transport = true; + } else if (streq(subsys, "bcma")) { + parent = handle_bcma(parent, &path); + supported_transport = true; } else if (streq(subsys, "serio")) { path_prepend(&path, "serio-%s", udev_device_get_sysnum(parent)); parent = skip_subsystem(parent, "serio"); } else if (streq(subsys, "pci")) { path_prepend(&path, "pci-%s", udev_device_get_sysname(parent)); parent = skip_subsystem(parent, "pci"); + supported_parent = true; } else if (streq(subsys, "platform")) { path_prepend(&path, "platform-%s", udev_device_get_sysname(parent)); parent = skip_subsystem(parent, "platform"); - some_transport = true; + supported_transport = true; + supported_parent = true; } else if (streq(subsys, "acpi")) { path_prepend(&path, "acpi-%s", udev_device_get_sysname(parent)); parent = skip_subsystem(parent, "acpi"); + supported_parent = true; } else if (streq(subsys, "xen")) { path_prepend(&path, "xen-%s", udev_device_get_sysname(parent)); parent = skip_subsystem(parent, "xen"); - } else if (streq(subsys, "virtio")) { - path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent)); - parent = skip_subsystem(parent, "virtio"); + supported_parent = true; } else if (streq(subsys, "scm")) { path_prepend(&path, "scm-%s", udev_device_get_sysname(parent)); parent = skip_subsystem(parent, "scm"); - some_transport = true; + supported_transport = true; + supported_parent = true; } parent = udev_device_get_parent(parent); } /* - * Do not return a single-parent-device-only for block - * devices, they might have entire buses behind it which - * do not get unique IDs only by using the parent device. + * Do not return devices with an unknown parent device type. They + * might produce conflicting IDs if the parent does not provide a + * unique and predictable name. + */ + if (!supported_parent) { + free(path); + path = NULL; + } + + /* + * Do not return block devices without a well-known transport. Some + * devices do not expose their buses and do not provide a unique + * and predictable name that way. */ - if (!some_transport && streq(udev_device_get_subsystem(dev), "block")) { + if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport) { free(path); path = NULL; }