sd-device.c revision afcac065c0f649ebcf0f450475a8d7c3bc776d14
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/***
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering This file is part of systemd.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is free software; you can redistribute it and/or modify it
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering under the terms of the GNU Lesser General Public License as published by
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (at your option) any later version.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is distributed in the hope that it will be useful, but
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Lesser General Public License for more details.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering You should have received a copy of the GNU Lesser General Public License
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering***/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <ctype.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <sys/types.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <net/if.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "util.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "macro.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "path-util.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "strxcpyx.h"
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek#include "fileio.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "hashmap.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "set.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "strv.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "sd-device.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "device-util.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "device-private.h"
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek#include "device-internal.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint device_new_aux(sd_device **ret) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_device_unref_ sd_device *device = NULL;
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(ret);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device = new0(sd_device, 1);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!device)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENOMEM;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device->n_ref = 1;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device->watch_handle = -1;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *ret = device;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering}
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering_public_ sd_device *sd_device_ref(sd_device *device) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (device)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_se(++ device->n_ref >= 2);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return device;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering_public_ sd_device *sd_device_unref(sd_device *device) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (device && -- device->n_ref == 0) {
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering sd_device_unref(device->parent);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(device->syspath);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering free(device->sysname);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering free(device->devtype);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering free(device->devname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(device->subsystem);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering free(device->driver);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering free(device->id_filename);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering free(device->properties_strv);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering free(device->properties_nulstr);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering ordered_hashmap_free_free_free(device->properties);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering ordered_hashmap_free_free_free(device->properties_db);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering hashmap_free_free_free(device->sysattr_values);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering set_free_free(device->sysattrs);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering set_free_free(device->tags);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering set_free_free(device->devlinks);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering OrderedHashmap **properties;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(device);
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek assert(_key);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (db)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering properties = &device->properties_db;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering properties = &device->properties;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (_value) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering key = strdup(_key);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!key)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENOMEM;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering value = strdup(_value);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!value)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENOMEM;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = ordered_hashmap_replace(*properties, key, value);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return r;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek key = NULL;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek value = NULL;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering } else {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_free_ char *key = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_free_ char *value = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!db) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device->properties_generation ++;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device->properties_buf_outdated = true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek}
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmekint device_add_property_internal(sd_device *device, const char *key, const char *value) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return device_add_property_aux(device, key, value, false);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek}
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmekint device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *syspath = NULL;
4b8268f843b0da1cfe1995d93a0b1f95faccc454Zbigniew Jędrzejewski-Szmek const char *devpath;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek int r;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
4b8268f843b0da1cfe1995d93a0b1f95faccc454Zbigniew Jędrzejewski-Szmek assert(device);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert(_syspath);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek /* must be a subdirectory of /sys */
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek if (!path_startswith(_syspath, "/sys/")) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return -EINVAL;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek }
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek if (verify) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek r = readlink_and_canonicalize(_syspath, &syspath);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r == -EINVAL) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* not a symlink */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = canonicalize_file_name(_syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!syspath) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return -errno;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* ignore errors due to the link not being a symlink */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (r < 0 && r != -EINVAL) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (path_startswith(syspath, "/sys/devices/")) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char *path;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* all 'devices' require an 'uevent' file */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering path = strjoina(syspath, "/uevent");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = access(path, F_OK);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek if (r < 0) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek log_debug("sd-device: %s does not have an uevent file: %m", syspath);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return -errno;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek }
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek } else {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek /* everything else just just needs to be a directory */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!is_dir(syspath, false)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("sd-device: %s is not a directory", syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strdup(_syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!syspath)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENOMEM;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering devpath = syspath + strlen("/sys");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_add_property_internal(device, "DEVPATH", devpath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(device->syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device->syspath = syspath;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device->devpath = devpath;
d3b6d0c21ea5a0d15ec6dbd8b8d179138b7463bcZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_device_unref_ sd_device *device = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek assert_return(ret, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(syspath, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_new_aux(&device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek r = device_set_syspath(device, syspath, true);
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *ret = device;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device = NULL;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek char *syspath;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(ret, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(type == 'b' || type == 'c', -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* use /sys/dev/{block,char}/<maj>:<min> link */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char *syspath;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert_return(ret, -EINVAL);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert_return(subsystem, -EINVAL);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert_return(sysname, -EINVAL);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek if (streq(subsystem, "subsystem")) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/subsystem/", sysname);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek if (access(syspath, F_OK) >= 0)
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/bus/", sysname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (access(syspath, F_OK) >= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/class/", sysname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (access(syspath, F_OK) >= 0)
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (streq(subsystem, "module")) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/module/", sysname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (access(syspath, F_OK) >= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (streq(subsystem, "drivers")) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char subsys[PATH_MAX];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char *driver;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering strscpy(subsys, sizeof(subsys), sysname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering driver = strchr(subsys, ':');
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (driver) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering driver[0] = '\0';
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering driver++;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (access(syspath, F_OK) >= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (access(syspath, F_OK) >= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (access(syspath, F_OK) >= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (access(syspath, F_OK) >= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering syspath = strjoina("/sys/class/", subsystem, "/", sysname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (access(syspath, F_OK) >= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENOENT;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint device_set_devtype(sd_device *device, const char *_devtype) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_free_ char *devtype = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(device);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(_devtype);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek devtype = strdup(_devtype);
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer if (!devtype)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return -ENOMEM;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek r = device_add_property_internal(device, "DEVTYPE", devtype);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek free(device->devtype);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek device->devtype = devtype;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek devtype = NULL;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekint device_set_ifindex(sd_device *device, const char *_ifindex) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek int ifindex, r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(device);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(_ifindex);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek r = safe_atoi(_ifindex, &ifindex);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (ifindex <= 0)
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek return -EINVAL;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek r = device_add_property_internal(device, "IFINDEX", _ifindex);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek device->ifindex = ifindex;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekint device_set_devname(sd_device *device, const char *_devname) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek _cleanup_free_ char *devname = NULL;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek int r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(device);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(_devname);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (_devname[0] != '/') {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek r = asprintf(&devname, "/dev/%s", _devname);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return -ENOMEM;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek } else {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek devname = strdup(_devname);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (!devname)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return -ENOMEM;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek }
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek r = device_add_property_internal(device, "DEVNAME", devname);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek free(device->devname);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek device->devname = devname;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek devname = NULL;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekint device_set_devmode(sd_device *device, const char *_devmode) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek unsigned devmode;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek int r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(_devmode);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = safe_atou(_devmode, &devmode);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (devmode > 07777)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_add_property_internal(device, "DEVMODE", _devmode);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek device->devmode = devmode;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekint device_set_devnum(sd_device *device, const char *major, const char *minor) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unsigned maj = 0, min = 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(major);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = safe_atou(major, &maj);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!maj)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (minor) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = safe_atou(minor, &min);
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek if (r < 0)
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_add_property_internal(device, "MAJOR", major);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (minor) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_add_property_internal(device, "MINOR", minor);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek device->devnum = makedev(maj, min);
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
7ff7394d9e4e9189c30fd018235e6b1728c6f2d0Zbigniew Jędrzejewski-Szmek int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(device);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(key);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(value);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(major);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(minor);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (streq(key, "DEVTYPE")) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_set_devtype(device, value);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek } else if (streq(key, "IFINDEX")) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek r = device_set_ifindex(device, value);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (streq(key, "DEVNAME")) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek r = device_set_devname(device, value);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek } else if (streq(key, "DEVMODE")) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_set_devmode(device, value);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (streq(key, "MAJOR"))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *major = value;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (streq(key, "MINOR"))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *minor = value;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_add_property_internal(device, key, value);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint device_read_uevent_file(sd_device *device) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_free_ char *uevent = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering const char *syspath, *key, *value, *major = NULL, *minor = NULL;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering char *path;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering size_t uevent_len;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unsigned i;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering enum {
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering PRE_KEY,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering KEY,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering PRE_VALUE,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering VALUE,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering INVALID_LINE,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } state = PRE_KEY;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering assert(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering if (device->uevent_loaded || device->sealed)
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering return 0;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_device_get_syspath(device, &syspath);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering path = strjoina(syspath, "/uevent");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = read_full_file(path, &uevent, &uevent_len);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering for (i = 0; i < uevent_len; i++) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering switch (state) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case PRE_KEY:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!strchr(NEWLINE, uevent[i])) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering key = &uevent[i];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering state = KEY;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case KEY:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (uevent[i] == '=') {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering uevent[i] = '\0';
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering state = PRE_VALUE;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (strchr(NEWLINE, uevent[i])) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uevent[i] = '\0';
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("sd-device: ignoring invalid uevent line '%s'", key);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering state = PRE_KEY;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case PRE_VALUE:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering value = &uevent[i];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering state = VALUE;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case VALUE:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (strchr(NEWLINE, uevent[i])) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uevent[i] = '\0';
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering r = handle_uevent_line(device, key, value, &major, &minor);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering if (r < 0)
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering state = PRE_KEY;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering default:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_not_reached("invalid state when parsing uevent file");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (major) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_set_devnum(device, major, minor);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device->uevent_loaded = true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering_public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(device, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(ifindex, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = device_read_uevent_file(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *ifindex = device->ifindex;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering_public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(ret, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(id, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering switch (id[0]) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case 'b':
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case 'c':
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char type;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int maj, min;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sscanf(id, "%c%i:%i", &type, &maj, &min);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r != 3)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_devnum(ret, type, makedev(maj, min));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case 'n':
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_device_unref_ sd_device *device = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_close_ int sk = -1;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering struct ifreq ifr = {};
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int ifindex;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = safe_atoi(&id[1], &ifr.ifr_ifindex);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return r;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek else if (ifr.ifr_ifindex <= 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return -EINVAL;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek sk = socket(PF_INET, SOCK_DGRAM, 0);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (sk < 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return -errno;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = ioctl(sk, SIOCGIFNAME, &ifr);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return -errno;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_device_get_ifindex(device, &ifindex);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* this si racey, so we might end up with the wrong device */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (ifr.ifr_ifindex != ifindex)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENODEV;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *ret = device;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek device = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case '+':
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char subsys[PATH_MAX];
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering char *sysname;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (void)strscpy(subsys, sizeof(subsys), id + 1);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sysname = strchr(subsys, ':');
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!sysname)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sysname[0] = '\0';
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek sysname ++;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering default:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering_public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert_return(device, -EINVAL);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert_return(ret, -EINVAL);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert(path_startswith(device->syspath, "/sys/"));
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek *ret = device->syspath;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return 0;
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer}
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmekstatic int device_new_from_child(sd_device **ret, sd_device *child) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *path = NULL;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek const char *subdir, *syspath;
2e8fb7026d3c560194cfe9f83935ce0b16263da0Lukas Nykryn int r;
464264ac5a35b655065c5d95b8d8ffbbc7ff3bcfLukas Nykryn
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert(ret);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert(child);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = sd_device_get_syspath(child, &syspath);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r < 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return r;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek path = strdup(syspath);
2e8fb7026d3c560194cfe9f83935ce0b16263da0Lukas Nykryn if (!path)
464264ac5a35b655065c5d95b8d8ffbbc7ff3bcfLukas Nykryn return -ENOMEM;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek subdir = path + strlen("/sys");
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek for (;;) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek char *pos;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek pos = strrchr(subdir, '/');
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (!pos || pos < subdir + 2)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek break;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
*pos = '\0';
r = sd_device_new_from_syspath(ret, path);
if (r < 0)
continue;
return 0;
}
return -ENOENT;
}
_public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
assert_return(ret, -EINVAL);
assert_return(child, -EINVAL);
if (!child->parent_set) {
child->parent_set = true;
(void)device_new_from_child(&child->parent, child);
}
if (!child->parent)
return -ENOENT;
*ret = child->parent;
return 0;
}
int device_set_subsystem(sd_device *device, const char *_subsystem) {
_cleanup_free_ char *subsystem = NULL;
int r;
assert(device);
assert(_subsystem);
subsystem = strdup(_subsystem);
if (!subsystem)
return -ENOMEM;
r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
if (r < 0)
return r;
free(device->subsystem);
device->subsystem = subsystem;
subsystem = NULL;
device->subsystem_set = true;
return 0;
}
_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
assert_return(ret, -EINVAL);
assert_return(device, -EINVAL);
if (!device->subsystem_set) {
_cleanup_free_ char *subsystem = NULL;
const char *syspath;
char *path;
int r;
/* read 'subsystem' link */
r = sd_device_get_syspath(device, &syspath);
if (r < 0)
return r;
path = strjoina(syspath, "/subsystem");
r = readlink_value(path, &subsystem);
if (r >= 0)
r = device_set_subsystem(device, subsystem);
/* use implicit names */
else if (path_startswith(device->devpath, "/module/"))
r = device_set_subsystem(device, "module");
else if (strstr(device->devpath, "/drivers/"))
r = device_set_subsystem(device, "drivers");
else if (path_startswith(device->devpath, "/subsystem/") ||
path_startswith(device->devpath, "/class/") ||
path_startswith(device->devpath, "/buss/"))
r = device_set_subsystem(device, "subsystem");
if (r < 0)
return r;
device->subsystem_set = true;
}
*ret = device->subsystem;
return 0;
}
_public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
int r;
assert(devtype);
assert(device);
r = device_read_uevent_file(device);
if (r < 0)
return r;
*devtype = device->devtype;
return 0;
}
_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
sd_device *parent = NULL;
int r;
assert_return(child, -EINVAL);
assert_return(subsystem, -EINVAL);
r = sd_device_get_parent(child, &parent);
while (r >= 0) {
const char *parent_subsystem = NULL;
const char *parent_devtype = NULL;
(void)sd_device_get_subsystem(parent, &parent_subsystem);
if (streq_ptr(parent_subsystem, subsystem)) {
if (!devtype)
break;
(void)sd_device_get_devtype(parent, &parent_devtype);
if (streq_ptr(parent_devtype, devtype))
break;
}
r = sd_device_get_parent(parent, &parent);
}
if (r < 0)
return r;
*ret = parent;
return 0;
}
_public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
int r;
assert_return(device, -EINVAL);
assert_return(devnum, -EINVAL);
r = device_read_uevent_file(device);
if (r < 0)
return r;
*devnum = device->devnum;
return 0;
}
int device_set_driver(sd_device *device, const char *_driver) {
_cleanup_free_ char *driver = NULL;
int r;
assert(device);
assert(_driver);
driver = strdup(_driver);
if (!driver)
return -ENOMEM;
r = device_add_property_internal(device, "DRIVER", driver);
if (r < 0)
return r;
free(device->driver);
device->driver = driver;
driver = NULL;
device->driver_set = true;
return 0;
}
_public_ int sd_device_get_driver(sd_device *device, const char **ret) {
assert_return(device, -EINVAL);
assert_return(ret, -EINVAL);
if (!device->driver_set) {
_cleanup_free_ char *driver = NULL;
const char *syspath;
char *path;
int r;
r = sd_device_get_syspath(device, &syspath);
if (r < 0)
return r;
path = strjoina(syspath, "/driver");
r = readlink_value(path, &driver);
if (r >= 0) {
r = device_set_driver(device, driver);
if (r < 0)
return r;
}
}
*ret = device->driver;
return 0;
}
_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
assert_return(device, -EINVAL);
assert_return(devpath, -EINVAL);
assert(device->devpath);
assert(device->devpath[0] == '/');
*devpath = device->devpath;
return 0;
}
_public_ int sd_device_get_devname(sd_device *device, const char **devname) {
int r;
assert_return(device, -EINVAL);
assert_return(devname, -EINVAL);
r = device_read_uevent_file(device);
if (r < 0)
return r;
if (!device->devname)
return -ENOENT;
assert(path_startswith(device->devname, "/dev/"));
*devname = device->devname;
return 0;
}
static int device_set_sysname(sd_device *device) {
_cleanup_free_ char *sysname = NULL;
const char *sysnum = NULL;
const char *pos;
size_t len = 0;
pos = strrchr(device->devpath, '/');
if (!pos)
return -EINVAL;
pos ++;
/* devpath is not a root directory */
if (*pos == '\0' || pos <= device->devpath)
return -EINVAL;
sysname = strdup(pos);
if (!sysname)
return -ENOMEM;
/* some devices have '!' in their name, change that to '/' */
while (sysname[len] != '\0') {
if (sysname[len] == '!')
sysname[len] = '/';
len ++;
}
/* trailing number */
while (len > 0 && isdigit(sysname[--len]))
sysnum = &sysname[len];
if (len == 0)
sysnum = NULL;
free(device->sysname);
device->sysname = sysname;
sysname = NULL;
device->sysnum = sysnum;
device->sysname_set = true;
return 0;
}
_public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
int r;
assert_return(device, -EINVAL);
assert_return(ret, -EINVAL);
if (!device->sysname_set) {
r = device_set_sysname(device);
if (r < 0)
return r;
}
*ret = device->sysname;
return 0;
}
_public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
int r;
assert_return(device, -EINVAL);
assert_return(ret, -EINVAL);
if (!device->sysname_set) {
r = device_set_sysname(device);
if (r < 0)
return r;
}
*ret = device->sysnum;
return 0;
}
static bool is_valid_tag(const char *tag) {
assert(tag);
return !strchr(tag, ':') && !strchr(tag, ' ');
}
int device_add_tag(sd_device *device, const char *tag) {
int r;
assert(device);
assert(tag);
if (!is_valid_tag(tag))
return -EINVAL;
r = set_ensure_allocated(&device->tags, &string_hash_ops);
if (r < 0)
return r;
r = set_put_strdup(device->tags, tag);
if (r < 0)
return r;
device->tags_generation ++;
device->property_tags_outdated = true;
return 0;
}
int device_add_devlink(sd_device *device, const char *devlink) {
int r;
assert(device);
assert(devlink);
r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
if (r < 0)
return r;
r = set_put_strdup(device->devlinks, devlink);
if (r < 0)
return r;
device->devlinks_generation ++;
device->property_devlinks_outdated = true;
return 0;
}
static int device_add_property_internal_from_string(sd_device *device, const char *str) {
_cleanup_free_ char *key = NULL;
char *value;
assert(device);
assert(str);
key = strdup(str);
if (!key)
return -ENOMEM;
value = strchr(key, '=');
if (!value)
return -EINVAL;
*value = '\0';
if (isempty(++value))
value = NULL;
return device_add_property_internal(device, key, value);
}
int device_set_usec_initialized(sd_device *device, const char *initialized) {
uint64_t usec_initialized;
int r;
assert(device);
assert(initialized);
r = safe_atou64(initialized, &usec_initialized);
if (r < 0)
return r;
r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
if (r < 0)
return r;
device->usec_initialized = usec_initialized;
return 0;
}
static int handle_db_line(sd_device *device, char key, const char *value) {
char *path;
int r;
assert(device);
assert(value);
switch (key) {
case 'G':
r = device_add_tag(device, value);
if (r < 0)
return r;
break;
case 'S':
path = strjoina("/dev/", value);
r = device_add_devlink(device, path);
if (r < 0)
return r;
break;
case 'E':
r = device_add_property_internal_from_string(device, value);
if (r < 0)
return r;
break;
case 'I':
r = device_set_usec_initialized(device, value);
if (r < 0)
return r;
break;
case 'L':
r = safe_atoi(value, &device->devlink_priority);
if (r < 0)
return r;
break;
case 'W':
r = safe_atoi(value, &device->watch_handle);
if (r < 0)
return r;
break;
default:
log_debug("device db: unknown key '%c'", key);
}
return 0;
}
int device_get_id_filename(sd_device *device, const char **ret) {
assert(device);
assert(ret);
if (!device->id_filename) {
_cleanup_free_ char *id = NULL;
const char *subsystem;
dev_t devnum;
int ifindex, r;
r = sd_device_get_subsystem(device, &subsystem);
if (r < 0)
return r;
r = sd_device_get_devnum(device, &devnum);
if (r < 0)
return r;
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0)
return r;
if (major(devnum) > 0) {
/* use dev_t -- b259:131072, c254:0 */
r = asprintf(&id, "%c%u:%u",
streq(subsystem, "block") ? 'b' : 'c',
major(devnum), minor(devnum));
if (r < 0)
return -errno;
} else if (ifindex > 0) {
/* use netdev ifindex -- n3 */
r = asprintf(&id, "n%u", ifindex);
if (r < 0)
return -errno;
} else {
/* use $subsys:$sysname -- pci:0000:00:1f.2
* sysname() has '!' translated, get it from devpath
*/
const char *sysname;
sysname = basename(device->devpath);
if (!sysname)
return -EINVAL;
r = asprintf(&id, "+%s:%s", subsystem, sysname);
if (r < 0)
return -errno;
}
device->id_filename = id;
id = NULL;
}
*ret = device->id_filename;
return 0;
}
static int device_read_db(sd_device *device) {
_cleanup_free_ char *db = NULL;
char *path;
const char *id, *value;
char key;
size_t db_len;
unsigned i;
int r;
enum {
PRE_KEY,
KEY,
PRE_VALUE,
VALUE,
INVALID_LINE,
} state = PRE_KEY;
if (device->db_loaded || device->sealed)
return 0;
r = device_get_id_filename(device, &id);
if (r < 0)
return r;
path = strjoina("/run/udev/data/", id);
r = read_full_file(path, &db, &db_len);
if (r < 0) {
if (r == -ENOENT)
return 0;
else {
log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
return r;
}
}
/* devices with a database entry are initialized */
device->is_initialized = true;;
for (i = 0; i < db_len; i++) {
switch (state) {
case PRE_KEY:
if (!strchr(NEWLINE, db[i])) {
key = db[i];
state = KEY;
}
break;
case KEY:
if (db[i] != ':') {
log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
state = INVALID_LINE;
} else {
db[i] = '\0';
state = PRE_VALUE;
}
break;
case PRE_VALUE:
value = &db[i];
state = VALUE;
break;
case INVALID_LINE:
if (strchr(NEWLINE, db[i]))
state = PRE_KEY;
break;
case VALUE:
if (strchr(NEWLINE, db[i])) {
db[i] = '\0';
r = handle_db_line(device, key, value);
if (r < 0)
log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
state = PRE_KEY;
}
break;
default:
assert_not_reached("invalid state when parsing db");
}
}
device->db_loaded = true;
return 0;
}
_public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
int r;
assert_return(device, -EINVAL);
assert_return(initialized, -EINVAL);
r = device_read_db(device);
if (r < 0)
return r;
*initialized = device->is_initialized;
return 0;
}
_public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
usec_t now_ts;
int r;
assert_return(device, -EINVAL);
assert_return(usec, -EINVAL);
r = device_read_db(device);
if (r < 0)
return r;
if (!device->is_initialized)
return -EBUSY;
if (!device->usec_initialized)
return -ENODATA;
now_ts = now(clock_boottime_or_monotonic());
if (now_ts < device->usec_initialized)
return -EIO;
*usec = now_ts - device->usec_initialized;
return 0;
}
_public_ const char *sd_device_get_tag_first(sd_device *device) {
assert_return(device, NULL);
(void) device_read_db(device);
device->tags_iterator_generation = device->tags_generation;
device->tags_iterator = ITERATOR_FIRST;
return set_iterate(device->tags, &device->tags_iterator);
}
_public_ const char *sd_device_get_tag_next(sd_device *device) {
assert_return(device, NULL);
(void) device_read_db(device);
if (device->tags_iterator_generation != device->tags_generation)
return NULL;
return set_iterate(device->tags, &device->tags_iterator);
}
_public_ const char *sd_device_get_devlink_first(sd_device *device) {
assert_return(device, NULL);
(void) device_read_db(device);
device->devlinks_iterator_generation = device->devlinks_generation;
device->devlinks_iterator = ITERATOR_FIRST;
return set_iterate(device->devlinks, &device->devlinks_iterator);
}
_public_ const char *sd_device_get_devlink_next(sd_device *device) {
assert_return(device, NULL);
(void) device_read_db(device);
if (device->devlinks_iterator_generation != device->devlinks_generation)
return NULL;
return set_iterate(device->devlinks, &device->devlinks_iterator);
}
static int device_properties_prepare(sd_device *device) {
int r;
assert(device);
r = device_read_uevent_file(device);
if (r < 0)
return r;
r = device_read_db(device);
if (r < 0)
return r;
if (device->property_devlinks_outdated) {
char *devlinks = NULL;
const char *devlink;
devlink = sd_device_get_devlink_first(device);
if (devlink)
devlinks = strdupa(devlink);
while ((devlink = sd_device_get_devlink_next(device)))
devlinks = strjoina(devlinks, " ", devlink);
r = device_add_property_internal(device, "DEVLINKS", devlinks);
if (r < 0)
return r;
device->property_devlinks_outdated = false;
}
if (device->property_tags_outdated) {
char *tags = NULL;
const char *tag;
tag = sd_device_get_tag_first(device);
if (tag)
tags = strjoina(":", tag);
while ((tag = sd_device_get_tag_next(device)))
tags = strjoina(tags, ":", tag);
tags = strjoina(tags, ":");
r = device_add_property_internal(device, "TAGS", tags);
if (r < 0)
return r;
device->property_tags_outdated = false;
}
return 0;
}
_public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
const char *key;
const char *value;
int r;
assert_return(device, NULL);
r = device_properties_prepare(device);
if (r < 0)
return NULL;
device->properties_iterator_generation = device->properties_generation;
device->properties_iterator = ITERATOR_FIRST;
value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
if (_value)
*_value = value;
return key;
}
_public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
const char *key;
const char *value;
int r;
assert_return(device, NULL);
r = device_properties_prepare(device);
if (r < 0)
return NULL;
if (device->properties_iterator_generation != device->properties_generation)
return NULL;
value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
if (_value)
*_value = value;
return key;
}
static int device_sysattrs_read_all(sd_device *device) {
_cleanup_closedir_ DIR *dir = NULL;
const char *syspath;
struct dirent *dent;
int r;
assert(device);
if (device->sysattrs_read)
return 0;
r = sd_device_get_syspath(device, &syspath);
if (r < 0)
return r;
dir = opendir(syspath);
if (!dir)
return -errno;
r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
if (r < 0)
return r;
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
char *path;
struct stat statbuf;
/* only handle symlinks and regular files */
if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
continue;
path = strjoina(syspath, "/", dent->d_name);
if (lstat(path, &statbuf) != 0)
continue;
if (!(statbuf.st_mode & S_IRUSR))
continue;
r = set_put_strdup(device->sysattrs, dent->d_name);
if (r < 0)
return r;
}
device->sysattrs_read = true;
return 0;
}
_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
int r;
assert_return(device, NULL);
if (!device->sysattrs_read) {
r = device_sysattrs_read_all(device);
if (r < 0) {
errno = -r;
return NULL;
}
}
device->sysattrs_iterator = ITERATOR_FIRST;
return set_iterate(device->sysattrs, &device->sysattrs_iterator);
}
_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
assert_return(device, NULL);
if (!device->sysattrs_read)
return NULL;
return set_iterate(device->sysattrs, &device->sysattrs_iterator);
}
_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
assert_return(device, -EINVAL);
assert_return(tag, -EINVAL);
(void) device_read_db(device);
return !!set_contains(device->tags, tag);
}
_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
char *value;
int r;
assert_return(device, -EINVAL);
assert_return(key, -EINVAL);
assert_return(_value, -EINVAL);
r = device_properties_prepare(device);
if (r < 0)
return r;
value = ordered_hashmap_get(device->properties, key);
if (!value)
return -ENOENT;
*_value = value;
return 0;
}
/* replaces the value if it already exists */
static int device_add_sysattr_value(sd_device *device, const char *_key, const char *_value) {
_cleanup_free_ char *key = NULL;
_cleanup_free_ char *value = NULL;
int r;
assert(device);
assert(_key);
r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
if (r < 0)
return r;
value = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
if (!key) {
key = strdup(_key);
if (!key)
return -ENOMEM;
}
free(value);
value = NULL;
if (_value) {
value = strdup(_value);
if (!value)
return -ENOMEM;
}
r = hashmap_put(device->sysattr_values, key, value);
if (r < 0)
return r;
key = NULL;
value = NULL;
return 0;
}
static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
const char *key = NULL, *value;
assert(device);
assert(_key);
value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
if (!key)
return -ENOENT;
if (_value)
*_value = value;
return 0;
}
/* We cache all sysattr lookups. If an attribute does not exist, it is stored
* with a NULL value in the cache, otherwise the returned string is stored */
_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
_cleanup_free_ char *value = NULL;
const char *syspath, *cached_value = NULL;
char *path;
struct stat statbuf;
int r;
assert_return(device, -EINVAL);
assert_return(sysattr, -EINVAL);
/* look for possibly already cached result */
r = device_get_sysattr_value(device, sysattr, &cached_value);
if (r != -ENOENT) {
if (r < 0)
return r;
if (!cached_value)
/* we looked up the sysattr before and it did not exist */
return -ENOENT;
if (_value)
*_value = cached_value;
return 0;
}
r = sd_device_get_syspath(device, &syspath);
if (r < 0)
return r;
path = strjoina(syspath, "/", sysattr);
r = lstat(path, &statbuf);
if (r < 0) {
/* remember that we could not access the sysattr */
r = device_add_sysattr_value(device, sysattr, NULL);
if (r < 0)
return r;
return -ENOENT;
} else if (S_ISLNK(statbuf.st_mode)) {
/* Some core links return only the last element of the target path,
* these are just values, the paths should not be exposed. */
if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
r = readlink_value(path, &value);
if (r < 0)
return r;
} else
return -EINVAL;
} else if (S_ISDIR(statbuf.st_mode)) {
/* skip directories */
return -EINVAL;
} else if (!(statbuf.st_mode & S_IRUSR)) {
/* skip non-readable files */
return -EPERM;
} else {
size_t size;
/* read attribute value */
r = read_full_file(path, &value, &size);
if (r < 0)
return r;
/* drop trailing newlines */
while (size > 0 && value[--size] == '\n')
value[size] = '\0';
}
r = device_add_sysattr_value(device, sysattr, value);
if (r < 0)
return r;
*_value = value;
value = NULL;
return 0;
}
static void device_remove_sysattr_value(sd_device *device, const char *_key) {
_cleanup_free_ char *key = NULL;
_cleanup_free_ char *value = NULL;
assert(device);
assert(_key);
value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
return;
}
/* set the attribute and save it in the cache. If a NULL value is passed the
* attribute is cleared from the cache */
_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *value) {
_cleanup_close_ int fd = -1;
const char *syspath;
char *path;
struct stat statbuf;
size_t value_len = 0;
ssize_t size;
int r;
assert_return(device, -EINVAL);
assert_return(sysattr, -EINVAL);
if (!value) {
device_remove_sysattr_value(device, sysattr);
return 0;
}
r = sd_device_get_syspath(device, &syspath);
if (r < 0)
return r;
path = strjoina(syspath, "/", sysattr);
r = lstat(path, &statbuf);
if (r < 0) {
r = device_add_sysattr_value(device, sysattr, "");
if (r < 0)
return r;
return -ENXIO;
}
if (S_ISLNK(statbuf.st_mode))
return -EINVAL;
/* skip directories */
if (S_ISDIR(statbuf.st_mode))
return -EISDIR;
/* skip non-readable files */
if ((statbuf.st_mode & S_IRUSR) == 0)
return -EACCES;
value_len = strlen(value);
/* drop trailing newlines */
while (value_len > 0 && value[--value_len] == '\n')
value[value_len] = '\0';
/* value length is limited to 4k */
if (value_len > 4096)
return -EINVAL;
fd = open(path, O_WRONLY | O_CLOEXEC);
if (fd < 0)
return -errno;
size = write(fd, value, value_len);
if (size < 0)
return -errno;
if ((size_t)size != value_len)
return -EIO;
r = device_add_sysattr_value(device, sysattr, value);
if (r < 0)
return r;
return 0;
}