Merge pull request #9200 from poettering/device-state-fix

core: rework device state serialization/enumeration
This commit is contained in:
Lennart Poettering 2018-06-07 17:04:57 +02:00 committed by GitHub
commit 3ceca73a59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 438 additions and 281 deletions

6
TODO
View File

@ -24,6 +24,12 @@ Janitorial Clean-ups:
Features:
* rework mount.c and swap.c to follow proper state enumeration/deserialization
semantics, like we do for device.c now
* When reloading configuration PID 1 should reset all its properties to the
original defaults before calling parse_config()
* Add OnTimezoneChange= and OnTimeChange= stanzas to .timer units in order to
schedule events based on time and timezone changes.

View File

@ -349,7 +349,7 @@ int conf_files_cat(const char *root, const char *name) {
assert(endswith(dir, "/"));
r = strv_extendf(&dirs, "%s%s.d", dir, name);
if (r < 0)
return log_error("Failed to build directory list: %m");
return log_error_errno(r, "Failed to build directory list: %m");
}
r = conf_files_list_strv(&files, ".conf", root, 0, (const char* const*) dirs);

View File

@ -1155,9 +1155,9 @@ int fsync_directory_of_file(int fd) {
r = fd_get_path(fd, &path);
if (r < 0) {
log_debug("Failed to query /proc/self/fd/%d%s: %m",
fd,
r == -EOPNOTSUPP ? ", ignoring" : "");
log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
fd,
r == -EOPNOTSUPP ? ", ignoring" : "");
if (r == -EOPNOTSUPP)
/* If /proc is not available, we're most likely running in some

View File

@ -79,7 +79,7 @@ int mac_selinux_init(void) {
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!label_hnd) {
log_enforcing("Failed to initialize SELinux context: %m");
log_enforcing_errno(errno, "Failed to initialize SELinux context: %m");
r = security_getenforce() == 1 ? -errno : 0;
} else {
char timespan[FORMAT_TIMESPAN_MAX];
@ -189,7 +189,7 @@ int mac_selinux_apply(const char *path, const char *label) {
assert(label);
if (setfilecon(path, label) < 0) {
log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
if (security_getenforce() > 0)
return -errno;
}
@ -349,12 +349,12 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
if (errno == ENOENT)
return 0;
log_enforcing("Failed to determine SELinux security context for %s: %m", path);
log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
} else {
if (setfscreatecon_raw(filecon) >= 0)
return 0; /* Success! */
log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, path);
}
if (security_getenforce() > 0)
@ -385,7 +385,7 @@ int mac_selinux_create_socket_prepare(const char *label) {
assert(label);
if (setsockcreatecon(label) < 0) {
log_enforcing("Failed to set SELinux security context %s for sockets: %m", label);
log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
if (security_getenforce() == 1)
return -errno;
@ -457,13 +457,13 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
if (errno == ENOENT)
goto skipped;
log_enforcing("Failed to determine SELinux security context for %s: %m", path);
log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
if (security_getenforce() > 0)
return -errno;
} else {
if (setfscreatecon_raw(fcon) < 0) {
log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
if (security_getenforce() > 0)
return -errno;
} else

View File

@ -177,7 +177,7 @@ static int automount_verify(Automount *a) {
r = unit_name_from_path(a->where, ".automount", &e);
if (r < 0)
return log_unit_error(UNIT(a), "Failed to generate unit name from path: %m");
return log_unit_error_errno(UNIT(a), r, "Failed to generate unit name from path: %m");
if (!unit_has_name(UNIT(a), e)) {
log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing.");

View File

@ -30,6 +30,7 @@ static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
};
static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask);
static void device_unset_sysfs(Device *d) {
Hashmap *devices;
@ -55,8 +56,8 @@ static void device_unset_sysfs(Device *d) {
}
static int device_set_sysfs(Device *d, const char *sysfs) {
_cleanup_free_ char *copy = NULL;
Device *first;
char *copy;
int r;
assert(d);
@ -80,12 +81,10 @@ static int device_set_sysfs(Device *d, const char *sysfs) {
r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first);
if (r < 0) {
LIST_REMOVE(same_sysfs, first, d);
free(copy);
return r;
}
d->sysfs = copy;
d->sysfs = TAKE_PTR(copy);
return 0;
}
@ -103,6 +102,8 @@ static void device_init(Unit *u) {
u->job_running_timeout = u->manager->default_timeout_start_usec;
u->ignore_on_isolate = true;
d->deserialized_state = _DEVICE_STATE_INVALID;
}
static void device_done(Unit *u) {
@ -120,6 +121,9 @@ static void device_set_state(Device *d, DeviceState state) {
old_state = d->state;
d->state = state;
if (state == DEVICE_DEAD)
device_unset_sysfs(d);
if (state != old_state)
log_unit_debug(UNIT(d), "Changed %s -> %s", device_state_to_string(old_state), device_state_to_string(state));
@ -132,34 +136,37 @@ static int device_coldplug(Unit *u) {
assert(d);
assert(d->state == DEVICE_DEAD);
/* This should happen only when we reexecute PID1 from an old version
* which didn't serialize d->found. In this case simply assume that the
* device was in plugged state right before we started reexecuting which
* might be a wrong assumption. */
if (d->found == DEVICE_FOUND_UDEV_DB)
d->found = DEVICE_FOUND_UDEV;
/* First, let's put the deserialized state and found mask into effect, if we have it. */
if (d->found & DEVICE_FOUND_UDEV)
/* If udev says the device is around, it's around */
device_set_state(d, DEVICE_PLUGGED);
else if (d->found != DEVICE_NOT_FOUND && d->deserialized_state != DEVICE_PLUGGED)
/* If a device is found in /proc/self/mountinfo or
* /proc/swaps, and was not yet announced via udev,
* it's "tentatively" around. */
device_set_state(d, DEVICE_TENTATIVE);
if (d->deserialized_state < 0 ||
(d->deserialized_state == d->state &&
d->deserialized_found == d->found))
return 0;
d->found = d->deserialized_found;
device_set_state(d, d->deserialized_state);
return 0;
}
static void device_catchup(Unit *u) {
Device *d = DEVICE(u);
assert(d);
/* Second, let's update the state with the enumerated state if it's different */
if (d->enumerated_found == d->found)
return;
device_update_found_one(d, d->enumerated_found, DEVICE_FOUND_MASK);
}
static const struct {
DeviceFound flag;
const char *name;
} device_found_map[] = {
{ DEVICE_FOUND_UDEV, "found-udev" },
{ DEVICE_FOUND_UDEV_DB, "found-udev-db" },
{ DEVICE_FOUND_MOUNT, "found-mount" },
{ DEVICE_FOUND_SWAP, "found-swap" },
{}
{ DEVICE_FOUND_UDEV, "found-udev" },
{ DEVICE_FOUND_MOUNT, "found-mount" },
{ DEVICE_FOUND_SWAP, "found-swap" },
};
static int device_found_to_string_many(DeviceFound flags, char **ret) {
@ -168,8 +175,8 @@ static int device_found_to_string_many(DeviceFound flags, char **ret) {
assert(ret);
for (i = 0; device_found_map[i].name; i++) {
if ((flags & device_found_map[i].flag) != device_found_map[i].flag)
for (i = 0; i < ELEMENTSOF(device_found_map); i++) {
if (!FLAGS_SET(flags, device_found_map[i].flag))
continue;
if (!strextend_with_separator(&s, ",", device_found_map[i].name, NULL))
@ -198,7 +205,7 @@ static int device_found_from_string_many(const char *name, DeviceFound *ret) {
if (r == 0)
break;
for (i = 0; device_found_map[i].name; i++)
for (i = 0; i < ELEMENTSOF(device_found_map); i++)
if (streq(word, device_found_map[i].name)) {
f = device_found_map[i].flag;
break;
@ -224,8 +231,8 @@ static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "state", device_state_to_string(d->state));
(void) device_found_to_string_many(d->found, &s);
unit_serialize_item(u, f, "found", s);
if (device_found_to_string_many(d->found, &s) >= 0)
unit_serialize_item(u, f, "found", s);
return 0;
}
@ -239,31 +246,19 @@ static int device_deserialize_item(Unit *u, const char *key, const char *value,
assert(value);
assert(fds);
/* The device was known at the time units were serialized but it's not
* anymore at the time units are deserialized. This happens when PID1 is
* re-executed after having switched to the new rootfs: devices were
* enumerated but udevd wasn't running yet thus the list of devices
* (handled by systemd) to initialize was empty. In such case we wait
* for the device events to be re-triggered by udev so device units are
* properly re-initialized. */
if (d->found == DEVICE_NOT_FOUND) {
assert(d->sysfs == NULL);
return 0;
}
if (streq(key, "state")) {
DeviceState state;
state = device_state_from_string(value);
if (state < 0)
log_unit_debug(u, "Failed to parse state value: %s", value);
log_unit_debug(u, "Failed to parse state value, ignoring: %s", value);
else
d->deserialized_state = state;
} else if (streq(key, "found")) {
r = device_found_from_string_many(value, &d->found);
r = device_found_from_string_many(value, &d->deserialized_found);
if (r < 0)
log_unit_debug(u, "Failed to parse found value: %s", value);
log_unit_debug_errno(u, r, "Failed to parse found value, ignoring: %s", value);
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@ -326,19 +321,18 @@ static int device_update_description(Unit *u, struct udev_device *dev, const cha
_cleanup_free_ char *j;
j = strjoin(model, " ", label);
if (j)
r = unit_set_description(u, j);
else
r = -ENOMEM;
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);
if (r < 0)
log_unit_error_errno(u, r, "Failed to set device description: %m");
return log_unit_error_errno(u, r, "Failed to set device description: %m");
return r;
return 0;
}
static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
@ -412,7 +406,7 @@ static bool device_is_bound_by_mounts(Device *d, struct udev_device *dev) {
return d->bind_mounts;
}
static int device_upgrade_mount_deps(Unit *u) {
static void device_upgrade_mount_deps(Unit *u) {
Unit *other;
Iterator i;
void *v;
@ -426,9 +420,8 @@ static int device_upgrade_mount_deps(Unit *u) {
r = unit_add_dependency(other, UNIT_BINDS_TO, u, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
return r;
log_unit_warning_errno(u, r, "Failed to add BindsTo= dependency between device and mount unit, ignoring: %m");
}
return 0;
}
static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
@ -443,8 +436,10 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
if (dev) {
sysfs = udev_device_get_syspath(dev);
if (!sysfs)
if (!sysfs) {
log_debug("Couldn't get syspath from udev device, ignoring.");
return 0;
}
}
r = unit_name_from_path(path, ".device", &e);
@ -453,17 +448,21 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
u = manager_get_unit(m, e);
if (u) {
/* The device unit can still be present even if the device was unplugged: a mount unit can reference it hence
* preventing the GC to have garbaged it. That's desired since the device unit may have a dependency on the
* mount unit which was added during the loading of the later. */
if (dev && DEVICE(u)->state == DEVICE_PLUGGED) {
/* The device unit can still be present even if the device was unplugged: a mount unit can reference it
* hence preventing the GC to have garbaged it. That's desired since the device unit may have a
* dependency on the mount unit which was added during the loading of the later. When the device is
* plugged the sysfs might not be initialized yet, as we serialize the device's state but do not
* serialize the sysfs path across reloads/reexecs. Hence, when coming back from a reload/restart we
* might have the state valid, but not the sysfs path. Hence, let's filter out conflicting devices, but
* let's accept devices in any state with no sysfs path set. */
/* This unit is in plugged state: we're sure it's attached to a device. */
if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s",
e, DEVICE(u)->sysfs, sysfs);
return -EEXIST;
}
if (DEVICE(u)->state == DEVICE_PLUGGED &&
DEVICE(u)->sysfs &&
sysfs &&
!path_equal(DEVICE(u)->sysfs, sysfs)) {
log_unit_debug(u, "Device %s appeared twice with different sysfs paths %s and %s, ignoring the latter.",
e, DEVICE(u)->sysfs, sysfs);
return -EEXIST;
}
delete = false;
@ -475,24 +474,26 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
delete = true;
r = unit_new_for_name(m, sizeof(Device), e, &u);
if (r < 0)
if (r < 0) {
log_error_errno(r, "Failed to allocate device unit %s: %m", e);
goto fail;
}
unit_add_to_load_queue(u);
}
/* If this was created via some dependency and has not
* actually been seen yet ->sysfs will not be
/* If this was created via some dependency and has not actually been seen yet ->sysfs will not be
* initialized. Hence initialize it if necessary. */
if (sysfs) {
r = device_set_sysfs(DEVICE(u), sysfs);
if (r < 0)
if (r < 0) {
log_error_errno(r, "Failed to set sysfs path %s for device unit %s: %m", sysfs, e);
goto fail;
}
(void) device_update_description(u, dev, path);
/* The additional systemd udev properties we only interpret
* for the main object */
/* The additional systemd udev properties we only interpret for the main object */
if (main)
(void) device_add_udev_wants(u, dev);
}
@ -504,13 +505,11 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
device_upgrade_mount_deps(u);
/* Note that this won't dispatch the load queue, the caller has to do that if needed and appropriate */
unit_add_to_dbus_queue(u);
return 0;
fail:
log_unit_warning_errno(u, r, "Failed to set up device unit: %m");
if (delete)
unit_free(u);
@ -574,76 +573,81 @@ static int device_process_new(Manager *m, struct udev_device *dev) {
r = extract_first_word(&alias, &word, NULL, EXTRACT_QUOTES);
if (r == 0)
return 0;
break;
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_warning_errno(r, "Failed to add parse SYSTEMD_ALIAS for %s: %m", sysfs);
if (path_is_absolute(word))
(void) device_setup_unit(m, dev, word, false);
else
if (!path_is_absolute(word))
log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, word);
else if (!path_is_normalized(word))
log_warning("SYSTEMD_ALIAS for %s is not a normalized path, ignoring: %s", sysfs, word);
else
(void) device_setup_unit(m, dev, word, false);
}
return 0;
}
static void device_update_found_one(Device *d, bool add, DeviceFound found, bool now) {
DeviceFound n, previous;
static void device_found_changed(Device *d, DeviceFound previous, DeviceFound now) {
assert(d);
n = add ? (d->found | found) : (d->found & ~found);
if (n == d->found)
return;
previous = d->found;
d->found = n;
if (!now)
return;
/* Didn't exist before, but does now? if so, generate a new invocation ID for it */
if (previous == DEVICE_NOT_FOUND && d->found != DEVICE_NOT_FOUND)
if (previous == DEVICE_NOT_FOUND && now != DEVICE_NOT_FOUND)
(void) unit_acquire_invocation_id(UNIT(d));
if (d->found & DEVICE_FOUND_UDEV)
/* When the device is known to udev we consider it
* plugged. */
if (FLAGS_SET(now, DEVICE_FOUND_UDEV))
/* When the device is known to udev we consider it plugged. */
device_set_state(d, DEVICE_PLUGGED);
else if (d->found != DEVICE_NOT_FOUND && (previous & DEVICE_FOUND_UDEV) == 0)
/* If the device has not been seen by udev yet, but is
* now referenced by the kernel, then we assume the
else if (now != DEVICE_NOT_FOUND && !FLAGS_SET(previous, DEVICE_FOUND_UDEV))
/* If the device has not been seen by udev yet, but is now referenced by the kernel, then we assume the
* kernel knows it now, and udev might soon too. */
device_set_state(d, DEVICE_TENTATIVE);
else {
/* If nobody sees the device, or if the device was
* previously seen by udev and now is only referenced
* from the kernel, then we consider the device is
* gone, the kernel just hasn't noticed it yet. */
else
/* If nobody sees the device, or if the device was previously seen by udev and now is only referenced
* from the kernel, then we consider the device is gone, the kernel just hasn't noticed it yet. */
device_set_state(d, DEVICE_DEAD);
device_unset_sysfs(d);
}
}
static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) {
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) {
assert(d);
if (MANAGER_IS_RUNNING(UNIT(d)->manager)) {
DeviceFound n, previous;
/* When we are already running, then apply the new mask right-away, and trigger state changes
* right-away */
n = (d->found & ~mask) | (found & mask);
if (n == d->found)
return;
previous = d->found;
d->found = n;
device_found_changed(d, previous, n);
} else
/* We aren't running yet, let's apply the new mask to the shadow variable instead, which we'll apply as
* soon as we catch-up with the state. */
d->enumerated_found = (d->enumerated_found & ~mask) | (found & mask);
}
static void device_update_found_by_sysfs(Manager *m, const char *sysfs, DeviceFound found, DeviceFound mask) {
Device *d, *l, *n;
assert(m);
assert(sysfs);
if (found == DEVICE_NOT_FOUND)
return 0;
if (mask == 0)
return;
l = hashmap_get(m->devices_by_sysfs, sysfs);
LIST_FOREACH_SAFE(same_sysfs, d, n, l)
device_update_found_one(d, add, found, now);
return 0;
device_update_found_one(d, found, mask);
}
static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) {
static int device_update_found_by_name(Manager *m, const char *path, DeviceFound found, DeviceFound mask) {
_cleanup_free_ char *e = NULL;
Unit *u;
int r;
@ -651,7 +655,7 @@ static int device_update_found_by_name(Manager *m, const char *path, bool add, D
assert(m);
assert(path);
if (found == DEVICE_NOT_FOUND)
if (mask == 0)
return 0;
r = unit_name_from_path(path, ".device", &e);
@ -662,7 +666,7 @@ static int device_update_found_by_name(Manager *m, const char *path, bool add, D
if (!u)
return 0;
device_update_found_one(DEVICE(u), add, found, now);
device_update_found_one(DEVICE(u), found, mask);
return 0;
}
@ -753,7 +757,7 @@ static void device_enumerate(Manager *m) {
if (!m->udev_monitor) {
m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
if (!m->udev_monitor) {
log_oom();
log_error_errno(errno, "Failed to allocate udev monitor: %m");
goto fail;
}
@ -785,7 +789,7 @@ static void device_enumerate(Manager *m) {
e = udev_enumerate_new(m->udev);
if (!e) {
log_oom();
log_error_errno(errno, "Failed to alloacte udev enumerator: %m");
goto fail;
}
@ -816,7 +820,13 @@ static void device_enumerate(Manager *m) {
dev = udev_device_new_from_syspath(m->udev, sysfs);
if (!dev) {
log_oom();
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;
}
@ -824,8 +834,7 @@ static void device_enumerate(Manager *m) {
continue;
(void) device_process_new(m, dev);
device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV_DB, false);
device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
}
return;
@ -834,6 +843,24 @@ fail:
device_shutdown(m);
}
static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) {
Device *d, *l, *n;
int r;
assert(m);
assert(sysfs);
l = hashmap_get(m->devices_by_sysfs, sysfs);
LIST_FOREACH_SAFE(same_sysfs, d, n, l) {
if (d->state == DEVICE_DEAD)
continue;
r = manager_propagate_reload(m, UNIT(d), JOB_REPLACE, NULL);
if (r < 0)
log_warning_errno(r, "Failed to propagate reload, ignoring: %m");
}
}
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;
Manager *m = userdata;
@ -871,20 +898,8 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
return 0;
}
if (streq(action, "change")) {
Unit *u;
Device *d, *l, *n;
l = hashmap_get(m->devices_by_sysfs, sysfs);
LIST_FOREACH_SAFE(same_sysfs, d, n, l) {
u = &d->meta;
if (u && UNIT_VTABLE(u)->active_state(u) == UNIT_ACTIVE) {
r = manager_propagate_reload(m, u, JOB_REPLACE, NULL);
if (r < 0)
log_error_errno(r, "Failed to propagate reload: %m");
}
}
}
if (streq(action, "change"))
device_propagate_reload_by_sysfs(m, sysfs);
/* A change event can signal that a device is becoming ready, in particular if
* the device is using the SYSTEMD_READY logic in udev
@ -892,12 +907,12 @@ 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_error_errno(r, "Failed to process swap device remove event: %m");
log_warning_errno(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
* found bits */
device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP, true);
device_update_found_by_sysfs(m, sysfs, 0, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP);
} else if (device_is_ready(dev)) {
@ -905,19 +920,19 @@ 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_error_errno(r, "Failed to process swap device new event: %m");
log_warning_errno(r, "Failed to process swap device new event, ignoring: %m");
manager_dispatch_load_queue(m);
/* The device is found now, set the udev found bit */
device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, true);
device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
} else {
/* The device is nominally around, but not ready for
* us. Hence unset the udev bit, but leave the rest
* around. */
device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV, true);
device_update_found_by_sysfs(m, sysfs, 0, DEVICE_FOUND_UDEV);
}
return 0;
@ -935,61 +950,88 @@ static bool device_supported(void) {
return read_only <= 0;
}
int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now) {
_cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
static int validate_node(Manager *m, const char *node, struct udev_device **ret) {
struct stat st;
int r;
assert(m);
assert(node);
assert(ret);
/* Validates a device node that showed up in /proc/swaps or /proc/self/mountinfo if it makes sense for us to
* track. Note that this validator is fine within missing device nodes, but not with badly set up ones! */
if (!path_startswith(node, "/dev")) {
*ret = NULL;
return 0; /* bad! */
}
if (stat(node, &st) < 0) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to stat() device node file %s: %m", node);
*ret = NULL;
return 1; /* good! (though missing) */
} else {
_cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
r = udev_device_new_from_stat_rdev(m->udev, &st, &dev);
if (r == -ENOENT) {
*ret = NULL;
return 1; /* good! (though missing) */
} else if (r == -ENOTTY) {
*ret = NULL;
return 0; /* bad! (not a device node but some other kind of file system node) */
} else if (r < 0)
return log_error_errno(r, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
*ret = TAKE_PTR(dev);
return 1; /* good! */
}
}
void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFound mask) {
int r;
assert(m);
assert(node);
if (!device_supported())
return 0;
return;
/* This is called whenever we find a device referenced in
* /proc/swaps or /proc/self/mounts. Such a device might be
* mounted/enabled at a time where udev has not finished
* probing it yet, and we thus haven't learned about it
* yet. In this case we will set the device unit to
* "tentative" state. */
if (mask == 0)
return;
if (add) {
if (!path_startswith(node, "/dev"))
return 0;
/* This is called whenever we find a device referenced in /proc/swaps or /proc/self/mounts. Such a device might
* be mounted/enabled at a time where udev has not finished probing it yet, and we thus haven't learned about
* it yet. In this case we will set the device unit to "tentative" state.
*
* This takes a pair of DeviceFound flags parameters. The 'mask' parameter is a bit mask that indicates which
* bits of 'found' to copy into the per-device DeviceFound flags field. Thus, this function may be used to set
* and unset individual bits in a single call, while merging partially with previous state. */
/* We make an extra check here, if the device node
* actually exists. If it's missing, then this is an
* indication that device was unplugged but is still
* referenced in /proc/swaps or
* /proc/self/mountinfo. Note that this check doesn't
* really cover all cases where a device might be gone
* away, since drives that can have a medium inserted
* will still have a device node even when the medium
* is not there... */
if ((found & mask) != 0) {
_cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
if (stat(node, &st) >= 0) {
if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
return 0;
/* 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
* everything is alright with the device node. */
dev = udev_device_new_from_devnum(m->udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
if (!dev && errno != ENOENT)
return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
} else if (errno != ENOENT)
return log_error_errno(errno, "Failed to stat device node file %s: %m", node);
/* 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. */
r = validate_node(m, node, &dev);
if (r <= 0)
return; /* Don't create a device unit for this if the device node is borked. */
(void) device_setup_unit(m, dev, node, false);
}
/* Update the device unit's state, should it exist */
return device_update_found_by_name(m, node, add, found, now);
(void) device_update_found_by_name(m, node, found, mask);
}
bool device_shall_be_bound_by(Unit *device, Unit *u) {
assert(device);
assert(u);
if (u->type != UNIT_MOUNT)
return false;
@ -1011,6 +1053,7 @@ const UnitVTable device_vtable = {
.load = unit_load_fragment_and_dropin_optional,
.coldplug = device_coldplug,
.catchup = device_catchup,
.serialize = device_serialize,
.deserialize_item = device_deserialize_item,

View File

@ -11,33 +11,36 @@
typedef struct Device Device;
/* A mask specifying where we have seen the device currently. This is a bitmask because the device might show up
* asynchronously from each other at various places. For example, in very common case a device might already be mounted
* before udev finished probing it (think: a script setting up a loopback block device, formatting it and mounting it
* in quick succession). Hence we need to track precisely where it is already visible and where not. */
typedef enum DeviceFound {
DEVICE_NOT_FOUND = 0,
DEVICE_FOUND_UDEV = 1 << 1,
DEVICE_FOUND_UDEV_DB = 1 << 2,
DEVICE_FOUND_MOUNT = 1 << 3,
DEVICE_FOUND_SWAP = 1 << 4,
DEVICE_NOT_FOUND = 0,
DEVICE_FOUND_UDEV = 1U << 1, /* The device has shown up in the udev database */
DEVICE_FOUND_MOUNT = 1U << 2, /* The device has shown up in /proc/self/mountinfo */
DEVICE_FOUND_SWAP = 1U << 3, /* The device has shown up in /proc/swaps */
DEVICE_FOUND_MASK = DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP,
} DeviceFound;
struct Device {
Unit meta;
char *sysfs;
DeviceFound found;
/* In order to be able to distinguish dependencies on
different device nodes we might end up creating multiple
devices for the same sysfs path. We chain them up here. */
/* In order to be able to distinguish dependencies on different device nodes we might end up creating multiple
* devices for the same sysfs path. We chain them up here. */
LIST_FIELDS(struct Device, same_sysfs);
DeviceState state, deserialized_state;
DeviceFound found, deserialized_found, enumerated_found;
bool bind_mounts;
};
extern const UnitVTable device_vtable;
int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFound mask);
bool device_shall_be_bound_by(Unit *device, Unit *u);
DEFINE_CAST(DEVICE, Device);

View File

@ -1322,13 +1322,30 @@ Manager* manager_free(Manager *m) {
return mfree(m);
}
static void manager_enumerate_perpetual(Manager *m) {
UnitType c;
assert(m);
/* Let's ask every type to load all units from disk/kernel that it might know */
for (c = 0; c < _UNIT_TYPE_MAX; c++) {
if (!unit_type_supported(c)) {
log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
continue;
}
if (unit_vtable[c]->enumerate_perpetual)
unit_vtable[c]->enumerate_perpetual(m);
}
}
static void manager_enumerate(Manager *m) {
UnitType c;
assert(m);
/* Let's ask every type to load all units from disk/kernel
* that it might know */
/* Let's ask every type to load all units from disk/kernel that it might know */
for (c = 0; c < _UNIT_TYPE_MAX; c++) {
if (!unit_type_supported(c)) {
log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
@ -1350,7 +1367,9 @@ static void manager_coldplug(Manager *m) {
assert(m);
/* Then, let's set up their initial state. */
log_debug("Invoking unit coldplug() handlers…");
/* Let's place the units back into their deserialized state */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
/* ignore aliases */
@ -1363,6 +1382,26 @@ static void manager_coldplug(Manager *m) {
}
}
static void manager_catchup(Manager *m) {
Iterator i;
Unit *u;
char *k;
assert(m);
log_debug("Invoking unit catchup() handlers…");
/* Let's catch up on any state changes that happened while we were reloading/reexecing */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
/* ignore aliases */
if (u->id != k)
continue;
unit_catchup(u);
}
}
static void manager_build_unit_path_cache(Manager *m) {
char **i;
int r;
@ -1463,6 +1502,48 @@ static bool manager_dbus_is_running(Manager *m, bool deserialized) {
return true;
}
static void manager_setup_bus(Manager *m) {
assert(m);
/* Let's set up our private bus connection now, unconditionally */
(void) bus_init_private(m);
/* If we are in --user mode also connect to the system bus now */
if (MANAGER_IS_USER(m))
(void) bus_init_system(m);
/* Let's connect to the bus now, but only if the unit is supposed to be up */
if (manager_dbus_is_running(m, MANAGER_IS_RELOADING(m))) {
(void) bus_init_api(m);
if (MANAGER_IS_SYSTEM(m))
(void) bus_init_system(m);
}
}
static void manager_preset_all(Manager *m) {
int r;
assert(m);
if (m->first_boot <= 0)
return;
if (!MANAGER_IS_SYSTEM(m))
return;
if (m->test_run_flags != 0)
return;
/* If this is the first boot, and we are in the host system, then preset everything */
r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
if (r < 0)
log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r,
"Failed to populate /etc with preset unit settings, ignoring: %m");
else
log_info("Populated /etc with preset unit settings.");
}
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
int r;
@ -1486,19 +1567,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (r < 0)
return r;
/* If this is the first boot, and we are in the host system, then preset everything */
if (m->first_boot > 0 &&
MANAGER_IS_SYSTEM(m) &&
!m->test_run_flags) {
r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
if (r < 0)
log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r,
"Failed to populate /etc with preset unit settings, ignoring: %m");
else
log_info("Populated /etc with preset unit settings.");
}
manager_preset_all(m);
lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
@ -1510,6 +1579,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* First, enumerate what we can from all config files */
dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_START);
manager_enumerate_perpetual(m);
manager_enumerate(m);
dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
@ -1543,20 +1613,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* This shouldn't fail, except if things are really broken. */
return r;
/* Let's set up our private bus connection now, unconditionally */
(void) bus_init_private(m);
/* If we are in --user mode also connect to the system bus now */
if (MANAGER_IS_USER(m))
(void) bus_init_system(m);
/* Let's connect to the bus now, but only if the unit is supposed to be up */
if (manager_dbus_is_running(m, !!serialization)) {
(void) bus_init_api(m);
if (MANAGER_IS_SYSTEM(m))
(void) bus_init_system(m);
}
/* Connect to the bus if we are good for it */
manager_setup_bus(m);
/* Now that we are connected to all possible busses, let's deserialize who is tracking us. */
(void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed);
@ -1584,6 +1642,9 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->send_reloading_done = true;
}
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);
return 0;
}
@ -3362,8 +3423,7 @@ int manager_reload(Manager *m) {
r = q;
}
fclose(f);
f = NULL;
f = safe_fclose(f);
/* Re-register notify_fd as event source */
q = manager_setup_notify(m);
@ -3397,6 +3457,9 @@ int manager_reload(Manager *m) {
manager_recheck_journal(m);
manager_recheck_dbus(m);
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);
/* Sync current state of bus names with our set of listening units */
q = manager_enqueue_sync_bus_names(m);
if (q < 0 && r >= 0)

View File

@ -1634,7 +1634,7 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
return log_oom();
(void) device_found_node(m, d, true, DEVICE_FOUND_MOUNT, set_flags);
device_found_node(m, d, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT);
k = mount_setup_unit(m, d, p, options, fstype, set_flags);
if (r == 0 && k < 0)
@ -1671,7 +1671,7 @@ static int mount_get_timeout(Unit *u, usec_t *timeout) {
return 1;
}
static int synthesize_root_mount(Manager *m) {
static void mount_enumerate_perpetual(Manager *m) {
Unit *u;
int r;
@ -1683,8 +1683,10 @@ static int synthesize_root_mount(Manager *m) {
u = manager_get_unit(m, SPECIAL_ROOT_MOUNT);
if (!u) {
r = unit_new_for_name(m, sizeof(Mount), SPECIAL_ROOT_MOUNT, &u);
if (r < 0)
return log_error_errno(r, "Failed to allocate the special " SPECIAL_ROOT_MOUNT " unit: %m");
if (r < 0) {
log_error_errno(r, "Failed to allocate the special " SPECIAL_ROOT_MOUNT " unit: %m");
return;
}
}
u->perpetual = true;
@ -1692,8 +1694,6 @@ static int synthesize_root_mount(Manager *m) {
unit_add_to_load_queue(u);
unit_add_to_dbus_queue(u);
return 0;
}
static bool mount_is_mounted(Mount *m) {
@ -1707,10 +1707,6 @@ static void mount_enumerate(Manager *m) {
assert(m);
r = synthesize_root_mount(m);
if (r < 0)
goto fail;
mnt_init_debug(0);
if (!m->mount_monitor) {
@ -1896,7 +1892,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
continue;
/* Let the device units know that the device is no longer mounted */
(void) device_found_node(m, what, false, DEVICE_FOUND_MOUNT, true);
device_found_node(m, what, 0, DEVICE_FOUND_MOUNT);
}
return 0;
@ -2001,6 +1997,7 @@ const UnitVTable mount_vtable = {
.can_transient = true,
.enumerate_perpetual = mount_enumerate_perpetual,
.enumerate = mount_enumerate,
.shutdown = mount_shutdown,

View File

@ -540,7 +540,7 @@ _pure_ static const char *scope_sub_state_to_string(Unit *u) {
return scope_state_to_string(SCOPE(u)->state);
}
static void scope_enumerate(Manager *m) {
static void scope_enumerate_perpetual(Manager *m) {
Unit *u;
int r;
@ -622,5 +622,5 @@ const UnitVTable scope_vtable = {
.bus_set_property = bus_scope_set_property,
.bus_commit_properties = bus_scope_commit_properties,
.enumerate = scope_enumerate,
.enumerate_perpetual = scope_enumerate_perpetual,
};

View File

@ -1947,7 +1947,7 @@ static void service_enter_start(Service *s) {
/* There's no command line configured for the main command? Hmm, that is strange. This can only
* happen if the configuration changes at runtime. In this case, let's enter a failure
* state. */
log_unit_error(UNIT(s), "There's no 'start' task anymore we could start: %m");
log_unit_error(UNIT(s), "There's no 'start' task anymore we could start.");
r = -ENXIO;
goto fail;
}

View File

@ -326,7 +326,7 @@ static int slice_make_perpetual(Manager *m, const char *name, Unit **ret) {
return 0;
}
static void slice_enumerate(Manager *m) {
static void slice_enumerate_perpetual(Manager *m) {
Unit *u;
int r;
@ -383,7 +383,7 @@ const UnitVTable slice_vtable = {
.bus_set_property = bus_slice_set_property,
.bus_commit_properties = bus_slice_commit_properties,
.enumerate = slice_enumerate,
.enumerate_perpetual = slice_enumerate_perpetual,
.status_message_formats = {
.finished_start_job = {

View File

@ -255,15 +255,19 @@ static int swap_load_devnode(Swap *s) {
_cleanup_(udev_device_unrefp) struct udev_device *d = NULL;
struct stat st;
const char *p;
int r;
assert(s);
if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode))
return 0;
d = udev_device_new_from_devnum(UNIT(s)->manager->udev, 'b', st.st_rdev);
if (!d)
r = udev_device_new_from_stat_rdev(UNIT(s)->manager->udev, &st, &d);
if (r < 0) {
log_unit_full(UNIT(s), r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to allocate udev device for swap %s: %m", s->what);
return 0;
}
p = udev_device_get_devnode(d);
if (!p)
@ -443,9 +447,12 @@ static int swap_process_new(Manager *m, const char *device, int prio, bool set_f
if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode))
return 0;
d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev);
if (!d)
r = udev_device_new_from_stat_rdev(m->udev, &st, &d);
if (r < 0) {
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to allocate udev device for swap %s: %m", device);
return 0;
}
/* Add the main device node */
dn = udev_device_get_devnode(d);
@ -1112,7 +1119,7 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) {
if (cunescape(dev, UNESCAPE_RELAX, &d) < 0)
return log_oom();
device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags);
device_found_node(m, d, DEVICE_FOUND_SWAP, DEVICE_FOUND_SWAP);
k = swap_process_new(m, d, prio, set_flags);
if (k < 0)
@ -1167,7 +1174,7 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
}
if (swap->what)
device_found_node(m, swap->what, false, DEVICE_FOUND_SWAP, true);
device_found_node(m, swap->what, 0, DEVICE_FOUND_SWAP);
} else if (swap->just_activated) {
@ -1270,9 +1277,7 @@ static void swap_shutdown(Manager *m) {
assert(m);
m->swap_event_source = sd_event_source_unref(m->swap_event_source);
m->proc_swaps = safe_fclose(m->proc_swaps);
m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode);
}
@ -1285,9 +1290,9 @@ static void swap_enumerate(Manager *m) {
m->proc_swaps = fopen("/proc/swaps", "re");
if (!m->proc_swaps) {
if (errno == ENOENT)
log_debug("Not swap enabled, skipping enumeration");
log_debug_errno(errno, "Not swap enabled, skipping enumeration.");
else
log_error_errno(errno, "Failed to open /proc/swaps: %m");
log_warning_errno(errno, "Failed to open /proc/swaps, ignoring: %m");
return;
}

View File

@ -2298,7 +2298,6 @@ static void unit_update_on_console(Unit *u) {
manager_ref_console(u->manager);
else
manager_unref_console(u->manager);
}
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags) {
@ -3730,8 +3729,7 @@ int unit_coldplug(Unit *u) {
assert(u);
/* Make sure we don't enter a loop, when coldplugging
* recursively. */
/* Make sure we don't enter a loop, when coldplugging recursively. */
if (u->coldplugged)
return 0;
@ -3759,6 +3757,13 @@ int unit_coldplug(Unit *u) {
return r;
}
void unit_catchup(Unit *u) {
assert(u);
if (UNIT_VTABLE(u)->catchup)
UNIT_VTABLE(u)->catchup(u);
}
static bool fragment_mtime_newer(const char *path, usec_t mtime, bool path_masked) {
struct stat st;

View File

@ -437,10 +437,14 @@ typedef struct UnitVTable {
* UNIT_STUB if no configuration could be found. */
int (*load)(Unit *u);
/* If a lot of units got created via enumerate(), this is
* where to actually set the state and call unit_notify(). */
/* During deserialization we only record the intended state to return to. With coldplug() we actually put the
* deserialized state in effect. This is where unit_notify() should be called to start things up. */
int (*coldplug)(Unit *u);
/* This is called shortly after all units' coldplug() call was invoked. It's supposed to catch up state changes
* we missed so far (for example because they took place while we were reloading/reexecing) */
void (*catchup)(Unit *u);
void (*dump)(Unit *u, FILE *f, const char *prefix);
int (*start)(Unit *u);
@ -531,11 +535,15 @@ typedef struct UnitVTable {
/* Returns true if the unit currently needs access to the console */
bool (*needs_console)(Unit *u);
/* This is called for each unit type and should be used to
* enumerate existing devices and load them. However,
* everything that is loaded here should still stay in
* inactive state. It is the job of the coldplug() call above
* to put the units into the initial state. */
/* Like the enumerate() callback further down, but only enumerates the perpetual units, i.e. all units that
* unconditionally exist and are always active. The main reason to keep both enumeration functions separate is
* philosophical: the state of perpetual units should be put in place by coldplug(), while the state of those
* discovered through regular enumeration should be put in place by catchup(), see below. */
void (*enumerate_perpetual)(Manager *m);
/* This is called for each unit type and should be used to enumerate units already existing in the system
* internally and load them. However, everything that is loaded here should still stay in inactive state. It is
* the job of the catchup() call above to put the units into the discovered state. */
void (*enumerate)(Manager *m);
/* Type specific cleanups. */
@ -687,6 +695,7 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *v
int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency d, UnitDependencyMask mask);
int unit_coldplug(Unit *u);
void unit_catchup(Unit *u);
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t);

View File

@ -182,11 +182,11 @@ typedef struct BootId {
} BootId;
static int add_matches_for_device(sd_journal *j, const char *devpath) {
int r;
_cleanup_(udev_unrefp) struct udev *udev = NULL;
_cleanup_(udev_device_unrefp) struct udev_device *device = NULL;
struct udev_device *d = NULL;
struct stat st;
int r;
assert(j);
assert(devpath);
@ -200,13 +200,12 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) {
if (!udev)
return log_oom();
r = stat(devpath, &st);
if (r < 0)
log_error_errno(errno, "Couldn't stat file: %m");
if (stat(devpath, &st) < 0)
return log_error_errno(errno, "Couldn't stat file: %m");
d = device = udev_device_new_from_devnum(udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
if (!device)
return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
r = udev_device_new_from_stat_rdev(udev, &st, &device);
if (r < 0)
return log_error_errno(r, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
while (d) {
_cleanup_free_ char *match = NULL;

View File

@ -766,8 +766,8 @@ int server_restore_streams(Server *s, FDSet *fds) {
/* No file descriptor? Then let's delete the state file */
log_debug("Cannot restore stream file %s", de->d_name);
if (unlinkat(dirfd(d), de->d_name, 0) < 0)
log_warning("Failed to remove /run/systemd/journal/streams/%s: %m",
de->d_name);
log_warning_errno(errno, "Failed to remove /run/systemd/journal/streams/%s: %m",
de->d_name);
continue;
}

View File

@ -245,7 +245,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_h
r = sd_netlink_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
if (r < 0)
return log_netdev_error(netdev, "Could not send rtnetlink message: %m");
return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
link_ref(link);

View File

@ -2930,7 +2930,7 @@ static int outer_child(
if (l < 0)
return log_error_errno(errno, "Failed to send cgroup mode: %m");
if (l != sizeof(arg_unified_cgroup_hierarchy)) {
log_error("Short write while sending cgroup mode: %m");
log_error("Short write while sending cgroup mode.");
return -EIO;
}

View File

@ -1156,8 +1156,10 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m");
if (r == 0)
return log_error("Failed to parse argument: %m");
if (r == 0) {
log_error("Failed to parse argument: %s", p);
return -EINVAL;
}
r = sd_bus_message_append(m, "(ss)", path, w);
if (r < 0)

View File

@ -303,8 +303,8 @@ int config_parse(const char *unit,
/* Only log on request, except for ENOENT,
* since we return 0 to the caller. */
if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
"Failed to open configuration file '%s': %m", filename);
log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
"Failed to open configuration file '%s': %m", filename);
return errno == ENOENT ? 0 : -errno;
}
}

View File

@ -210,7 +210,7 @@ static int unit_file_find_dirs(
type = unit_name_to_type(name);
if (type < 0) {
log_error("Failed to to derive unit type from unit name: %m");
log_error("Failed to to derive unit type from unit name: %s", name);
return -EINVAL;
}

View File

@ -42,3 +42,26 @@ int udev_parse_config(void) {
return 0;
}
int udev_device_new_from_stat_rdev(struct udev *udev, const struct stat *st, struct udev_device **ret) {
struct udev_device *nd;
char type;
assert(udev);
assert(st);
assert(ret);
if (S_ISBLK(st->st_mode))
type = 'b';
else if (S_ISCHR(st->st_mode))
type = 'c';
else
return -ENOTTY;
nd = udev_device_new_from_devnum(udev, type, st->st_rdev);
if (!nd)
return -errno;
*ret = nd;
return 0;
}

View File

@ -21,3 +21,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_msg*, udev_ctrl_msg_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref);
int udev_parse_config(void);
int udev_device_new_from_stat_rdev(struct udev *udev, const struct stat *st, struct udev_device **ret);