chiark / gitweb /
libudev: implement udev_device_set_attribute_value()
authorHannes Reinecke <hare@suse.de>
Mon, 11 Mar 2013 11:49:27 +0000 (12:49 +0100)
committerKay Sievers <kay@vrfy.org>
Wed, 13 Mar 2013 16:44:45 +0000 (17:44 +0100)
Makefile.am
docs/libudev/libudev-sections.txt
src/libudev/libudev-device.c
src/libudev/libudev.h
src/libudev/libudev.sym

index 2a010c7..3073b0d 100644 (file)
@@ -31,9 +31,9 @@ SUBDIRS = . po
 # keep intermediate files
 .SECONDARY:
 
-LIBUDEV_CURRENT=3
-LIBUDEV_REVISION=2
-LIBUDEV_AGE=2
+LIBUDEV_CURRENT=4
+LIBUDEV_REVISION=0
+LIBUDEV_AGE=3
 
 LIBGUDEV_CURRENT=1
 LIBGUDEV_REVISION=3
index 067a3f5..c154645 100644 (file)
@@ -53,6 +53,7 @@ udev_device_get_driver
 udev_device_get_devnum
 udev_device_get_action
 udev_device_get_sysattr_value
+udev_device_set_sysattr_value
 udev_device_get_sysattr_list_entry
 udev_device_get_seqnum
 udev_device_get_usec_since_initialized
index 9fe3d63..05c5fbc 100644 (file)
@@ -1440,6 +1440,108 @@ out:
         return val;
 }
 
+/**
+ * udev_device_set_sysattr_value:
+ * @udev_device: udev device
+ * @sysattr: attribute name
+ * @value: new value to be set
+ *
+ * Update the contents of the sys attribute and the cached value of the device.
+ *
+ * Returns: Negative error code on failure or 0 on success.
+ **/
+_public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value)
+{
+        struct udev_device *dev;
+        char path[UTIL_PATH_SIZE];
+        struct stat statbuf;
+        int fd;
+        ssize_t size, value_len;
+        int ret = 0;
+
+        if (udev_device == NULL)
+                return -EINVAL;
+        dev = udev_device;
+        if (sysattr == NULL)
+                return -EINVAL;
+        if (value == NULL)
+                value_len = 0;
+        else
+                value_len = strlen(value);
+restart:
+        strscpyl(path, sizeof(path), udev_device_get_syspath(dev), "/", sysattr, NULL);
+        if (lstat(path, &statbuf) != 0) {
+                udev_list_entry_add(&dev->sysattr_value_list, sysattr, NULL);
+                ret = -ENXIO;
+                goto out;
+        }
+
+        if (S_ISLNK(statbuf.st_mode)) {
+                /*
+                 * Cannot modify core link values
+                 */
+                if (streq(sysattr, "driver") ||
+                    streq(sysattr, "subsystem") ||
+                    streq(sysattr, "module")) {
+                        ret = -EPERM;
+                } else if (!streq(sysattr, "device")) {
+                        /* resolve custom link to a device */
+                        strscpyl(path, sizeof(path), udev_device->syspath, "/", sysattr, NULL);
+                        dev = udev_device_new_from_syspath(udev_device->udev, path);
+                        if (dev != NULL)
+                                goto restart;
+                        ret = -ENXIO;
+                } else {
+                        /* Unhandled, to not try to modify anything */
+                        ret = -EINVAL;
+                }
+                goto out;
+        }
+
+        /* skip directories */
+        if (S_ISDIR(statbuf.st_mode)) {
+                ret = -EISDIR;
+                goto out;
+        }
+
+        /* skip non-readable files */
+        if ((statbuf.st_mode & S_IRUSR) == 0) {
+                ret = -EACCES;
+                goto out;
+        }
+
+        /* Value is limited to 4k */
+        if (value_len > 4096) {
+                ret = -EINVAL;
+                goto out;
+        }
+        util_remove_trailing_chars(value, '\n');
+
+        /* write attribute value */
+        fd = open(path, O_WRONLY|O_CLOEXEC);
+        if (fd < 0) {
+                ret = -errno;
+                goto out;
+        }
+        size = write(fd, value, value_len);
+        close(fd);
+        if (size < 0) {
+                ret = -errno;
+                goto out;
+        }
+        if (size < value_len) {
+                ret = -EIO;
+                goto out;
+        }
+
+        /* wrote a valid value, store it in cache and return it */
+        udev_list_entry_add(&dev->sysattr_value_list, sysattr, value);
+out:
+        if (dev != udev_device)
+                udev_device_unref(dev);
+        return ret;
+}
+
 static int udev_device_sysattr_list_read(struct udev_device *udev_device)
 {
         struct dirent *dent;
index bb41532..61567b1 100644 (file)
@@ -107,6 +107,7 @@ const char *udev_device_get_action(struct udev_device *udev_device);
 unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
 unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
 const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
+int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value);
 int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
 
 /*
index df6a1ae..c232fbf 100644 (file)
@@ -108,3 +108,7 @@ global:
         udev_hwdb_unref;
         udev_hwdb_get_properties_list_entry;
 } LIBUDEV_189;
+
+LIBUDEV_199 {
+        udev_device_set_sysattr_value;
+} LIBUDEV_196;