summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS63
-rw-r--r--configure.ac4
-rw-r--r--man/systemd.service.xml82
-rw-r--r--man/systemd.unit.xml49
-rw-r--r--src/basic/time-util.h14
-rw-r--r--src/core/busname.c24
-rw-r--r--src/core/busname.h2
-rw-r--r--src/core/dbus-service.c9
-rw-r--r--src/core/dbus-unit.c4
-rw-r--r--src/core/load-fragment-gperf.gperf.m412
-rw-r--r--src/core/service.c27
-rw-r--r--src/core/service.h4
-rw-r--r--src/core/socket.c47
-rw-r--r--src/core/socket.h2
-rw-r--r--src/core/unit.c46
-rw-r--r--src/core/unit.h7
-rw-r--r--src/test/test-time.c13
17 files changed, 196 insertions, 213 deletions
diff --git a/NEWS b/NEWS
index e3b281af97..51c0faefd5 100644
--- a/NEWS
+++ b/NEWS
@@ -19,9 +19,9 @@ CHANGES WITH 229:
/etc/hosts.
* The systemd-resolve tool (which is a client utility for
- systemd-resolved, and previously experimental) has been beefed up
- considerably and is now fully supported and documented. It has moved
- from /usr/lib/systemd to /usr/bin because.
+ systemd-resolved, and previously experimental) has been improved
+ considerably and is now fully supported and documented. Hence it has
+ moved from /usr/lib/systemd to /usr/bin.
* /dev/disk/by-path/ symlink support has been (re-)added for virtio
devices.
@@ -32,8 +32,8 @@ CHANGES WITH 229:
new-style and inetd-style file descriptor passing. Use the new
--inetd switch to request inetd-style file descriptor passing.
- * Most systemd tools now honour a new $SYSTEMD_COLORS environment
- variable, which takes a boolean value. If set to false ANSI color
+ * Most systemd tools now honor a new $SYSTEMD_COLORS environment
+ variable, which takes a boolean value. If set to false, ANSI color
output is disabled in the tools even when run on a terminal that
supports it.
@@ -74,20 +74,19 @@ CHANGES WITH 229:
sd_journal_restart_fields().
* Most configurable timeouts in systemd now expect an argument of
- "infinity" to turn them off, instead of "0" as before. This follows
- of a logic where a timeout of "0" means "now", and one of "infinity"
- means "never". For compatibility where this was supported before 0
- continues to be accepted to turn off timeouts.
+ "infinity" to turn them off, instead of "0" as before. The semantics
+ from now on is that a timeout of "0" means "now", and "infinity"
+ means "never". To maintain backwards compatibility, "0" continues to
+ turn off previously existing timeout settings.
* "systemctl reload-or-try-restart" has been renamed to "systemctl
- try-reload-or-restart" to make clearer what it actually does, and
- indicate that the "try" logic applies to both reloading and
- restarting and not just restarting. The old name continues to be
- accepted for compatibility.
-
- * On boot-up when PID 1 detects that the system clock is before the
- release date of the systemd version in use, the clock is now bumped
- ahead to it. Previously, this was already done in timesyncd, in order
+ try-reload-or-restart" to clarify what it actually does: the "try"
+ logic applies to both reloading and restarting, not just restarting.
+ The old name continues to be accepted for compatibility.
+
+ * On boot-up, when PID 1 detects that the system clock is behind the
+ release date of the systemd version in use, the clock is now set
+ to the latter. Previously, this was already done in timesyncd, in order
to avoid running with clocks set to the various clock epochs such as
1902, 1938 or 1970. With this change the logic is now done in PID 1
in addition to timesyncd during early boot-up, so that it is enforced
@@ -99,37 +98,35 @@ CHANGES WITH 229:
by PID 1.
* A new service setting RuntimeMaxSec= has been added that may be used
- to specify a maximum runtime for a service. If the timeout is hit the
+ to specify a maximum runtime for a service. If the timeout is hit, the
service is terminated and put into a failure state.
- * A new service setting AmbientCapabilities= has been added, that
- allows configuration of additional Linux process capabilities that
- are passed to the activated processes. This is only available on very
+ * A new service setting AmbientCapabilities= has been added. It allows
+ configuration of additional Linux process capabilities that are
+ passed to the activated processes. This is only available on very
recent kernels.
* The process resource limit settings in service units may now be used
to configure hard and soft limits individually.
- * The various libsystemd APIs such as sd-bus or sd-event now publically
+ * The various libsystemd APIs such as sd-bus or sd-event now publicly
expose support for gcc's __attribute__((cleanup())) C
extension. Specifically, for many object destructor functions
- alternative versions whose names are suffixed with "p" and take a
- pointer to a pointer to the object to destroy instead of just a
- pointer to the object itself have been added. This is useful because
+ alternative versions whose names are suffixed with "p" have been
+ added, which take a pointer to a pointer to the object to destroy,
+ instead of just a pointer to the object itself. This is useful because
these destructor functions may be used directly as parameters to the
cleanup construct. Internally, systemd has been a heavy user of the
GCC extension since a long time, and with this change similar support
is now available to consumers of the library outside of systemd. Note
- of course, that by using this extension in your sources compatibility
- with old and strictly ANSI compatible C compilers is lost. However,
- any gcc or LLVM version of the last years has been supporting this
- extension just fine.
+ that by using this extension in your sources compatibility with old
+ and strictly ANSI compatible C compilers is lost. However, any gcc or
+ LLVM version of recent years have supported this extension.
* Timer units gained support for a new setting RandomizedDelaySec= that
- allows configuring an amount of additional randomized delay to add
- to the time a timer elapses. This is useful to distribute timer
- events over a time range to avoid load peaks in clusters or larger
- setups.
+ allows configuring some additional randomized delay to the configured
+ time. This is useful to spread out timer events to avoid load peaks in
+ clusters or larger setups.
* Calendar time specifications now support sub-second accuracy.
diff --git a/configure.ac b/configure.ac
index 1517b4e197..0374b3f39b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -556,7 +556,7 @@ AM_CONDITIONAL(HAVE_ZLIB, [test "$have_zlib" = "yes"])
# ------------------------------------------------------------------------------
have_bzip2=no
-AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--enable-bzip2], [Disable optional BZIP2 support]))
+AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--enable-bzip2], [Enable optional BZIP2 support]))
AS_IF([test "x$enable_bzip2" != "xno"], [
AC_CHECK_HEADERS(bzlib.h,
[AC_DEFINE(HAVE_BZIP2, 1, [Define if BZIP2 is available])
@@ -1176,7 +1176,7 @@ AC_SUBST([EFI_ARCH])
AC_SUBST([EFI_MACHINE_TYPE_NAME])
have_gnuefi=no
-AC_ARG_ENABLE(gnuefi, AS_HELP_STRING([--enable-gnuefi], [Disable optional gnuefi support]))
+AC_ARG_ENABLE(gnuefi, AS_HELP_STRING([--enable-gnuefi], [Enable optional gnuefi support]))
AS_IF([test "x$enable_gnuefi" != "xno"], [
AC_CHECK_HEADERS(efi/${EFI_ARCH}/efibind.h,
[AC_DEFINE(HAVE_GNUEFI, 1, [Define if gnuefi is available])
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 4cd36ac70e..2145e33d05 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -874,85 +874,11 @@
</varlistentry>
<varlistentry>
- <term><varname>StartLimitInterval=</varname></term>
- <term><varname>StartLimitBurst=</varname></term>
-
- <listitem><para>Configure service start rate limiting. By
- default, services which are started more than 5 times within
- 10 seconds are not permitted to start any more times until the
- 10 second interval ends. With these two options, this rate
- limiting may be modified. Use
- <varname>StartLimitInterval=</varname> to configure the
- checking interval (defaults to
- <varname>DefaultStartLimitInterval=</varname> in manager
- configuration file, set to 0 to disable any kind of rate
- limiting). Use <varname>StartLimitBurst=</varname> to
- configure how many starts per interval are allowed (defaults
- to <varname>DefaultStartLimitBurst=</varname> in manager
- configuration file). These configuration options are
- particularly useful in conjunction with
- <varname>Restart=</varname>; however, they apply to all kinds
- of starts (including manual), not just those triggered by the
- <varname>Restart=</varname> logic. Note that units which are
- configured for <varname>Restart=</varname> and which reach the
- start limit are not attempted to be restarted anymore;
- however, they may still be restarted manually at a later
- point, from which point on, the restart logic is again
- activated. Note that <command>systemctl reset-failed</command>
- will cause the restart rate counter for a service to be
- flushed, which is useful if the administrator wants to
- manually start a service and the start limit interferes with
- that.</para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><varname>StartLimitAction=</varname></term>
-
- <listitem><para>Configure the action to take if the rate limit
- configured with <varname>StartLimitInterval=</varname> and
- <varname>StartLimitBurst=</varname> is hit. Takes one of
- <option>none</option>,
- <option>reboot</option>,
- <option>reboot-force</option>,
- <option>reboot-immediate</option>,
- <option>poweroff</option>,
- <option>poweroff-force</option> or
- <option>poweroff-immediate</option>. If
- <option>none</option> is set, hitting the rate limit will
- trigger no action besides that the start will not be
- permitted. <option>reboot</option> causes a reboot following
- the normal shutdown procedure (i.e. equivalent to
- <command>systemctl reboot</command>).
- <option>reboot-force</option> causes a forced reboot which
- will terminate all processes forcibly but should cause no
- dirty file systems on reboot (i.e. equivalent to
- <command>systemctl reboot -f</command>) and
- <option>reboot-immediate</option> causes immediate execution
- of the
- <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- system call, which might result in data loss. Similarly,
- <option>poweroff</option>, <option>poweroff-force</option>,
- <option>poweroff-immediate</option> have the effect of
- powering down the system with similar semantics. Defaults to
- <option>none</option>.</para></listitem>
- </varlistentry>
-
- <varlistentry>
<term><varname>FailureAction=</varname></term>
- <listitem><para>Configure the action to take when the service
- enters a failed state. Takes the same values as
- <varname>StartLimitAction=</varname> and executes the same
- actions. Defaults to <option>none</option>. </para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><varname>RebootArgument=</varname></term>
- <listitem><para>Configure the optional argument for the
- <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- system call if <varname>StartLimitAction=</varname> or
- <varname>FailureAction=</varname> is a reboot action. This
- works just like the optional argument to <command>systemctl
- reboot</command> command.</para></listitem>
+ <listitem><para>Configure the action to take when the service enters a failed state. Takes the same values as
+ the unit setting <varname>StartLimitAction=</varname> and executes the same actions (see
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>). Defaults to
+ <option>none</option>. </para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index a95c160954..2d3274bbfb 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -760,6 +760,55 @@
</varlistentry>
<varlistentry>
+ <term><varname>StartLimitInterval=</varname></term>
+ <term><varname>StartLimitBurst=</varname></term>
+
+ <listitem><para>Configure unit start rate limiting. By default, units which are started more than 5 times
+ within 10 seconds are not permitted to start any more times until the 10 second interval ends. With these two
+ options, this rate limiting may be modified. Use <varname>StartLimitInterval=</varname> to configure the
+ checking interval (defaults to <varname>DefaultStartLimitInterval=</varname> in manager configuration file, set
+ to 0 to disable any kind of rate limiting). Use <varname>StartLimitBurst=</varname> to configure how many
+ starts per interval are allowed (defaults to <varname>DefaultStartLimitBurst=</varname> in manager
+ configuration file). These configuration options are particularly useful in conjunction with the service
+ setting <varname>Restart=</varname> (see
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>); however,
+ they apply to all kinds of starts (including manual), not just those triggered by the
+ <varname>Restart=</varname> logic. Note that units which are configured for <varname>Restart=</varname> and
+ which reach the start limit are not attempted to be restarted anymore; however, they may still be restarted
+ manually at a later point, from which point on, the restart logic is again activated. Note that
+ <command>systemctl reset-failed</command> will cause the restart rate counter for a service to be flushed,
+ which is useful if the administrator wants to manually start a unit and the start limit interferes with
+ that.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>StartLimitAction=</varname></term>
+
+ <listitem><para>Configure the action to take if the rate limit configured with
+ <varname>StartLimitInterval=</varname> and <varname>StartLimitBurst=</varname> is hit. Takes one of
+ <option>none</option>, <option>reboot</option>, <option>reboot-force</option>,
+ <option>reboot-immediate</option>, <option>poweroff</option>, <option>poweroff-force</option> or
+ <option>poweroff-immediate</option>. If <option>none</option> is set, hitting the rate limit will trigger no
+ action besides that the start will not be permitted. <option>reboot</option> causes a reboot following the
+ normal shutdown procedure (i.e. equivalent to <command>systemctl reboot</command>).
+ <option>reboot-force</option> causes a forced reboot which will terminate all processes forcibly but should
+ cause no dirty file systems on reboot (i.e. equivalent to <command>systemctl reboot -f</command>) and
+ <option>reboot-immediate</option> causes immediate execution of the
+ <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call, which
+ might result in data loss. Similarly, <option>poweroff</option>, <option>poweroff-force</option>,
+ <option>poweroff-immediate</option> have the effect of powering down the system with similar
+ semantics. Defaults to <option>none</option>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>RebootArgument=</varname></term>
+ <listitem><para>Configure the optional argument for the
+ <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call if
+ <varname>StartLimitAction=</varname> or a service's <varname>FailureAction=</varname> is a reboot action. This
+ works just like the optional argument to <command>systemctl reboot</command> command.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>ConditionArchitecture=</varname></term>
<term><varname>ConditionVirtualization=</varname></term>
<term><varname>ConditionHost=</varname></term>
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index 26b5a4df0a..9894e626c5 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -139,11 +139,13 @@ static inline usec_t usec_add(usec_t a, usec_t b) {
static inline usec_t usec_sub(usec_t timestamp, int64_t delta) {
if (delta < 0)
- timestamp = usec_add(timestamp, (usec_t) (-delta));
- else if (timestamp > (usec_t) delta)
- timestamp -= delta;
- else
- timestamp = 0;
+ return usec_add(timestamp, (usec_t) (-delta));
- return timestamp;
+ if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */
+ return USEC_INFINITY;
+
+ if (timestamp < (usec_t) delta)
+ return 0;
+
+ return timestamp - delta;
}
diff --git a/src/core/busname.c b/src/core/busname.c
index 8427459953..de2a21ccde 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -943,7 +943,6 @@ static void busname_reset_failed(Unit *u) {
static void busname_trigger_notify(Unit *u, Unit *other) {
BusName *n = BUSNAME(u);
- Service *s;
assert(n);
assert(other);
@@ -951,19 +950,22 @@ static void busname_trigger_notify(Unit *u, Unit *other) {
if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
return;
- if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
+ if (other->start_limit_hit) {
+ busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT);
return;
+ }
- s = SERVICE(other);
+ if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
+ return;
- if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT)
- busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT);
- else if (IN_SET(s->state,
- SERVICE_DEAD, SERVICE_FAILED,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
- SERVICE_AUTO_RESTART))
+ if (IN_SET(SERVICE(other)->state,
+ SERVICE_DEAD, SERVICE_FAILED,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+ SERVICE_AUTO_RESTART))
busname_enter_listening(n);
+
+ if (SERVICE(other)->state == SERVICE_RUNNING)
+ busname_set_state(n, BUSNAME_RUNNING);
}
static int busname_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
@@ -1004,7 +1006,7 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
[BUSNAME_FAILURE_EXIT_CODE] = "exit-code",
[BUSNAME_FAILURE_SIGNAL] = "signal",
[BUSNAME_FAILURE_CORE_DUMP] = "core-dump",
- [BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent",
+ [BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
diff --git a/src/core/busname.h b/src/core/busname.h
index 8d736fb144..6b6f6c62d4 100644
--- a/src/core/busname.h
+++ b/src/core/busname.h
@@ -31,7 +31,7 @@ typedef enum BusNameResult {
BUSNAME_FAILURE_EXIT_CODE,
BUSNAME_FAILURE_SIGNAL,
BUSNAME_FAILURE_CORE_DUMP,
- BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT,
+ BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT,
_BUSNAME_RESULT_MAX,
_BUSNAME_RESULT_INVALID = -1
} BusNameResult;
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 67ec3ae75c..03eecca911 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -50,10 +50,11 @@ 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("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Service, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
+ /* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */
+ 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_failure_action, offsetof(Unit, start_limit_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_PROPERTY("FailureAction", "s", property_get_failure_action, offsetof(Service, failure_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),
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 2c96d89d04..33da1a61e9 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -702,6 +702,10 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NetClass", "u", NULL, offsetof(Unit, cgroup_netclass_id), 0),
+ SD_BUS_PROPERTY("StartLimitInterval", "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_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 2507db1932..c2a47c7b11 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -164,6 +164,10 @@ Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LE
Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout)
Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action)
Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg)
+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_failure_action, 0, offsetof(Unit, start_limit_action)
+Unit.RebootArgument, config_parse_string, 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)
Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions)
@@ -216,10 +220,10 @@ Service.TimeoutStartSec, config_parse_service_timeout, 0,
Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec)
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
-Service.StartLimitInterval, config_parse_sec, 0, offsetof(Service, start_limit.interval)
-Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst)
-Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Service, start_limit_action)
-Service.RebootArgument, config_parse_string, 0, offsetof(Service, reboot_arg)
+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_failure_action, 0, offsetof(Unit, start_limit_action)
+Service.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg)
Service.FailureAction, config_parse_failure_action, 0, offsetof(Service, failure_action)
Service.Type, config_parse_service_type, 0, offsetof(Service, type)
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
diff --git a/src/core/service.c b/src/core/service.c
index d87f472e9f..ac7e41d777 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -117,8 +117,6 @@ static void service_init(Unit *u) {
s->stdin_fd = s->stdout_fd = s->stderr_fd = -1;
s->guess_main_pid = true;
- RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst);
-
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
}
@@ -300,7 +298,6 @@ static void service_done(Unit *u) {
s->pid_file = mfree(s->pid_file);
s->status_text = mfree(s->status_text);
- s->reboot_arg = mfree(s->reboot_arg);
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
@@ -1420,7 +1417,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
if (s->result != SERVICE_SUCCESS) {
log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result));
- failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg);
+ failure_action(UNIT(s)->manager, s->failure_action, UNIT(s)->reboot_arg);
}
if (allow_restart && service_shall_restart(s)) {
@@ -1987,20 +1984,8 @@ fail:
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
-static int service_start_limit_test(Service *s) {
- assert(s);
-
- if (ratelimit_test(&s->start_limit))
- return 0;
-
- log_unit_warning(UNIT(s), "Start request repeated too quickly.");
-
- return failure_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg);
-}
-
static int service_start(Unit *u) {
Service *s = SERVICE(u);
- int r;
assert(s);
@@ -2027,13 +2012,6 @@ static int service_start(Unit *u) {
assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
- /* Make sure we don't enter a busy loop of some kind. */
- r = service_start_limit_test(s);
- if (r < 0) {
- service_enter_dead(s, SERVICE_FAILURE_START_LIMIT, false);
- return r;
- }
-
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
s->main_pid_known = false;
@@ -3246,8 +3224,6 @@ static void service_reset_failed(Unit *u) {
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
-
- RATELIMIT_RESET(s->start_limit);
}
static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
@@ -3315,7 +3291,6 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
[SERVICE_FAILURE_SIGNAL] = "signal",
[SERVICE_FAILURE_CORE_DUMP] = "core-dump",
[SERVICE_FAILURE_WATCHDOG] = "watchdog",
- [SERVICE_FAILURE_START_LIMIT] = "start-limit"
};
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
diff --git a/src/core/service.h b/src/core/service.h
index 0580e076cb..d342e000bb 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -86,7 +86,6 @@ typedef enum ServiceResult {
SERVICE_FAILURE_SIGNAL,
SERVICE_FAILURE_CORE_DUMP,
SERVICE_FAILURE_WATCHDOG,
- SERVICE_FAILURE_START_LIMIT,
_SERVICE_RESULT_MAX,
_SERVICE_RESULT_INVALID = -1
} ServiceResult;
@@ -176,10 +175,7 @@ struct Service {
char *status_text;
int status_errno;
- RateLimit start_limit;
- FailureAction start_limit_action;
FailureAction failure_action;
- char *reboot_arg;
UnitRef accept_socket;
diff --git a/src/core/socket.c b/src/core/socket.c
index 21dbad4240..976687af41 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2700,23 +2700,6 @@ static void socket_reset_failed(Unit *u) {
s->result = SOCKET_SUCCESS;
}
-static void socket_notify_service_dead(Socket *s, bool failed_permanent) {
- assert(s);
-
- /* The service is dead. Dang!
- *
- * This is strictly for one-instance-for-all-connections
- * services. */
-
- if (s->state == SOCKET_RUNNING) {
- log_unit_debug(UNIT(s), "Got notified about service death (failed permanently: %s)", yes_no(failed_permanent));
- if (failed_permanent)
- socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT);
- else
- socket_enter_listening(s);
- }
-}
-
void socket_connection_unref(Socket *s) {
assert(s);
@@ -2733,34 +2716,30 @@ void socket_connection_unref(Socket *s) {
static void socket_trigger_notify(Unit *u, Unit *other) {
Socket *s = SOCKET(u);
- Service *se;
assert(u);
assert(other);
/* Don't propagate state changes from the service if we are
already down or accepting connections */
- if ((s->state != SOCKET_RUNNING &&
- s->state != SOCKET_LISTENING) ||
- s->accept)
+ if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING) || s->accept)
return;
- if (other->load_state != UNIT_LOADED ||
- other->type != UNIT_SERVICE)
+ if (other->start_limit_hit) {
+ socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT);
return;
+ }
- se = SERVICE(other);
-
- if (se->state == SERVICE_FAILED)
- socket_notify_service_dead(s, se->result == SERVICE_FAILURE_START_LIMIT);
+ if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
+ return;
- if (se->state == SERVICE_DEAD ||
- se->state == SERVICE_FINAL_SIGTERM ||
- se->state == SERVICE_FINAL_SIGKILL ||
- se->state == SERVICE_AUTO_RESTART)
- socket_notify_service_dead(s, false);
+ if (IN_SET(SERVICE(other)->state,
+ SERVICE_DEAD, SERVICE_FAILED,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+ SERVICE_AUTO_RESTART))
+ socket_enter_listening(s);
- if (se->state == SERVICE_RUNNING)
+ if (SERVICE(other)->state == SERVICE_RUNNING)
socket_set_state(s, SOCKET_RUNNING);
}
@@ -2816,7 +2795,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
[SOCKET_FAILURE_EXIT_CODE] = "exit-code",
[SOCKET_FAILURE_SIGNAL] = "signal",
[SOCKET_FAILURE_CORE_DUMP] = "core-dump",
- [SOCKET_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent"
+ [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
};
DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
diff --git a/src/core/socket.h b/src/core/socket.h
index 5d1ae7718b..b537b026a7 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -52,7 +52,7 @@ typedef enum SocketResult {
SOCKET_FAILURE_EXIT_CODE,
SOCKET_FAILURE_SIGNAL,
SOCKET_FAILURE_CORE_DUMP,
- SOCKET_FAILURE_SERVICE_FAILED_PERMANENT,
+ SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
_SOCKET_RESULT_MAX,
_SOCKET_RESULT_INVALID = -1
} SocketResult;
diff --git a/src/core/unit.c b/src/core/unit.c
index 93395faad0..ffefae2b94 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -99,6 +99,7 @@ Unit *unit_new(Manager *m, size_t size) {
u->cgroup_inotify_wd = -1;
u->job_timeout = USEC_INFINITY;
+ RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst);
RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
return u;
@@ -557,6 +558,8 @@ void unit_free(Unit *u) {
condition_free_list(u->conditions);
condition_free_list(u->asserts);
+ free(u->reboot_arg);
+
unit_ref_unset(&u->slice);
while (u->refs)
@@ -1444,23 +1447,36 @@ void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
unit_status_print_starting_stopping(u, t);
}
+static int unit_start_limit_test(Unit *u) {
+ assert(u);
+
+ if (ratelimit_test(&u->start_limit)) {
+ u->start_limit_hit = false;
+ return 0;
+ }
+
+ log_unit_warning(u, "Start request repeated too quickly.");
+ u->start_limit_hit = true;
+
+ return failure_action(u->manager, u->start_limit_action, u->reboot_arg);
+}
+
/* Errors:
- * -EBADR: This unit type does not support starting.
- * -EALREADY: Unit is already started.
- * -EAGAIN: An operation is already in progress. Retry later.
- * -ECANCELED: Too many requests for now.
- * -EPROTO: Assert failed
+ * -EBADR: This unit type does not support starting.
+ * -EALREADY: Unit is already started.
+ * -EAGAIN: An operation is already in progress. Retry later.
+ * -ECANCELED: Too many requests for now.
+ * -EPROTO: Assert failed
+ * -EINVAL: Unit not loaded
+ * -EOPNOTSUPP: Unit type not supported
*/
int unit_start(Unit *u) {
UnitActiveState state;
Unit *following;
+ int r;
assert(u);
- /* Units that aren't loaded cannot be started */
- if (u->load_state != UNIT_LOADED)
- return -EINVAL;
-
/* If this is already started, then this will succeed. Note
* that this will even succeed if this unit is not startable
* by the user. This is relied on to detect when we need to
@@ -1469,6 +1485,15 @@ int unit_start(Unit *u) {
if (UNIT_IS_ACTIVE_OR_RELOADING(state))
return -EALREADY;
+ /* Make sure we don't enter a busy loop of some kind. */
+ r = unit_start_limit_test(u);
+ if (r < 0)
+ return r;
+
+ /* Units that aren't loaded cannot be started */
+ if (u->load_state != UNIT_LOADED)
+ return -EINVAL;
+
/* If the conditions failed, don't do anything at all. If we
* already are activating this call might still be useful to
* speed up activation in case there is some hold-off time,
@@ -2986,6 +3011,9 @@ void unit_reset_failed(Unit *u) {
if (UNIT_VTABLE(u)->reset_failed)
UNIT_VTABLE(u)->reset_failed(u);
+
+ RATELIMIT_RESET(u->start_limit);
+ u->start_limit_hit = false;
}
Unit *unit_following(Unit *u) {
diff --git a/src/core/unit.h b/src/core/unit.h
index 37a7a51181..601e763ce2 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -165,6 +165,11 @@ struct Unit {
/* Error code when we didn't manage to load the unit (negative) */
int load_error;
+ /* Put a ratelimit on unit starting */
+ RateLimit start_limit;
+ FailureAction start_limit_action;
+ char *reboot_arg;
+
/* Make sure we never enter endless loops with the check unneeded logic, or the BindsTo= logic */
RateLimit auto_stop_ratelimit;
@@ -228,6 +233,8 @@ struct Unit {
bool cgroup_members_mask_valid:1;
bool cgroup_subtree_mask_valid:1;
+ bool start_limit_hit:1;
+
/* Did we already invoke unit_coldplug() for this unit? */
bool coldplugged:1;
};
diff --git a/src/test/test-time.c b/src/test/test-time.c
index 69e12dd94c..9062c3f3c1 100644
--- a/src/test/test-time.c
+++ b/src/test/test-time.c
@@ -189,6 +189,18 @@ static void test_usec_add(void) {
assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY);
}
+static void test_usec_sub(void) {
+ assert_se(usec_sub(0, 0) == 0);
+ assert_se(usec_sub(4, 1) == 3);
+ assert_se(usec_sub(4, 4) == 0);
+ assert_se(usec_sub(4, 5) == 0);
+ assert_se(usec_sub(USEC_INFINITY-3, -3) == USEC_INFINITY);
+ assert_se(usec_sub(USEC_INFINITY-3, -3) == USEC_INFINITY);
+ assert_se(usec_sub(USEC_INFINITY-3, -4) == USEC_INFINITY);
+ assert_se(usec_sub(USEC_INFINITY-3, -5) == USEC_INFINITY);
+ assert_se(usec_sub(USEC_INFINITY, 5) == USEC_INFINITY);
+}
+
int main(int argc, char *argv[]) {
uintmax_t x;
@@ -201,6 +213,7 @@ int main(int argc, char *argv[]) {
test_timezone_is_valid();
test_get_timezones();
test_usec_add();
+ test_usec_sub();
/* Ensure time_t is signed */
assert_cc((time_t) -1 < (time_t) 1);