sd-device.c revision 5a917c064b23c1b8a12d6abd2f9f31c575ddebc6
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack This file is part of systemd.
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack Copyright 2014 Tom Gundersen <teg@jklm.no>
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack systemd is free software; you can redistribute it and/or modify it
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack under the terms of the GNU Lesser General Public License as published by
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack the Free Software Foundation; either version 2.1 of the License, or
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack (at your option) any later version.
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack systemd is distributed in the hope that it will be useful, but
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack WITHOUT ANY WARRANTY; without even the implied warranty of
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack Lesser General Public License for more details.
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack You should have received a copy of the GNU Lesser General Public License
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack along with systemd; If not, see <http://www.gnu.org/licenses/>.
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack _cleanup_device_unref_ sd_device *device = NULL;
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack_public_ sd_device *sd_device_ref(sd_device *device) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack_public_ sd_device *sd_device_unref(sd_device *device) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack ordered_hashmap_free_free_free(device->properties);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack ordered_hashmap_free_free_free(device->properties_db);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackint device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack r = ordered_hashmap_replace(*properties, key, value);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackint device_add_property_internal(sd_device *device, const char *key, const char *value) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack return device_add_property_aux(device, key, value, false);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackint device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack /* must be a subdirectory of /sys */
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack r = readlink_and_canonicalize(_syspath, &syspath);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack /* not a symlink */
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack /* ignore errors due to the link not being a symlink */
c2a23db0b91faca3795099fd4b41587bac170ff7Daniel Mack } else if (r < 0 && r != -EINVAL) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack if (path_startswith(syspath, "/sys/devices/")) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack /* all 'devices' require an 'uevent' file */
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack if (r < 0) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack log_debug("sd-device: %s does not have an uevent file: %m", syspath);
return -EINVAL;
if (!syspath)
return -ENOMEM;
char *syspath;
_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;