sd-device.c revision bba061662b0f759abb43bad60c9733305c191045
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen This file is part of systemd.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen Copyright 2014 Tom Gundersen <teg@jklm.no>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen systemd is free software; you can redistribute it and/or modify it
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen under the terms of the GNU Lesser General Public License as published by
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen (at your option) any later version.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen systemd is distributed in the hope that it will be useful, but
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen Lesser General Public License for more details.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen You should have received a copy of the GNU Lesser General Public License
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen _cleanup_device_unref_ sd_device *device = NULL;
f0213e3796b4dd66e546e2de4d677db319f9171bTom Gundersen_public_ sd_device *sd_device_ref(sd_device *device) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen_public_ sd_device *sd_device_unref(sd_device *device) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen ordered_hashmap_free_free_free(device->properties);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen ordered_hashmap_free_free_free(device->properties_db);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen hashmap_free_free_free(device->sysattr_values);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenint device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = ordered_hashmap_replace(*properties, key, value);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenint device_add_property_internal(sd_device *device, const char *key, const char *value) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return device_add_property_aux(device, key, value, false);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenint device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* must be a subdirectory of /sys */
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = readlink_and_canonicalize(_syspath, &syspath);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* not a symlink */
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* ignore errors due to the link not being a symlink */
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen } else if (r < 0 && r != -EINVAL) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (path_startswith(syspath, "/sys/devices/")) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* all 'devices' require an 'uevent' file */
be19c5b5e0c0f78b8429b126936fa15856550a23David Herrmann log_debug("sd-device: %s does not have an uevent file: %m", syspath);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* everything else just just needs to be a directory */
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_debug("sd-device: %s is not a directory", syspath);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = device_add_property_internal(device, "DEVPATH", devpath);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen _cleanup_device_unref_ sd_device *device = NULL;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = device_set_syspath(device, syspath, true);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_return(type == 'b' || type == 'c', -EINVAL);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* use /sys/dev/{block,char}/<maj>:<min> link */
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
char *syspath;
char *driver;
if (driver) {
driver++;
return -EINVAL;
return -ENOENT;
if (!devtype)
return -ENOMEM;
int ifindex, r;
if (ifindex <= 0)
return -EINVAL;
return -ENOMEM;
if (!devname)
return -ENOMEM;
unsigned devmode;
return -EINVAL;
if (!maj)
if (minor) {
if (minor) {
static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
char *path;
KEY,
if (r == -EACCES)
for (i = 0; i < uevent_len; i++) {
switch (state) {
case PRE_KEY:
case KEY:
case PRE_VALUE:
case VALUE:
if (major) {
log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
switch (id[0]) {
char type;
return -EINVAL;
int ifindex;
return -EINVAL;
if (sk < 0)
return -errno;
return -errno;
return -ENODEV;
char *sysname;
if (!sysname)
return -EINVAL;
sysname ++;
return -EINVAL;
if (!path)
return -ENOMEM;
char *pos;
return -ENOENT;
return -ENOENT;
if (!subsystem)
return -ENOMEM;
const char *syspath;
char *path;
_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
if (!devtype)
if (!driver)
return -ENOMEM;
const char *syspath;
char *path;
return -ENOENT;
const char *pos;
if (!pos)
return -EINVAL;
pos ++;
return -EINVAL;
if (!sysname)
return -ENOMEM;
len ++;
if (len == 0)
return -EINVAL;
char *value;
if (!key)
return -ENOMEM;
if (!value)
return -EINVAL;
char *path;
switch (key) {
const char *subsystem;
int ifindex, r;
return -errno;
} else if (ifindex > 0) {
return -errno;
const char *sysname;
if (!sysname)
return -EINVAL;
return -errno;
char *path;
char key;
KEY,
if (r == -ENOENT)
for (i = 0; i < db_len; i++) {
switch (state) {
case PRE_KEY:
case KEY:
case PRE_VALUE:
case INVALID_LINE:
case VALUE:
return -EBUSY;
return -ENODATA;
return -EIO;
return NULL;
return NULL;
const char *devlink;
if (devlink)
const char *tag;
if (tag)
const char *key;
const char *value;
return NULL;
value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
if (_value)
return key;
const char *key;
const char *value;
return NULL;
return NULL;
value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
if (_value)
return key;
const char *syspath;
if (!dir)
return -errno;
char *path;
errno = -r;
return NULL;
return NULL;
_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
char *value;
if (!value)
return -ENOENT;
if (!key) {
if (!key)
return -ENOMEM;
if (!key)
return -ENOENT;
if (_value)
_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
char *path;
if (r != -ENOENT) {
if (!cached_value)
return -ENOENT;
if (_value)
return -ENOENT;
return -EINVAL;
return -EINVAL;
return -EPERM;
const char *syspath;
char *path;
if (!_value) {
if (!value)
return -ENOMEM;
return -ENXIO;
return -EINVAL;
return -EISDIR;
return -EACCES;
return -EINVAL;
if (fd < 0)
return -errno;
if (!value)
return -ENOMEM;
if (size < 0)
return -errno;
return -EIO;