*
* Representation of kernel sys devices. Devices are uniquely identified
* by their syspath, every device has exactly one path in the kernel sys
- * filesystem. Devices usually belong to a kernel subsystem, and and have
+ * filesystem. Devices usually belong to a kernel subsystem, and have
* a unique name inside that subsystem.
*/
const char *sysnum;
char *devnode;
mode_t devnode_mode;
+ uid_t devnode_uid;
+ gid_t devnode_gid;
char *subsystem;
char *devtype;
char *driver;
return 0;
}
+uid_t udev_device_get_devnode_uid(struct udev_device *udev_device)
+{
+ if (!udev_device->info_loaded)
+ udev_device_read_uevent_file(udev_device);
+ return udev_device->devnode_uid;
+}
+
+static int udev_device_set_devnode_uid(struct udev_device *udev_device, uid_t uid)
+{
+ char num[32];
+
+ udev_device->devnode_uid = uid;
+ snprintf(num, sizeof(num), "%u", uid);
+ udev_device_add_property(udev_device, "DEVUID", num);
+ return 0;
+}
+
+gid_t udev_device_get_devnode_gid(struct udev_device *udev_device)
+{
+ if (!udev_device->info_loaded)
+ udev_device_read_uevent_file(udev_device);
+ return udev_device->devnode_gid;
+}
+
+static int udev_device_set_devnode_gid(struct udev_device *udev_device, gid_t gid)
+{
+ char num[32];
+
+ udev_device->devnode_gid = gid;
+ snprintf(num, sizeof(num), "%u", gid);
+ udev_device_add_property(udev_device, "DEVGID", num);
+ return 0;
+}
+
struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
{
udev_device->envp_uptodate = false;
char name[UTIL_LINE_SIZE];
char *val;
- util_strscpy(name, sizeof(name), property);
+ strscpy(name, sizeof(name), property);
val = strchr(name, '=');
if (val == NULL)
return NULL;
if (startswith(property, "DEVPATH=")) {
char path[UTIL_PATH_SIZE];
- util_strscpyl(path, sizeof(path), "/sys", &property[8], NULL);
+ strscpyl(path, sizeof(path), "/sys", &property[8], NULL);
udev_device_set_syspath(udev_device, path);
} else if (startswith(property, "SUBSYSTEM=")) {
udev_device_set_subsystem(udev_device, &property[10]);
char *slink;
char *next;
- util_strscpy(devlinks, sizeof(devlinks), &property[9]);
+ strscpy(devlinks, sizeof(devlinks), &property[9]);
slink = devlinks;
next = strchr(slink, ' ');
while (next != NULL) {
char tags[UTIL_PATH_SIZE];
char *next;
- util_strscpy(tags, sizeof(tags), &property[5]);
+ strscpy(tags, sizeof(tags), &property[5]);
next = strchr(tags, ':');
if (next != NULL) {
next++;
udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10));
} else if (startswith(property, "DEVMODE=")) {
udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8));
+ } else if (startswith(property, "DEVUID=")) {
+ udev_device_set_devnode_uid(udev_device, strtoul(&property[7], NULL, 10));
+ } else if (startswith(property, "DEVGID=")) {
+ udev_device_set_devnode_gid(udev_device, strtoul(&property[7], NULL, 10));
} else {
udev_device_add_property_from_string(udev_device, property);
}
id = udev_device_get_id_filename(udev_device);
if (id == NULL)
return -1;
- util_strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL);
+ strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL);
dbfile = filename;
}
val = &line[2];
switch(line[0]) {
case 'S':
- util_strscpyl(filename, sizeof(filename), "/dev/", val, NULL);
+ strscpyl(filename, sizeof(filename), "/dev/", val, NULL);
udev_device_add_devlink(udev_device, filename);
break;
case 'L':
if (udev_device->uevent_loaded)
return 0;
- util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
+ strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
f = fopen(filename, "re");
if (f == NULL)
return -1;
return NULL;
/* resolve possible symlink to real path */
- util_strscpy(path, sizeof(path), syspath);
+ strscpy(path, sizeof(path), syspath);
util_resolve_sys_link(udev, path, sizeof(path));
if (startswith(path + strlen("/sys"), "/devices/")) {
char file[UTIL_PATH_SIZE];
/* all "devices" require a "uevent" file */
- util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
+ strscpyl(file, sizeof(file), path, "/uevent", NULL);
if (stat(file, &statbuf) != 0)
return NULL;
} else {
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
-_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, char *id)
+_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id)
{
char type;
int maj, min;
return NULL;
}
case '+':
- util_strscpy(subsys, sizeof(subsys), &id[1]);
+ strscpy(subsys, sizeof(subsys), &id[1]);
sysname = strchr(subsys, ':');
if (sysname == NULL)
return NULL;
struct stat statbuf;
if (streq(subsystem, "subsystem")) {
- util_strscpyl(path, sizeof(path), "/sys/subsystem/", sysname, NULL);
+ strscpyl(path, sizeof(path), "/sys/subsystem/", sysname, NULL);
if (stat(path, &statbuf) == 0)
goto found;
- util_strscpyl(path, sizeof(path), "/sys/bus/", sysname, NULL);
+ strscpyl(path, sizeof(path), "/sys/bus/", sysname, NULL);
if (stat(path, &statbuf) == 0)
goto found;
- util_strscpyl(path, sizeof(path), "/sys/class/", sysname, NULL);
+ strscpyl(path, sizeof(path), "/sys/class/", sysname, NULL);
if (stat(path, &statbuf) == 0)
goto found;
goto out;
}
if (streq(subsystem, "module")) {
- util_strscpyl(path, sizeof(path), "/sys/module/", sysname, NULL);
+ strscpyl(path, sizeof(path), "/sys/module/", sysname, NULL);
if (stat(path, &statbuf) == 0)
goto found;
goto out;
char subsys[UTIL_NAME_SIZE];
char *driver;
- util_strscpy(subsys, sizeof(subsys), sysname);
+ strscpy(subsys, sizeof(subsys), sysname);
driver = strchr(subsys, ':');
if (driver != NULL) {
driver[0] = '\0';
driver = &driver[1];
- util_strscpyl(path, sizeof(path), "/sys/subsystem/", subsys, "/drivers/", driver, NULL);
+ strscpyl(path, sizeof(path), "/sys/subsystem/", subsys, "/drivers/", driver, NULL);
if (stat(path, &statbuf) == 0)
goto found;
- util_strscpyl(path, sizeof(path), "/sys/bus/", subsys, "/drivers/", driver, NULL);
+ strscpyl(path, sizeof(path), "/sys/bus/", subsys, "/drivers/", driver, NULL);
if (stat(path, &statbuf) == 0)
goto found;
}
goto out;
}
- util_strscpyl(path, sizeof(path), "/sys/subsystem/", subsystem, "/devices/", sysname, NULL);
+ strscpyl(path, sizeof(path), "/sys/subsystem/", subsystem, "/devices/", sysname, NULL);
if (stat(path, &statbuf) == 0)
goto found;
- util_strscpyl(path, sizeof(path), "/sys/bus/", subsystem, "/devices/", sysname, NULL);
+ strscpyl(path, sizeof(path), "/sys/bus/", subsystem, "/devices/", sysname, NULL);
if (stat(path, &statbuf) == 0)
goto found;
- util_strscpyl(path, sizeof(path), "/sys/class/", subsystem, "/", sysname, NULL);
+ strscpyl(path, sizeof(path), "/sys/class/", subsystem, "/", sysname, NULL);
if (stat(path, &statbuf) == 0)
goto found;
out:
char path[UTIL_PATH_SIZE];
const char *subdir;
- util_strscpy(path, sizeof(path), udev_device->syspath);
+ strscpy(path, sizeof(path), udev_device->syspath);
subdir = path + strlen("/sys/");
for (;;) {
char *pos;
size_t l;
s = symlinks;
- l = util_strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL);
+ l = strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL);
udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
- l = util_strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL);
+ l = strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL);
udev_device_add_property(udev_device, "DEVLINKS", symlinks);
}
}
size_t l;
s = tags;
- l = util_strpcpyl(&s, sizeof(tags), ":", NULL);
+ l = strpcpyl(&s, sizeof(tags), ":", NULL);
udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
- l = util_strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL);
+ l = strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL);
udev_device_add_property(udev_device, "TAGS", tags);
}
}
if (list_entry != NULL)
return udev_list_entry_get_value(list_entry);
- util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL);
+ strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL);
if (lstat(path, &statbuf) != 0) {
udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL);
goto out;
}
if (S_ISLNK(statbuf.st_mode)) {
- struct udev_device *dev;
-
/*
* Some core links return only the last element of the target path,
* these are just values, the paths should not be exposed.
goto out;
}
- /* resolve link to a device and return its syspath */
- util_strscpyl(path, sizeof(path), udev_device->syspath, "/", sysattr, NULL);
- dev = udev_device_new_from_syspath(udev_device->udev, path);
- if (dev != NULL) {
- list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr,
- udev_device_get_syspath(dev));
- val = udev_list_entry_get_value(list_entry);
- udev_device_unref(dev);
- }
-
goto 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);
+
+ 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;
if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
continue;
- util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", dent->d_name, NULL);
+ strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", dent->d_name, NULL);
if (lstat(path, &statbuf) != 0)
continue;
if ((statbuf.st_mode & S_IRUSR) == 0)
return -EINVAL;
/* add property string to monitor buffer */
- l = util_strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL);
+ l = strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL);
if (l == 0)
return -EINVAL;
- /* advance past the trailing '\0' that util_strpcpyl() guarantees */
+ /* advance past the trailing '\0' that strpcpyl() guarantees */
s++;
l--;
}