]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-device: device_id - set correctly for 'drivers'
authorTom Gundersen <teg@jklm.no>
Sun, 26 Jun 2016 21:05:27 +0000 (23:05 +0200)
committerTom Gundersen <teg@jklm.no>
Mon, 27 Jun 2016 07:54:20 +0000 (09:54 +0200)
The 'drivers' pseudo-subsystem needs special treatment. These pseudo-devices are
found under /sys/bus/drivers/, so needs the real subsystem encoded
in the device_id in order to be resolved.

The reader side already assumed this to be the case.

src/libsystemd/sd-device/device-internal.h
src/libsystemd/sd-device/sd-device.c

index ab222e27decf02d54c2935289db459f4e442704c..9fad388953f589e42c9d4765e0a5c2e02dc97119 100644 (file)
@@ -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 */
 
index 5c9e00ed80c69589213df6594b8bc4bbd6258125..c13f6fca287b488443c41607b71ccdb8245eb538 100644 (file)
@@ -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;