summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libudev/libudev-device.c121
-rw-r--r--src/libudev/libudev-util.c9
-rw-r--r--src/libudev/libudev.h1
-rw-r--r--src/libudev/libudev.sym5
4 files changed, 132 insertions, 4 deletions
diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c
index e911b73b2b..aa82507e94 100644
--- a/src/libudev/libudev-device.c
+++ b/src/libudev/libudev-device.c
@@ -915,6 +915,42 @@ found:
return udev_device_new_from_syspath(udev, path);
}
+/**
+ * udev_device_new_from_environment
+ * @udev: udev library context
+ *
+ * Create new udev device, and fill in information from the
+ * current process environment. This only works reliable if
+ * the process is called from a udev rule. It is usually used
+ * for tools executed from IMPORT= rules.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev device.
+ *
+ * Returns: a new udev device, or #NULL, if it does not exist
+ **/
+_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev)
+{
+ int i;
+ struct udev_device *udev_device;
+
+ udev_device = udev_device_new(udev);
+ if (udev_device == NULL)
+ return NULL;
+ udev_device_set_info_loaded(udev_device);
+
+ for (i = 0; environ[i] != NULL; i++)
+ udev_device_add_property_from_string_parse(udev_device, environ[i]);
+
+ if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) {
+ udev_dbg(udev, "missing values, invalid device\n");
+ udev_device_unref(udev_device);
+ udev_device = NULL;
+ }
+
+ return udev_device;
+}
+
static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
{
struct udev_device *udev_device_parent = NULL;
@@ -1403,6 +1439,91 @@ 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);
+
+ util_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)) {
+ 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;
diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c
index 0ca86c815d..ac906bfec4 100644
--- a/src/libudev/libudev-util.c
+++ b/src/libudev/libudev-util.c
@@ -670,17 +670,18 @@ static unsigned int murmur_hash2(const char *key, int len, unsigned int seed)
/* mix 4 bytes at a time into the hash */
const unsigned char * data = (const unsigned char *)key;
- while(len >= 4) {
- unsigned int k = *(unsigned int *)data;
+ while(len >= sizeof(unsigned int)) {
+ unsigned int k;
+ memcpy(&k, data, sizeof(k));
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
- data += 4;
- len -= 4;
+ data += sizeof(k);
+ len -= sizeof(k);
}
/* handle the last few bytes of the input array */
diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h
index bb41532a21..61567b1d67 100644
--- a/src/libudev/libudev.h
+++ b/src/libudev/libudev.h
@@ -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);
/*
diff --git a/src/libudev/libudev.sym b/src/libudev/libudev.sym
index 261df13ed3..ddbcf94b6e 100644
--- a/src/libudev/libudev.sym
+++ b/src/libudev/libudev.sym
@@ -107,6 +107,11 @@ global:
udev_hwdb_get_properties_list_entry;
} LIBUDEV_189;
+LIBUDEV_199 {
+global:
+ udev_device_set_sysattr_value;
+} LIBUDEV_196;
+
LIBUDEV_internal {
global:
*;