From c80a9a33d04fb4381327a69ce929c94a9f1d0e6c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2020 11:48:57 +0100 Subject: [PATCH 1/3] 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; From f2e5e70410aba12aed9ac5184900218c3ae33a34 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2020 11:56:06 +0100 Subject: [PATCH 2/3] man: document that scope units can fail, but not due to process exit statusses Let's clarify that scope units can fail, but not due to process exit statusses. This hopefully clears up some confusion that manifested in #14142: scope units can fail, but for other reasons than assumed there. Fixes: #14142 --- man/systemd.scope.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/man/systemd.scope.xml b/man/systemd.scope.xml index daf3554db2..e4de2b0fd0 100644 --- a/man/systemd.scope.xml +++ b/man/systemd.scope.xml @@ -45,6 +45,15 @@ url="https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/">New Control Group Interfaces for an introduction on how to make use of scope units from programs. + + Note that unlike service units scope units have no "main" process, all processes in the scope are + equivalent. The lifecycle of the scope unit is thus not bound to the lifetime of one specific process but + to the existance of any processes in the scope. This also means that the exit status of these processes + do not cause the scope unit to enter a failure state. Scope units may still enter a failure state, for + example due to resource exhaustion or stop timeouts being reached, but not due to programs inside of them + terminating uncleanly. Since processes managed as scope units generally remain children of the original + process that forked them off it's also the job of that process to collect their exit statuses and act on + them as needed. From ab015b13df5e5a01eaceaba23eed6be9f7ade4a9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2020 15:13:10 +0100 Subject: [PATCH 3/3] man: small casing fix --- man/systemd.net-naming-scheme.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml index 70b4b27d7b..4fc85d40ec 100644 --- a/man/systemd.net-naming-scheme.xml +++ b/man/systemd.net-naming-scheme.xml @@ -79,7 +79,7 @@ sl - serial line IP (slip) + Serial line IP (slip) wl