diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index fe83581b6e..ada92369e1 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -893,14 +893,6 @@
effect.
-
- FailureAction=
- Configure the action to take when the service enters a failed state. Takes the same values as
- the unit setting StartLimitAction= and executes the same actions (see
- systemd.unit5). Defaults to
- .
-
-
FileDescriptorStoreMax=
Configure how many file descriptors may be stored in the service manager for the service using
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 6047524623..6e9cdaebcf 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -877,11 +877,19 @@
semantics. Defaults to .
+
+ FailureAction=
+ Configure the action to take when the unit enters the failed state. Takes the same values as
+ the setting StartLimitAction= setting and executes the same actions (see
+ systemd.unit5). Defaults to
+ .
+
+
RebootArgument=
Configure the optional argument for the
reboot2 system call if
- StartLimitAction= or a service's FailureAction= is a reboot action. This
+ StartLimitAction= or FailureAction= is a reboot action. This
works just like the optional argument to systemctl reboot command.
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 6b83982cf8..7b6cb395d8 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -51,7 +51,6 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
- SD_BUS_PROPERTY("FailureAction", "s", property_get_emergency_action, offsetof(Service, emergency_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -82,6 +81,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("FailureAction", "s", property_get_emergency_action, offsetof(Unit, failure_action), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_VTABLE_END
};
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 7e5c889830..5344183508 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -798,6 +798,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("FailureAction", "s", property_get_emergency_action, offsetof(Unit, failure_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), 0),
SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), 0),
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 73b13977ed..5fc3371170 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -223,6 +223,7 @@ m4_dnl The following is a legacy alias name for compatibility
Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
Unit.StartLimitAction, config_parse_emergency_action, 0, offsetof(Unit, start_limit_action)
+Unit.FailureAction, config_parse_emergency_action, 0, offsetof(Unit, failure_action)
Unit.RebootArgument, config_parse_unit_string_printf, 0, offsetof(Unit, reboot_arg)
Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions)
Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions)
@@ -281,12 +282,12 @@ Service.TimeoutStartSec, config_parse_service_timeout, 0,
Service.TimeoutStopSec, config_parse_service_timeout, 0, 0
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
-m4_dnl The following three only exist for compatibility, they moved into Unit, see above
+m4_dnl The following five only exist for compatibility, they moved into Unit, see above
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
Service.StartLimitAction, config_parse_emergency_action, 0, offsetof(Unit, start_limit_action)
+Service.FailureAction, config_parse_emergency_action, 0, offsetof(Unit, failure_action)
Service.RebootArgument, config_parse_unit_path_printf, 0, offsetof(Unit, reboot_arg)
-Service.FailureAction, config_parse_emergency_action, 0, offsetof(Service, emergency_action)
Service.Type, config_parse_service_type, 0, offsetof(Service, type)
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only)
diff --git a/src/core/service.c b/src/core/service.c
index 445d1becc1..1dfde82816 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1532,9 +1532,6 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
- if (s->result != SERVICE_SUCCESS)
- emergency_action(UNIT(s)->manager, s->emergency_action, UNIT(s)->reboot_arg, "service failed");
-
if (allow_restart && service_shall_restart(s)) {
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
diff --git a/src/core/service.h b/src/core/service.h
index a529f48a63..a995c89605 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -174,8 +174,6 @@ struct Service {
char *status_text;
int status_errno;
- EmergencyAction emergency_action;
-
UnitRef accept_socket;
sd_event_source *timer_event_source;
diff --git a/src/core/unit.c b/src/core/unit.c
index d5e6b3891b..07656c117f 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2503,6 +2503,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
* units go directly from starting to inactive,
* without ever entering started.) */
unit_check_binds_to(u);
+
+ if (os != UNIT_FAILED && ns == UNIT_FAILED)
+ (void) emergency_action(u->manager, u->failure_action, u->reboot_arg, "unit failed");
}
unit_add_to_dbus_queue(u);
diff --git a/src/core/unit.h b/src/core/unit.h
index 2b11a285d4..d3403cba20 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -248,6 +248,8 @@ struct Unit {
/* Put a ratelimit on unit starting */
RateLimit start_limit;
EmergencyAction start_limit_action;
+
+ EmergencyAction failure_action;
char *reboot_arg;
/* Make sure we never enter endless loops with the check unneeded logic, or the BindsTo= logic */