diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 5c4bd6569f..e584a1f006 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -139,9 +139,10 @@
If set to
(the default
- value if neither
+ if neither
Type= nor
- BusName= are
+ BusName=, but
+ ExecStart= are
specified), it is expected that the
process configured with
ExecStart= is the
@@ -177,13 +178,17 @@
exits.Behavior of
- is similar
- to ; however,
- it is expected that the process has to
+ is similar to
+ ; however, it
+ is expected that the process has to
exit before systemd starts follow-up
units. RemainAfterExit=
is particularly useful for this type
- of service.
+ of service. This is the implied
+ default if neither
+ Type= or
+ ExecStart= are
+ specified.
Behavior of
is similar to
@@ -313,22 +318,27 @@
When Type is
not , only one
- command may be given. When
+ command may and must be given. When
Type=oneshot is
- used, more than one command may be
- specified. Multiple command lines may
- be concatenated in a single directive
- by separating them with semicolons
- (these semicolons must be passed as
- separate words). Alternatively, this
- directive may be specified more than
- once with the same effect.
- Lone semicolons may be escaped as
+ used, none or more than one command
+ may be specified. Multiple command
+ lines may be concatenated in a single
+ directive by separating them with
+ semicolons (these semicolons must be
+ passed as separate
+ words). Alternatively, this directive
+ may be specified more than once with
+ the same effect. Lone semicolons may
+ be escaped as
\;. If the empty
string is assigned to this option, the
list of commands to start is reset,
prior assignments of this option will
- have no effect.
+ have no effect. If no
+ ExecStart= is
+ specified, then the service must have
+ RemainAfterExit=yes
+ set.Each command line is split on
whitespace, with the first item being
diff --git a/src/core/service.c b/src/core/service.c
index 7d6ea73e05..1b864c4c8c 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -313,14 +313,23 @@ static int service_verify(Service *s) {
if (UNIT(s)->load_state != UNIT_LOADED)
return 0;
- if (!s->exec_command[SERVICE_EXEC_START]) {
- log_error_unit(UNIT(s)->id, "%s lacks ExecStart setting. Refusing.", UNIT(s)->id);
+ if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP]) {
+ log_error_unit(UNIT(s)->id, "%s lacks both ExecStart= and ExecStop= setting. Refusing.", UNIT(s)->id);
return -EINVAL;
}
- if (s->type != SERVICE_ONESHOT &&
- s->exec_command[SERVICE_EXEC_START]->command_next) {
- log_error_unit(UNIT(s)->id, "%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) {
+ log_error_unit(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ return -EINVAL;
+ }
+
+ if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START]) {
+ log_error_unit(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.", UNIT(s)->id);
+ return -EINVAL;
+ }
+
+ if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) {
+ log_error_unit(UNIT(s)->id, "%s has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
return -EINVAL;
}
@@ -410,8 +419,15 @@ static int service_load(Unit *u) {
if (r < 0)
return r;
- if (s->type == _SERVICE_TYPE_INVALID)
- s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE;
+ if (s->type == _SERVICE_TYPE_INVALID) {
+ /* Figure out a type automatically */
+ if (s->bus_name)
+ s->type = SERVICE_DBUS;
+ else if (s->exec_command[SERVICE_EXEC_START])
+ s->type = SERVICE_SIMPLE;
+ else
+ s->type = SERVICE_ONESHOT;
+ }
/* Oneshot services have disabled start timeout by default */
if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined)
@@ -1309,9 +1325,6 @@ static void service_enter_start(Service *s) {
assert(s);
- assert(s->exec_command[SERVICE_EXEC_START]);
- assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT);
-
service_unwatch_control_pid(s);
service_unwatch_main_pid(s);
@@ -1332,6 +1345,12 @@ static void service_enter_start(Service *s) {
c = s->main_command = s->exec_command[SERVICE_EXEC_START];
}
+ if (!c) {
+ assert(s->type == SERVICE_ONESHOT);
+ service_enter_start_post(s);
+ return;
+ }
+
r = service_spawn(s,
c,
IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_ONESHOT) ? s->timeout_start_usec : 0,