sd-device.c revision 23446f01480e1d6f72a03d71f9c67cbf34ddaf3b
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek This file is part of systemd.
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek Copyright 2014 Tom Gundersen <teg@jklm.no>
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek (at your option) any later version.
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
892213bf1fd23e48d64a407ece6e10b07bef1926Zbigniew Jędrzejewski-Szmekint device_new_aux(sd_device **ret) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek _cleanup_device_unref_ sd_device *device = NULL;
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek_public_ sd_device *sd_device_ref(sd_device *device) {
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt_public_ sd_device *sd_device_unref(sd_device *device) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek ordered_hashmap_free_free_free(device->properties);
c099716487df4a4f5394e57e7ca14da1d358166aZbigniew Jędrzejewski-Szmek ordered_hashmap_free_free_free(device->properties_db);
c099716487df4a4f5394e57e7ca14da1d358166aZbigniew Jędrzejewski-Szmek hashmap_free_free_free(device->sysattr_values);
c099716487df4a4f5394e57e7ca14da1d358166aZbigniew Jędrzejewski-Szmek set_free_free(device->sysattrs);
c099716487df4a4f5394e57e7ca14da1d358166aZbigniew Jędrzejewski-Szmek set_free_free(device->devlinks);
fff40a51ccbb02e8dec4ff2ee505bc84f75e445cZbigniew Jędrzejewski-Szmekint device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek properties = &device->properties_db;
175a3d25d0e8596d4ba0759aea3f89ee228e7d6dLennart Poettering _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
2c408cb6276e3b8d18fb4e2a81a1128d8bbaa70dLennart Poettering old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
29a5ca9baa58e55c4d9e1d008cdd014aa9c3c3e1Lennart Poettering r = ordered_hashmap_replace(*properties, key, value);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *key = NULL;
23ea3dab15181a3966ec45fa2ccbb81e59d2e0a7Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *value = NULL;
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek device->properties_buf_outdated = true;
30374ebe5e9f0b37e99dcbdc965c00fcf542f89dLennart Poetteringint device_add_property_internal(sd_device *device, const char *key, const char *value) {
30374ebe5e9f0b37e99dcbdc965c00fcf542f89dLennart Poettering return device_add_property_aux(device, key, value, false);
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmekint device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *syspath = NULL;
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek /* must be a subdirectory of /sys */
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek if (!path_startswith(_syspath, "/sys/")) {
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmek log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = readlink_and_canonicalize(_syspath, &syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* the device does not exist (any more?) */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek else if (r == -EINVAL) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* not a symlink */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek syspath = canonicalize_file_name(_syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* the device does not exist (any more?) */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath);
30374ebe5e9f0b37e99dcbdc965c00fcf542f89dLennart Poettering } else if (r < 0) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
30374ebe5e9f0b37e99dcbdc965c00fcf542f89dLennart Poettering if (path_startswith(syspath, "/sys/devices/")) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* all 'devices' require an 'uevent' file */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek path = strjoina(syspath, "/uevent");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* this is not a valid device */
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt log_debug("sd-device: %s does not have an uevent file: %m", syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek /* everything else just just needs to be a directory */
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek devpath = syspath + strlen("/sys");
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = device_add_property_internal(device, "DEVPATH", devpath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek _cleanup_device_unref_ sd_device *device = NULL;
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert_return(syspath, -EINVAL);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = device_set_syspath(device, syspath, true);
30374ebe5e9f0b37e99dcbdc965c00fcf542f89dLennart Poettering_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert_return(type == 'b' || type == 'c', -EINVAL);
30374ebe5e9f0b37e99dcbdc965c00fcf542f89dLennart Poettering /* use /sys/dev/{block,char}/<maj>:<min> link */
30374ebe5e9f0b37e99dcbdc965c00fcf542f89dLennart Poettering snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
30374ebe5e9f0b37e99dcbdc965c00fcf542f89dLennart Poettering syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
9d458c0902cdc5d993fd2f78d36fb83a8130c81bLennart Poettering_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek assert_return(sysname, -EINVAL);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek if (streq(subsystem, "subsystem")) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/subsystem/", sysname);
c099716487df4a4f5394e57e7ca14da1d358166aZbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
c099716487df4a4f5394e57e7ca14da1d358166aZbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/bus/", sysname);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek } else if (streq(subsystem, "module")) {
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/module/", sysname);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek } else if (streq(subsystem, "drivers")) {
892213bf1fd23e48d64a407ece6e10b07bef1926Zbigniew Jędrzejewski-Szmek strscpy(subsys, sizeof(subsys), sysname);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
892213bf1fd23e48d64a407ece6e10b07bef1926Zbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
892213bf1fd23e48d64a407ece6e10b07bef1926Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek syspath = strjoina("/sys/class/", subsystem, "/", sysname);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek return sd_device_new_from_syspath(ret, syspath);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekint device_set_devtype(sd_device *device, const char *_devtype) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *devtype = NULL;
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = device_add_property_internal(device, "DEVTYPE", devtype);
5e65c93a433447b15180249166f7b3944c3e6156Zbigniew Jędrzejewski-Szmekint device_set_ifindex(sd_device *device, const char *_ifindex) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = device_add_property_internal(device, "IFINDEX", _ifindex);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekint device_set_devname(sd_device *device, const char *_devname) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *devname = NULL;
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = asprintf(&devname, "/dev/%s", _devname);
2c408cb6276e3b8d18fb4e2a81a1128d8bbaa70dLennart Poettering r = device_add_property_internal(device, "DEVNAME", devname);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmekint device_set_devmode(sd_device *device, const char *_devmode) {
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = safe_atou(_devmode, &devmode);
2ca0435be9359bde3020eeb528c2a6d72ac1e0b0Zbigniew Jędrzejewski-Szmek r = device_add_property_internal(device, "DEVMODE", _devmode);
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;