]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd/sd-device/sd-device.c
fileio: introduce read_full_virtual_file() for reading virtual files in sysfs, procfs
[thirdparty/systemd.git] / src / libsystemd / sd-device / sd-device.c
index db58615df53df64109360cdd469ac5d17ad5fcbf..f35612fe12bc7cc2f9b3bd2f8066d59c49a4f0d4 100644 (file)
@@ -29,7 +29,7 @@
 #include "util.h"
 
 int device_new_aux(sd_device **ret) {
-        sd_device *device = NULL;
+        sd_device *device;
 
         assert(ret);
 
@@ -43,6 +43,7 @@ int device_new_aux(sd_device **ret) {
                 .devmode = (mode_t) -1,
                 .devuid = (uid_t) -1,
                 .devgid = (gid_t) -1,
+                .action = _DEVICE_ACTION_INVALID,
         };
 
         *ret = device;
@@ -145,7 +146,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
                                        _syspath);
 
         if (verify) {
-                r = chase_symlinks(_syspath, NULL, 0, &syspath);
+                r = chase_symlinks(_syspath, NULL, 0, &syspath, NULL);
                 if (r == -ENOENT)
                         return -ENODEV; /* the device does not exist (any more?) */
                 if (r < 0)
@@ -156,7 +157,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
                         char *p;
 
                         /* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
-                        r = chase_symlinks("/sys", NULL, 0, &real_sys);
+                        r = chase_symlinks("/sys", NULL, 0, &real_sys, NULL);
                         if (r < 0)
                                 return log_debug_errno(r, "sd-device: Failed to chase symlink /sys: %m");
 
@@ -166,7 +167,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
                                                        "sd-device: Canonicalized path '%s' does not starts with sysfs mount point '%s'",
                                                        syspath, real_sys);
 
-                        new_syspath = strjoin("/sys/", p);
+                        new_syspath = path_join("/sys", p);
                         if (!new_syspath)
                                 return -ENOMEM;
 
@@ -200,14 +201,16 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
 
         devpath = syspath + STRLEN("/sys");
 
+        if (devpath[0] == '\0')
+                /* '/sys' alone is not a valid device path */
+                return -ENODEV;
+
         r = device_add_property_internal(device, "DEVPATH", devpath);
         if (r < 0)
                 return r;
 
         free_and_replace(device->syspath, syspath);
-
         device->devpath = devpath;
-
         return 0;
 }
 
@@ -227,7 +230,6 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
                 return r;
 
         *ret = TAKE_PTR(device);
-
         return 0;
 }
 
@@ -239,7 +241,7 @@ _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum)
         assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
 
         /* use /sys/dev/{block,char}/<maj>:<min> link */
-        snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
+        xsprintf(id, "%u:%u", major(devnum), minor(devnum));
 
         syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
 
@@ -610,8 +612,8 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
 
                 return sd_device_new_from_devnum(ret, id[0], devt);
         }
-        case 'n':
-        {
+
+        case 'n': {
                 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
                 _cleanup_close_ int sk = -1;
                 struct ifreq ifr = {};
@@ -642,11 +644,10 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
                         return -ENODEV;
 
                 *ret = TAKE_PTR(device);
-
                 return 0;
         }
-        case '+':
-        {
+
+        case '+': {
                 char subsys[PATH_MAX];
                 char *sysname;
 
@@ -660,6 +661,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
 
                 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
         }
+
         default:
                 return -EINVAL;
         }
@@ -727,7 +729,6 @@ _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
                 return -ENOENT;
 
         *ret = child->parent;
-
         return 0;
 }
 
@@ -746,11 +747,8 @@ int device_set_subsystem(sd_device *device, const char *_subsystem) {
         if (r < 0)
                 return r;
 
-        free_and_replace(device->subsystem, subsystem);
-
         device->subsystem_set = true;
-
-        return 0;
+        return free_and_replace(device->subsystem, subsystem);
 }
 
 static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) {
@@ -769,9 +767,7 @@ static int device_set_drivers_subsystem(sd_device *device, const char *_subsyste
         if (r < 0)
                 return r;
 
-        free_and_replace(device->driver_subsystem, subsystem);
-
-        return 0;
+        return free_and_replace(device->driver_subsystem, subsystem);
 }
 
 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
@@ -836,15 +832,13 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
                 return -ENOENT;
 
         *ret = device->subsystem;
-
         return 0;
 }
 
 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
         int r;
 
-        assert(devtype);
-        assert(device);
+        assert_return(device, -EINVAL);
 
         r = device_read_uevent_file(device);
         if (r < 0)
@@ -853,9 +847,10 @@ _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
         if (!device->devtype)
                 return -ENOENT;
 
-        *devtype = device->devtype;
+        if (devtype)
+                *devtype = device->devtype;
 
-        return 0;
+        return !!device->devtype;
 }
 
 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
@@ -886,7 +881,6 @@ _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const
                 return r;
 
         *ret = parent;
-
         return 0;
 }
 
@@ -923,11 +917,8 @@ int device_set_driver(sd_device *device, const char *_driver) {
         if (r < 0)
                 return r;
 
-        free_and_replace(device->driver, driver);
-
         device->driver_set = true;
-
-        return 0;
+        return free_and_replace(device->driver, driver);
 }
 
 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
@@ -960,7 +951,6 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
                 return -ENOENT;
 
         *ret = device->driver;
-
         return 0;
 }
 
@@ -972,7 +962,6 @@ _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
         assert(device->devpath[0] == '/');
 
         *devpath = device->devpath;
-
         return 0;
 }
 
@@ -992,7 +981,6 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
         assert(path_startswith(device->devname, "/dev/"));
 
         *devname = device->devname;
-
         return 0;
 }
 
@@ -1002,6 +990,9 @@ static int device_set_sysname(sd_device *device) {
         const char *pos;
         size_t len = 0;
 
+        if (!device->devpath)
+                return -EINVAL;
+
         pos = strrchr(device->devpath, '/');
         if (!pos)
                 return -EINVAL;
@@ -1030,13 +1021,9 @@ static int device_set_sysname(sd_device *device) {
         if (len == 0)
                 sysnum = NULL;
 
-        free_and_replace(device->sysname, sysname);
-
-        device->sysnum = sysnum;
-
         device->sysname_set = true;
-
-        return 0;
+        device->sysnum = sysnum;
+        return free_and_replace(device->sysname, sysname);
 }
 
 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
@@ -1054,7 +1041,6 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
         assert_return(device->sysname, -ENOENT);
 
         *ret = device->sysname;
-
         return 0;
 }
 
@@ -1074,7 +1060,6 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
                 return -ENOENT;
 
         *ret = device->sysnum;
-
         return 0;
 }
 
@@ -1130,6 +1115,7 @@ int device_add_devlink(sd_device *device, const char *devlink) {
 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
         _cleanup_free_ char *key = NULL;
         char *value;
+        int r;
 
         assert(device);
         assert(str);
@@ -1147,7 +1133,13 @@ static int device_add_property_internal_from_string(sd_device *device, const cha
         if (isempty(++value))
                 value = NULL;
 
-        return device_add_property_internal(device, key, value);
+        /* Add the property to both sd_device::properties and sd_device::properties_db,
+         * as this is called by only handle_db_line(). */
+        r = device_add_property_aux(device, key, value, false);
+        if (r < 0)
+                return r;
+
+        return device_add_property_aux(device, key, value, true);
 }
 
 int device_set_usec_initialized(sd_device *device, usec_t when) {
@@ -1283,17 +1275,14 @@ int device_get_id_filename(sd_device *device, const char **ret) {
         }
 
         *ret = device->id_filename;
-
         return 0;
 }
 
-int device_read_db_internal(sd_device *device, bool force) {
+int device_read_db_internal_filename(sd_device *device, const char *filename) {
         _cleanup_free_ char *db = NULL;
-        char *path;
-        const char *id, *value;
+        const char *value;
+        size_t db_len, i;
         char key;
-        size_t db_len;
-        unsigned i;
         int r;
 
         enum {
@@ -1305,22 +1294,14 @@ int device_read_db_internal(sd_device *device, bool force) {
         } state = PRE_KEY;
 
         assert(device);
+        assert(filename);
 
-        if (device->db_loaded || (!force && device->sealed))
-                return 0;
-
-        r = device_get_id_filename(device, &id);
-        if (r < 0)
-                return r;
-
-        path = strjoina("/run/udev/data/", id);
-
-        r = read_full_file(path, &db, &db_len);
+        r = read_full_file(filename, &db, &db_len);
         if (r < 0) {
                 if (r == -ENOENT)
                         return 0;
-                else
-                        return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", path);
+
+                return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", filename);
         }
 
         /* devices with a database entry are initialized */
@@ -1373,13 +1354,31 @@ int device_read_db_internal(sd_device *device, bool force) {
 
                         break;
                 default:
-                        assert_not_reached("Invalid state when parsing db");
+                        return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), "sd-device: invalid db syntax.");
                 }
         }
 
         return 0;
 }
 
+int device_read_db_internal(sd_device *device, bool force) {
+        const char *id, *path;
+        int r;
+
+        assert(device);
+
+        if (device->db_loaded || (!force && device->sealed))
+                return 0;
+
+        r = device_get_id_filename(device, &id);
+        if (r < 0)
+                return r;
+
+        path = strjoina("/run/udev/data/", id);
+
+        return device_read_db_internal_filename(device, path);
+}
+
 _public_ int sd_device_get_is_initialized(sd_device *device) {
         int r;
 
@@ -1415,7 +1414,6 @@ _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *u
                 return -EIO;
 
         *usec = now_ts - device->usec_initialized;
-
         return 0;
 }
 
@@ -1475,7 +1473,7 @@ _public_ const char *sd_device_get_devlink_next(sd_device *device) {
         return v;
 }
 
-static int device_properties_prepare(sd_device *device) {
+int device_properties_prepare(sd_device *device) {
         int r;
 
         assert(device);
@@ -1542,7 +1540,6 @@ static int device_properties_prepare(sd_device *device) {
 
 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
         const char *key;
-        const char *value;
         int r;
 
         assert_return(device, NULL);
@@ -1554,17 +1551,12 @@ _public_ const char *sd_device_get_property_first(sd_device *device, const char
         device->properties_iterator_generation = device->properties_generation;
         device->properties_iterator = ITERATOR_FIRST;
 
-        ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
-
-        if (_value)
-                *_value = value;
-
+        (void) ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)_value, (const void**)&key);
         return key;
 }
 
 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
         const char *key;
-        const char *value;
         int r;
 
         assert_return(device, NULL);
@@ -1576,11 +1568,7 @@ _public_ const char *sd_device_get_property_next(sd_device *device, const char *
         if (device->properties_iterator_generation != device->properties_generation)
                 return NULL;
 
-        ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
-
-        if (_value)
-                *_value = value;
-
+        (void) ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)_value, (const void**)&key);
         return key;
 }
 
@@ -1608,14 +1596,16 @@ static int device_sysattrs_read_all(sd_device *device) {
                 return r;
 
         FOREACH_DIRENT_ALL(dent, dir, return -errno) {
-                char *path;
+                _cleanup_free_ char *path = NULL;
                 struct stat statbuf;
 
                 /* only handle symlinks and regular files */
                 if (!IN_SET(dent->d_type, DT_LNK, DT_REG))
                         continue;
 
-                path = strjoina(syspath, "/", dent->d_name);
+                path = path_join(syspath, dent->d_name);
+                if (!path)
+                        return -ENOMEM;
 
                 if (lstat(path, &statbuf) != 0)
                         continue;
@@ -1691,7 +1681,6 @@ _public_ int sd_device_get_property_value(sd_device *device, const char *key, co
 
         if (_value)
                 *_value = value;
-
         return 0;
 }
 
@@ -1718,8 +1707,7 @@ static int device_add_sysattr_value(sd_device *device, const char *_key, char *v
         r = hashmap_put(device->sysattr_values, key, value);
         if (r < 0)
                 return r;
-
-        key = NULL;
+        TAKE_PTR(key);
 
         return 0;
 }
@@ -1736,7 +1724,6 @@ static int device_get_sysattr_value(sd_device *device, const char *_key, const c
 
         if (_value)
                 *_value = value;
-
         return 0;
 }
 
@@ -1744,8 +1731,7 @@ static int device_get_sysattr_value(sd_device *device, const char *_key, const c
  * with a NULL value in the cache, otherwise the returned string is stored */
 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
         _cleanup_free_ char *value = NULL;
-        const char *syspath, *cached_value = NULL;
-        char *path;
+        const char *path, *syspath, *cached_value = NULL;
         struct stat statbuf;
         int r;
 
@@ -1772,7 +1758,7 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
         if (r < 0)
                 return r;
 
-        path = strjoina(syspath, "/", sysattr);
+        path = prefix_roota(syspath, sysattr);
         r = lstat(path, &statbuf);
         if (r < 0) {
                 /* remember that we could not access the sysattr */
@@ -1800,7 +1786,7 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
                 size_t size;
 
                 /* read attribute value */
-                r = read_full_file(path, &value, &size);
+                r = read_full_virtual_file(path, &value, &size);
                 if (r < 0)
                         return r;
 
@@ -1820,14 +1806,11 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
 
 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
         _cleanup_free_ char *key = NULL;
-        _cleanup_free_ char *value = NULL;
 
         assert(device);
         assert(_key);
 
-        value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
-
-        return;
+        free(hashmap_remove2(device->sysattr_values, _key, (void **) &key));
 }
 
 /* set the attribute and save it in the cache. If a NULL value is passed the
@@ -1843,7 +1826,6 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr,
 
         if (!_value) {
                 device_remove_sysattr_value(device, sysattr);
-
                 return 0;
         }
 
@@ -1851,7 +1833,7 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr,
         if (r < 0)
                 return r;
 
-        path = strjoina(syspath, "/", sysattr);
+        path = prefix_roota(syspath, sysattr);
 
         len = strlen(_value);
 
@@ -1874,23 +1856,22 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr,
                 if (r == -EISDIR)
                         return r;
 
-                free(value);
-                value = strdup("");
-                if (!value)
-                        return -ENOMEM;
+                r = free_and_strdup(&value, "");
+                if (r < 0)
+                        return r;
 
                 r = device_add_sysattr_value(device, sysattr, value);
                 if (r < 0)
                         return r;
+                TAKE_PTR(value);
 
-                value = NULL;
                 return -ENXIO;
         }
 
         r = device_add_sysattr_value(device, sysattr, value);
         if (r < 0)
                 return r;
+        TAKE_PTR(value);
 
-        value = NULL;
         return 0;
 }