167 lines
8.4 KiB
Diff
167 lines
8.4 KiB
Diff
From 96fb8242cc1ef6b0e28f6c86a4f57950095dd7f1 Mon Sep 17 00:00:00 2001
|
|
From: Lennart Poettering <lennart@poettering.net>
|
|
Date: Thu, 21 Aug 2014 18:50:42 +0200
|
|
Subject: [PATCH] service: allow services of Type=oneshot that specify no
|
|
ExecStart= commands
|
|
|
|
This is useful for services that simply want to run something on
|
|
shutdown, but not at bootup. They should only set ExecStop= but leave
|
|
ExecStart= unset.
|
|
---
|
|
man/systemd.service.xml | 44 +++++++++++++++++++++++++++-----------------
|
|
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,
|