diff --git a/man/udev.conf.xml b/man/udev.conf.xml index 29c9743d1d..23a4595fa9 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,55 @@ . + + + 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. + + + + + resolve_names= + + + Specifes when systemd-udevd should resolve names of users and groups. When set to + (the default), names will be resolved when the rules are parsed. + When set to , names will be resolved for every event. When set to + , names will never be resolved and all devices will be owned by + root. + + This is the same as the option. + + diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9f69ee10a8..621968ef8e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3862,7 +3862,8 @@ static int run(int master, if (l < 0) return log_error_errno(errno, "Failed to read cgroup mode: %m"); if (l != sizeof(arg_unified_cgroup_hierarchy)) { - log_error("Short read while reading cgroup mode."); + log_error("Short read while reading cgroup mode (%zu bytes).%s", + l, l == 0 ? " The child is most likely dead." : ""); return -EIO; } } diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 7841f4a359..c6b7a02ad9 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -769,7 +769,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, } } - if ((flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY)) + if (flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY) return 0; r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags); diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c index a603867b16..959217c511 100644 --- a/src/shared/udev-util.c +++ b/src/shared/udev-util.c @@ -6,36 +6,88 @@ #include "alloc-util.h" #include "fileio.h" #include "log.h" +#include "parse-util.h" +#include "string-table.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; +static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = { + [RESOLVE_NAME_NEVER] = "never", + [RESOLVE_NAME_LATE] = "late", + [RESOLVE_NAME_EARLY] = "early", +}; + +DEFINE_STRING_TABLE_LOOKUP(resolve_name_timing, ResolveNameTiming); + +int udev_parse_config_full( + unsigned *ret_children_max, + usec_t *ret_exec_delay_usec, + usec_t *ret_event_timeout_usec, + ResolveNameTiming *ret_resolve_name_timing) { + + _cleanup_free_ char *log_val = NULL, *children_max = NULL, *exec_delay = NULL, *event_timeout = NULL, *resolve_names = 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); + } + + if (ret_resolve_name_timing && resolve_names) { + ResolveNameTiming t; + + t = resolve_name_timing_from_string(resolve_names); + if (t < 0) + log_notice("/etc/udev/udev.conf: failed to set parse resolve_names=%s, ignoring.", resolve_names); + else + *ret_resolve_name_timing = t; + } return 0; } diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h index 0df2cf9eb1..be08fe1ff8 100644 --- a/src/shared/udev-util.h +++ b/src/shared/udev-util.h @@ -1,4 +1,25 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -int udev_parse_config(void); +#include "time-util.h" + +typedef enum ResolveNameTiming { + RESOLVE_NAME_NEVER, + RESOLVE_NAME_LATE, + RESOLVE_NAME_EARLY, + _RESOLVE_NAME_TIMING_MAX, + _RESOLVE_NAME_TIMING_INVALID = -1, +} ResolveNameTiming; + +ResolveNameTiming resolve_name_timing_from_string(const char *s) _pure_; +const char *resolve_name_timing_to_string(ResolveNameTiming i) _const_; + +int udev_parse_config_full( + unsigned *ret_children_max, + usec_t *ret_exec_delay_usec, + usec_t *ret_event_timeout_usec, + ResolveNameTiming *ret_resolve_name_timing); + +static inline int udev_parse_config(void) { + return udev_parse_config_full(NULL, NULL, NULL, NULL); +} diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 7c70336e1b..b93876d26f 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -119,8 +119,8 @@ int main(int argc, char *argv[]) { } } - udev_event_execute_rules(event, 3 * USEC_PER_SEC, USEC_PER_SEC, NULL, rules); - udev_event_execute_run(event, 3 * USEC_PER_SEC, USEC_PER_SEC); + udev_event_execute_rules(event, 3 * USEC_PER_SEC, NULL, rules); + udev_event_execute_run(event, 3 * USEC_PER_SEC); out: mac_selinux_finish(); diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index d5666c1079..40f4dac05e 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -596,7 +596,6 @@ static int spawn_wait(Spawn *spawn) { int udev_event_spawn(struct udev_event *event, usec_t timeout_usec, - usec_t timeout_warn_usec, bool accept_failure, const char *cmd, char *result, size_t ressize) { @@ -667,7 +666,7 @@ int udev_event_spawn(struct udev_event *event, .cmd = cmd, .pid = pid, .accept_failure = accept_failure, - .timeout_warn_usec = timeout_warn_usec, + .timeout_warn_usec = udev_warn_timeout(timeout_usec), .timeout_usec = timeout_usec, .event_birth_usec = event->birth_usec, .fd_stdout = outpipe[READ_END], @@ -780,7 +779,7 @@ static int update_devnode(struct udev_event *event) { static void event_execute_rules_on_remove( struct udev_event *event, - usec_t timeout_usec, usec_t timeout_warn_usec, + usec_t timeout_usec, Hashmap *properties_list, struct udev_rules *rules) { @@ -802,16 +801,14 @@ static void event_execute_rules_on_remove( if (sd_device_get_devnum(dev, NULL) >= 0) (void) udev_watch_end(dev); - (void) udev_rules_apply_to_event(rules, event, - timeout_usec, timeout_warn_usec, - properties_list); + (void) udev_rules_apply_to_event(rules, event, timeout_usec, properties_list); if (sd_device_get_devnum(dev, NULL) >= 0) (void) udev_node_remove(dev); } int udev_event_execute_rules(struct udev_event *event, - usec_t timeout_usec, usec_t timeout_warn_usec, + usec_t timeout_usec, Hashmap *properties_list, struct udev_rules *rules) { sd_device *dev = event->dev; @@ -830,7 +827,7 @@ int udev_event_execute_rules(struct udev_event *event, return log_device_error_errno(dev, r, "Failed to get property 'ACTION': %m"); if (streq(action, "remove")) { - event_execute_rules_on_remove(event, timeout_usec, timeout_warn_usec, properties_list, rules); + event_execute_rules_on_remove(event, timeout_usec, properties_list, rules); return 0; } @@ -854,9 +851,7 @@ int udev_event_execute_rules(struct udev_event *event, (void) udev_watch_end(event->dev_db_clone); } - (void) udev_rules_apply_to_event(rules, event, - timeout_usec, timeout_warn_usec, - properties_list); + (void) udev_rules_apply_to_event(rules, event, timeout_usec, properties_list); (void) rename_netif(event); (void) update_devnode(event); @@ -882,7 +877,7 @@ int udev_event_execute_rules(struct udev_event *event, return 0; } -void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec) { +void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec) { const char *cmd; void *val; Iterator i; @@ -901,7 +896,7 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_ (void) usleep(event->exec_delay_usec); } - udev_event_spawn(event, timeout_usec, timeout_warn_usec, false, command, NULL, 0); + udev_event_spawn(event, timeout_usec, false, command, NULL, 0); } } } diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index c8b905a873..d582319cf7 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -30,7 +30,6 @@ #include "stat-util.h" #include "stdio-util.h" #include "strbuf.h" -#include "string-table.h" #include "string-util.h" #include "strv.h" #include "sysctl-util.h" @@ -641,13 +640,12 @@ static int import_file_into_properties(sd_device *dev, const char *filename) { static int import_program_into_properties(struct udev_event *event, usec_t timeout_usec, - usec_t timeout_warn_usec, const char *program) { char result[UTIL_LINE_SIZE]; char *line; int err; - err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, true, program, result, sizeof(result)); + err = udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)); if (err < 0) return err; @@ -1728,7 +1726,6 @@ int udev_rules_apply_to_event( struct udev_rules *rules, struct udev_event *event, usec_t timeout_usec, - usec_t timeout_warn_usec, Hashmap *properties_list) { sd_device *dev = event->dev; enum escape_type esc = ESCAPE_UNSET; @@ -1965,7 +1962,7 @@ int udev_rules_apply_to_event( rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); - if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, true, program, result, sizeof(result)) < 0) { + if (udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)) < 0) { if (cur->key.op != OP_NOMATCH) goto nomatch; } else { @@ -2001,7 +1998,7 @@ int udev_rules_apply_to_event( rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); - if (import_program_into_properties(event, timeout_usec, timeout_warn_usec, import) != 0) + if (import_program_into_properties(event, timeout_usec, import) != 0) if (cur->key.op != OP_NOMATCH) goto nomatch; break; @@ -2601,11 +2598,3 @@ finish: return 0; } - -static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = { - [RESOLVE_NAME_NEVER] = "never", - [RESOLVE_NAME_LATE] = "late", - [RESOLVE_NAME_EARLY] = "early", -}; - -DEFINE_STRING_TABLE_LOOKUP(resolve_name_timing, ResolveNameTiming); diff --git a/src/udev/udev.conf b/src/udev/udev.conf index 0d812d4a65..7deb7715be 100644 --- a/src/udev/udev.conf +++ b/src/udev/udev.conf @@ -3,4 +3,8 @@ # 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 +#resolve_names=early diff --git a/src/udev/udev.h b/src/udev/udev.h index 5c6ca6bf9f..e92e878e24 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -18,6 +18,7 @@ #include "macro.h" #include "strv.h" #include "util.h" +#include "udev-util.h" struct udev_event { sd_device *dev; @@ -48,26 +49,19 @@ struct udev_event { bool run_final; }; -typedef enum ResolveNameTiming { - RESOLVE_NAME_NEVER, - RESOLVE_NAME_LATE, - RESOLVE_NAME_EARLY, - _RESOLVE_NAME_TIMING_MAX, - _RESOLVE_NAME_TIMING_INVALID = -1, -} ResolveNameTiming; - /* udev-rules.c */ struct udev_rules; struct udev_rules *udev_rules_new(ResolveNameTiming resolve_name_timing); struct udev_rules *udev_rules_unref(struct udev_rules *rules); bool udev_rules_check_timestamp(struct udev_rules *rules); int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, - usec_t timeout_usec, usec_t timeout_warn_usec, + usec_t timeout_usec, Hashmap *properties_list); int udev_rules_apply_static_dev_perms(struct udev_rules *rules); -ResolveNameTiming resolve_name_timing_from_string(const char *s) _pure_; -const char *resolve_name_timing_to_string(ResolveNameTiming i) _const_; +static inline usec_t udev_warn_timeout(usec_t timeout_usec) { + return DIV_ROUND_UP(timeout_usec, 3); +} /* udev-event.c */ struct udev_event *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl); @@ -77,14 +71,13 @@ ssize_t udev_event_apply_format(struct udev_event *event, bool replace_whitespace); int udev_event_spawn(struct udev_event *event, usec_t timeout_usec, - usec_t timeout_warn_usec, bool accept_failure, const char *cmd, char *result, size_t ressize); int udev_event_execute_rules(struct udev_event *event, - usec_t timeout_usec, usec_t timeout_warn_usec, + usec_t timeout_usec, Hashmap *properties_list, struct udev_rules *rules); -void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec); +void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec); /* Cleanup functions */ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_free); diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index dd0fc4f91f..6f3b6099a9 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -131,10 +131,7 @@ int test_main(int argc, char *argv[], void *userdata) { sigfillset(&mask); sigprocmask(SIG_SETMASK, &mask, &sigmask_orig); - udev_event_execute_rules(event, - 60 * USEC_PER_SEC, 20 * USEC_PER_SEC, - NULL, - rules); + udev_event_execute_rules(event, 60 * USEC_PER_SEC, NULL, rules); FOREACH_DEVICE_PROPERTY(dev, key, value) printf("%s=%s\n", key, value); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 354910e684..409d32b8b5 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -66,7 +66,6 @@ static ResolveNameTiming arg_resolve_name_timing = RESOLVE_NAME_EARLY; static unsigned arg_children_max = 0; static usec_t arg_exec_delay_usec = 0; static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC; -static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3; typedef struct Manager { sd_event *event; @@ -271,7 +270,7 @@ static void worker_attach_event(struct worker *worker, struct event *event) { assert_se(sd_event_now(e, CLOCK_MONOTONIC, &usec) >= 0); (void) sd_event_add_time(e, &event->timeout_warning, CLOCK_MONOTONIC, - usec + arg_event_timeout_warn_usec, USEC_PER_SEC, on_event_timeout_warning, event); + usec + udev_warn_timeout(arg_event_timeout_usec), USEC_PER_SEC, on_event_timeout_warning, event); (void) sd_event_add_time(e, &event->timeout, CLOCK_MONOTONIC, usec + arg_event_timeout_usec, USEC_PER_SEC, on_event_timeout, event); @@ -442,13 +441,8 @@ static void worker_spawn(Manager *manager, struct event *event) { } /* apply rules, create node, symlinks */ - udev_event_execute_rules(udev_event, - arg_event_timeout_usec, arg_event_timeout_warn_usec, - manager->properties, - manager->rules); - - udev_event_execute_run(udev_event, - arg_event_timeout_usec, arg_event_timeout_warn_usec); + udev_event_execute_rules(udev_event, arg_event_timeout_usec, manager->properties, manager->rules); + udev_event_execute_run(udev_event, arg_event_timeout_usec); if (!rtnl) /* in case rtnl was initialized */ @@ -1421,8 +1415,6 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat return 0; r = parse_sec(value, &arg_event_timeout_usec); - if (r >= 0) - arg_event_timeout_warn_usec = DIV_ROUND_UP(arg_event_timeout_usec, 3); } else if (proc_cmdline_key_streq(key, "udev.children_max")) { @@ -1514,8 +1506,6 @@ static int parse_argv(int argc, char *argv[]) { r = parse_sec(optarg, &arg_event_timeout_usec); if (r < 0) log_warning_errno(r, "Failed to parse --event-timeout= value '%s', ignoring: %m", optarg); - - arg_event_timeout_warn_usec = DIV_ROUND_UP(arg_event_timeout_usec, 3); break; case 'D': arg_debug = true; @@ -1713,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, &arg_resolve_name_timing); log_parse_environment(); log_open();