X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibudev%2Flibudev-device.c;h=6bb2e41510ab97d36eac96a0d326724905792165;hp=212163bb92d12d2c5c733e2a07339575f73c6937;hb=53726349e1d7a85bdf572ce81f122e66e438c6ec;hpb=6ada823a9a0979ea145fd70add1007c21caa45c0 diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c index 212163bb9..6bb2e4151 100644 --- a/src/libudev/libudev-device.c +++ b/src/libudev/libudev-device.c @@ -1,13 +1,21 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ #include #include @@ -52,6 +60,8 @@ struct udev_device { const char *sysnum; char *devnode; mode_t devnode_mode; + uid_t devnode_uid; + gid_t devnode_gid; char *subsystem; char *devtype; char *driver; @@ -67,7 +77,7 @@ struct udev_device { struct udev_list sysattr_list; struct udev_list tags_list; unsigned long long int seqnum; - unsigned long long int usec_initialized; + usec_t usec_initialized; int devlink_priority; int refcount; dev_t devnum; @@ -136,7 +146,9 @@ static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) * udev_device_get_devnum: * @udev_device: udev device * - * Returns: the device major/minor number. + * Get the device major/minor number. + * + * Returns: the dev_t number. **/ _public_ dev_t udev_device_get_devnum(struct udev_device *udev_device) { @@ -185,7 +197,9 @@ static int udev_device_set_devpath_old(struct udev_device *udev_device, const ch * udev_device_get_driver: * @udev_device: udev device * - * Returns: the driver string, or #NULL if there is no driver attached. + * Get the kernel driver name. + * + * Returns: the driver name string, or #NULL if there is no driver attached. **/ _public_ const char *udev_device_get_driver(struct udev_device *udev_device) { @@ -242,7 +256,7 @@ static int udev_device_set_devtype(struct udev_device *udev_device, const char * return 0; } -static int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem) +int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem) { free(udev_device->subsystem); udev_device->subsystem = strdup(subsystem); @@ -276,7 +290,7 @@ _public_ const char *udev_device_get_subsystem(struct udev_device *udev_device) return udev_device->subsystem; } /* implicit names */ - if (strncmp(udev_device->devpath, "/module/", 8) == 0) { + if (startswith(udev_device->devpath, "/module/")) { udev_device_set_subsystem(udev_device, "module"); return udev_device->subsystem; } @@ -284,9 +298,9 @@ _public_ const char *udev_device_get_subsystem(struct udev_device *udev_device) udev_device_set_subsystem(udev_device, "drivers"); return udev_device->subsystem; } - if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 || - strncmp(udev_device->devpath, "/class/", 7) == 0 || - strncmp(udev_device->devpath, "/bus/", 5) == 0) { + if (startswith(udev_device->devpath, "/subsystem/") || + startswith(udev_device->devpath, "/class/") || + startswith(udev_device->devpath, "/bus/")) { udev_device_set_subsystem(udev_device, "subsystem"); return udev_device->subsystem; } @@ -311,6 +325,40 @@ static int udev_device_set_devnode_mode(struct udev_device *udev_device, mode_t 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; @@ -331,7 +379,7 @@ static struct udev_list_entry *udev_device_add_property_from_string(struct udev_ 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; @@ -353,38 +401,38 @@ static struct udev_list_entry *udev_device_add_property_from_string(struct udev_ */ void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property) { - if (strncmp(property, "DEVPATH=", 8) == 0) { + if (startswith(property, "DEVPATH=")) { char path[UTIL_PATH_SIZE]; - util_strscpyl(path, sizeof(path), TEST_PREFIX "/sys", &property[8], NULL); + strscpyl(path, sizeof(path), "/sys", &property[8], NULL); udev_device_set_syspath(udev_device, path); - } else if (strncmp(property, "SUBSYSTEM=", 10) == 0) { + } else if (startswith(property, "SUBSYSTEM=")) { udev_device_set_subsystem(udev_device, &property[10]); - } else if (strncmp(property, "DEVTYPE=", 8) == 0) { + } else if (startswith(property, "DEVTYPE=")) { udev_device_set_devtype(udev_device, &property[8]); - } else if (strncmp(property, "DEVNAME=", 8) == 0) { + } else if (startswith(property, "DEVNAME=")) { udev_device_set_devnode(udev_device, &property[8]); - } else if (strncmp(property, "DEVLINKS=", 9) == 0) { + } else if (startswith(property, "DEVLINKS=")) { char devlinks[UTIL_PATH_SIZE]; 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) { next[0] = '\0'; - udev_device_add_devlink(udev_device, slink, 0); + udev_device_add_devlink(udev_device, slink); slink = &next[1]; next = strchr(slink, ' '); } if (slink[0] != '\0') - udev_device_add_devlink(udev_device, slink, 0); - } else if (strncmp(property, "TAGS=", 5) == 0) { + udev_device_add_devlink(udev_device, slink); + } else if (startswith(property, "TAGS=")) { 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++; @@ -400,24 +448,28 @@ void udev_device_add_property_from_string_parse(struct udev_device *udev_device, udev_device_add_tag(udev_device, tag); } } - } else if (strncmp(property, "USEC_INITIALIZED=", 19) == 0) { + } else if (startswith(property, "USEC_INITIALIZED=")) { udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10)); - } else if (strncmp(property, "DRIVER=", 7) == 0) { + } else if (startswith(property, "DRIVER=")) { udev_device_set_driver(udev_device, &property[7]); - } else if (strncmp(property, "ACTION=", 7) == 0) { + } else if (startswith(property, "ACTION=")) { udev_device_set_action(udev_device, &property[7]); - } else if (strncmp(property, "MAJOR=", 6) == 0) { + } else if (startswith(property, "MAJOR=")) { udev_device->maj = strtoull(&property[6], NULL, 10); - } else if (strncmp(property, "MINOR=", 6) == 0) { + } else if (startswith(property, "MINOR=")) { udev_device->min = strtoull(&property[6], NULL, 10); - } else if (strncmp(property, "DEVPATH_OLD=", 12) == 0) { + } else if (startswith(property, "DEVPATH_OLD=")) { udev_device_set_devpath_old(udev_device, &property[12]); - } else if (strncmp(property, "SEQNUM=", 7) == 0) { + } else if (startswith(property, "SEQNUM=")) { udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10)); - } else if (strncmp(property, "IFINDEX=", 8) == 0) { + } else if (startswith(property, "IFINDEX=")) { udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10)); - } else if (strncmp(property, "DEVMODE=", 8) == 0) { + } 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); } @@ -440,7 +492,9 @@ int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_d * @udev_device: udev device * @key: property name * - * Returns: the value of a device property, or #NULL if there is no such property. + * Get the value of a given property. + * + * Returns: the property string, or #NULL if there is no such property. **/ _public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) { @@ -473,13 +527,13 @@ int udev_device_read_db(struct udev_device *udev_device, const char *dbfile) id = udev_device_get_id_filename(udev_device); if (id == NULL) return -1; - util_strscpyl(filename, sizeof(filename), TEST_PREFIX "/run/udev/data/", id, NULL); + strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); dbfile = filename; } f = fopen(dbfile, "re"); if (f == NULL) { - dbg(udev_device->udev, "no db file to read %s: %m\n", dbfile); + udev_dbg(udev_device->udev, "no db file to read %s: %m\n", dbfile); return -1; } udev_device->is_initialized = true; @@ -496,8 +550,8 @@ int udev_device_read_db(struct udev_device *udev_device, const char *dbfile) val = &line[2]; switch(line[0]) { case 'S': - util_strscpyl(filename, sizeof(filename), TEST_PREFIX "/dev/", val, NULL); - udev_device_add_devlink(udev_device, filename, 0); + strscpyl(filename, sizeof(filename), "/dev/", val, NULL); + udev_device_add_devlink(udev_device, filename); break; case 'L': udev_device_set_devlink_priority(udev_device, atoi(val)); @@ -519,7 +573,7 @@ int udev_device_read_db(struct udev_device *udev_device, const char *dbfile) } fclose(f); - dbg(udev_device->udev, "device %p filled with db file data\n", udev_device); + udev_dbg(udev_device->udev, "device %p filled with db file data\n", udev_device); return 0; } @@ -534,7 +588,7 @@ int udev_device_read_uevent_file(struct udev_device *udev_device) 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; @@ -548,24 +602,24 @@ int udev_device_read_uevent_file(struct udev_device *udev_device) continue; pos[0] = '\0'; - if (strncmp(line, "DEVTYPE=", 8) == 0) { + if (startswith(line, "DEVTYPE=")) { udev_device_set_devtype(udev_device, &line[8]); continue; } - if (strncmp(line, "IFINDEX=", 8) == 0) { + if (startswith(line, "IFINDEX=")) { udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10)); continue; } - if (strncmp(line, "DEVNAME=", 8) == 0) { + if (startswith(line, "DEVNAME=")) { udev_device_set_devnode(udev_device, &line[8]); continue; } - if (strncmp(line, "MAJOR=", 6) == 0) + if (startswith(line, "MAJOR=")) maj = strtoull(&line[6], NULL, 10); - else if (strncmp(line, "MINOR=", 6) == 0) + else if (startswith(line, "MINOR=")) min = strtoull(&line[6], NULL, 10); - else if (strncmp(line, "DEVMODE=", 8) == 0) + else if (startswith(line, "DEVMODE=")) udev_device->devnode_mode = strtoul(&line[8], NULL, 8); udev_device_add_property_from_string(udev_device, line); @@ -636,26 +690,26 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con return NULL; /* path starts in sys */ - if (strncmp(syspath, TEST_PREFIX "/sys", strlen(TEST_PREFIX "/sys")) != 0) { - dbg(udev, "not in sys :%s\n", syspath); + if (!startswith(syspath, "/sys")) { + udev_dbg(udev, "not in sys :%s\n", syspath); return NULL; } /* path is not a root directory */ - subdir = syspath + strlen(TEST_PREFIX "/sys"); + subdir = syspath + strlen("/sys"); pos = strrchr(subdir, '/'); if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) 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 (strncmp(path + strlen(TEST_PREFIX "/sys"), "/devices/", 9) == 0) { + 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 { @@ -669,7 +723,7 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con return NULL; udev_device_set_syspath(udev_device, path); - dbg(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device)); + udev_dbg(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device)); return udev_device; } @@ -703,12 +757,30 @@ _public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char return NULL; /* use /sys/dev/{block,char}/: link */ - snprintf(path, sizeof(path), TEST_PREFIX "/sys/dev/%s/%u:%u", + snprintf(path, sizeof(path), "/sys/dev/%s/%u:%u", type_str, major(devnum), minor(devnum)); return udev_device_new_from_syspath(udev, path); } -struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id) +/** + * udev_device_new_from_device_id: + * @udev: udev library context + * @id: text string identifying a kernel device + * + * Create new udev device, and fill in information from the sys + * device and the udev database entry. The device is looked-up + * by a special string: + * b8:2 - block device major:minor + * c128:1 - char device major:minor + * n3 - network device ifindex + * +sound:card29 - kernel driver core subsystem:device name + * + * 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_device_id(struct udev *udev, char *id) { char type; int maj, min; @@ -751,7 +823,7 @@ struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id return NULL; } case '+': - util_strscpy(subsys, sizeof(subsys), &id[1]); + strscpy(subsys, sizeof(subsys), &id[1]); sysname = strchr(subsys, ':'); if (sysname == NULL) return NULL; @@ -783,58 +855,58 @@ _public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev char path[UTIL_PATH_SIZE]; struct stat statbuf; - if (strcmp(subsystem, "subsystem") == 0) { - util_strscpyl(path, sizeof(path), TEST_PREFIX "/sys/subsystem/", sysname, NULL); + if (streq(subsystem, "subsystem")) { + strscpyl(path, sizeof(path), "/sys/subsystem/", sysname, NULL); if (stat(path, &statbuf) == 0) goto found; - util_strscpyl(path, sizeof(path), TEST_PREFIX "/sys/bus/", sysname, NULL); + strscpyl(path, sizeof(path), "/sys/bus/", sysname, NULL); if (stat(path, &statbuf) == 0) goto found; - util_strscpyl(path, sizeof(path), TEST_PREFIX "/sys/class/", sysname, NULL); + strscpyl(path, sizeof(path), "/sys/class/", sysname, NULL); if (stat(path, &statbuf) == 0) goto found; goto out; } - if (strcmp(subsystem, "module") == 0) { - util_strscpyl(path, sizeof(path), TEST_PREFIX "/sys/module/", sysname, NULL); + if (streq(subsystem, "module")) { + strscpyl(path, sizeof(path), "/sys/module/", sysname, NULL); if (stat(path, &statbuf) == 0) goto found; goto out; } - if (strcmp(subsystem, "drivers") == 0) { + if (streq(subsystem, "drivers")) { 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), TEST_PREFIX "/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), TEST_PREFIX "/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), TEST_PREFIX "/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), TEST_PREFIX "/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), TEST_PREFIX "/sys/class/", subsystem, "/", sysname, NULL); + strscpyl(path, sizeof(path), "/sys/class/", subsystem, "/", sysname, NULL); if (stat(path, &statbuf) == 0) goto found; out: @@ -871,7 +943,7 @@ _public_ struct udev_device *udev_device_new_from_environment(struct udev *udev) udev_device_add_property_from_string_parse(udev_device, environ[i]); if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { - dbg(udev, "missing values, invalid device\n"); + udev_dbg(udev, "missing values, invalid device\n"); udev_device_unref(udev_device); udev_device = NULL; } @@ -885,8 +957,8 @@ static struct udev_device *device_new_from_parent(struct udev_device *udev_devic char path[UTIL_PATH_SIZE]; const char *subdir; - util_strscpy(path, sizeof(path), udev_device->syspath); - subdir = path + strlen(TEST_PREFIX "/sys/"); + strscpy(path, sizeof(path), udev_device->syspath); + subdir = path + strlen("/sys/"); for (;;) { char *pos; @@ -966,11 +1038,11 @@ _public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struc const char *parent_devtype; parent_subsystem = udev_device_get_subsystem(parent); - if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) { + if (parent_subsystem != NULL && streq(parent_subsystem, subsystem)) { if (devtype == NULL) break; parent_devtype = udev_device_get_devtype(parent); - if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0) + if (parent_devtype != NULL && streq(parent_devtype, devtype)) break; } parent = udev_device_get_parent(parent); @@ -1016,14 +1088,15 @@ _public_ struct udev_device *udev_device_ref(struct udev_device *udev_device) * Drop a reference of a udev device. If the refcount reaches zero, * the resources of the device will be released. * + * Returns: the passed udev device if it has still an active reference, or #NULL otherwise. **/ -_public_ void udev_device_unref(struct udev_device *udev_device) +_public_ struct udev_device *udev_device_unref(struct udev_device *udev_device) { if (udev_device == NULL) - return; + return NULL; udev_device->refcount--; if (udev_device->refcount > 0) - return; + return udev_device; if (udev_device->parent_device != NULL) udev_device_unref(udev_device->parent_device); free(udev_device->syspath); @@ -1043,6 +1116,7 @@ _public_ void udev_device_unref(struct udev_device *udev_device) free(udev_device->envp); free(udev_device->monitor_buf); free(udev_device); + return NULL; } /** @@ -1081,7 +1155,9 @@ _public_ const char *udev_device_get_syspath(struct udev_device *udev_device) * udev_device_get_sysname: * @udev_device: udev device * - * Returns: the sys name of the device device + * Get the kernel device name in /sys. + * + * Returns: the name string of the device device **/ _public_ const char *udev_device_get_sysname(struct udev_device *udev_device) { @@ -1094,7 +1170,9 @@ _public_ const char *udev_device_get_sysname(struct udev_device *udev_device) * udev_device_get_sysnum: * @udev_device: udev device * - * Returns: the trailing number of of the device name + * Get the instance number of the device. + * + * Returns: the trailing number string of the device name **/ _public_ const char *udev_device_get_sysnum(struct udev_device *udev_device) { @@ -1182,9 +1260,9 @@ _public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct ud 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); } } @@ -1197,9 +1275,9 @@ _public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct ud 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); } } @@ -1237,7 +1315,7 @@ _public_ const char *udev_device_get_action(struct udev_device *udev_device) **/ _public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) { - unsigned long long now; + usec_t now_ts; if (udev_device == NULL) return 0; @@ -1245,23 +1323,23 @@ _public_ unsigned long long int udev_device_get_usec_since_initialized(struct ud udev_device_read_db(udev_device, NULL); if (udev_device->usec_initialized == 0) return 0; - now = now_usec(); - if (now == 0) + now_ts = now(CLOCK_MONOTONIC); + if (now_ts == 0) return 0; - return now - udev_device->usec_initialized; + return now_ts - udev_device->usec_initialized; } -unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device) +usec_t udev_device_get_usec_initialized(struct udev_device *udev_device) { return udev_device->usec_initialized; } -void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized) +void udev_device_set_usec_initialized(struct udev_device *udev_device, usec_t usec_initialized) { char num[32]; udev_device->usec_initialized = usec_initialized; - snprintf(num, sizeof(num), "%llu", usec_initialized); + snprintf(num, sizeof(num), "%llu", (unsigned long long)usec_initialized); udev_device_add_property(udev_device, "USEC_INITIALIZED", num); } @@ -1296,22 +1374,20 @@ _public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_devi 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. */ - if (strcmp(sysattr, "driver") == 0 || - strcmp(sysattr, "subsystem") == 0 || - strcmp(sysattr, "module") == 0) { + if (streq(sysattr, "driver") || + streq(sysattr, "subsystem") || + streq(sysattr, "module")) { if (util_get_sys_core_link_value(udev_device->udev, sysattr, udev_device->syspath, value, sizeof(value)) < 0) return NULL; @@ -1320,16 +1396,6 @@ _public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_devi 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; } @@ -1361,6 +1427,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); + + 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; @@ -1384,7 +1535,7 @@ static int udev_device_sysattr_list_read(struct udev_device *udev_device) 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) @@ -1431,7 +1582,7 @@ int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath udev_device->syspath = strdup(syspath); if (udev_device->syspath == NULL) return -ENOMEM; - udev_device->devpath = udev_device->syspath + strlen(TEST_PREFIX "/sys"); + udev_device->devpath = udev_device->syspath + strlen("/sys"); udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath); pos = strrchr(udev_device->syspath, '/'); @@ -1464,7 +1615,7 @@ int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode { free(udev_device->devnode); if (devnode[0] != '/') { - if (asprintf(&udev_device->devnode, TEST_PREFIX "/dev/%s", devnode) < 0) + if (asprintf(&udev_device->devnode, "/dev/%s", devnode) < 0) udev_device->devnode = NULL; } else { udev_device->devnode = strdup(devnode); @@ -1475,7 +1626,7 @@ int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode return 0; } -int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique) +int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink) { struct udev_list_entry *list_entry; @@ -1483,8 +1634,6 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink list_entry = udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL); if (list_entry == NULL) return -ENOMEM; - if (unique) - udev_list_entry_set_num(list_entry, true); return 0; } @@ -1497,7 +1646,7 @@ const char *udev_device_get_id_filename(struct udev_device *udev_device) if (major(udev_device_get_devnum(udev_device)) > 0) { /* use dev_t -- b259:131072, c254:0 */ if (asprintf(&udev_device->id_filename, "%c%u:%u", - strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? 'b' : 'c', + streq(udev_device_get_subsystem(udev_device), "block") ? 'b' : 'c', major(udev_device_get_devnum(udev_device)), minor(udev_device_get_devnum(udev_device))) < 0) udev_device->id_filename = NULL; @@ -1583,6 +1732,15 @@ _public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_dev return udev_list_get_entry(&udev_device->tags_list); } +/** + * udev_device_has_tag: + * @udev_device: udev device + * @tag: tag name + * + * Check if a given device has a certain tag associated. + * + * Returns: 1 if the tag is found. 0 otherwise. + **/ _public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag) { struct udev_list_entry *list_entry; @@ -1636,10 +1794,10 @@ static int update_envp_monitor_buf(struct udev_device *udev_device) 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--; }