diff --git a/man/udevadm.xml b/man/udevadm.xml
index eb77356d86..ca6fa0353a 100644
--- a/man/udevadm.xml
+++ b/man/udevadm.xml
@@ -577,6 +577,17 @@
+
+
+
+ Trigger parent devices of found devices even if the parents
+ won't match the filter condition.
+ This is useful if we are interested to limit the coldplug activities to
+ some devices or subsystems.
+
+
+
+
diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm
index 3842d722e7..e5626c9301 100644
--- a/shell-completion/bash/udevadm
+++ b/shell-completion/bash/udevadm
@@ -58,7 +58,7 @@ _udevadm() {
--json --subsystem-match --subsystem-nomatch --attr-match --attr-nomatch --property-match
--tag-match --sysname-match --name-match --parent-match'
[TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid
- --initialized-match --initialized-nomatch'
+ --initialized-match --initialized-nomatch --include-parents'
[TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch
-a --attr-match -A --attr-nomatch -p --property-match
-g --tag-match -y --sysname-match --name-match -b --parent-match
diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm
index 9ff87d8312..5f5761cbfa 100644
--- a/shell-completion/zsh/_udevadm
+++ b/shell-completion/zsh/_udevadm
@@ -38,6 +38,7 @@ _udevadm_trigger(){
'--tag-match=[Trigger events for devices with a matching tag.]:TAG' \
'--sysname-match=[Trigger events for devices with a matching sys device name.]:NAME' \
'--parent-match=[Trigger events for all children of a given device.]:NAME' \
+ '--include-parents[Also trigger parent devices of found devices.]' \
'--initialized-match[Trigger events for devices that are already initialized.]' \
'--initialized-nomatch[Trigger events for devices that are not initialized yet.]' \
'--uuid[Print synthetic uevent UUID.]' \
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 35f55d0cdd..6fbe621c3d 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -1065,4 +1065,5 @@ global:
sd_json_variant_type_from_string;
sd_json_variant_type_to_string;
sd_varlink_reset_fds;
+ sd_device_enumerator_add_all_parents;
} LIBSYSTEMD_257;
diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c
index 00d3328471..ca7e70393b 100644
--- a/src/libsystemd/sd-device/device-enumerator.c
+++ b/src/libsystemd/sd-device/device-enumerator.c
@@ -24,6 +24,17 @@ typedef enum DeviceEnumerationType {
_DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL,
} DeviceEnumerationType;
+typedef enum MatchFlag {
+ MATCH_NONE = 0,
+ MATCH_BASIC = 1u << 0,
+ MATCH_SYSNAME = 1u << 1,
+ MATCH_SUBSYSTEM = 1u << 2,
+ MATCH_PARENT = 1u << 3,
+ MATCH_TAG = 1u << 4,
+
+ MATCH_ALL = (1u << 5) - 1,
+} MatchFlag;
+
struct sd_device_enumerator {
unsigned n_ref;
@@ -46,6 +57,7 @@ struct sd_device_enumerator {
Set *match_tag;
Set *match_parent;
MatchInitializedType match_initialized;
+ MatchFlag parent_match_flags;
};
_public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
@@ -61,6 +73,7 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
.n_ref = 1,
.type = _DEVICE_ENUMERATION_TYPE_INVALID,
.match_initialized = MATCH_INITIALIZED_COMPAT,
+ .parent_match_flags = MATCH_ALL,
};
*ret = TAKE_PTR(enumerator);
@@ -273,6 +286,15 @@ _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enum
return 1;
}
+_public_ int sd_device_enumerator_add_all_parents(sd_device_enumerator *enumerator) {
+ assert_return(enumerator, -EINVAL);
+
+ enumerator->parent_match_flags = MATCH_NONE;
+
+ enumerator->scan_uptodate = false;
+
+ return 1;
+}
int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type) {
assert_return(enumerator, -EINVAL);
@@ -567,15 +589,6 @@ static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsys
return set_fnmatch(enumerator->match_subsystem, enumerator->nomatch_subsystem, subsystem);
}
-typedef enum MatchFlag {
- MATCH_SYSNAME = 1u << 0,
- MATCH_SUBSYSTEM = 1u << 1,
- MATCH_PARENT = 1u << 2,
- MATCH_TAG = 1u << 3,
-
- MATCH_ALL = (1u << 4) - 1,
-} MatchFlag;
-
static int test_matches(
sd_device_enumerator *enumerator,
sd_device *device,
@@ -618,18 +631,20 @@ static int test_matches(
!match_tag(enumerator, device))
return false;
- r = match_initialized(enumerator, device);
- if (r <= 0)
- return r;
+ if (FLAGS_SET(flags, MATCH_BASIC)) {
+ r = match_initialized(enumerator, device);
+ if (r <= 0)
+ return r;
- if (!match_property(enumerator->match_property, device, /* match_all = */ false))
- return false;
+ if (!match_property(enumerator->match_property, device, /* match_all = */ false))
+ return false;
- if (!match_property(enumerator->match_property_required, device, /* match_all = */ true))
- return false;
+ if (!match_property(enumerator->match_property_required, device, /* match_all = */ true))
+ return false;
- if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
- return false;
+ if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
+ return false;
+ }
return true;
}
@@ -743,7 +758,7 @@ static int enumerator_scan_dir_and_add_devices(
/* Also include all potentially matching parent devices in the enumeration. These are things
* like root busses — e.g. /sys/devices/pci0000:00/ or /sys/devices/pnp0/, which ar not
* linked from /sys/class/ or /sys/bus/, hence pick them up explicitly here. */
- k = enumerator_add_parent_devices(enumerator, device, MATCH_ALL);
+ k = enumerator_add_parent_devices(enumerator, device, enumerator->parent_match_flags);
if (k < 0)
r = k;
}
diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c
index 620615b6bb..230493ed18 100644
--- a/src/libsystemd/sd-device/test-sd-device.c
+++ b/src/libsystemd/sd-device/test-sd-device.c
@@ -499,6 +499,43 @@ TEST(sd_device_enumerator_add_match_parent) {
}
}
+TEST(sd_device_enumerator_add_all_parents) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+
+ /* STEP 1: enumerate all block devices without all_parents() */
+ ASSERT_OK(sd_device_enumerator_new(&e));
+ ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
+
+ /* filter in only a subsystem */
+ ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
+ ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
+ ASSERT_OK(sd_device_enumerator_add_match_property(e, "DEVTYPE", "partition"));
+
+ unsigned devices_count_with_parents = 0;
+ unsigned devices_count_without_parents = 0;
+ FOREACH_DEVICE(e, dev) {
+ ASSERT_TRUE(device_in_subsystem(dev, "block"));
+ ASSERT_TRUE(device_is_devtype(dev, "partition"));
+ devices_count_without_parents++;
+ }
+
+ log_debug("found %u devices", devices_count_without_parents);
+
+ /* STEP 2: enumerate again with all_parents() */
+ ASSERT_OK(sd_device_enumerator_add_all_parents(e) >= 0);
+
+ unsigned not_filtered_parent_count = 0;
+ FOREACH_DEVICE(e, dev) {
+ if (!device_in_subsystem(dev, "block") || !device_is_devtype(dev, "partition"))
+ not_filtered_parent_count++;
+ devices_count_with_parents++;
+ }
+ log_debug("found %u devices out of %u that would have been excluded without all_parents()",
+ not_filtered_parent_count,
+ devices_count_with_parents);
+ ASSERT_EQ(devices_count_with_parents, devices_count_without_parents + not_filtered_parent_count);
+}
+
TEST(sd_device_get_child) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
int r;
diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h
index 41e6719963..f627ae6dae 100644
--- a/src/systemd/sd-device.h
+++ b/src/systemd/sd-device.h
@@ -137,6 +137,7 @@ int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, c
int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag);
int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent);
int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator);
+int sd_device_enumerator_add_all_parents(sd_device_enumerator *enumerator);
/* device monitor */
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 13413a1f72..695f440b8f 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -266,6 +266,7 @@ static int help(void) {
" -y --sysname-match=NAME Trigger devices with this /sys path\n"
" --name-match=NAME Trigger devices with this /dev name\n"
" -b --parent-match=NAME Trigger devices with that parent device\n"
+ " --include-parents Trigger parent devices of found devices\n"
" --initialized-match Trigger devices that are already initialized\n"
" --initialized-nomatch Trigger devices that are not initialized yet\n"
" -w --settle Wait for the triggered events to complete\n"
@@ -287,6 +288,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
ARG_PRIORITIZED_SUBSYSTEM,
ARG_INITIALIZED_MATCH,
ARG_INITIALIZED_NOMATCH,
+ ARG_INCLUDE_PARENTS,
};
static const struct option options[] = {
@@ -304,6 +306,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
{ "sysname-match", required_argument, NULL, 'y' },
{ "name-match", required_argument, NULL, ARG_NAME },
{ "parent-match", required_argument, NULL, 'b' },
+ { "include-parents", no_argument, NULL, ARG_INCLUDE_PARENTS },
{ "initialized-match", no_argument, NULL, ARG_INITIALIZED_MATCH },
{ "initialized-nomatch", no_argument, NULL, ARG_INITIALIZED_NOMATCH },
{ "settle", no_argument, NULL, 'w' },
@@ -428,6 +431,11 @@ int trigger_main(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
break;
}
+ case ARG_INCLUDE_PARENTS:
+ r = sd_device_enumerator_add_all_parents(e);
+ if (r < 0)
+ return log_error_errno(r, "Failed to always include all parents: %m");
+ break;
case 'w':
arg_settle = true;
break;