mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
udev: move config parsers and related things to udev-config.c (#35624)
No functional change, just refactoring and preparation for later changes.
This commit is contained in:
commit
b5ea69f5ac
@ -19,6 +19,7 @@ udevadm_sources = files(
|
|||||||
|
|
||||||
libudevd_core_sources = files(
|
libudevd_core_sources = files(
|
||||||
'net/link-config.c',
|
'net/link-config.c',
|
||||||
|
'udev-config.c',
|
||||||
'udev-ctrl.c',
|
'udev-ctrl.c',
|
||||||
'udev-event.c',
|
'udev-event.c',
|
||||||
'udev-format.c',
|
'udev-format.c',
|
||||||
|
341
src/udev/udev-config.c
Normal file
341
src/udev/udev-config.c
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
/* 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 void manager_parse_udev_config(UdevConfig *config) {
|
||||||
|
assert(config);
|
||||||
|
|
||||||
|
const ConfigTableItem config_table[] = {
|
||||||
|
{ NULL, "udev_log", config_parse_log_level, 0, &config->log_level },
|
||||||
|
{ NULL, "children_max", config_parse_unsigned, 0, &config->children_max },
|
||||||
|
{ NULL, "exec_delay", config_parse_sec, 0, &config->exec_delay_usec },
|
||||||
|
{ NULL, "event_timeout", config_parse_sec, 0, &config->timeout_usec },
|
||||||
|
{ NULL, "resolve_names", config_parse_resolve_name_timing, 0, &config->resolve_name_timing },
|
||||||
|
{ NULL, "timeout_signal", config_parse_signal, 0, &config->timeout_signal },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
(void) udev_parse_config_full(config_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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) {
|
||||||
|
UdevConfig *config = 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)
|
||||||
|
config->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, &config->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, &config->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, &config->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)
|
||||||
|
config->timeout_signal = r;
|
||||||
|
|
||||||
|
} else if (proc_cmdline_key_streq(key, "udev.blockdev_read_only")) {
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
config->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
|
||||||
|
config->blockdev_read_only = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->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[], UdevConfig *config) {
|
||||||
|
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(config);
|
||||||
|
|
||||||
|
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, &config->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, &config->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
|
||||||
|
config->timeout_signal = r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
r = parse_sec(optarg, &config->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;
|
||||||
|
config->log_level = LOG_DEBUG;
|
||||||
|
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
|
||||||
|
config->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MERGE_NON_NEGATIVE(name, default_value) \
|
||||||
|
manager->config.name = \
|
||||||
|
manager->config_by_control.name >= 0 ? manager->config_by_control.name : \
|
||||||
|
manager->config_by_kernel.name >= 0 ? manager->config_by_kernel.name : \
|
||||||
|
manager->config_by_command.name >= 0 ? manager->config_by_command.name : \
|
||||||
|
manager->config_by_udev_conf.name >= 0 ? manager->config_by_udev_conf.name : \
|
||||||
|
default_value;
|
||||||
|
|
||||||
|
#define MERGE_NON_ZERO(name, default_value) \
|
||||||
|
manager->config.name = \
|
||||||
|
manager->config_by_control.name ?: \
|
||||||
|
manager->config_by_kernel.name ?: \
|
||||||
|
manager->config_by_command.name ?: \
|
||||||
|
manager->config_by_udev_conf.name ?: \
|
||||||
|
default_value;
|
||||||
|
|
||||||
|
#define MERGE_BOOL(name) \
|
||||||
|
manager->config.name = \
|
||||||
|
manager->config_by_control.name || \
|
||||||
|
manager->config_by_kernel.name || \
|
||||||
|
manager->config_by_command.name || \
|
||||||
|
manager->config_by_udev_conf.name;
|
||||||
|
|
||||||
|
static void manager_merge_config(Manager *manager) {
|
||||||
|
assert(manager);
|
||||||
|
|
||||||
|
/* udev.conf has the lowest priority, then followed by command line arguments, kernel command line
|
||||||
|
options, and values set by udev control. */
|
||||||
|
|
||||||
|
MERGE_NON_NEGATIVE(log_level, log_get_max_level());
|
||||||
|
MERGE_NON_NEGATIVE(resolve_name_timing, RESOLVE_NAME_EARLY);
|
||||||
|
MERGE_NON_ZERO(exec_delay_usec, 0);
|
||||||
|
MERGE_NON_ZERO(timeout_usec, DEFAULT_WORKER_TIMEOUT_USEC);
|
||||||
|
MERGE_NON_ZERO(timeout_signal, SIGKILL);
|
||||||
|
MERGE_BOOL(blockdev_read_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
void udev_config_set_default_children_max(UdevConfig *config) {
|
||||||
|
uint64_t cpu_limit, mem_limit, cpu_count = 1;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(config);
|
||||||
|
|
||||||
|
if (config->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));
|
||||||
|
|
||||||
|
config->children_max = MIN3(cpu_limit, mem_limit, WORKER_NUM_MAX);
|
||||||
|
log_debug("Set children_max to %u", config->children_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_adjust_config(UdevConfig *config) {
|
||||||
|
assert(config);
|
||||||
|
|
||||||
|
if (config->timeout_usec < MIN_WORKER_TIMEOUT_USEC) {
|
||||||
|
log_debug("Timeout (%s) for processing event is too small, using the default: %s",
|
||||||
|
FORMAT_TIMESPAN(config->timeout_usec, 1),
|
||||||
|
FORMAT_TIMESPAN(DEFAULT_WORKER_TIMEOUT_USEC, 1));
|
||||||
|
|
||||||
|
config->timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->exec_delay_usec >= config->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(config->exec_delay_usec, 1),
|
||||||
|
FORMAT_TIMESPAN(config->timeout_usec, 1));
|
||||||
|
|
||||||
|
config->exec_delay_usec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
udev_config_set_default_children_max(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
int manager_load(Manager *manager, int argc, char *argv[]) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(manager);
|
||||||
|
|
||||||
|
manager_parse_udev_config(&manager->config_by_udev_conf);
|
||||||
|
|
||||||
|
r = parse_argv(argc, argv, &manager->config_by_command);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = proc_cmdline_parse(parse_proc_cmdline_item, &manager->config_by_kernel, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||||
|
|
||||||
|
manager_merge_config(manager);
|
||||||
|
|
||||||
|
if (arg_debug)
|
||||||
|
log_set_target(LOG_TARGET_CONSOLE);
|
||||||
|
|
||||||
|
log_set_max_level(manager->config.log_level);
|
||||||
|
manager_adjust_config(&manager->config);
|
||||||
|
return 1;
|
||||||
|
}
|
30
src/udev/udev-config.h
Normal file
30
src/udev/udev-config.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "time-util.h"
|
||||||
|
#include "udev-def.h"
|
||||||
|
|
||||||
|
extern bool arg_daemonize;
|
||||||
|
|
||||||
|
typedef struct Manager Manager;
|
||||||
|
|
||||||
|
typedef struct UdevConfig {
|
||||||
|
int log_level;
|
||||||
|
ResolveNameTiming resolve_name_timing;
|
||||||
|
unsigned children_max;
|
||||||
|
usec_t exec_delay_usec;
|
||||||
|
usec_t timeout_usec;
|
||||||
|
int timeout_signal;
|
||||||
|
bool blockdev_read_only;
|
||||||
|
} UdevConfig;
|
||||||
|
|
||||||
|
#define UDEV_CONFIG_INIT \
|
||||||
|
(UdevConfig) { \
|
||||||
|
.log_level = -1, \
|
||||||
|
.resolve_name_timing = _RESOLVE_NAME_TIMING_INVALID, \
|
||||||
|
}
|
||||||
|
|
||||||
|
int manager_load(Manager *manager, int argc, char *argv[]);
|
||||||
|
void udev_config_set_default_children_max(UdevConfig *c);
|
@ -19,7 +19,7 @@
|
|||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
|
|
||||||
UdevEvent* udev_event_new(sd_device *dev, UdevWorker *worker, EventMode mode) {
|
UdevEvent* udev_event_new(sd_device *dev, UdevWorker *worker, EventMode mode) {
|
||||||
int log_level = worker ? worker->log_level : log_get_max_level();
|
int log_level = worker ? worker->config.log_level : log_get_max_level();
|
||||||
UdevEvent *event;
|
UdevEvent *event;
|
||||||
|
|
||||||
assert(dev);
|
assert(dev);
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "blockdev-util.h"
|
#include "blockdev-util.h"
|
||||||
#include "cgroup-util.h"
|
#include "cgroup-util.h"
|
||||||
#include "common-signal.h"
|
#include "common-signal.h"
|
||||||
#include "cpu-set-util.h"
|
|
||||||
#include "daemon-util.h"
|
#include "daemon-util.h"
|
||||||
#include "device-monitor-private.h"
|
#include "device-monitor-private.h"
|
||||||
#include "device-private.h"
|
#include "device-private.h"
|
||||||
@ -15,7 +14,6 @@
|
|||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "inotify-util.h"
|
#include "inotify-util.h"
|
||||||
#include "iovec-util.h"
|
#include "iovec-util.h"
|
||||||
#include "limits-util.h"
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
@ -25,6 +23,7 @@
|
|||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "syslog-util.h"
|
#include "syslog-util.h"
|
||||||
#include "udev-builtin.h"
|
#include "udev-builtin.h"
|
||||||
|
#include "udev-config.h"
|
||||||
#include "udev-ctrl.h"
|
#include "udev-ctrl.h"
|
||||||
#include "udev-event.h"
|
#include "udev-event.h"
|
||||||
#include "udev-manager.h"
|
#include "udev-manager.h"
|
||||||
@ -36,8 +35,6 @@
|
|||||||
#include "udev-watch.h"
|
#include "udev-watch.h"
|
||||||
#include "udev-worker.h"
|
#include "udev-worker.h"
|
||||||
|
|
||||||
#define WORKER_NUM_MAX UINT64_C(2048)
|
|
||||||
|
|
||||||
#define EVENT_RETRY_INTERVAL_USEC (200 * USEC_PER_MSEC)
|
#define EVENT_RETRY_INTERVAL_USEC (200 * USEC_PER_MSEC)
|
||||||
#define EVENT_RETRY_TIMEOUT_USEC (3 * USEC_PER_MINUTE)
|
#define EVENT_RETRY_TIMEOUT_USEC (3 * USEC_PER_MINUTE)
|
||||||
|
|
||||||
@ -243,7 +240,7 @@ static void notify_ready(Manager *manager) {
|
|||||||
|
|
||||||
r = sd_notifyf(/* unset= */ false,
|
r = sd_notifyf(/* unset= */ false,
|
||||||
"READY=1\n"
|
"READY=1\n"
|
||||||
"STATUS=Processing with %u children at max", manager->children_max);
|
"STATUS=Processing with %u children at max", manager->config.children_max);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
|
log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
|
||||||
}
|
}
|
||||||
@ -281,7 +278,7 @@ static void manager_reload(Manager *manager, bool force) {
|
|||||||
udev_builtin_exit();
|
udev_builtin_exit();
|
||||||
udev_builtin_init();
|
udev_builtin_init();
|
||||||
|
|
||||||
r = udev_rules_load(&rules, manager->resolve_name_timing);
|
r = udev_rules_load(&rules, manager->config.resolve_name_timing);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
|
log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
|
||||||
else
|
else
|
||||||
@ -306,7 +303,7 @@ static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
|
|||||||
assert(event->manager);
|
assert(event->manager);
|
||||||
assert(event->worker);
|
assert(event->worker);
|
||||||
|
|
||||||
kill_and_sigcont(event->worker->pid, event->manager->timeout_signal);
|
kill_and_sigcont(event->worker->pid, event->manager->config.timeout_signal);
|
||||||
event->worker->state = WORKER_KILLED;
|
event->worker->state = WORKER_KILLED;
|
||||||
|
|
||||||
log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
|
log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
|
||||||
@ -366,7 +363,7 @@ static void worker_attach_event(Worker *worker, Event *event) {
|
|||||||
event->worker = worker;
|
event->worker = worker;
|
||||||
|
|
||||||
(void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
|
(void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
|
||||||
udev_warn_timeout(manager->timeout_usec), USEC_PER_SEC,
|
udev_warn_timeout(manager->config.timeout_usec), USEC_PER_SEC,
|
||||||
on_event_timeout_warning, event);
|
on_event_timeout_warning, event);
|
||||||
|
|
||||||
/* Manager.timeout_usec is also used as the timeout for running programs specified in
|
/* Manager.timeout_usec is also used as the timeout for running programs specified in
|
||||||
@ -374,7 +371,7 @@ static void worker_attach_event(Worker *worker, Event *event) {
|
|||||||
* kills a worker, to make it possible that the worker detects timed out of spawned programs,
|
* kills a worker, to make it possible that the worker detects timed out of spawned programs,
|
||||||
* kills them, and finalizes the event. */
|
* kills them, and finalizes the event. */
|
||||||
(void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
|
(void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
|
||||||
usec_add(manager->timeout_usec, extra_timeout_usec()), USEC_PER_SEC,
|
usec_add(manager->config.timeout_usec, extra_timeout_usec()), USEC_PER_SEC,
|
||||||
on_event_timeout, event);
|
on_event_timeout, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,11 +405,7 @@ static int worker_spawn(Manager *manager, Event *event) {
|
|||||||
.rules = TAKE_PTR(manager->rules),
|
.rules = TAKE_PTR(manager->rules),
|
||||||
.pipe_fd = TAKE_FD(manager->worker_watch[WRITE_END]),
|
.pipe_fd = TAKE_FD(manager->worker_watch[WRITE_END]),
|
||||||
.inotify_fd = TAKE_FD(manager->inotify_fd),
|
.inotify_fd = TAKE_FD(manager->inotify_fd),
|
||||||
.exec_delay_usec = manager->exec_delay_usec,
|
.config = manager->config,
|
||||||
.timeout_usec = manager->timeout_usec,
|
|
||||||
.timeout_signal = manager->timeout_signal,
|
|
||||||
.log_level = manager->log_level,
|
|
||||||
.blockdev_read_only = manager->blockdev_read_only,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Worker process */
|
/* Worker process */
|
||||||
@ -461,10 +454,10 @@ static int event_run(Event *event) {
|
|||||||
return 1; /* event is now processing. */
|
return 1; /* event is now processing. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashmap_size(manager->workers) >= manager->children_max) {
|
if (hashmap_size(manager->workers) >= manager->config.children_max) {
|
||||||
/* Avoid spamming the debug logs if the limit is already reached and
|
/* Avoid spamming the debug logs if the limit is already reached and
|
||||||
* many events still need to be processed */
|
* many events still need to be processed */
|
||||||
if (log_children_max_reached && manager->children_max > 1) {
|
if (log_children_max_reached && manager->config.children_max > 1) {
|
||||||
log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
|
log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
|
||||||
log_children_max_reached = false;
|
log_children_max_reached = false;
|
||||||
}
|
}
|
||||||
@ -845,28 +838,6 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
|||||||
return 1;
|
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 */
|
/* receive the udevd message from userspace */
|
||||||
static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
|
static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
|
||||||
Manager *manager = ASSERT_PTR(userdata);
|
Manager *manager = ASSERT_PTR(userdata);
|
||||||
@ -888,7 +859,7 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
log_set_max_level(value->intval);
|
log_set_max_level(value->intval);
|
||||||
manager->log_level = value->intval;
|
manager->config.log_level = manager->config_by_control.log_level = value->intval;
|
||||||
manager_kill_workers(manager, false);
|
manager_kill_workers(manager, false);
|
||||||
break;
|
break;
|
||||||
case UDEV_CTRL_STOP_EXEC_QUEUE:
|
case UDEV_CTRL_STOP_EXEC_QUEUE:
|
||||||
@ -959,10 +930,11 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_debug("Received udev control message (SET_MAX_CHILDREN), setting children_max=%i", value->intval);
|
log_debug("Received udev control message (SET_MAX_CHILDREN), setting children_max=%i", value->intval);
|
||||||
manager->children_max = value->intval;
|
manager->config_by_control.children_max = value->intval;
|
||||||
|
|
||||||
/* When 0 is specified, determine the maximum based on the system resources. */
|
/* When 0 is specified, determine the maximum based on the system resources. */
|
||||||
manager_set_default_children_max(manager);
|
udev_config_set_default_children_max(&manager->config_by_control);
|
||||||
|
manager->config.children_max = manager->config_by_control.children_max;
|
||||||
|
|
||||||
notify_ready(manager);
|
notify_ready(manager);
|
||||||
break;
|
break;
|
||||||
@ -1199,35 +1171,16 @@ Manager* manager_new(void) {
|
|||||||
*manager = (Manager) {
|
*manager = (Manager) {
|
||||||
.inotify_fd = -EBADF,
|
.inotify_fd = -EBADF,
|
||||||
.worker_watch = EBADF_PAIR,
|
.worker_watch = EBADF_PAIR,
|
||||||
.log_level = LOG_INFO,
|
.config_by_udev_conf = UDEV_CONFIG_INIT,
|
||||||
.resolve_name_timing = RESOLVE_NAME_EARLY,
|
.config_by_command = UDEV_CONFIG_INIT,
|
||||||
.timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC,
|
.config_by_kernel = UDEV_CONFIG_INIT,
|
||||||
.timeout_signal = SIGKILL,
|
.config_by_control = UDEV_CONFIG_INIT,
|
||||||
|
.config = UDEV_CONFIG_INIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
return manager;
|
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) {
|
static int listen_fds(int *ret_ctrl, int *ret_netlink) {
|
||||||
_cleanup_strv_free_ char **names = NULL;
|
_cleanup_strv_free_ char **names = NULL;
|
||||||
_cleanup_close_ int ctrl_fd = -EBADF, netlink_fd = -EBADF;
|
_cleanup_close_ int ctrl_fd = -EBADF, netlink_fd = -EBADF;
|
||||||
@ -1303,8 +1256,6 @@ int manager_init(Manager *manager) {
|
|||||||
|
|
||||||
(void) sd_device_monitor_set_description(manager->monitor, "manager");
|
(void) sd_device_monitor_set_description(manager->monitor, "manager");
|
||||||
|
|
||||||
manager->log_level = log_get_max_level();
|
|
||||||
|
|
||||||
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
|
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug_errno(r, "Failed to get cgroup, ignoring: %m");
|
log_debug_errno(r, "Failed to get cgroup, ignoring: %m");
|
||||||
@ -1319,8 +1270,6 @@ int manager_init(Manager *manager) {
|
|||||||
int manager_main(Manager *manager) {
|
int manager_main(Manager *manager) {
|
||||||
int fd_worker, r;
|
int fd_worker, r;
|
||||||
|
|
||||||
manager_set_default_children_max(manager);
|
|
||||||
|
|
||||||
/* unnamed socket from workers to the main daemon */
|
/* unnamed socket from workers to the main daemon */
|
||||||
r = socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
|
r = socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1412,7 +1361,7 @@ int manager_main(Manager *manager) {
|
|||||||
|
|
||||||
udev_builtin_init();
|
udev_builtin_init();
|
||||||
|
|
||||||
r = udev_rules_load(&manager->rules, manager->resolve_name_timing);
|
r = udev_rules_load(&manager->rules, manager->config.resolve_name_timing);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read udev rules: %m");
|
return log_error_errno(r, "Failed to read udev rules: %m");
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
#include "udev-config.h"
|
||||||
#include "udev-ctrl.h"
|
#include "udev-ctrl.h"
|
||||||
#include "udev-def.h"
|
#include "udev-def.h"
|
||||||
|
|
||||||
@ -21,7 +22,6 @@ typedef struct Manager {
|
|||||||
Hashmap *workers;
|
Hashmap *workers;
|
||||||
LIST_HEAD(Event, events);
|
LIST_HEAD(Event, events);
|
||||||
char *cgroup;
|
char *cgroup;
|
||||||
int log_level;
|
|
||||||
|
|
||||||
UdevRules *rules;
|
UdevRules *rules;
|
||||||
Hashmap *properties;
|
Hashmap *properties;
|
||||||
@ -38,12 +38,11 @@ typedef struct Manager {
|
|||||||
|
|
||||||
usec_t last_usec;
|
usec_t last_usec;
|
||||||
|
|
||||||
ResolveNameTiming resolve_name_timing;
|
UdevConfig config_by_udev_conf;
|
||||||
unsigned children_max;
|
UdevConfig config_by_command;
|
||||||
usec_t exec_delay_usec;
|
UdevConfig config_by_kernel;
|
||||||
usec_t timeout_usec;
|
UdevConfig config_by_control;
|
||||||
int timeout_signal;
|
UdevConfig config;
|
||||||
bool blockdev_read_only;
|
|
||||||
|
|
||||||
bool stop_exec_queue;
|
bool stop_exec_queue;
|
||||||
bool exit;
|
bool exit;
|
||||||
@ -53,7 +52,6 @@ Manager* manager_new(void);
|
|||||||
Manager* manager_free(Manager *manager);
|
Manager* manager_free(Manager *manager);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
||||||
|
|
||||||
void manager_adjust_arguments(Manager *manager);
|
|
||||||
int manager_init(Manager *manager);
|
int manager_init(Manager *manager);
|
||||||
int manager_main(Manager *manager);
|
int manager_main(Manager *manager);
|
||||||
|
|
||||||
|
@ -240,8 +240,8 @@ int udev_event_spawn(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int timeout_signal = event->worker ? event->worker->timeout_signal : SIGKILL;
|
int timeout_signal = event->worker ? event->worker->config.timeout_signal : SIGKILL;
|
||||||
usec_t timeout_usec = event->worker ? event->worker->timeout_usec : DEFAULT_WORKER_TIMEOUT_USEC;
|
usec_t timeout_usec = event->worker ? event->worker->config.timeout_usec : DEFAULT_WORKER_TIMEOUT_USEC;
|
||||||
usec_t now_usec = now(CLOCK_MONOTONIC);
|
usec_t now_usec = now(CLOCK_MONOTONIC);
|
||||||
usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec);
|
usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec);
|
||||||
usec_t cmd_timeout_usec = usec_sub_unsigned(timeout_usec, age_usec);
|
usec_t cmd_timeout_usec = usec_sub_unsigned(timeout_usec, age_usec);
|
||||||
@ -349,20 +349,20 @@ void udev_event_execute_run(UdevEvent *event) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command);
|
log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command);
|
||||||
} else {
|
} else {
|
||||||
if (event->worker && event->worker->exec_delay_usec > 0) {
|
if (event->worker && event->worker->config.exec_delay_usec > 0) {
|
||||||
usec_t now_usec = now(CLOCK_MONOTONIC);
|
usec_t now_usec = now(CLOCK_MONOTONIC);
|
||||||
usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec);
|
usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec);
|
||||||
|
|
||||||
if (event->worker->exec_delay_usec >= usec_sub_unsigned(event->worker->timeout_usec, age_usec)) {
|
if (event->worker->config.exec_delay_usec >= usec_sub_unsigned(event->worker->config.timeout_usec, age_usec)) {
|
||||||
log_device_warning(event->dev,
|
log_device_warning(event->dev,
|
||||||
"Cannot delay execution of \"%s\" for %s, skipping.",
|
"Cannot delay execution of \"%s\" for %s, skipping.",
|
||||||
command, FORMAT_TIMESPAN(event->worker->exec_delay_usec, USEC_PER_SEC));
|
command, FORMAT_TIMESPAN(event->worker->config.exec_delay_usec, USEC_PER_SEC));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.",
|
log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.",
|
||||||
command, FORMAT_TIMESPAN(event->worker->exec_delay_usec, USEC_PER_SEC));
|
command, FORMAT_TIMESPAN(event->worker->config.exec_delay_usec, USEC_PER_SEC));
|
||||||
(void) usleep_safe(event->worker->exec_delay_usec);
|
(void) usleep_safe(event->worker->config.exec_delay_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_device_debug(event->dev, "Running command \"%s\"", command);
|
log_device_debug(event->dev, "Running command \"%s\"", command);
|
||||||
|
@ -194,7 +194,7 @@ static int worker_process_device(UdevWorker *worker, sd_device *dev) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (worker->blockdev_read_only)
|
if (worker->config.blockdev_read_only)
|
||||||
(void) worker_mark_block_device_read_only(dev);
|
(void) worker_mark_block_device_read_only(dev);
|
||||||
|
|
||||||
/* Disable watch during event processing. */
|
/* Disable watch during event processing. */
|
||||||
@ -321,7 +321,7 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device *
|
|||||||
log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m");
|
log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m");
|
||||||
|
|
||||||
/* Reset the log level, as it might be changed by "OPTIONS=log_level=". */
|
/* Reset the log level, as it might be changed by "OPTIONS=log_level=". */
|
||||||
log_set_max_level(worker->log_level);
|
log_set_max_level(worker->config.log_level);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "errno-list.h"
|
#include "errno-list.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
#include "udev-config.h"
|
||||||
|
|
||||||
#define DEFAULT_WORKER_TIMEOUT_USEC (3 * USEC_PER_MINUTE)
|
#define DEFAULT_WORKER_TIMEOUT_USEC (3 * USEC_PER_MINUTE)
|
||||||
#define MIN_WORKER_TIMEOUT_USEC (1 * USEC_PER_MSEC)
|
#define MIN_WORKER_TIMEOUT_USEC (1 * USEC_PER_MSEC)
|
||||||
@ -27,11 +28,7 @@ typedef struct UdevWorker {
|
|||||||
int pipe_fd;
|
int pipe_fd;
|
||||||
int inotify_fd; /* Do not close! */
|
int inotify_fd; /* Do not close! */
|
||||||
|
|
||||||
usec_t exec_delay_usec;
|
UdevConfig config;
|
||||||
usec_t timeout_usec;
|
|
||||||
int timeout_signal;
|
|
||||||
int log_level;
|
|
||||||
bool blockdev_read_only;
|
|
||||||
} UdevWorker;
|
} UdevWorker;
|
||||||
|
|
||||||
/* passed from worker to main process */
|
/* passed from worker to main process */
|
||||||
|
250
src/udev/udevd.c
250
src/udev/udevd.c
@ -5,250 +5,17 @@
|
|||||||
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>
|
* 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 "errno-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "parse-util.h"
|
|
||||||
#include "pretty-print.h"
|
|
||||||
#include "proc-cmdline.h"
|
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "rlimit-util.h"
|
#include "rlimit-util.h"
|
||||||
#include "selinux-util.h"
|
#include "selinux-util.h"
|
||||||
#include "signal-util.h"
|
#include "udev-config.h"
|
||||||
#include "syslog-util.h"
|
|
||||||
#include "udev-manager.h"
|
#include "udev-manager.h"
|
||||||
#include "udev-rules.h"
|
|
||||||
#include "udev-util.h"
|
|
||||||
#include "udevd.h"
|
#include "udevd.h"
|
||||||
#include "version.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[]) {
|
int run_udevd(int argc, char *argv[]) {
|
||||||
_cleanup_(manager_freep) Manager *manager = NULL;
|
_cleanup_(manager_freep) Manager *manager = NULL;
|
||||||
int r;
|
int r;
|
||||||
@ -259,23 +26,10 @@ int run_udevd(int argc, char *argv[]) {
|
|||||||
if (!manager)
|
if (!manager)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
manager_parse_udev_config(manager);
|
r = manager_load(manager, argc, argv);
|
||||||
|
|
||||||
r = parse_argv(argc, argv, manager);
|
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
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();
|
r = must_be_root();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
Loading…
Reference in New Issue
Block a user