diff options
-rw-r--r-- | man/systemd.service.xml | 44 | ||||
-rw-r--r-- | src/core/service.c | 39 |
2 files changed, 56 insertions, 27 deletions
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 @@ <para>If set to <option>simple</option> (the default - value if neither + if neither <varname>Type=</varname> nor - <varname>BusName=</varname> are + <varname>BusName=</varname>, but + <varname>ExecStart=</varname> are specified), it is expected that the process configured with <varname>ExecStart=</varname> is the @@ -177,13 +178,17 @@ exits.</para> <para>Behavior of - <option>oneshot</option> is similar - to <option>simple</option>; however, - it is expected that the process has to + <option>oneshot</option> is similar to + <option>simple</option>; however, it + is expected that the process has to exit before systemd starts follow-up units. <varname>RemainAfterExit=</varname> is particularly useful for this type - of service.</para> + of service. This is the implied + default if neither + <varname>Type=</varname> or + <varname>ExecStart=</varname> are + specified.</para> <para>Behavior of <option>dbus</option> is similar to @@ -313,22 +318,27 @@ <para>When <varname>Type</varname> is not <option>oneshot</option>, only one - command may be given. When + command may and must be given. When <varname>Type=oneshot</varname> 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 <literal>\;</literal>. 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.</para> + have no effect. If no + <varname>ExecStart=</varname> is + specified, then the service must have + <varname>RemainAfterExit=yes</varname> + set.</para> <para>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, |