diff options
-rw-r--r-- | src/libsystemd/sd-device/device-internal.h | 2 | ||||
-rw-r--r-- | src/libsystemd/sd-device/sd-device.c | 84 |
2 files changed, 72 insertions, 14 deletions
diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h index ab222e27de..9fad388953 100644 --- a/src/libsystemd/sd-device/device-internal.h +++ b/src/libsystemd/sd-device/device-internal.h @@ -76,6 +76,8 @@ struct sd_device { char *subsystem; bool subsystem_set; /* don't reread subsystem */ + char *driver_subsystem; /* only set for the 'drivers' subsystem */ + bool driver_subsystem_set; /* don't reread subsystem */ char *driver; bool driver_set; /* don't reread driver */ diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 5c9e00ed80..c13f6fca28 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -75,6 +75,7 @@ _public_ sd_device *sd_device_unref(sd_device *device) { free(device->devtype); free(device->devname); free(device->subsystem); + free(device->driver_subsystem); free(device->driver); free(device->id_filename); free(device->properties_strv); @@ -766,21 +767,45 @@ int device_set_subsystem(sd_device *device, const char *_subsystem) { return 0; } +static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) { + _cleanup_free_ char *subsystem = NULL; + int r; + + assert(device); + assert(_subsystem); + assert(*_subsystem); + + subsystem = strdup(_subsystem); + if (!subsystem) + return -ENOMEM; + + r = device_set_subsystem(device, "drivers"); + if (r < 0) + return r; + + free(device->driver_subsystem); + device->driver_subsystem = subsystem; + subsystem = NULL; + + return 0; +} + _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { + const char *syspath, *drivers = NULL; + int r; + assert_return(ret, -EINVAL); assert_return(device, -EINVAL); + r = sd_device_get_syspath(device, &syspath); + if (r < 0) + return r; + if (!device->subsystem_set) { _cleanup_free_ char *subsystem = NULL; - const char *syspath; char *path; - int r; /* read 'subsystem' link */ - r = sd_device_get_syspath(device, &syspath); - if (r < 0) - return r; - path = strjoina(syspath, "/subsystem"); r = readlink_value(path, &subsystem); if (r >= 0) @@ -788,16 +813,39 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { /* use implicit names */ else if (path_startswith(device->devpath, "/module/")) r = device_set_subsystem(device, "module"); - else if (strstr(device->devpath, "/drivers/")) - r = device_set_subsystem(device, "drivers"); - else if (path_startswith(device->devpath, "/subsystem/") || - path_startswith(device->devpath, "/class/") || - path_startswith(device->devpath, "/bus/")) + else if (!(drivers = strstr(syspath, "/drivers/")) && + (path_startswith(device->devpath, "/subsystem/") || + path_startswith(device->devpath, "/class/") || + path_startswith(device->devpath, "/bus/"))) r = device_set_subsystem(device, "subsystem"); if (r < 0 && r != -ENOENT) return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath); device->subsystem_set = true; + } else if (!device->driver_subsystem_set) + drivers = strstr(syspath, "/drivers/"); + + if (!device->driver_subsystem_set) { + if (drivers) { + _cleanup_free_ char *subpath = NULL; + + subpath = strndup(syspath, drivers - syspath); + if (!subpath) + r = -ENOMEM; + else { + const char *subsys; + + subsys = strrchr(subpath, '/'); + if (!subsys) + r = -EINVAL; + else + r = device_set_drivers_subsystem(device, subsys + 1); + } + if (r < 0 && r != -ENOENT) + return log_debug_errno(r, "sd-device: could not set subsystem for driver %s: %m", device->devpath); + } + + device->driver_subsystem_set = true; } if (!device->subsystem) @@ -1234,9 +1282,17 @@ int device_get_id_filename(sd_device *device, const char **ret) { if (!subsystem) return -EINVAL; - r = asprintf(&id, "+%s:%s", subsystem, sysname); - if (r < 0) - return -ENOMEM; + if (streq(subsystem, "drivers")) { + /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem + * encoded as well */ + r = asprintf(&id, "+drivers:%s:%s", device->driver_subsystem, sysname); + if (r < 0) + return -ENOMEM; + } else { + r = asprintf(&id, "+%s:%s", subsystem, sysname); + if (r < 0) + return -ENOMEM; + } } device->id_filename = id; |