summaryrefslogtreecommitdiff
path: root/src/core/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/device.c')
-rw-r--r--src/core/device.c291
1 files changed, 129 insertions, 162 deletions
diff --git a/src/core/device.c b/src/core/device.c
index a2d00a0fbe..960f403718 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -3,19 +3,20 @@
#include <errno.h>
#include <sys/epoll.h>
-#include "libudev.h"
-
#include "alloc-util.h"
#include "bus-error.h"
#include "dbus-device.h"
+#include "dbus-unit.h"
+#include "device-private.h"
+#include "device-util.h"
#include "device.h"
#include "log.h"
#include "parse-util.h"
#include "path-util.h"
+#include "serialize.h"
#include "stat-util.h"
#include "string-util.h"
#include "swap.h"
-#include "udev-util.h"
#include "unit-name.h"
#include "unit.h"
@@ -25,7 +26,7 @@ static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
[DEVICE_PLUGGED] = UNIT_ACTIVE,
};
-static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata);
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask);
static void device_unset_sysfs(Device *d) {
@@ -111,10 +112,31 @@ static void device_done(Unit *u) {
d->wants_property = strv_free(d->wants_property);
}
+static int device_load(Unit *u) {
+ int r;
+
+ r = unit_load_fragment_and_dropin_optional(u);
+ if (r < 0)
+ return r;
+
+ if (!u->description) {
+ /* Generate a description based on the path, to be used until the
+ device is initialized properly */
+ r = unit_name_to_path(u->id, &u->description);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to unescape name: %m");
+ }
+
+ return 0;
+}
+
static void device_set_state(Device *d, DeviceState state) {
DeviceState old_state;
assert(d);
+ if (d->state != state)
+ bus_unit_send_pending_change_signal(UNIT(d), false);
+
old_state = d->state;
d->state = state;
@@ -226,10 +248,10 @@ static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
assert(f);
assert(fds);
- unit_serialize_item(u, f, "state", device_state_to_string(d->state));
+ (void) serialize_item(f, "state", device_state_to_string(d->state));
if (device_found_to_string_many(d->found, &s) >= 0)
- unit_serialize_item(u, f, "found", s);
+ (void) serialize_item(f, "found", s);
return 0;
}
@@ -255,7 +277,7 @@ static int device_deserialize_item(Unit *u, const char *key, const char *value,
} else if (streq(key, "found")) {
r = device_found_from_string_many(value, &d->deserialized_found);
if (r < 0)
- log_unit_debug_errno(u, r, "Failed to parse found value, ignoring: %s", value);
+ log_unit_debug_errno(u, r, "Failed to parse found value '%s', ignoring: %m", value);
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -300,47 +322,40 @@ _pure_ static const char *device_sub_state_to_string(Unit *u) {
return device_state_to_string(DEVICE(u)->state);
}
-static int device_update_description(Unit *u, struct udev_device *dev, const char *path) {
- const char *model;
+static int device_update_description(Unit *u, sd_device *dev, const char *path) {
+ _cleanup_free_ char *j = NULL;
+ const char *model, *label, *desc;
int r;
assert(u);
- assert(dev);
assert(path);
- model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
- if (!model)
- model = udev_device_get_property_value(dev, "ID_MODEL");
+ desc = path;
- if (model) {
- const char *label;
+ if (dev &&
+ (sd_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE", &model) >= 0 ||
+ sd_device_get_property_value(dev, "ID_MODEL", &model) >= 0)) {
+ desc = model;
/* Try to concatenate the device model string with a label, if there is one */
- label = udev_device_get_property_value(dev, "ID_FS_LABEL");
- if (!label)
- label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NAME");
- if (!label)
- label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER");
+ if (sd_device_get_property_value(dev, "ID_FS_LABEL", &label) >= 0 ||
+ sd_device_get_property_value(dev, "ID_PART_ENTRY_NAME", &label) >= 0 ||
+ sd_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER", &label) >= 0) {
- if (label) {
- _cleanup_free_ char *j;
-
- j = strjoin(model, " ", label);
+ desc = j = strjoin(model, " ", label);
if (!j)
return log_oom();
+ }
+ }
- r = unit_set_description(u, j);
- } else
- r = unit_set_description(u, model);
- } else
- r = unit_set_description(u, path);
+ r = unit_set_description(u, desc);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to set device description: %m");
return 0;
}
-static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
+static int device_add_udev_wants(Unit *u, sd_device *dev) {
_cleanup_strv_free_ char **added = NULL;
const char *wants, *property;
Device *d = DEVICE(u);
@@ -351,8 +366,8 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
- wants = udev_device_get_property_value(dev, property);
- if (!wants)
+ r = sd_device_get_property_value(dev, property, &wants);
+ if (r < 0)
return 0;
for (;;) {
@@ -387,7 +402,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word);
}
- r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true, UNIT_DEPENDENCY_UDEV);
+ r = unit_add_dependency_by_name(u, UNIT_WANTS, k, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to add Wants= dependency: %m");
@@ -429,18 +444,17 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
return 0;
}
-static bool device_is_bound_by_mounts(Device *d, struct udev_device *dev) {
+static bool device_is_bound_by_mounts(Device *d, sd_device *dev) {
const char *bound_by;
int r;
assert(d);
assert(dev);
- bound_by = udev_device_get_property_value(dev, "SYSTEMD_MOUNT_DEVICE_BOUND");
- if (bound_by) {
+ if (sd_device_get_property_value(dev, "SYSTEMD_MOUNT_DEVICE_BOUND", &bound_by) >= 0) {
r = parse_boolean(bound_by);
if (r < 0)
- log_warning_errno(r, "Failed to parse SYSTEMD_MOUNT_DEVICE_BOUND='%s' udev property of %s, ignoring: %m", bound_by, strna(d->sysfs));
+ log_device_warning_errno(dev, r, "Failed to parse SYSTEMD_MOUNT_DEVICE_BOUND='%s' udev property, ignoring: %m", bound_by);
d->bind_mounts = r > 0;
} else
@@ -467,7 +481,7 @@ static void device_upgrade_mount_deps(Unit *u) {
}
}
-static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
+static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool main) {
_cleanup_free_ char *e = NULL;
const char *sysfs = NULL;
Unit *u = NULL;
@@ -478,16 +492,16 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
assert(path);
if (dev) {
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs) {
- log_debug("Couldn't get syspath from udev device, ignoring.");
+ r = sd_device_get_syspath(dev, &sysfs);
+ if (r < 0) {
+ log_device_debug_errno(dev, r, "Couldn't get syspath from device, ignoring: %m");
return 0;
}
}
r = unit_name_from_path(path, ".device", &e);
if (r < 0)
- return log_error_errno(r, "Failed to generate unit name from device path: %m");
+ return log_device_error_errno(dev, r, "Failed to generate unit name from device path: %m");
u = manager_get_unit(m, e);
if (u) {
@@ -518,7 +532,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
r = unit_new_for_name(m, sizeof(Device), e, &u);
if (r < 0) {
- log_error_errno(r, "Failed to allocate device unit %s: %m", e);
+ log_device_error_errno(dev, r, "Failed to allocate device unit %s: %m", e);
goto fail;
}
@@ -530,17 +544,17 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
if (sysfs) {
r = device_set_sysfs(DEVICE(u), sysfs);
if (r < 0) {
- log_error_errno(r, "Failed to set sysfs path %s for device unit %s: %m", sysfs, e);
+ log_unit_error_errno(u, r, "Failed to set sysfs path %s: %m", sysfs);
goto fail;
}
- (void) device_update_description(u, dev, path);
-
/* The additional systemd udev properties we only interpret for the main object */
if (main)
(void) device_add_udev_wants(u, dev);
}
+ (void) device_update_description(u, dev, path);
+
/* So the user wants the mount units to be bound to the device but a mount unit might has been seen by systemd
* before the device appears on its radar. In this case the device unit is partially initialized and includes
* the deps on the mount unit but at that time the "bind mounts" flag wasn't not present. Fix this up now. */
@@ -559,15 +573,14 @@ fail:
return r;
}
-static int device_process_new(Manager *m, struct udev_device *dev) {
+static int device_process_new(Manager *m, sd_device *dev) {
const char *sysfs, *dn, *alias;
- struct udev_list_entry *item = NULL, *first = NULL;
+ dev_t devnum;
int r;
assert(m);
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs)
+ if (sd_device_get_syspath(dev, &sysfs) < 0)
return 0;
/* Add the main unit named after the sysfs path */
@@ -576,40 +589,39 @@ static int device_process_new(Manager *m, struct udev_device *dev) {
return r;
/* Add an additional unit for the device node */
- dn = udev_device_get_devnode(dev);
- if (dn)
+ if (sd_device_get_devname(dev, &dn) >= 0)
(void) device_setup_unit(m, dev, dn, false);
/* Add additional units for all symlinks */
- first = udev_device_get_devlinks_list_entry(dev);
- udev_list_entry_foreach(item, first) {
+ if (sd_device_get_devnum(dev, &devnum) >= 0) {
const char *p;
- struct stat st;
- /* Don't bother with the /dev/block links */
- p = udev_list_entry_get_name(item);
+ FOREACH_DEVICE_DEVLINK(dev, p) {
+ struct stat st;
- if (PATH_STARTSWITH_SET(p, "/dev/block/", "/dev/char/"))
- continue;
+ if (PATH_STARTSWITH_SET(p, "/dev/block/", "/dev/char/"))
+ continue;
- /* Verify that the symlink in the FS actually belongs
- * to this device. This is useful to deal with
- * conflicting devices, e.g. when two disks want the
- * same /dev/disk/by-label/xxx link because they have
- * the same label. We want to make sure that the same
- * device that won the symlink wins in systemd, so we
- * check the device node major/minor */
- if (stat(p, &st) >= 0)
- if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
- st.st_rdev != udev_device_get_devnum(dev))
+ /* Verify that the symlink in the FS actually belongs
+ * to this device. This is useful to deal with
+ * conflicting devices, e.g. when two disks want the
+ * same /dev/disk/by-label/xxx link because they have
+ * the same label. We want to make sure that the same
+ * device that won the symlink wins in systemd, so we
+ * check the device node major/minor */
+ if (stat(p, &st) >= 0 &&
+ ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
+ st.st_rdev != devnum))
continue;
- (void) device_setup_unit(m, dev, p, false);
+ (void) device_setup_unit(m, dev, p, false);
+ }
}
- /* Add additional units for all explicitly configured
- * aliases */
- alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
+ /* Add additional units for all explicitly configured aliases */
+ if (sd_device_get_property_value(dev, "SYSTEMD_ALIAS", &alias) < 0)
+ return 0;
+
for (;;) {
_cleanup_free_ char *word = NULL;
@@ -619,12 +631,12 @@ static int device_process_new(Manager *m, struct udev_device *dev) {
if (r == -ENOMEM)
return log_oom();
if (r < 0)
- return log_warning_errno(r, "Failed to add parse SYSTEMD_ALIAS for %s: %m", sysfs);
+ return log_device_warning_errno(dev, r, "Failed to add parse SYSTEMD_ALIAS property: %m");
if (!path_is_absolute(word))
- log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, word);
+ log_device_warning(dev, "SYSTEMD_ALIAS is not an absolute path, ignoring: %s", word);
else if (!path_is_normalized(word))
- log_warning("SYSTEMD_ALIAS for %s is not a normalized path, ignoring: %s", sysfs, word);
+ log_device_warning(dev, "SYSTEMD_ALIAS is not a normalized path, ignoring: %s", word);
else
(void) device_setup_unit(m, dev, word, false);
}
@@ -712,13 +724,12 @@ static int device_update_found_by_name(Manager *m, const char *path, DeviceFound
return 0;
}
-static bool device_is_ready(struct udev_device *dev) {
+static bool device_is_ready(sd_device *dev) {
const char *ready;
assert(dev);
- ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
- if (!ready)
+ if (sd_device_get_property_value(dev, "SYSTEMD_READY", &ready) < 0)
return true;
return parse_boolean(ready) != 0;
@@ -734,11 +745,11 @@ static Unit *device_following(Unit *u) {
return NULL;
/* Make everybody follow the unit that's named after the sysfs path */
- for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
+ LIST_FOREACH_AFTER(same_sysfs, other, d)
if (startswith(UNIT(other)->id, "sys-"))
return UNIT(other);
- for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
+ LIST_FOREACH_BEFORE(same_sysfs, other, d) {
if (startswith(UNIT(other)->id, "sys-"))
return UNIT(other);
@@ -784,98 +795,71 @@ static int device_following_set(Unit *u, Set **_set) {
static void device_shutdown(Manager *m) {
assert(m);
- m->udev_event_source = sd_event_source_unref(m->udev_event_source);
- m->udev_monitor = udev_monitor_unref(m->udev_monitor);
+ m->device_monitor = sd_device_monitor_unref(m->device_monitor);
m->devices_by_sysfs = hashmap_free(m->devices_by_sysfs);
}
static void device_enumerate(Manager *m) {
- _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ sd_device *dev;
int r;
assert(m);
- if (!m->udev_monitor) {
- m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
- if (!m->udev_monitor) {
- log_error_errno(errno, "Failed to allocate udev monitor: %m");
+ if (!m->device_monitor) {
+ r = sd_device_monitor_new(&m->device_monitor);
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate device monitor: %m");
goto fail;
}
/* This will fail if we are unprivileged, but that
* should not matter much, as user instances won't run
* during boot. */
- (void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
+ (void) sd_device_monitor_set_receive_buffer_size(m->device_monitor, 128*1024*1024);
- r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd");
+ r = sd_device_monitor_filter_add_match_tag(m->device_monitor, "systemd");
if (r < 0) {
log_error_errno(r, "Failed to add udev tag match: %m");
goto fail;
}
- r = udev_monitor_enable_receiving(m->udev_monitor);
+ r = sd_device_monitor_attach_event(m->device_monitor, m->event);
if (r < 0) {
- log_error_errno(r, "Failed to enable udev event reception: %m");
+ log_error_errno(r, "Failed to attach event to device monitor: %m");
goto fail;
}
- r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m);
+ r = sd_device_monitor_start(m->device_monitor, device_dispatch_io, m);
if (r < 0) {
- log_error_errno(r, "Failed to watch udev file descriptor: %m");
+ log_error_errno(r, "Failed to start device monitor: %m");
goto fail;
}
-
- (void) sd_event_source_set_description(m->udev_event_source, "device");
- }
-
- e = udev_enumerate_new(m->udev);
- if (!e) {
- log_error_errno(errno, "Failed to alloacte udev enumerator: %m");
- goto fail;
- }
-
- r = udev_enumerate_add_match_tag(e, "systemd");
- if (r < 0) {
- log_error_errno(r, "Failed to create udev tag enumeration: %m");
- goto fail;
}
- r = udev_enumerate_add_match_is_initialized(e);
+ r = sd_device_enumerator_new(&e);
if (r < 0) {
- log_error_errno(r, "Failed to install initialization match into enumeration: %m");
+ log_error_errno(r, "Failed to allocate device enumerator: %m");
goto fail;
}
- r = udev_enumerate_scan_devices(e);
+ r = sd_device_enumerator_add_match_tag(e, "systemd");
if (r < 0) {
- log_error_errno(r, "Failed to enumerate devices: %m");
+ log_error_errno(r, "Failed to set tag for device enumeration: %m");
goto fail;
}
- first = udev_enumerate_get_list_entry(e);
- udev_list_entry_foreach(item, first) {
- _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
+ FOREACH_DEVICE(e, dev) {
const char *sysfs;
- sysfs = udev_list_entry_get_name(item);
-
- dev = udev_device_new_from_syspath(m->udev, sysfs);
- if (!dev) {
- if (errno == ENOMEM) {
- log_oom();
- goto fail;
- }
-
- /* If we can't create a device, don't bother, it probably just disappeared. */
- log_debug_errno(errno, "Failed to create udev device object for %s: %m", sysfs);
- continue;
- }
-
if (!device_is_ready(dev))
continue;
(void) device_process_new(m, dev);
+
+ if (sd_device_get_syspath(dev, &sysfs) < 0)
+ continue;
+
device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
}
@@ -903,40 +887,23 @@ static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) {
}
}
-static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
+static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
Manager *m = userdata;
const char *action, *sysfs;
int r;
assert(m);
+ assert(dev);
- if (revents != EPOLLIN) {
- static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
-
- if (ratelimit_below(&limit))
- log_warning("Failed to get udev event");
- if (!(revents & EPOLLIN))
- return 0;
- }
-
- /*
- * libudev might filter-out devices which pass the bloom
- * filter, so getting NULL here is not necessarily an error.
- */
- dev = udev_monitor_receive_device(m->udev_monitor);
- if (!dev)
- return 0;
-
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs) {
- log_error("Failed to get udev sys path.");
+ r = sd_device_get_syspath(dev, &sysfs);
+ if (r < 0) {
+ log_device_error_errno(dev, r, "Failed to get device sys path: %m");
return 0;
}
- action = udev_device_get_action(dev);
- if (!action) {
- log_error("Failed to get udev action string.");
+ r = sd_device_get_property_value(dev, "ACTION", &action);
+ if (r < 0) {
+ log_device_error_errno(dev, r, "Failed to get udev action string: %m");
return 0;
}
@@ -949,7 +916,7 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (streq(action, "remove")) {
r = swap_process_device_remove(m, dev);
if (r < 0)
- log_warning_errno(r, "Failed to process swap device remove event, ignoring: %m");
+ log_device_warning_errno(dev, r, "Failed to process swap device remove event, ignoring: %m");
/* If we get notified that a device was removed by
* udev, then it's completely gone, hence unset all
@@ -962,7 +929,7 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
r = swap_process_device_new(m, dev);
if (r < 0)
- log_warning_errno(r, "Failed to process swap device new event, ignoring: %m");
+ log_device_warning_errno(dev, r, "Failed to process swap device new event, ignoring: %m");
manager_dispatch_load_queue(m);
@@ -992,7 +959,7 @@ static bool device_supported(void) {
return read_only <= 0;
}
-static int validate_node(Manager *m, const char *node, struct udev_device **ret) {
+static int validate_node(Manager *m, const char *node, sd_device **ret) {
struct stat st;
int r;
@@ -1016,9 +983,9 @@ static int validate_node(Manager *m, const char *node, struct udev_device **ret)
return 1; /* good! (though missing) */
} else {
- _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
+ _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
- r = udev_device_new_from_stat_rdev(m->udev, &st, &dev);
+ r = device_new_from_stat_rdev(&dev, &st);
if (r == -ENOENT) {
*ret = NULL;
return 1; /* good! (though missing) */
@@ -1054,7 +1021,7 @@ void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFo
* and unset individual bits in a single call, while merging partially with previous state. */
if ((found & mask) != 0) {
- _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
+ _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
/* If the device is known in the kernel and newly appeared, then we'll create a device unit for it,
* under the name referenced in /proc/swaps or /proc/self/mountinfo. But first, let's validate if
@@ -1092,7 +1059,7 @@ const UnitVTable device_vtable = {
.init = device_init,
.done = device_done,
- .load = unit_load_fragment_and_dropin_optional,
+ .load = device_load,
.coldplug = device_coldplug,
.catchup = device_catchup,