From c80a9a33d04fb4381327a69ce929c94a9f1d0e6c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2020 11:48:57 +0100 Subject: [PATCH] core: clearly refuse OnFailure= deps on units that can't fail Similar, refuse triggering deps on units that cannot trigger. And rework how we ignore After= dependencies on device units, to work the same way. See: #14142 --- src/core/automount.c | 6 ++++-- src/core/device.c | 1 + src/core/mount.c | 5 +++-- src/core/path.c | 2 ++ src/core/scope.c | 1 + src/core/service.c | 1 + src/core/socket.c | 2 ++ src/core/swap.c | 2 ++ src/core/timer.c | 6 ++++-- src/core/unit.c | 22 +++++++++++++++++++--- src/core/unit.h | 9 +++++++++ 11 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/core/automount.c b/src/core/automount.c index 091b59fe78..0b3f498bfc 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -1106,6 +1106,10 @@ const UnitVTable automount_vtable = { "Automount\0" "Install\0", + .can_transient = true, + .can_fail = true, + .can_trigger = true, + .init = automount_init, .load = automount_load, .done = automount_done, @@ -1132,8 +1136,6 @@ const UnitVTable automount_vtable = { .bus_vtable = bus_automount_vtable, .bus_set_property = bus_automount_set_property, - .can_transient = true, - .shutdown = automount_shutdown, .supported = automount_supported, diff --git a/src/core/device.c b/src/core/device.c index 45149e7555..06bbbf8d2c 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -1064,6 +1064,7 @@ const UnitVTable device_vtable = { "Device\0" "Install\0", + .refuse_after = true, .gc_jobs = true, .init = device_init, diff --git a/src/core/mount.c b/src/core/mount.c index dfed691c43..8ae76dd03a 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -2065,6 +2065,9 @@ const UnitVTable mount_vtable = { "Install\0", .private_section = "Mount", + .can_transient = true, + .can_fail = true, + .init = mount_init, .load = mount_load, .done = mount_done, @@ -2103,8 +2106,6 @@ const UnitVTable mount_vtable = { .get_timeout = mount_get_timeout, - .can_transient = true, - .enumerate_perpetual = mount_enumerate_perpetual, .enumerate = mount_enumerate, .shutdown = mount_shutdown, diff --git a/src/core/path.c b/src/core/path.c index ca15ca884e..cb75d778af 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -806,6 +806,8 @@ const UnitVTable path_vtable = { .private_section = "Path", .can_transient = true, + .can_fail = true, + .can_trigger = true, .init = path_init, .done = path_done, diff --git a/src/core/scope.c b/src/core/scope.c index e8cfedb0d4..76358c416a 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -619,6 +619,7 @@ const UnitVTable scope_vtable = { .can_transient = true, .can_delegate = true, + .can_fail = true, .once_only = true, .init = scope_init, diff --git a/src/core/service.c b/src/core/service.c index 49ad166c26..d355618e38 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -4391,6 +4391,7 @@ const UnitVTable service_vtable = { .can_transient = true, .can_delegate = true, + .can_fail = true, .init = service_init, .done = service_done, diff --git a/src/core/socket.c b/src/core/socket.c index fc5ee69c9c..b5f297e510 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -3417,6 +3417,8 @@ const UnitVTable socket_vtable = { .private_section = "Socket", .can_transient = true, + .can_trigger = true, + .can_fail = true, .init = socket_init, .done = socket_done, diff --git a/src/core/swap.c b/src/core/swap.c index 03f443daec..b9879ba1ea 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1593,6 +1593,8 @@ const UnitVTable swap_vtable = { "Install\0", .private_section = "Swap", + .can_fail = true, + .init = swap_init, .load = swap_load, .done = swap_done, diff --git a/src/core/timer.c b/src/core/timer.c index 051ca76273..57d979d52d 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -895,6 +895,10 @@ const UnitVTable timer_vtable = { "Install\0", .private_section = "Timer", + .can_transient = true, + .can_fail = true, + .can_trigger = true, + .init = timer_init, .done = timer_done, .load = timer_load, @@ -923,6 +927,4 @@ const UnitVTable timer_vtable = { .bus_vtable = bus_timer_vtable, .bus_set_property = bus_timer_set_property, - - .can_transient = true, }; diff --git a/src/core/unit.c b/src/core/unit.c index 399a8cf655..b6b03ac4f4 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2937,12 +2937,28 @@ int unit_add_dependency( return 0; } - if ((d == UNIT_BEFORE && other->type == UNIT_DEVICE) || - (d == UNIT_AFTER && u->type == UNIT_DEVICE)) { - log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id); + if (d == UNIT_AFTER && UNIT_VTABLE(u)->refuse_after) { + log_unit_warning(u, "Requested dependency After=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(u->type)); return 0; } + if (d == UNIT_BEFORE && UNIT_VTABLE(other)->refuse_after) { + log_unit_warning(u, "Requested dependency Before=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(other->type)); + return 0; + } + + if (d == UNIT_ON_FAILURE && !UNIT_VTABLE(u)->can_fail) { + log_unit_warning(u, "Requested dependency OnFailure=%s ignored (%s units cannot fail).", other->id, unit_type_to_string(u->type)); + return 0; + } + + if (d == UNIT_TRIGGERS && !UNIT_VTABLE(u)->can_trigger) + return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL), + "Requested dependency Triggers=%s refused (%s units cannot trigger other units).", other->id, unit_type_to_string(u->type)); + if (d == UNIT_TRIGGERED_BY && !UNIT_VTABLE(other)->can_trigger) + return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL), + "Requested dependency TriggeredBy=%s refused (%s units cannot trigger other units).", other->id, unit_type_to_string(other->type)); + r = unit_add_dependency_hashmap(u->dependencies + d, other, mask, 0); if (r < 0) return r; diff --git a/src/core/unit.h b/src/core/unit.h index c5d8170c92..21f34a3ad9 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -600,6 +600,15 @@ typedef struct UnitVTable { /* True if cgroup delegation is permissible */ bool can_delegate:1; + /* True if the unit type triggers other units, i.e. can have a UNIT_TRIGGERS dependency */ + bool can_trigger:1; + + /* True if the unit type knows a failure state, and thus can be source of an OnFailure= dependency */ + bool can_fail:1; + + /* True if After= dependencies should be refused */ + bool refuse_after:1; + /* True if units of this type shall be startable only once and then never again */ bool once_only:1;