summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard Phibel <rphibel@googlemail.com>2023-07-06 14:33:52 +0200
committerRichard Phibel <rphibel@googlemail.com>2023-07-06 14:33:52 +0200
commite568fea9fcd2189d4366df254a8a4031dc433762 (patch)
tree19ca4fa497560b5516319dba14cef427cb841f8d /src
parenttreewide: fix "an" before consonant U sounds (diff)
downloadsystemd-e568fea9fcd2189d4366df254a8a4031dc433762.tar.xz
systemd-e568fea9fcd2189d4366df254a8a4031dc433762.zip
service: add new RestartMode option
When this option is set to direct, the service restarts without entering a failed state. Dependent units are not notified of transitory failure. This is useful for the following use case: We have a target with Requires=my-service, After=my-service. my-service.service is a oneshot service and has Restart=on-failure in its definition. my-service.service can get stuck for various reasons and time out, in which case it is restarted. Currently, when it fails the first time, the target fails, even though my-service is restarted. The behavior we're looking for is that until my-service is not restarted anymore, the target stays pending waiting for my-service.service to start successfully or fail without being restarted anymore.
Diffstat (limited to 'src')
-rw-r--r--src/core/dbus-service.c6
-rw-r--r--src/core/load-fragment-gperf.gperf.in1
-rw-r--r--src/core/load-fragment.c2
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/service.c10
-rw-r--r--src/core/service.h11
-rw-r--r--src/shared/bus-unit-util.c1
-rw-r--r--src/test/test-tables.c1
8 files changed, 32 insertions, 1 deletions
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index ea82a665a6..6068c742ca 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -33,6 +33,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exit_type, service_exit_type, ServiceExitType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart_mode, service_restart_mode, ServiceRestartMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
static BUS_DEFINE_PROPERTY_GET2(property_get_notify_access, "s", Service, service_get_notify_access, notify_access_to_string);
static BUS_DEFINE_PROPERTY_GET(property_get_restart_usec_next, "t", Service, service_restart_usec_next);
@@ -322,6 +323,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ExitType", "s", property_get_exit_type, offsetof(Service, exit_type), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Restart", "s", property_get_restart, offsetof(Service, restart), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RestartMode", "s", property_get_restart_mode, offsetof(Service, restart_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PIDFile", "s", NULL, offsetof(Service, pid_file), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -512,6 +514,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(notify_access, NotifyAccess, notify_access
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_type, ServiceType, service_type_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_exit_type, ServiceExitType, service_exit_type_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_restart_from_string);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart_mode, ServiceRestartMode, service_restart_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
static BUS_DEFINE_SET_TRANSIENT_PARSE(timeout_failure_mode, ServiceTimeoutFailureMode, service_timeout_failure_mode_from_string);
@@ -660,6 +663,9 @@ static int bus_service_set_transient_property(
if (streq(name, "Restart"))
return bus_set_transient_service_restart(u, name, &s->restart, message, flags, error);
+ if (streq(name, "RestartMode"))
+ return bus_set_transient_service_restart_mode(u, name, &s->restart_mode, message, flags, error);
+
if (streq(name, "RestartPreventExitStatus"))
return bus_set_transient_exit_status(u, name, &s->restart_prevent_status, message, flags, error);
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 382b60ea90..b66adf2811 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -427,6 +427,7 @@ Service.RebootArgument, config_parse_unit_string_printf,
Service.Type, config_parse_service_type, 0, offsetof(Service, type)
Service.ExitType, config_parse_service_exit_type, 0, offsetof(Service, exit_type)
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
+Service.RestartMode, config_parse_service_restart_mode, 0, offsetof(Service, restart_mode)
Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only)
Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only)
Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index f0f60cf2ab..c69d47c228 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -142,6 +142,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_preserve_mode, exec_preserve_mode, Ex
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_exit_type, service_exit_type, ServiceExitType, "Failed to parse service exit type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart_mode, service_restart_mode, ServiceRestartMode, "Failed to parse service restart mode");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode, "Failed to parse timeout failure mode");
DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
@@ -6299,6 +6300,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_service_type, "SERVICETYPE" },
{ config_parse_service_exit_type, "SERVICEEXITTYPE" },
{ config_parse_service_restart, "SERVICERESTART" },
+ { config_parse_service_restart_mode, "SERVICERESTARTMODE" },
{ config_parse_service_timeout_failure_mode, "TIMEOUTMODE" },
{ config_parse_kill_mode, "KILLMODE" },
{ config_parse_signal, "SIGNAL" },
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 3cfb50969a..39378b3a3c 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -41,6 +41,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_failure_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_service_exit_type);
CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
+CONFIG_PARSER_PROTOTYPE(config_parse_service_restart_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_output);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_input);
diff --git a/src/core/service.c b/src/core/service.c
index a90b4de536..c6178cf2cd 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -2011,7 +2011,8 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
* are only transitionary and followed by an automatic restart. We have fine-grained
* low-level states for this though so that software can distinguish the permanent UNIT_INACTIVE
* state from this transitionary UNIT_INACTIVE state by looking at the low-level states. */
- service_set_state(s, restart_state);
+ if (s->restart_mode != SERVICE_RESTART_MODE_DIRECT)
+ service_set_state(s, restart_state);
r = service_arm_timer(s, /* relative= */ true, service_restart_usec_next(s));
if (r < 0)
@@ -5009,6 +5010,13 @@ static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
+static const char* const service_restart_mode_table[_SERVICE_RESTART_MODE_MAX] = {
+ [SERVICE_RESTART_MODE_NORMAL] = "normal",
+ [SERVICE_RESTART_MODE_DIRECT] = "direct",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_restart_mode, ServiceRestartMode);
+
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
[SERVICE_SIMPLE] = "simple",
[SERVICE_FORKING] = "forking",
diff --git a/src/core/service.h b/src/core/service.h
index 0e578c9280..3bf5fb1e14 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -91,6 +91,13 @@ typedef enum ServiceTimeoutFailureMode {
_SERVICE_TIMEOUT_FAILURE_MODE_INVALID = -EINVAL,
} ServiceTimeoutFailureMode;
+typedef enum ServiceRestartMode {
+ SERVICE_RESTART_MODE_NORMAL,
+ SERVICE_RESTART_MODE_DIRECT,
+ _SERVICE_RESTART_MODE_MAX,
+ _SERVICE_RESTART_MODE_INVALID = -EINVAL,
+} ServiceRestartMode;
+
struct ServiceFDStore {
Service *service;
@@ -108,6 +115,7 @@ struct Service {
ServiceType type;
ServiceExitType exit_type;
ServiceRestart restart;
+ ServiceRestartMode restart_mode;
ExitStatusSet restart_prevent_status;
ExitStatusSet restart_force_status;
ExitStatusSet success_status;
@@ -249,6 +257,9 @@ usec_t service_restart_usec_next(Service *s);
const char* service_restart_to_string(ServiceRestart i) _const_;
ServiceRestart service_restart_from_string(const char *s) _pure_;
+const char* service_restart_mode_to_string(ServiceRestartMode i) _const_;
+ServiceRestartMode service_restart_mode_from_string(const char *s) _pure_;
+
const char* service_type_to_string(ServiceType i) _const_;
ServiceType service_type_from_string(const char *s) _pure_;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index cc287feb8e..494484f0bf 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2206,6 +2206,7 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
"Type",
"ExitType",
"Restart",
+ "RestartMode",
"BusName",
"NotifyAccess",
"USBFunctionDescriptors",
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index 6301dedb09..db41c69df5 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -95,6 +95,7 @@ int main(int argc, char **argv) {
test_table(scope_state, SCOPE_STATE);
test_table(service_exec_command, SERVICE_EXEC_COMMAND);
test_table(service_restart, SERVICE_RESTART);
+ test_table(service_restart_mode, SERVICE_RESTART_MODE);
test_table(service_result, SERVICE_RESULT);
test_table(service_state, SERVICE_STATE);
test_table(service_type, SERVICE_TYPE);