diff --git a/man/udev.conf.xml b/man/udev.conf.xml
index 29c9743d1d6..7b7cae16b20 100644
--- a/man/udev.conf.xml
+++ b/man/udev.conf.xml
@@ -42,7 +42,7 @@
- udev_log
+ udev_log=
The log level. Valid values are the numerical
@@ -51,6 +51,42 @@
.
+
+
+ children_max=
+
+
+ An integer. The maximum number of events executed in parallel.
+
+ This is the same as the option.
+
+
+
+
+ exec_delay=
+
+
+ An integer. Delay the execution of RUN
+ instructions by the given number of seconds. This option
+ might be useful when debugging system crashes during
+ coldplug caused by loading non-working kernel
+ modules.
+
+ This is the same as the option.
+
+
+
+
+ event_timeout=
+
+
+ An integer. The number of seconds to wait for events to finish. After
+ this time, the event will be terminated. The default is 180 seconds.
+
+ This is the same as the option.
+
+
+
diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c
index a603867b16e..057aabcd542 100644
--- a/src/shared/udev-util.c
+++ b/src/shared/udev-util.c
@@ -6,36 +6,68 @@
#include "alloc-util.h"
#include "fileio.h"
#include "log.h"
+#include "parse-util.h"
#include "string-util.h"
#include "udev-util.h"
+#include "udev.h"
-int udev_parse_config(void) {
- _cleanup_free_ char *val = NULL;
- const char *log;
- size_t n;
+int udev_parse_config_full(
+ unsigned *ret_children_max,
+ usec_t *ret_exec_delay_usec,
+ usec_t *ret_event_timeout_usec) {
+
+ _cleanup_free_ char *log_val = NULL, *children_max = NULL, *exec_delay = NULL, *event_timeout = NULL;
int r;
- r = parse_env_file(NULL, "/etc/udev/udev.conf", NEWLINE, "udev_log", &val, NULL);
- if (r == -ENOENT || !val)
+ r = parse_env_file(NULL, "/etc/udev/udev.conf", NEWLINE,
+ "udev_log", &log_val,
+ "children_max", &children_max,
+ "exec_delay", &exec_delay,
+ "event_timeout", &event_timeout,
+ NULL);
+ if (r == -ENOENT)
return 0;
if (r < 0)
return r;
- /* unquote */
- n = strlen(val);
- if (n >= 2 &&
- ((val[0] == '"' && val[n-1] == '"') ||
- (val[0] == '\'' && val[n-1] == '\''))) {
- val[n - 1] = '\0';
- log = val + 1;
- } else
- log = val;
+ if (log_val) {
+ const char *log;
+ size_t n;
- /* we set the udev log level here explicitly, this is supposed
- * to regulate the code in libudev/ and udev/. */
- r = log_set_max_level_from_string_realm(LOG_REALM_UDEV, log);
- if (r < 0)
- log_debug_errno(r, "/etc/udev/udev.conf: failed to set udev log level '%s', ignoring: %m", log);
+ /* unquote */
+ n = strlen(log_val);
+ if (n >= 2 &&
+ ((log_val[0] == '"' && log_val[n-1] == '"') ||
+ (log_val[0] == '\'' && log_val[n-1] == '\''))) {
+ log_val[n - 1] = '\0';
+ log = log_val + 1;
+ } else
+ log = log_val;
+
+ /* we set the udev log level here explicitly, this is supposed
+ * to regulate the code in libudev/ and udev/. */
+ r = log_set_max_level_from_string_realm(LOG_REALM_UDEV, log);
+ if (r < 0)
+ log_debug_errno(r, "/etc/udev/udev.conf: failed to set udev log level '%s', ignoring: %m", log);
+ }
+
+ if (ret_children_max && children_max) {
+ r = safe_atou(children_max, ret_children_max);
+ if (r < 0)
+ log_notice_errno(r, "/etc/udev/udev.conf: failed to set parse children_max=%s, ignoring: %m", children_max);
+ }
+
+ if (ret_exec_delay_usec && exec_delay) {
+ r = parse_sec(exec_delay, ret_exec_delay_usec);
+ if (r < 0)
+ log_notice_errno(r, "/etc/udev/udev.conf: failed to set parse exec_delay=%s, ignoring: %m", exec_delay);
+ }
+
+ if (ret_event_timeout_usec && event_timeout) {
+ r = parse_sec(event_timeout, ret_event_timeout_usec);
+ if (r < 0)
+ log_notice_errno(r, "/etc/udev/udev.conf: failed to set parse event_timeout=%s, ignoring: %m", event_timeout);
+ }
return 0;
}
diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h
index 0df2cf9eb19..efbcd82976f 100644
--- a/src/shared/udev-util.h
+++ b/src/shared/udev-util.h
@@ -1,4 +1,13 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-int udev_parse_config(void);
+#include "time-util.h"
+
+int udev_parse_config_full(
+ unsigned *ret_children_max,
+ usec_t *ret_exec_delay_usec,
+ usec_t *ret_event_timeout_usec);
+
+static inline int udev_parse_config(void) {
+ return udev_parse_config_full(NULL, NULL, NULL);
+}
diff --git a/src/udev/udev.conf b/src/udev/udev.conf
index 0d812d4a656..3395a8b7ea6 100644
--- a/src/udev/udev.conf
+++ b/src/udev/udev.conf
@@ -3,4 +3,7 @@
# udevd is also started in the initrd. When this file is modified you might
# also want to rebuild the initrd, so that it will include the modified configuration.
-#udev_log="info"
+#udev_log=info
+#children_max=
+#exec_delay=
+#event_timeout=180
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index c77ca57d933..9b316c80db1 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -1703,7 +1703,7 @@ int main(int argc, char *argv[]) {
int r;
log_set_target(LOG_TARGET_AUTO);
- udev_parse_config();
+ udev_parse_config_full(&arg_children_max, &arg_exec_delay_usec, &arg_event_timeout_usec);
log_parse_environment();
log_open();