765 lines
28 KiB
Diff
765 lines
28 KiB
Diff
From ce2b557c15680ec67accc5242d34dc651c2be3e7 Mon Sep 17 00:00:00 2001
|
|
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
|
Date: Wed, 4 Dec 2024 02:33:47 +0900
|
|
Subject: [PATCH] udev: move parsers for config file, kerenel command line, and
|
|
positional arguments to udev-config.c
|
|
|
|
No functional change, just refactoring and preparation for later
|
|
commits.
|
|
|
|
(cherry picked from commit 394a678aec3b8bba0f0b1a8d7b9427c62468fe68)
|
|
|
|
Resolves: RHEL-75774
|
|
---
|
|
src/udev/meson.build | 1 +
|
|
src/udev/udev-config.c | 311 ++++++++++++++++++++++++++++++++++++++++
|
|
src/udev/udev-config.h | 11 ++
|
|
src/udev/udev-manager.c | 49 +------
|
|
src/udev/udev-manager.h | 1 -
|
|
src/udev/udevd.c | 250 +-------------------------------
|
|
6 files changed, 326 insertions(+), 297 deletions(-)
|
|
create mode 100644 src/udev/udev-config.c
|
|
create mode 100644 src/udev/udev-config.h
|
|
|
|
diff --git a/src/udev/meson.build b/src/udev/meson.build
|
|
index 921dfac39c..d7acbae6bb 100644
|
|
--- a/src/udev/meson.build
|
|
+++ b/src/udev/meson.build
|
|
@@ -19,6 +19,7 @@ udevadm_sources = files(
|
|
|
|
libudevd_core_sources = files(
|
|
'net/link-config.c',
|
|
+ 'udev-config.c',
|
|
'udev-ctrl.c',
|
|
'udev-event.c',
|
|
'udev-format.c',
|
|
diff --git a/src/udev/udev-config.c b/src/udev/udev-config.c
|
|
new file mode 100644
|
|
index 0000000000..b774e7676e
|
|
--- /dev/null
|
|
+++ b/src/udev/udev-config.c
|
|
@@ -0,0 +1,311 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
+
|
|
+#include <getopt.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include "conf-parser.h"
|
|
+#include "cpu-set-util.h"
|
|
+#include "limits-util.h"
|
|
+#include "parse-util.h"
|
|
+#include "pretty-print.h"
|
|
+#include "proc-cmdline.h"
|
|
+#include "signal-util.h"
|
|
+#include "syslog-util.h"
|
|
+#include "udev-config.h"
|
|
+#include "udev-manager.h"
|
|
+#include "udev-rules.h"
|
|
+#include "udev-util.h"
|
|
+#include "udev-worker.h"
|
|
+#include "version.h"
|
|
+
|
|
+#define WORKER_NUM_MAX UINT64_C(2048)
|
|
+
|
|
+static bool arg_debug = false;
|
|
+bool arg_daemonize = false;
|
|
+
|
|
+static DEFINE_CONFIG_PARSE_ENUM(config_parse_resolve_name_timing, resolve_name_timing, ResolveNameTiming);
|
|
+
|
|
+static int manager_parse_udev_config(Manager *manager) {
|
|
+ int r, log_val = -1;
|
|
+
|
|
+ assert(manager);
|
|
+
|
|
+ const ConfigTableItem config_table[] = {
|
|
+ { NULL, "udev_log", config_parse_log_level, 0, &log_val },
|
|
+ { NULL, "children_max", config_parse_unsigned, 0, &manager->children_max },
|
|
+ { NULL, "exec_delay", config_parse_sec, 0, &manager->exec_delay_usec },
|
|
+ { NULL, "event_timeout", config_parse_sec, 0, &manager->timeout_usec },
|
|
+ { NULL, "resolve_names", config_parse_resolve_name_timing, 0, &manager->resolve_name_timing },
|
|
+ { NULL, "timeout_signal", config_parse_signal, 0, &manager->timeout_signal },
|
|
+ {}
|
|
+ };
|
|
+
|
|
+ r = udev_parse_config_full(config_table);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ if (log_val >= 0)
|
|
+ log_set_max_level(log_val);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * read the kernel command line, in case we need to get into debug mode
|
|
+ * udev.log_level=<level> syslog priority
|
|
+ * udev.children_max=<number of workers> events are fully serialized if set to 1
|
|
+ * udev.exec_delay=<number of seconds> delay execution of every executed program
|
|
+ * udev.event_timeout=<number of seconds> seconds to wait before terminating an event
|
|
+ * udev.blockdev_read_only<=bool> mark all block devices read-only when they appear
|
|
+ */
|
|
+static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
|
+ Manager *manager = ASSERT_PTR(data);
|
|
+ int r;
|
|
+
|
|
+ assert(key);
|
|
+
|
|
+ if (proc_cmdline_key_streq(key, "udev.log_level") ||
|
|
+ proc_cmdline_key_streq(key, "udev.log_priority")) { /* kept for backward compatibility */
|
|
+
|
|
+ if (proc_cmdline_value_missing(key, value))
|
|
+ return 0;
|
|
+
|
|
+ r = log_level_from_string(value);
|
|
+ if (r >= 0)
|
|
+ manager->log_level = r;
|
|
+
|
|
+ } else if (proc_cmdline_key_streq(key, "udev.event_timeout")) {
|
|
+
|
|
+ if (proc_cmdline_value_missing(key, value))
|
|
+ return 0;
|
|
+
|
|
+ r = parse_sec(value, &manager->timeout_usec);
|
|
+
|
|
+ } else if (proc_cmdline_key_streq(key, "udev.children_max")) {
|
|
+
|
|
+ if (proc_cmdline_value_missing(key, value))
|
|
+ return 0;
|
|
+
|
|
+ r = safe_atou(value, &manager->children_max);
|
|
+
|
|
+ } else if (proc_cmdline_key_streq(key, "udev.exec_delay")) {
|
|
+
|
|
+ if (proc_cmdline_value_missing(key, value))
|
|
+ return 0;
|
|
+
|
|
+ r = parse_sec(value, &manager->exec_delay_usec);
|
|
+
|
|
+ } else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) {
|
|
+
|
|
+ if (proc_cmdline_value_missing(key, value))
|
|
+ return 0;
|
|
+
|
|
+ r = signal_from_string(value);
|
|
+ if (r > 0)
|
|
+ manager->timeout_signal = r;
|
|
+
|
|
+ } else if (proc_cmdline_key_streq(key, "udev.blockdev_read_only")) {
|
|
+
|
|
+ if (!value)
|
|
+ manager->blockdev_read_only = true;
|
|
+ else {
|
|
+ r = parse_boolean(value);
|
|
+ if (r < 0)
|
|
+ log_warning_errno(r, "Failed to parse udev.blockdev-read-only argument, ignoring: %s", value);
|
|
+ else
|
|
+ manager->blockdev_read_only = r;
|
|
+ }
|
|
+
|
|
+ if (manager->blockdev_read_only)
|
|
+ log_notice("All physical block devices will be marked read-only.");
|
|
+
|
|
+ return 0;
|
|
+
|
|
+ } else {
|
|
+ if (startswith(key, "udev."))
|
|
+ log_warning("Unknown udev kernel command line option \"%s\", ignoring.", key);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (r < 0)
|
|
+ log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int help(void) {
|
|
+ _cleanup_free_ char *link = NULL;
|
|
+ int r;
|
|
+
|
|
+ r = terminal_urlify_man("systemd-udevd.service", "8", &link);
|
|
+ if (r < 0)
|
|
+ return log_oom();
|
|
+
|
|
+ printf("%s [OPTIONS...]\n\n"
|
|
+ "Rule-based manager for device events and files.\n\n"
|
|
+ " -h --help Print this message\n"
|
|
+ " -V --version Print version of the program\n"
|
|
+ " -d --daemon Detach and run in the background\n"
|
|
+ " -D --debug Enable debug output\n"
|
|
+ " -c --children-max=INT Set maximum number of workers\n"
|
|
+ " -e --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
|
|
+ " -t --event-timeout=SECONDS Seconds to wait before terminating an event\n"
|
|
+ " -N --resolve-names=early|late|never\n"
|
|
+ " When to resolve users and groups\n"
|
|
+ "\nSee the %s for details.\n",
|
|
+ program_invocation_short_name,
|
|
+ link);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int parse_argv(int argc, char *argv[], Manager *manager) {
|
|
+ enum {
|
|
+ ARG_TIMEOUT_SIGNAL,
|
|
+ };
|
|
+
|
|
+ static const struct option options[] = {
|
|
+ { "daemon", no_argument, NULL, 'd' },
|
|
+ { "debug", no_argument, NULL, 'D' },
|
|
+ { "children-max", required_argument, NULL, 'c' },
|
|
+ { "exec-delay", required_argument, NULL, 'e' },
|
|
+ { "event-timeout", required_argument, NULL, 't' },
|
|
+ { "resolve-names", required_argument, NULL, 'N' },
|
|
+ { "help", no_argument, NULL, 'h' },
|
|
+ { "version", no_argument, NULL, 'V' },
|
|
+ { "timeout-signal", required_argument, NULL, ARG_TIMEOUT_SIGNAL },
|
|
+ {}
|
|
+ };
|
|
+
|
|
+ int c, r;
|
|
+
|
|
+ assert(argc >= 0);
|
|
+ assert(argv);
|
|
+ assert(manager);
|
|
+
|
|
+ while ((c = getopt_long(argc, argv, "c:de:Dt:N:hV", options, NULL)) >= 0) {
|
|
+ switch (c) {
|
|
+
|
|
+ case 'd':
|
|
+ arg_daemonize = true;
|
|
+ break;
|
|
+ case 'c':
|
|
+ r = safe_atou(optarg, &manager->children_max);
|
|
+ if (r < 0)
|
|
+ log_warning_errno(r, "Failed to parse --children-max= value '%s', ignoring: %m", optarg);
|
|
+ break;
|
|
+ case 'e':
|
|
+ r = parse_sec(optarg, &manager->exec_delay_usec);
|
|
+ if (r < 0)
|
|
+ log_warning_errno(r, "Failed to parse --exec-delay= value '%s', ignoring: %m", optarg);
|
|
+ break;
|
|
+ case ARG_TIMEOUT_SIGNAL:
|
|
+ r = signal_from_string(optarg);
|
|
+ if (r <= 0)
|
|
+ log_warning_errno(r, "Failed to parse --timeout-signal= value '%s', ignoring: %m", optarg);
|
|
+ else
|
|
+ manager->timeout_signal = r;
|
|
+
|
|
+ break;
|
|
+ case 't':
|
|
+ r = parse_sec(optarg, &manager->timeout_usec);
|
|
+ if (r < 0)
|
|
+ log_warning_errno(r, "Failed to parse --event-timeout= value '%s', ignoring: %m", optarg);
|
|
+ break;
|
|
+ case 'D':
|
|
+ arg_debug = true;
|
|
+ break;
|
|
+ case 'N': {
|
|
+ ResolveNameTiming t;
|
|
+
|
|
+ t = resolve_name_timing_from_string(optarg);
|
|
+ if (t < 0)
|
|
+ log_warning("Invalid --resolve-names= value '%s', ignoring.", optarg);
|
|
+ else
|
|
+ manager->resolve_name_timing = t;
|
|
+ break;
|
|
+ }
|
|
+ case 'h':
|
|
+ return help();
|
|
+ case 'V':
|
|
+ printf("%s\n", GIT_VERSION);
|
|
+ return 0;
|
|
+ case '?':
|
|
+ return -EINVAL;
|
|
+ default:
|
|
+ assert_not_reached();
|
|
+
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+void manager_set_default_children_max(Manager *manager) {
|
|
+ uint64_t cpu_limit, mem_limit, cpu_count = 1;
|
|
+ int r;
|
|
+
|
|
+ assert(manager);
|
|
+
|
|
+ if (manager->children_max != 0)
|
|
+ return;
|
|
+
|
|
+ r = cpus_in_affinity_mask();
|
|
+ if (r < 0)
|
|
+ log_warning_errno(r, "Failed to determine number of local CPUs, ignoring: %m");
|
|
+ else
|
|
+ cpu_count = r;
|
|
+
|
|
+ cpu_limit = cpu_count * 2 + 16;
|
|
+ mem_limit = MAX(physical_memory() / (128*1024*1024), UINT64_C(10));
|
|
+
|
|
+ manager->children_max = MIN3(cpu_limit, mem_limit, WORKER_NUM_MAX);
|
|
+ log_debug("Set children_max to %u", manager->children_max);
|
|
+}
|
|
+
|
|
+static void manager_adjust_config(Manager *manager) {
|
|
+ assert(manager);
|
|
+
|
|
+ if (manager->timeout_usec < MIN_WORKER_TIMEOUT_USEC) {
|
|
+ log_debug("Timeout (%s) for processing event is too small, using the default: %s",
|
|
+ FORMAT_TIMESPAN(manager->timeout_usec, 1),
|
|
+ FORMAT_TIMESPAN(DEFAULT_WORKER_TIMEOUT_USEC, 1));
|
|
+
|
|
+ manager->timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC;
|
|
+ }
|
|
+
|
|
+ if (manager->exec_delay_usec >= manager->timeout_usec) {
|
|
+ log_debug("Delay (%s) for executing RUN= commands is too large compared with the timeout (%s) for event execution, ignoring the delay.",
|
|
+ FORMAT_TIMESPAN(manager->exec_delay_usec, 1),
|
|
+ FORMAT_TIMESPAN(manager->timeout_usec, 1));
|
|
+
|
|
+ manager->exec_delay_usec = 0;
|
|
+ }
|
|
+
|
|
+ manager_set_default_children_max(manager);
|
|
+}
|
|
+
|
|
+int manager_load(Manager *manager, int argc, char *argv[]) {
|
|
+ int r;
|
|
+
|
|
+ assert(manager);
|
|
+
|
|
+ manager_parse_udev_config(manager);
|
|
+
|
|
+ r = parse_argv(argc, argv, manager);
|
|
+ if (r <= 0)
|
|
+ return r;
|
|
+
|
|
+ r = proc_cmdline_parse(parse_proc_cmdline_item, manager, PROC_CMDLINE_STRIP_RD_PREFIX);
|
|
+ if (r < 0)
|
|
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
|
+
|
|
+ if (arg_debug) {
|
|
+ log_set_target(LOG_TARGET_CONSOLE);
|
|
+ log_set_max_level(LOG_DEBUG);
|
|
+ }
|
|
+
|
|
+ manager_adjust_config(manager);
|
|
+ return 1;
|
|
+}
|
|
diff --git a/src/udev/udev-config.h b/src/udev/udev-config.h
|
|
new file mode 100644
|
|
index 0000000000..9a8a18821f
|
|
--- /dev/null
|
|
+++ b/src/udev/udev-config.h
|
|
@@ -0,0 +1,11 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
+#pragma once
|
|
+
|
|
+#include <stdbool.h>
|
|
+
|
|
+extern bool arg_daemonize;
|
|
+
|
|
+typedef struct Manager Manager;
|
|
+
|
|
+int manager_load(Manager *manager, int argc, char *argv[]);
|
|
+void manager_set_default_children_max(Manager *manager);
|
|
diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c
|
|
index 6e1935a731..23a57dbed3 100644
|
|
--- a/src/udev/udev-manager.c
|
|
+++ b/src/udev/udev-manager.c
|
|
@@ -3,7 +3,6 @@
|
|
#include "blockdev-util.h"
|
|
#include "cgroup-util.h"
|
|
#include "common-signal.h"
|
|
-#include "cpu-set-util.h"
|
|
#include "daemon-util.h"
|
|
#include "device-monitor-private.h"
|
|
#include "device-private.h"
|
|
@@ -15,7 +14,6 @@
|
|
#include "hashmap.h"
|
|
#include "inotify-util.h"
|
|
#include "iovec-util.h"
|
|
-#include "limits-util.h"
|
|
#include "list.h"
|
|
#include "mkdir.h"
|
|
#include "process-util.h"
|
|
@@ -25,6 +23,7 @@
|
|
#include "string-util.h"
|
|
#include "syslog-util.h"
|
|
#include "udev-builtin.h"
|
|
+#include "udev-config.h"
|
|
#include "udev-ctrl.h"
|
|
#include "udev-event.h"
|
|
#include "udev-manager.h"
|
|
@@ -36,8 +35,6 @@
|
|
#include "udev-watch.h"
|
|
#include "udev-worker.h"
|
|
|
|
-#define WORKER_NUM_MAX UINT64_C(2048)
|
|
-
|
|
#define EVENT_RETRY_INTERVAL_USEC (200 * USEC_PER_MSEC)
|
|
#define EVENT_RETRY_TIMEOUT_USEC (3 * USEC_PER_MINUTE)
|
|
|
|
@@ -845,28 +842,6 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
|
return 1;
|
|
}
|
|
|
|
-static void manager_set_default_children_max(Manager *manager) {
|
|
- uint64_t cpu_limit, mem_limit, cpu_count = 1;
|
|
- int r;
|
|
-
|
|
- assert(manager);
|
|
-
|
|
- if (manager->children_max != 0)
|
|
- return;
|
|
-
|
|
- r = cpus_in_affinity_mask();
|
|
- if (r < 0)
|
|
- log_warning_errno(r, "Failed to determine number of local CPUs, ignoring: %m");
|
|
- else
|
|
- cpu_count = r;
|
|
-
|
|
- cpu_limit = cpu_count * 2 + 16;
|
|
- mem_limit = MAX(physical_memory() / (128*1024*1024), UINT64_C(10));
|
|
-
|
|
- manager->children_max = MIN3(cpu_limit, mem_limit, WORKER_NUM_MAX);
|
|
- log_debug("Set children_max to %u", manager->children_max);
|
|
-}
|
|
-
|
|
/* receive the udevd message from userspace */
|
|
static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
|
|
Manager *manager = ASSERT_PTR(userdata);
|
|
@@ -1208,26 +1183,6 @@ Manager* manager_new(void) {
|
|
return manager;
|
|
}
|
|
|
|
-void manager_adjust_arguments(Manager *manager) {
|
|
- assert(manager);
|
|
-
|
|
- if (manager->timeout_usec < MIN_WORKER_TIMEOUT_USEC) {
|
|
- log_debug("Timeout (%s) for processing event is too small, using the default: %s",
|
|
- FORMAT_TIMESPAN(manager->timeout_usec, 1),
|
|
- FORMAT_TIMESPAN(DEFAULT_WORKER_TIMEOUT_USEC, 1));
|
|
-
|
|
- manager->timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC;
|
|
- }
|
|
-
|
|
- if (manager->exec_delay_usec >= manager->timeout_usec) {
|
|
- log_debug("Delay (%s) for executing RUN= commands is too large compared with the timeout (%s) for event execution, ignoring the delay.",
|
|
- FORMAT_TIMESPAN(manager->exec_delay_usec, 1),
|
|
- FORMAT_TIMESPAN(manager->timeout_usec, 1));
|
|
-
|
|
- manager->exec_delay_usec = 0;
|
|
- }
|
|
-}
|
|
-
|
|
static int listen_fds(int *ret_ctrl, int *ret_netlink) {
|
|
_cleanup_strv_free_ char **names = NULL;
|
|
_cleanup_close_ int ctrl_fd = -EBADF, netlink_fd = -EBADF;
|
|
@@ -1319,8 +1274,6 @@ int manager_init(Manager *manager) {
|
|
int manager_main(Manager *manager) {
|
|
int fd_worker, r;
|
|
|
|
- manager_set_default_children_max(manager);
|
|
-
|
|
/* unnamed socket from workers to the main daemon */
|
|
r = socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
|
|
if (r < 0)
|
|
diff --git a/src/udev/udev-manager.h b/src/udev/udev-manager.h
|
|
index 7c20e29594..14b458bcdb 100644
|
|
--- a/src/udev/udev-manager.h
|
|
+++ b/src/udev/udev-manager.h
|
|
@@ -53,7 +53,6 @@ Manager* manager_new(void);
|
|
Manager* manager_free(Manager *manager);
|
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
|
|
|
-void manager_adjust_arguments(Manager *manager);
|
|
int manager_init(Manager *manager);
|
|
int manager_main(Manager *manager);
|
|
|
|
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
|
|
index ef1c07a2ca..018a3cd6e7 100644
|
|
--- a/src/udev/udevd.c
|
|
+++ b/src/udev/udevd.c
|
|
@@ -5,250 +5,17 @@
|
|
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>
|
|
*/
|
|
|
|
-#include <getopt.h>
|
|
-#include <unistd.h>
|
|
-
|
|
-#include "conf-parser.h"
|
|
-#include "env-file.h"
|
|
#include "errno-util.h"
|
|
#include "fd-util.h"
|
|
#include "mkdir.h"
|
|
-#include "parse-util.h"
|
|
-#include "pretty-print.h"
|
|
-#include "proc-cmdline.h"
|
|
#include "process-util.h"
|
|
#include "rlimit-util.h"
|
|
#include "selinux-util.h"
|
|
-#include "signal-util.h"
|
|
-#include "syslog-util.h"
|
|
+#include "udev-config.h"
|
|
#include "udev-manager.h"
|
|
-#include "udev-rules.h"
|
|
-#include "udev-util.h"
|
|
#include "udevd.h"
|
|
#include "version.h"
|
|
|
|
-static bool arg_debug = false;
|
|
-static int arg_daemonize = false;
|
|
-
|
|
-static DEFINE_CONFIG_PARSE_ENUM(config_parse_resolve_name_timing, resolve_name_timing, ResolveNameTiming);
|
|
-
|
|
-static int manager_parse_udev_config(Manager *manager) {
|
|
- int r, log_val = -1;
|
|
-
|
|
- assert(manager);
|
|
-
|
|
- const ConfigTableItem config_table[] = {
|
|
- { NULL, "udev_log", config_parse_log_level, 0, &log_val },
|
|
- { NULL, "children_max", config_parse_unsigned, 0, &manager->children_max },
|
|
- { NULL, "exec_delay", config_parse_sec, 0, &manager->exec_delay_usec },
|
|
- { NULL, "event_timeout", config_parse_sec, 0, &manager->timeout_usec },
|
|
- { NULL, "resolve_names", config_parse_resolve_name_timing, 0, &manager->resolve_name_timing },
|
|
- { NULL, "timeout_signal", config_parse_signal, 0, &manager->timeout_signal },
|
|
- {}
|
|
- };
|
|
-
|
|
- r = udev_parse_config_full(config_table);
|
|
- if (r < 0)
|
|
- return r;
|
|
-
|
|
- if (log_val >= 0)
|
|
- log_set_max_level(log_val);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * read the kernel command line, in case we need to get into debug mode
|
|
- * udev.log_level=<level> syslog priority
|
|
- * udev.children_max=<number of workers> events are fully serialized if set to 1
|
|
- * udev.exec_delay=<number of seconds> delay execution of every executed program
|
|
- * udev.event_timeout=<number of seconds> seconds to wait before terminating an event
|
|
- * udev.blockdev_read_only<=bool> mark all block devices read-only when they appear
|
|
- */
|
|
-static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
|
- Manager *manager = ASSERT_PTR(data);
|
|
- int r;
|
|
-
|
|
- assert(key);
|
|
-
|
|
- if (proc_cmdline_key_streq(key, "udev.log_level") ||
|
|
- proc_cmdline_key_streq(key, "udev.log_priority")) { /* kept for backward compatibility */
|
|
-
|
|
- if (proc_cmdline_value_missing(key, value))
|
|
- return 0;
|
|
-
|
|
- r = log_level_from_string(value);
|
|
- if (r >= 0)
|
|
- log_set_max_level(r);
|
|
-
|
|
- } else if (proc_cmdline_key_streq(key, "udev.event_timeout")) {
|
|
-
|
|
- if (proc_cmdline_value_missing(key, value))
|
|
- return 0;
|
|
-
|
|
- r = parse_sec(value, &manager->timeout_usec);
|
|
-
|
|
- } else if (proc_cmdline_key_streq(key, "udev.children_max")) {
|
|
-
|
|
- if (proc_cmdline_value_missing(key, value))
|
|
- return 0;
|
|
-
|
|
- r = safe_atou(value, &manager->children_max);
|
|
-
|
|
- } else if (proc_cmdline_key_streq(key, "udev.exec_delay")) {
|
|
-
|
|
- if (proc_cmdline_value_missing(key, value))
|
|
- return 0;
|
|
-
|
|
- r = parse_sec(value, &manager->exec_delay_usec);
|
|
-
|
|
- } else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) {
|
|
-
|
|
- if (proc_cmdline_value_missing(key, value))
|
|
- return 0;
|
|
-
|
|
- r = signal_from_string(value);
|
|
- if (r > 0)
|
|
- manager->timeout_signal = r;
|
|
-
|
|
- } else if (proc_cmdline_key_streq(key, "udev.blockdev_read_only")) {
|
|
-
|
|
- if (!value)
|
|
- manager->blockdev_read_only = true;
|
|
- else {
|
|
- r = parse_boolean(value);
|
|
- if (r < 0)
|
|
- log_warning_errno(r, "Failed to parse udev.blockdev-read-only argument, ignoring: %s", value);
|
|
- else
|
|
- manager->blockdev_read_only = r;
|
|
- }
|
|
-
|
|
- if (manager->blockdev_read_only)
|
|
- log_notice("All physical block devices will be marked read-only.");
|
|
-
|
|
- return 0;
|
|
-
|
|
- } else {
|
|
- if (startswith(key, "udev."))
|
|
- log_warning("Unknown udev kernel command line option \"%s\", ignoring.", key);
|
|
-
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (r < 0)
|
|
- log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int help(void) {
|
|
- _cleanup_free_ char *link = NULL;
|
|
- int r;
|
|
-
|
|
- r = terminal_urlify_man("systemd-udevd.service", "8", &link);
|
|
- if (r < 0)
|
|
- return log_oom();
|
|
-
|
|
- printf("%s [OPTIONS...]\n\n"
|
|
- "Rule-based manager for device events and files.\n\n"
|
|
- " -h --help Print this message\n"
|
|
- " -V --version Print version of the program\n"
|
|
- " -d --daemon Detach and run in the background\n"
|
|
- " -D --debug Enable debug output\n"
|
|
- " -c --children-max=INT Set maximum number of workers\n"
|
|
- " -e --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
|
|
- " -t --event-timeout=SECONDS Seconds to wait before terminating an event\n"
|
|
- " -N --resolve-names=early|late|never\n"
|
|
- " When to resolve users and groups\n"
|
|
- "\nSee the %s for details.\n",
|
|
- program_invocation_short_name,
|
|
- link);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int parse_argv(int argc, char *argv[], Manager *manager) {
|
|
- enum {
|
|
- ARG_TIMEOUT_SIGNAL,
|
|
- };
|
|
-
|
|
- static const struct option options[] = {
|
|
- { "daemon", no_argument, NULL, 'd' },
|
|
- { "debug", no_argument, NULL, 'D' },
|
|
- { "children-max", required_argument, NULL, 'c' },
|
|
- { "exec-delay", required_argument, NULL, 'e' },
|
|
- { "event-timeout", required_argument, NULL, 't' },
|
|
- { "resolve-names", required_argument, NULL, 'N' },
|
|
- { "help", no_argument, NULL, 'h' },
|
|
- { "version", no_argument, NULL, 'V' },
|
|
- { "timeout-signal", required_argument, NULL, ARG_TIMEOUT_SIGNAL },
|
|
- {}
|
|
- };
|
|
-
|
|
- int c, r;
|
|
-
|
|
- assert(argc >= 0);
|
|
- assert(argv);
|
|
- assert(manager);
|
|
-
|
|
- while ((c = getopt_long(argc, argv, "c:de:Dt:N:hV", options, NULL)) >= 0) {
|
|
- switch (c) {
|
|
-
|
|
- case 'd':
|
|
- arg_daemonize = true;
|
|
- break;
|
|
- case 'c':
|
|
- r = safe_atou(optarg, &manager->children_max);
|
|
- if (r < 0)
|
|
- log_warning_errno(r, "Failed to parse --children-max= value '%s', ignoring: %m", optarg);
|
|
- break;
|
|
- case 'e':
|
|
- r = parse_sec(optarg, &manager->exec_delay_usec);
|
|
- if (r < 0)
|
|
- log_warning_errno(r, "Failed to parse --exec-delay= value '%s', ignoring: %m", optarg);
|
|
- break;
|
|
- case ARG_TIMEOUT_SIGNAL:
|
|
- r = signal_from_string(optarg);
|
|
- if (r <= 0)
|
|
- log_warning_errno(r, "Failed to parse --timeout-signal= value '%s', ignoring: %m", optarg);
|
|
- else
|
|
- manager->timeout_signal = r;
|
|
-
|
|
- break;
|
|
- case 't':
|
|
- r = parse_sec(optarg, &manager->timeout_usec);
|
|
- if (r < 0)
|
|
- log_warning_errno(r, "Failed to parse --event-timeout= value '%s', ignoring: %m", optarg);
|
|
- break;
|
|
- case 'D':
|
|
- arg_debug = true;
|
|
- break;
|
|
- case 'N': {
|
|
- ResolveNameTiming t;
|
|
-
|
|
- t = resolve_name_timing_from_string(optarg);
|
|
- if (t < 0)
|
|
- log_warning("Invalid --resolve-names= value '%s', ignoring.", optarg);
|
|
- else
|
|
- manager->resolve_name_timing = t;
|
|
- break;
|
|
- }
|
|
- case 'h':
|
|
- return help();
|
|
- case 'V':
|
|
- printf("%s\n", GIT_VERSION);
|
|
- return 0;
|
|
- case '?':
|
|
- return -EINVAL;
|
|
- default:
|
|
- assert_not_reached();
|
|
-
|
|
- }
|
|
- }
|
|
-
|
|
- return 1;
|
|
-}
|
|
-
|
|
int run_udevd(int argc, char *argv[]) {
|
|
_cleanup_(manager_freep) Manager *manager = NULL;
|
|
int r;
|
|
@@ -259,23 +26,10 @@ int run_udevd(int argc, char *argv[]) {
|
|
if (!manager)
|
|
return log_oom();
|
|
|
|
- manager_parse_udev_config(manager);
|
|
-
|
|
- r = parse_argv(argc, argv, manager);
|
|
+ r = manager_load(manager, argc, argv);
|
|
if (r <= 0)
|
|
return r;
|
|
|
|
- r = proc_cmdline_parse(parse_proc_cmdline_item, manager, PROC_CMDLINE_STRIP_RD_PREFIX);
|
|
- if (r < 0)
|
|
- log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
|
-
|
|
- if (arg_debug) {
|
|
- log_set_target(LOG_TARGET_CONSOLE);
|
|
- log_set_max_level(LOG_DEBUG);
|
|
- }
|
|
-
|
|
- manager_adjust_arguments(manager);
|
|
-
|
|
r = must_be_root();
|
|
if (r < 0)
|
|
return r;
|