libudev: implement udev_device_set_attribute_value()

This commit is contained in:
Hannes Reinecke
2013-03-13 17:44:45 +01:00
committed by Kay Sievers
parent 814cc56212
commit 946f182575
5 changed files with 111 additions and 3 deletions
+3 -3
View 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
+1
View 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
+102
View 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;
+1
View 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);
/*
+4
View 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;