sd-device.c revision f4f15635ec05293ffcc83a5b39f624bbabbd8fd0
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering This file is part of systemd.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering systemd is free software; you can redistribute it and/or modify it
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering under the terms of the GNU Lesser General Public License as published by
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering (at your option) any later version.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering systemd is distributed in the hope that it will be useful, but
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering Lesser General Public License for more details.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering You should have received a copy of the GNU Lesser General Public License
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering _cleanup_device_unref_ sd_device *device = NULL;
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering_public_ sd_device *sd_device_ref(sd_device *device) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering_public_ sd_device *sd_device_unref(sd_device *device) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ordered_hashmap_free_free_free(device->properties);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering ordered_hashmap_free_free_free(device->properties_db);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering hashmap_free_free_free(device->sysattr_values);
0e2656744f6d2e2cf65788a497f266d469865e30Lennart Poetteringint device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
0e2656744f6d2e2cf65788a497f266d469865e30Lennart Poettering _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering r = ordered_hashmap_replace(*properties, key, value);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringint device_add_property_internal(sd_device *device, const char *key, const char *value) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering return device_add_property_aux(device, key, value, false);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poetteringint device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* must be a subdirectory of /sys */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering if (!path_startswith(_syspath, "/sys/")) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering r = readlink_and_canonicalize(_syspath, &syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* the device does not exist (any more?) */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering else if (r == -EINVAL) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* not a symlink */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering syspath = canonicalize_file_name(_syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* the device does not exist (any more?) */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering } else if (r < 0) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering if (path_startswith(syspath, "/sys/devices/")) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* all 'devices' require an 'uevent' file */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* this is not a valid device */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering log_debug("sd-device: %s does not have an uevent file: %m", syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* everything else just just needs to be a directory */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering r = device_add_property_internal(device, "DEVPATH", devpath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering _cleanup_device_unref_ sd_device *device = NULL;
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering r = device_set_syspath(device, syspath, true);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering assert_return(type == 'b' || type == 'c', -EINVAL);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering /* use /sys/dev/{block,char}/<maj>:<min> link */
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering syspath = strjoina("/sys/subsystem/", sysname);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering syspath = strjoina("/sys/bus/", sysname);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering syspath = strjoina("/sys/class/", sysname);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering syspath = strjoina("/sys/module/", sysname);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering return sd_device_new_from_syspath(ret, syspath);
f757855e81fc0bc116de372220096e532afb5cb8Lennart Poettering } else if (streq(subsystem, "drivers")) {
if (driver) {
driver++;
return -EINVAL;
char *name;
len ++;
return -ENODEV;
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)
else if (r == -ENOENT)
for (i = 0; i < uevent_len; i++) {
switch (state) {
case PRE_KEY:
case KEY:
case PRE_VALUE:
case VALUE:
if (major) {
log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path);
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 -ENODEV;
return -ENOENT;
if (!subsystem)
return -ENOMEM;
const char *syspath;
char *path;
if (r < 0 && r != -ENOENT)
return -ENOENT;
_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;
} else if (r == -ENOENT)
return -ENOENT;
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 -ENOMEM;
} else if (ifindex > 0) {
return -ENOMEM;
const char *sysname;
if (!sysname)
return -EINVAL;
if (!subsystem)
return -EINVAL;
return -ENOMEM;
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;
ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
if (_value)
return key;
const char *key;
const char *value;
return NULL;
return NULL;
ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (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;