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
+1 -1
View File
@@ -240,7 +240,7 @@
<term><option>--device-id-of-file=<replaceable>FILE</replaceable></option></term>
<listitem>
<para>Print major/minor numbers of the underlying device, where the file lives on.
If this is specified, all positional arguments are ignored.</para>
If this is specified, no positional arguments are accepted.</para>
</listitem>
</varlistentry>
<varlistentry>
+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),
+7
View File
@@ -120,7 +120,9 @@ udevadm info -e --json=short | jq . >/dev/null
udevadm info -e --subsystem-match acpi >/dev/null
udevadm info -e --subsystem-nomatch acpi >/dev/null
udevadm info -e --attr-match ifindex=2 >/dev/null
udevadm info -e --attr-match ifindex >/dev/null
udevadm info -e --attr-nomatch ifindex=2 >/dev/null
udevadm info -e --attr-nomatch ifindex >/dev/null
udevadm info -e --property-match SUBSYSTEM=acpi >/dev/null
udevadm info -e --tag-match systemd >/dev/null
udevadm info -e --sysname-match lo >/dev/null
@@ -150,6 +152,7 @@ udevadm monitor -h
udevadm settle
udevadm settle -t 5
udevadm settle -E /sys/class/net/$netdev
(! udevadm settle /no/such/argument)
udevadm settle -h
udevadm test /dev/null
@@ -279,6 +282,7 @@ udevadm trigger --parent-match /sys/class/net/$netdev --name-match /dev/null
udevadm trigger --initialized-match
udevadm trigger --initialized-nomatch
udevadm trigger -w
(! udevadm trigger --dry-run --wait-daemon=bad)
udevadm trigger --uuid /sys/class/net/$netdev
udevadm settle -t 300
udevadm trigger --wait-daemon
@@ -301,6 +305,9 @@ udevadm wait -t 5 /sys/class/net/$netdev
udevadm wait --initialized true /sys/class/net/$netdev
udevadm wait --initialized false /sys/class/net/$netdev
(! udevadm wait --initialized hello /sys/class/net/$netdev)
udevadm wait --timeout=0 --removed /dev/no-such-test-device
udevadm wait --timeout=0 --removed --initialized=no /dev/no-such-test-device
udevadm wait --timeout=0 --initialized=no --removed /dev/no-such-test-device
assert_rc 124 timeout 5 udevadm wait --removed /sys/class/net/$netdev
udevadm wait --settle /sys/class/net/$netdev
udevadm wait -h