diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index be4c1282f5..7196f361e1 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -9357,6 +9357,10 @@ node /org/freedesktop/systemd1/unit/cups_2epath {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u DirectoryMode = ...;
readonly s Result = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly t TriggerLimitIntervalUSec = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly u TriggerLimitBurst = ...;
};
interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... };
@@ -9369,6 +9373,10 @@ node /org/freedesktop/systemd1/unit/cups_2epath {
+
+
+
+
@@ -9389,6 +9397,10 @@ node /org/freedesktop/systemd1/unit/cups_2epath {
+
+
+
+
diff --git a/man/systemd.path.xml b/man/systemd.path.xml
index 44afba08c9..fd3d4efc2a 100644
--- a/man/systemd.path.xml
+++ b/man/systemd.path.xml
@@ -186,6 +186,21 @@
in question. Takes an access mode in octal notation. Defaults
to .
+
+ TriggerLimitIntervalSec=
+ TriggerLimitBurst=
+
+ Configures a limit on how often this path unit may be activated within a specific time
+ interval. The TriggerLimitIntervalSec= may be used to configure the length of the time
+ interval in the usual time units us, ms, s,
+ min, h, … and defaults to 2s (See
+ systemd.time7 for details on
+ the various time units understood). The TriggerLimitBurst= setting takes a positive integer
+ value and specifies the number of permitted activations per time interval, and defaults to 200. Set either to
+ 0 to disable any form of trigger rate limiting. If the limit is hit, the unit is placed into a failure mode,
+ and will not watch the path(s) anymore until restarted. Note that this limit is enforced before the service
+ activation is enqueued.
+
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
index e025c31532..f143ad5d4a 100644
--- a/src/core/dbus-path.c
+++ b/src/core/dbus-path.c
@@ -49,6 +49,8 @@ const sd_bus_vtable bus_path_vtable[] = {
SD_BUS_PROPERTY("MakeDirectory", "b", bus_property_get_bool, offsetof(Path, make_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Path, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Path, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Path, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Path, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
@@ -136,6 +138,12 @@ static int bus_path_set_transient_property(
return 1;
}
+ if (streq(name, "TriggerLimitBurst"))
+ return bus_set_transient_unsigned(u, name, &p->trigger_limit.burst, message, flags, error);
+
+ if (streq(name, "TriggerLimitIntervalUSec"))
+ return bus_set_transient_usec(u, name, &p->trigger_limit.interval, message, flags, error);
+
return 0;
}
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 6baa3b3b74..deea540e10 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -542,6 +542,8 @@ Path.DirectoryNotEmpty, config_parse_path_spec,
Path.Unit, config_parse_trigger_unit, 0, 0
Path.MakeDirectory, config_parse_bool, 0, offsetof(Path, make_directory)
Path.DirectoryMode, config_parse_mode, 0, offsetof(Path, directory_mode)
+Path.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Path, trigger_limit.interval)
+Path.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Path, trigger_limit.burst)
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Slice') }}
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Scope') }}
{{ KILL_CONTEXT_CONFIG_ITEMS('Scope') }}
diff --git a/src/core/path.c b/src/core/path.c
index f89e35a001..0b736f00bf 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -266,8 +266,8 @@ static void path_init(Unit *u) {
p->directory_mode = 0755;
- p->trigger_limit.interval = 2 * USEC_PER_SEC;
- p->trigger_limit.burst = 200;
+ p->trigger_limit.interval = USEC_INFINITY;
+ p->trigger_limit.burst = UINT_MAX;
}
void path_free_specs(Path *p) {
@@ -356,6 +356,16 @@ static int path_add_trigger_dependencies(Path *p) {
static int path_add_extras(Path *p) {
int r;
+ assert(p);
+
+ /* To avoid getting pid1 in a busy-loop state (eg: failed condition on associated service),
+ * set a default trigger limit if the user didn't specify any. */
+ if (p->trigger_limit.interval == USEC_INFINITY)
+ p->trigger_limit.interval = 2 * USEC_PER_SEC;
+
+ if (p->trigger_limit.burst == UINT_MAX)
+ p->trigger_limit.burst = 200;
+
r = path_add_trigger_dependencies(p);
if (r < 0)
return r;
@@ -403,12 +413,16 @@ static void path_dump(Unit *u, FILE *f, const char *prefix) {
"%sResult: %s\n"
"%sUnit: %s\n"
"%sMakeDirectory: %s\n"
- "%sDirectoryMode: %04o\n",
+ "%sDirectoryMode: %04o\n"
+ "%sTriggerLimitIntervalSec: %s\n"
+ "%sTriggerLimitBurst: %u\n",
prefix, path_state_to_string(p->state),
prefix, path_result_to_string(p->result),
prefix, trigger ? trigger->id : "n/a",
prefix, yes_no(p->make_directory),
- prefix, p->directory_mode);
+ prefix, p->directory_mode,
+ prefix, FORMAT_TIMESPAN(p->trigger_limit.interval, USEC_PER_SEC),
+ prefix, p->trigger_limit.burst);
LIST_FOREACH(spec, s, p->specs)
path_spec_dump(s, f, prefix);
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index c58394e63e..dcce530c99 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2113,6 +2113,12 @@ static int bus_append_path_property(sd_bus_message *m, const char *field, const
return 1;
}
+ if (streq(field, "TriggerLimitBurst"))
+ return bus_append_safe_atou(m, field, eq);
+
+ if (streq(field, "TriggerLimitIntervalSec"))
+ return bus_append_parse_sec_rename(m, field, eq);
+
return 0;
}
diff --git a/test/fuzz/fuzz-unit-file/directives.path b/test/fuzz/fuzz-unit-file/directives.path
index 213beff0f1..3c4df76b23 100644
--- a/test/fuzz/fuzz-unit-file/directives.path
+++ b/test/fuzz/fuzz-unit-file/directives.path
@@ -7,4 +7,6 @@ PathChanged=
PathExists=
PathExistsGlob=
PathModified=
+TriggerLimitBurst=
+TriggerLimitIntervalSec=
Unit=