57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen This file is part of systemd.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2014 Tom Gundersen <teg@jklm.no>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen systemd is free software; you can redistribute it and/or modify it
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen under the terms of the GNU Lesser General Public License as published by
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (at your option) any later version.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen systemd is distributed in the hope that it will be useful, but
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Lesser General Public License for more details.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen You should have received a copy of the GNU Lesser General Public License
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ sd_device *sd_device_ref(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ sd_device *sd_device_unref(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ordered_hashmap_free_free_free(device->properties);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ordered_hashmap_free_free_free(device->properties_db);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen hashmap_free_free_free(device->sysattr_values);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = ordered_hashmap_replace(*properties, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_add_property_internal(sd_device *device, const char *key, const char *value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return device_add_property_aux(device, key, value, false);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* must be a subdirectory of /sys */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = readlink_and_canonicalize(_syspath, &syspath);
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen /* the device does not exist (any more?) */
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen else if (r == -EINVAL) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* not a symlink */
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen /* the device does not exist (any more?) */
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath);
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen } else if (r < 0) {
23446f01480e1d6f72a03d71f9c67cbf34ddaf3bMichal Schmidt log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (path_startswith(syspath, "/sys/devices/")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* all 'devices' require an 'uevent' file */
52d629010db73a9466c359201916494bd55186d1Tom Gundersen /* this is not a valid device */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: %s does not have an uevent file: %m", syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* everything else just just needs to be a directory */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVPATH", devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_syspath(device, syspath, true);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(type == 'b' || type == 'c', -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use /sys/dev/{block,char}/<maj>:<min> link */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/subsystem/", sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers /* translate sysname back to sysfs filename */
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers syspath = strjoina("/sys/bus/", subsystem, "/devices/", name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers syspath = strjoina("/sys/class/", subsystem, "/", name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_devtype(sd_device *device, const char *_devtype) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVTYPE", devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_ifindex(sd_device *device, const char *_ifindex) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "IFINDEX", _ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_devname(sd_device *device, const char *_devname) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVNAME", devname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_devmode(sd_device *device, const char *_devmode) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVMODE", _devmode);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_devnum(sd_device *device, const char *major, const char *minor) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "MAJOR", major);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "MINOR", minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_read_uevent_file(sd_device *device) {
97c94b9865c239a849cf9870122afd1e9332cf03Zbigniew Jędrzejewski-Szmek const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = read_full_file(path, &uevent, &uevent_len);
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen /* empty uevent files may be write-only */
2a2137401b3aef20618308d2b2694e21b0124f89Tom Gundersen else if (r == -ENOENT)
2a2137401b3aef20618308d2b2694e21b0124f89Tom Gundersen /* some devices may not have uevent files, see set_syspath() */
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen else if (r < 0) {
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < uevent_len; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: ignoring invalid uevent line '%s'", key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = handle_uevent_line(device, key, value, &major, &minor);
19c29853804f8806866695d743fd4e3586996dbbMichal Schmidt log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_not_reached("invalid state when parsing uevent file");
23446f01480e1d6f72a03d71f9c67cbf34ddaf3bMichal Schmidt log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen switch (id[0]) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_devnum(ret, type, makedev(maj, min));
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_device_unrefp) sd_device *device = NULL;
6ad623a3f77e087e308f334525fd4046811f2a9aLennart Poettering r = parse_ifindex(&id[1], &ifr.ifr_ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen /* this is racey, so we might end up with the wrong device */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void)strscpy(subsys, sizeof(subsys), id + 1);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(path_startswith(device->syspath, "/sys/"));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_new_from_child(sd_device **ret, sd_device *child) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void)device_new_from_child(&child->parent, child);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_subsystem(sd_device *device, const char *_subsystem) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* read 'subsystem' link */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use implicit names */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (path_startswith(device->devpath, "/module/"))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (strstr(device->devpath, "/drivers/"))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (path_startswith(device->devpath, "/subsystem/") ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path_startswith(device->devpath, "/class/") ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_subsystem(device, "subsystem");
4189708ad0cde8e211e38d27de943579772f8869Tom Gundersen if (r < 0 && r != -ENOENT)
5a917c064b23c1b8a12d6abd2f9f31c575ddebc6Tom Gundersen return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while (r >= 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void)sd_device_get_subsystem(parent, &parent_subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void)sd_device_get_devtype(parent, &parent_devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_driver(sd_device *device, const char *_driver) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DRIVER", driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_driver(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r >= 0) {
7283a80d10217b929acf58899f016ca06dacdc53Tom Gundersen return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
7283a80d10217b929acf58899f016ca06dacdc53Tom Gundersen } else if (r == -ENOENT)
7283a80d10217b929acf58899f016ca06dacdc53Tom Gundersen return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_devname(sd_device *device, const char **devname) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(path_startswith(device->devname, "/dev/"));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_set_sysname(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* devpath is not a root directory */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* some devices have '!' in their name, change that to '/' */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* trailing number */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return !strchr(tag, ':') && !strchr(tag, ' ');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_add_tag(sd_device *device, const char *tag) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_ensure_allocated(&device->tags, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_add_devlink(sd_device *device, const char *devlink) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_put_strdup(device->devlinks, devlink);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_add_property_internal_from_string(sd_device *device, const char *str) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return device_add_property_internal(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_usec_initialized(sd_device *device, const char *initialized) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atou64(initialized, &usec_initialized);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int handle_db_line(sd_device *device, char key, const char *value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal_from_string(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_usec_initialized(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atoi(value, &device->devlink_priority);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("device db: unknown key '%c'", key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_id_filename(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_subsystem(device, &subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use dev_t -- b259:131072, c254:0 */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (ifindex > 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use netdev ifindex -- n3 */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use $subsys:$sysname -- pci:0000:00:1f.2
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * sysname() has '!' translated, get it from devpath
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = asprintf(&id, "+%s:%s", subsystem, sysname);
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersenint device_read_db_aux(sd_device *device, bool force) {
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen if (device->db_loaded || (!force && device->sealed))
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* devices with a database entry are initialized */
7e518afab9fb55b8052f68888210927259275560Thomas Hindoe Paaboel Andersen device->is_initialized = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < db_len; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
19c29853804f8806866695d743fd4e3586996dbbMichal Schmidt log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_not_reached("invalid state when parsing db");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_tag_first(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->tags_iterator_generation = device->tags_generation;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->tags, &device->tags_iterator, &v);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_tag_next(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->tags_iterator_generation != device->tags_generation)
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->tags, &device->tags_iterator, &v);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_devlink_first(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devlinks_iterator_generation = device->devlinks_generation;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->devlinks, &device->devlinks_iterator, &v);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_devlink_next(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->devlinks_iterator_generation != device->devlinks_generation)
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->devlinks, &device->devlinks_iterator, &v);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_properties_prepare(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devlink = sd_device_get_devlink_first(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while ((devlink = sd_device_get_devlink_next(device)))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVLINKS", devlinks);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while ((tag = sd_device_get_tag_next(device)))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "TAGS", tags);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->properties_iterator_generation = device->properties_generation;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->properties_iterator_generation != device->properties_generation)
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_sysattrs_read_all(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* only handle symlinks and regular files */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_put_strdup(device->sysattrs, dent->d_name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = ordered_hashmap_get(device->properties, key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/* replaces the value if it already exists */
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersenstatic int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = hashmap_put(device->sysattr_values, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/* We cache all sysattr lookups. If an attribute does not exist, it is stored
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * with a NULL value in the cache, otherwise the returned string is stored */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* look for possibly already cached result */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_get_sysattr_value(device, sysattr, &cached_value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* we looked up the sysattr before and it did not exist */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* remember that we could not access the sysattr */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_sysattr_value(device, sysattr, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Some core links return only the last element of the target path,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * these are just values, the paths should not be exposed. */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* skip directories */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* skip non-readable files */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* read attribute value */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* drop trailing newlines */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_sysattr_value(device, sysattr, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic void device_remove_sysattr_value(sd_device *device, const char *_key) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/* set the attribute and save it in the cache. If a NULL value is passed the
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * attribute is cleared from the cache */
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen r = device_add_sysattr_value(device, sysattr, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* skip directories */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* skip non-readable files */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* drop trailing newlines */
24eb4a30982ed18d4716bd59c454a72f161d5982David Herrmann while (value_len > 0 && _value[value_len - 1] == '\n')
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* value length is limited to 4k */