57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/***
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen This file is part of systemd.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2014 Tom Gundersen <teg@jklm.no>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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
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
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/>.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen***/
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include <ctype.h>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include <net/if.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/types.h>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "sd-device.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "alloc-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "device-internal.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "device-private.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "device-util.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "fileio.h"
f4f15635ec05293ffcc83a5b39f624bbabbd8fd0Lennart Poettering#include "fs-util.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "hashmap.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "macro.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "parse-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "path-util.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "set.h"
8fcde01280adcbd07e8205b91ac52b06305b6208Lennart Poettering#include "stat-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "string-util.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "strv.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "strxcpyx.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "util.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_new_aux(sd_device **ret) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device = new0(sd_device, 1);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->n_ref = 1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->watch_handle = -1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ sd_device *sd_device_ref(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_se(++ device->n_ref >= 2);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return device;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ sd_device *sd_device_unref(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device && -- device->n_ref == 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sd_device_unref(device->parent);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->devname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->id_filename);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->properties_strv);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->properties_nulstr);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 Gundersen set_free_free(device->sysattrs);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen set_free_free(device->tags);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen set_free_free(device->devlinks);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen OrderedHashmap **properties;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (db)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen properties = &device->properties_db;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen properties = &device->properties;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = strdup(_key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!key)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = strdup(_value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = ordered_hashmap_replace(*properties, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *key = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!db) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->properties_generation ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->properties_buf_outdated = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *syspath = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *devpath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* must be a subdirectory of /sys */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!path_startswith(_syspath, "/sys/")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (verify) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = readlink_and_canonicalize(_syspath, &syspath);
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen if (r == -ENOENT)
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen /* the device does not exist (any more?) */
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen return -ENODEV;
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen else if (r == -EINVAL) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* not a symlink */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = canonicalize_file_name(_syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!syspath) {
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen if (errno == ENOENT)
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen /* the device does not exist (any more?) */
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen return -ENODEV;
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen } else if (r < 0) {
23446f01480e1d6f72a03d71f9c67cbf34ddaf3bMichal Schmidt log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (path_startswith(syspath, "/sys/devices/")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* all 'devices' require an 'uevent' file */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina(syspath, "/uevent");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = access(path, F_OK);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
52d629010db73a9466c359201916494bd55186d1Tom Gundersen if (errno == ENOENT)
52d629010db73a9466c359201916494bd55186d1Tom Gundersen /* this is not a valid device */
52d629010db73a9466c359201916494bd55186d1Tom Gundersen return -ENODEV;
52d629010db73a9466c359201916494bd55186d1Tom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: %s does not have an uevent file: %m", syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* everything else just just needs to be a directory */
52d629010db73a9466c359201916494bd55186d1Tom Gundersen if (!is_dir(syspath, false))
52d629010db73a9466c359201916494bd55186d1Tom Gundersen return -ENODEV;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strdup(_syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!syspath)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devpath = syspath + strlen("/sys");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVPATH", devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->syspath = syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devpath = devpath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(syspath, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_new_aux(&device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_syspath(device, syspath, true);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(type == 'b' || type == 'c', -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use /sys/dev/{block,char}/<maj>:<min> link */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(subsystem, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(sysname, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (streq(subsystem, "subsystem")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/subsystem/", sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/bus/", sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/class/", sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(subsystem, "module")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/module/", sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(subsystem, "drivers")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char subsys[PATH_MAX];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *driver;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen strscpy(subsys, sizeof(subsys), sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen driver = strchr(subsys, ':');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (driver) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen driver[0] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen driver++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers char *name;
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers size_t len = 0;
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers /* translate sysname back to sysfs filename */
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers name = strdupa(sysname);
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers while (name[len] != '\0') {
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers if (name[len] == '/')
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers name[len] = '!';
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers len ++;
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers }
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers syspath = strjoina("/sys/bus/", subsystem, "/devices/", name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers syspath = strjoina("/sys/class/", subsystem, "/", name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (access(syspath, F_OK) >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_syspath(ret, syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen return -ENODEV;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_devtype(sd_device *device, const char *_devtype) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *devtype = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devtype = strdup(_devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!devtype)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVTYPE", devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devtype = devtype;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devtype = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_ifindex(sd_device *device, const char *_ifindex) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int ifindex, r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
6ad623a3f77e087e308f334525fd4046811f2a9aLennart Poettering r = parse_ifindex(_ifindex, &ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "IFINDEX", _ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->ifindex = ifindex;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_devname(sd_device *device, const char *_devname) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *devname = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_devname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (_devname[0] != '/') {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = asprintf(&devname, "/dev/%s", _devname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devname = strdup(_devname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!devname)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVNAME", devname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->devname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devname = devname;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devname = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_devmode(sd_device *device, const char *_devmode) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned devmode;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_devmode);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atou(_devmode, &devmode);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (devmode > 07777)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVMODE", _devmode);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devmode = devmode;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_devnum(sd_device *device, const char *major, const char *minor) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned maj = 0, min = 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(major);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atou(major, &maj);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!maj)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (minor) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atou(minor, &min);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "MAJOR", major);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (minor) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "MINOR", minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devnum = makedev(maj, min);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(major);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (streq(key, "DEVTYPE")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devtype(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "IFINDEX")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_ifindex(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DEVNAME")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devname(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "DEVMODE")) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devmode(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (streq(key, "MAJOR"))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *major = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (streq(key, "MINOR"))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *minor = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_read_uevent_file(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *uevent = NULL;
97c94b9865c239a849cf9870122afd1e9332cf03Zbigniew Jędrzejewski-Szmek const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen size_t uevent_len;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned i;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen enum {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen PRE_KEY,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen KEY,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen PRE_VALUE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen VALUE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen INVALID_LINE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->uevent_loaded || device->sealed)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
7141e4f62c3f220872df3114c42d9e4b9525e43eTom Gundersen device->uevent_loaded = true;
7141e4f62c3f220872df3114c42d9e4b9525e43eTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_syspath(device, &syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina(syspath, "/uevent");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = read_full_file(path, &uevent, &uevent_len);
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen if (r == -EACCES)
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen /* empty uevent files may be write-only */
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen return 0;
2a2137401b3aef20618308d2b2694e21b0124f89Tom Gundersen else if (r == -ENOENT)
2a2137401b3aef20618308d2b2694e21b0124f89Tom Gundersen /* some devices may not have uevent files, see set_syspath() */
2a2137401b3aef20618308d2b2694e21b0124f89Tom Gundersen return 0;
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen else if (r < 0) {
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < uevent_len; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen switch (state) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case PRE_KEY:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!strchr(NEWLINE, uevent[i])) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = &uevent[i];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case KEY:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (uevent[i] == '=') {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uevent[i] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_VALUE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (strchr(NEWLINE, uevent[i])) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uevent[i] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: ignoring invalid uevent line '%s'", key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case PRE_VALUE:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = &uevent[i];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = VALUE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case VALUE:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (strchr(NEWLINE, uevent[i])) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uevent[i] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = handle_uevent_line(device, key, value, &major, &minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
19c29853804f8806866695d743fd4e3586996dbbMichal Schmidt log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen default:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_not_reached("invalid state when parsing uevent file");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (major) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_devnum(device, major, minor);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
23446f01480e1d6f72a03d71f9c67cbf34ddaf3bMichal Schmidt log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ifindex, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_uevent_file(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ifindex = device->ifindex;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(id, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen switch (id[0]) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'b':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'c':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char type;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int maj, min;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sscanf(id, "%c%i:%i", &type, &maj, &min);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r != 3)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_devnum(ret, type, makedev(maj, min));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'n':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_close_ int sk = -1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen struct ifreq ifr = {};
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int ifindex;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
6ad623a3f77e087e308f334525fd4046811f2a9aLennart Poettering r = parse_ifindex(&id[1], &ifr.ifr_ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sk = socket(PF_INET, SOCK_DGRAM, 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (sk < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = ioctl(sk, SIOCGIFNAME, &ifr);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_ifindex(device, &ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen /* this is racey, so we might end up with the wrong device */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (ifr.ifr_ifindex != ifindex)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENODEV;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case '+':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char subsys[PATH_MAX];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *sysname;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void)strscpy(subsys, sizeof(subsys), id + 1);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysname = strchr(subsys, ':');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!sysname)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysname[0] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysname ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen default:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(path_startswith(device->syspath, "/sys/"));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device->syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_new_from_child(sd_device **ret, sd_device *child) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *path = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *subdir, *syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(child);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_syspath(child, &syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strdup(syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!path)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen subdir = path + strlen("/sys");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (;;) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *pos;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen pos = strrchr(subdir, '/');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!pos || pos < subdir + 2)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *pos = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_new_from_syspath(ret, path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen continue;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen return -ENODEV;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(child, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!child->parent_set) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen child->parent_set = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void)device_new_from_child(&child->parent, child);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!child->parent)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOENT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = child->parent;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_subsystem(sd_device *device, const char *_subsystem) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *subsystem = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen subsystem = strdup(_subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!subsystem)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->subsystem = subsystem;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen subsystem = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->subsystem_set = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->subsystem_set) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *subsystem = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* read 'subsystem' link */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_syspath(device, &syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina(syspath, "/subsystem");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = readlink_value(path, &subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r >= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_subsystem(device, subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use implicit names */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (path_startswith(device->devpath, "/module/"))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_subsystem(device, "module");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (strstr(device->devpath, "/drivers/"))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_subsystem(device, "drivers");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (path_startswith(device->devpath, "/subsystem/") ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path_startswith(device->devpath, "/class/") ||
85091685af65831f379580c75b40776c20e245eeTom Gundersen path_startswith(device->devpath, "/bus/"))
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
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->subsystem_set = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
bf4c113e179650c07a8f95a14d71f365dbfe66e4David Herrmann if (!device->subsystem)
bf4c113e179650c07a8f95a14d71f365dbfe66e4David Herrmann return -ENOENT;
bf4c113e179650c07a8f95a14d71f365dbfe66e4David Herrmann
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device->subsystem;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_uevent_file(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *devtype = device->devtype;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 sd_device *parent = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(child, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(subsystem, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_parent(child, &parent);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while (r >= 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *parent_subsystem = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *parent_devtype = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void)sd_device_get_subsystem(parent, &parent_subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (streq_ptr(parent_subsystem, subsystem)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!devtype)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void)sd_device_get_devtype(parent, &parent_devtype);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (streq_ptr(parent_devtype, devtype))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_parent(parent, &parent);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = parent;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(devnum, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_uevent_file(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *devnum = device->devnum;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_driver(sd_device *device, const char *_driver) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *driver = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen driver = strdup(_driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!driver)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DRIVER", driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->driver = driver;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen driver = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->driver_set = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_driver(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->driver_set) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *driver = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_syspath(device, &syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina(syspath, "/driver");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = readlink_value(path, &driver);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r >= 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_driver(device, driver);
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 device->driver_set = true;
7283a80d10217b929acf58899f016ca06dacdc53Tom Gundersen else
7283a80d10217b929acf58899f016ca06dacdc53Tom Gundersen return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
bf4c113e179650c07a8f95a14d71f365dbfe66e4David Herrmann if (!device->driver)
bf4c113e179650c07a8f95a14d71f365dbfe66e4David Herrmann return -ENOENT;
bf4c113e179650c07a8f95a14d71f365dbfe66e4David Herrmann
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device->driver;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(devpath, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device->devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device->devpath[0] == '/');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *devpath = device->devpath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_devname(sd_device *device, const char **devname) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(devname, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_uevent_file(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->devname)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOENT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(path_startswith(device->devname, "/dev/"));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *devname = device->devname;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_set_sysname(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *sysname = NULL;
afcac065c0f649ebcf0f450475a8d7c3bc776d14Tom Gundersen const char *sysnum = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *pos;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen size_t len = 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen pos = strrchr(device->devpath, '/');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!pos)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen pos ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* devpath is not a root directory */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (*pos == '\0' || pos <= device->devpath)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysname = strdup(pos);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!sysname)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* some devices have '!' in their name, change that to '/' */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while (sysname[len] != '\0') {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (sysname[len] == '!')
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysname[len] = '/';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen len ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* trailing number */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while (len > 0 && isdigit(sysname[--len]))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysnum = &sysname[len];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (len == 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysnum = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(device->sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->sysname = sysname;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysname = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->sysnum = sysnum;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->sysname_set = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->sysname_set) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_sysname(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
bf4c113e179650c07a8f95a14d71f365dbfe66e4David Herrmann assert_return(device->sysname, -ENOENT);
bf4c113e179650c07a8f95a14d71f365dbfe66e4David Herrmann
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device->sysname;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(ret, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->sysname_set) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_sysname(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device->sysnum;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic bool is_valid_tag(const char *tag) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return !strchr(tag, ':') && !strchr(tag, ' ');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_add_tag(sd_device *device, const char *tag) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!is_valid_tag(tag))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_ensure_allocated(&device->tags, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_put_strdup(device->tags, tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->tags_generation ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->property_tags_outdated = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_add_devlink(sd_device *device, const char *devlink) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(devlink);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_put_strdup(device->devlinks, devlink);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devlinks_generation ++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->property_devlinks_outdated = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_add_property_internal_from_string(sd_device *device, const char *str) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *key = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(str);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = strdup(str);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!key)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = strchr(key, '=');
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *value = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (isempty(++value))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return device_add_property_internal(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_set_usec_initialized(sd_device *device, const char *initialized) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uint64_t usec_initialized;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(initialized);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atou64(initialized, &usec_initialized);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->usec_initialized = usec_initialized;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int handle_db_line(sd_device *device, char key, const char *value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen switch (key) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'G':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_tag(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'S':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina("/dev/", value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_devlink(device, path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'E':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal_from_string(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'I':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_set_usec_initialized(device, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'L':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atoi(value, &device->devlink_priority);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case 'W':
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = safe_atoi(value, &device->watch_handle);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen default:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("device db: unknown key '%c'", key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint device_get_id_filename(sd_device *device, const char **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->id_filename) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *id = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *subsystem;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dev_t devnum;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int ifindex, r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_subsystem(device, &subsystem);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_devnum(device, &devnum);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_ifindex(device, &ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (major(devnum) > 0) {
4189708ad0cde8e211e38d27de943579772f8869Tom Gundersen assert(subsystem);
4189708ad0cde8e211e38d27de943579772f8869Tom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use dev_t -- b259:131072, c254:0 */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = asprintf(&id, "%c%u:%u",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen streq(subsystem, "block") ? 'b' : 'c',
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen major(devnum), minor(devnum));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
53fae771bcf1623cd28791c48fa60d9d5e5086e4Zbigniew Jędrzejewski-Szmek return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (ifindex > 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use netdev ifindex -- n3 */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = asprintf(&id, "n%u", ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
53fae771bcf1623cd28791c48fa60d9d5e5086e4Zbigniew Jędrzejewski-Szmek return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* use $subsys:$sysname -- pci:0000:00:1f.2
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * sysname() has '!' translated, get it from devpath
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *sysname;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sysname = basename(device->devpath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!sysname)
4189708ad0cde8e211e38d27de943579772f8869Tom Gundersen return -EINVAL;
4189708ad0cde8e211e38d27de943579772f8869Tom Gundersen
4189708ad0cde8e211e38d27de943579772f8869Tom Gundersen if (!subsystem)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = asprintf(&id, "+%s:%s", subsystem, sysname);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
53fae771bcf1623cd28791c48fa60d9d5e5086e4Zbigniew Jędrzejewski-Szmek return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->id_filename = id;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen id = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = device->id_filename;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersenint device_read_db_aux(sd_device *device, bool force) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *db = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *id, *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char key;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen size_t db_len;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned i;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen enum {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen PRE_KEY,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen KEY,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen PRE_VALUE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen VALUE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen INVALID_LINE,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen if (device->db_loaded || (!force && device->sealed))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
7141e4f62c3f220872df3114c42d9e4b9525e43eTom Gundersen device->db_loaded = true;
7141e4f62c3f220872df3114c42d9e4b9525e43eTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_get_id_filename(device, &id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina("/run/udev/data/", id);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = read_full_file(path, &db, &db_len);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r == -ENOENT)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering else
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* devices with a database entry are initialized */
7e518afab9fb55b8052f68888210927259275560Thomas Hindoe Paaboel Andersen device->is_initialized = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < db_len; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen switch (state) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case PRE_KEY:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!strchr(NEWLINE, db[i])) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = db[i];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case KEY:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (db[i] != ':') {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = INVALID_LINE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen db[i] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_VALUE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case PRE_VALUE:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = &db[i];
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = VALUE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case INVALID_LINE:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (strchr(NEWLINE, db[i]))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen case VALUE:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (strchr(NEWLINE, db[i])) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen db[i] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = handle_db_line(device, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
19c29853804f8806866695d743fd4e3586996dbbMichal Schmidt log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen state = PRE_KEY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen break;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen default:
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_not_reached("invalid state when parsing db");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersenstatic int device_read_db(sd_device *device) {
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen return device_read_db_aux(device, false);
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen}
107f2e2526d476c6cc9b81a690391c111027d641Tom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(initialized, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *initialized = device->is_initialized;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen usec_t now_ts;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(usec, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->is_initialized)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EBUSY;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->usec_initialized)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENODATA;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen now_ts = now(clock_boottime_or_monotonic());
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (now_ts < device->usec_initialized)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EIO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *usec = now_ts - device->usec_initialized;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_tag_first(sd_device *device) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann void *v;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void) device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->tags_iterator_generation = device->tags_generation;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->tags_iterator = ITERATOR_FIRST;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->tags, &device->tags_iterator, &v);
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann return v;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_tag_next(sd_device *device) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann void *v;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void) device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->tags_iterator_generation != device->tags_generation)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->tags, &device->tags_iterator, &v);
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann return v;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_devlink_first(sd_device *device) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann void *v;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void) device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devlinks_iterator_generation = device->devlinks_generation;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->devlinks_iterator = ITERATOR_FIRST;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->devlinks, &device->devlinks_iterator, &v);
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann return v;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_devlink_next(sd_device *device) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann void *v;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void) device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->devlinks_iterator_generation != device->devlinks_generation)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->devlinks, &device->devlinks_iterator, &v);
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann return v;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_properties_prepare(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_uevent_file(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->property_devlinks_outdated) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *devlinks = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *devlink;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devlink = sd_device_get_devlink_first(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (devlink)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devlinks = strdupa(devlink);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while ((devlink = sd_device_get_devlink_next(device)))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen devlinks = strjoina(devlinks, " ", devlink);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "DEVLINKS", devlinks);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->property_devlinks_outdated = false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->property_tags_outdated) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *tags = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *tag;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen tag = sd_device_get_tag_first(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (tag)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen tags = strjoina(":", tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while ((tag = sd_device_get_tag_next(device)))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen tags = strjoina(tags, ":", tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen tags = strjoina(tags, ":");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_property_internal(device, "TAGS", tags);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->property_tags_outdated = false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *key;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_properties_prepare(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->properties_iterator_generation = device->properties_generation;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->properties_iterator = ITERATOR_FIRST;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (_value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_value = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return key;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *key;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_properties_prepare(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->properties_iterator_generation != device->properties_generation)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (_value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_value = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return key;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_sysattrs_read_all(sd_device *device) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_closedir_ DIR *dir = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen struct dirent *dent;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (device->sysattrs_read)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_syspath(device, &syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dir = opendir(syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!dir)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen struct stat statbuf;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* only handle symlinks and regular files */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen continue;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina(syspath, "/", dent->d_name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (lstat(path, &statbuf) != 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen continue;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!(statbuf.st_mode & S_IRUSR))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen continue;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = set_put_strdup(device->sysattrs, dent->d_name);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->sysattrs_read = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann void *v;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->sysattrs_read) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_sysattrs_read_all(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen errno = -r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device->sysattrs_iterator = ITERATOR_FIRST;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann return v;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann void *v;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!device->sysattrs_read)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann return v;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(tag, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (void) device_read_db(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return !!set_contains(device->tags, tag);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(key, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(_value, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_properties_prepare(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = ordered_hashmap_get(device->properties, key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOENT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_value = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 _cleanup_free_ char *key = NULL;
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen _cleanup_free_ char *value_old = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!key) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = strdup(_key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!key)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = hashmap_put(device->sysattr_values, key, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen key = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *key = NULL, *value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!key)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOENT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (_value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_value = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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 _cleanup_free_ char *value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *syspath, *cached_value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen struct stat statbuf;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(sysattr, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* look for possibly already cached result */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_get_sysattr_value(device, sysattr, &cached_value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r != -ENOENT) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!cached_value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* we looked up the sysattr before and it did not exist */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOENT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (_value)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_value = cached_value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_syspath(device, &syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina(syspath, "/", sysattr);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = lstat(path, &statbuf);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* remember that we could not access the sysattr */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_sysattr_value(device, sysattr, NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOENT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (S_ISLNK(statbuf.st_mode)) {
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 r = readlink_value(path, &value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (S_ISDIR(statbuf.st_mode)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* skip directories */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (!(statbuf.st_mode & S_IRUSR)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* skip non-readable files */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EPERM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen size_t size;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* read attribute value */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = read_full_file(path, &value, &size);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* drop trailing newlines */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while (size > 0 && value[--size] == '\n')
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value[size] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_sysattr_value(device, sysattr, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *_value = value;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic void device_remove_sysattr_value(sd_device *device, const char *_key) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *key = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_free_ char *value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(device);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(_key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
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) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_close_ int fd = -1;
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen _cleanup_free_ char *value = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *syspath;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char *path;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen struct stat statbuf;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen size_t value_len = 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ssize_t size;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(device, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_return(sysattr, -EINVAL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen if (!_value) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen device_remove_sysattr_value(device, sysattr);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = sd_device_get_syspath(device, &syspath);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen path = strjoina(syspath, "/", sysattr);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = lstat(path, &statbuf);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen value = strdup("");
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen if (!value)
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen return -ENOMEM;
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen r = device_add_sysattr_value(device, sysattr, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENXIO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (S_ISLNK(statbuf.st_mode))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* skip directories */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (S_ISDIR(statbuf.st_mode))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EISDIR;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* skip non-readable files */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if ((statbuf.st_mode & S_IRUSR) == 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EACCES;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen value_len = strlen(_value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* drop trailing newlines */
24eb4a30982ed18d4716bd59c454a72f161d5982David Herrmann while (value_len > 0 && _value[value_len - 1] == '\n')
24eb4a30982ed18d4716bd59c454a72f161d5982David Herrmann _value[--value_len] = '\0';
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* value length is limited to 4k */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (value_len > 4096)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = open(path, O_WRONLY | O_CLOEXEC);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (fd < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen value = strdup(_value);
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen if (!value)
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen return -ENOMEM;
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen size = write(fd, value, value_len);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (size < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if ((size_t)size != value_len)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EIO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = device_add_sysattr_value(device, sysattr, value);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen value = NULL;
2fe29a46a3e16a787098f9fb410e1b756506fd52Tom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}