udev: fix several option parsing edge cases (#42997)

Boundary tests were conducted on the udev subsystem, and some issues
were identified and resolved.
This commit is contained in:
Luca Boccassi
2026-07-13 13:42:27 +01:00
committed by GitHub
9 changed files with 35 additions and 14 deletions
+13
View File
@@ -2,6 +2,7 @@
#include "alloc-util.h"
#include "tests.h"
#include "udev-config.h"
#include "udev-manager.h"
TEST(devpath_conflict) {
@@ -35,4 +36,16 @@ TEST(worker_free_detaches_event) {
ASSERT_NULL(event->worker);
}
TEST(manager_load_merges_children_max) {
_cleanup_(manager_freep) Manager *manager = ASSERT_PTR(manager_new());
char *argv[] = {
(char*) "systemd-udevd",
(char*) "--children-max=1",
NULL,
};
ASSERT_OK_POSITIVE(manager_load(manager, ELEMENTSOF(argv) - 1, argv));
ASSERT_EQ(manager->config.children_max, 1U);
}
DEFINE_TEST_MAIN(LOG_DEBUG);
+1 -1
View File
@@ -118,7 +118,7 @@ static void get_cap_mask(
val = bitmask_size / sizeof (unsigned long);
/* skip trailing zeros */
while (bitmask[val-1] == 0 && val > 0)
while (val > 0 && bitmask[val-1] == 0)
--val;
/* IN_SET() cannot be used in assert_cc(). */
+1
View File
@@ -281,6 +281,7 @@ static void manager_merge_config(Manager *manager) {
manager_merge_config_log_level(manager);
MERGE_NON_NEGATIVE(resolve_name_timing, RESOLVE_NAME_EARLY);
MERGE_NON_ZERO(children_max, 0);
MERGE_NON_ZERO(exec_delay_usec, 0);
MERGE_NON_ZERO(timeout_usec, DEFAULT_WORKER_TIMEOUT_USEC);
MERGE_NON_ZERO(timeout_signal, SIGKILL);
+2 -10
View File
@@ -530,7 +530,7 @@ static int setup_matches(sd_device_enumerator *e) {
STRV_FOREACH(a, arg_attr_match) {
_cleanup_free_ char *k = NULL, *v = NULL;
r = parse_key_value_argument(*a, /* require_value= */ true, &k, &v);
r = parse_key_value_argument(*a, /* require_value= */ false, &k, &v);
if (r < 0)
return r;
@@ -542,7 +542,7 @@ static int setup_matches(sd_device_enumerator *e) {
STRV_FOREACH(a, arg_attr_nomatch) {
_cleanup_free_ char *k = NULL, *v = NULL;
r = parse_key_value_argument(*a, /* require_value= */ true, &k, &v);
r = parse_key_value_argument(*a, /* require_value= */ false, &k, &v);
if (r < 0)
return r;
@@ -1118,10 +1118,6 @@ static int parse_argv(int argc, char *argv[]) {
OPTION_LONG("attr-match", "FILE[=VALUE]",
"Query devices that match an attribute"):
if (!strchr(opts.arg, '='))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected <ATTR>=<value> instead of '%s'", opts.arg);
r = strv_extend(&arg_attr_match, opts.arg);
if (r < 0)
return log_oom();
@@ -1129,10 +1125,6 @@ static int parse_argv(int argc, char *argv[]) {
OPTION_LONG("attr-nomatch", "FILE[=VALUE]",
"Query devices that do not match an attribute"):
if (!strchr(opts.arg, '='))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected <ATTR>=<value> instead of '%s'", opts.arg);
r = strv_extend(&arg_attr_nomatch, opts.arg);
if (r < 0)
return log_oom();
+4
View File
@@ -88,6 +88,10 @@ static int parse_argv(int argc, char *argv[]) {
opts.opt->short_code);
}
if (option_parser_get_n_args(&opts) > 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"This subprogram takes no positional arguments.");
return 1;
}
+1 -1
View File
@@ -469,7 +469,7 @@ static int parse_argv(int argc, char *argv[]) {
if (opts.arg) {
r = parse_sec(opts.arg, &arg_ping_timeout_usec);
if (r < 0)
log_error_errno(r, "Failed to parse timeout value '%s', ignoring: %m", opts.arg);
return log_error_errno(r, "Failed to parse timeout value '%s': %m", opts.arg);
}
break;
+5 -1
View File
@@ -32,6 +32,7 @@ typedef enum WaitUntil {
static WaitUntil arg_wait_until = WAIT_UNTIL_INITIALIZED;
static usec_t arg_timeout_usec = USEC_INFINITY;
static bool arg_removed = false;
static bool arg_settle = false;
static char **arg_devices = NULL;
@@ -350,7 +351,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
OPTION_LONG("removed", NULL, "Wait for devices being removed"):
arg_wait_until = WAIT_UNTIL_REMOVED;
arg_removed = true;
break;
OPTION_LONG("settle", NULL, "Also wait for all queued events being processed"):
@@ -358,6 +359,9 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
if (arg_removed)
arg_wait_until = WAIT_UNTIL_REMOVED;
char **args = option_parser_get_args(&opts);
if (strv_isempty(args))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),