From: Andre Eikmeyer Date: Sun, 2 Aug 2026 13:48:41 +0000 (+0200) Subject: udev: derive path ID for PNP devices from ACPI firmware node X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6044c31038a2c24294f29df40a0cae9c19cc5e9b;p=thirdparty%2Fsystemd.git udev: derive path ID for PNP devices from ACPI firmware node PNP devices may represent ACPI-enumerated hardware but do not have a parent type supported by path_id. Consequently, importing path_id fails even when the PNP device exposes a stable ACPI firmware_node. This also prevents later assignments in rules such as the systemd-backlight activation rule from taking effect. Resolve the PNP device's firmware_node and use its ACPI sysname for the path component. This gives PNP-backed devices the same stable identity as their firmware representation. Add a regression test using an RTC device below a PNP parent with an ACPI firmware node. --- diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 8ae66b30f26..32028c83f6b 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -677,6 +677,30 @@ static void add_id_tag(UdevEvent *event, const char *path) { (void) udev_builtin_add_property(event, "ID_PATH_TAG", tag); } +static int handle_pnp(sd_device *parent, char **path) { + _cleanup_(sd_device_unrefp) sd_device *firmware_node = NULL; + const char *sysname; + int r; + + assert(parent); + assert(path); + + r = sd_device_new_child(&firmware_node, parent, "firmware_node"); + if (r < 0) + return r; + + if (device_in_subsystem(firmware_node, "acpi") <= 0) + return -ENODEV; + + r = sd_device_get_sysname(firmware_node, &sysname); + if (r < 0) + return r; + + path_prepend(path, "acpi-%s", sysname); + + return 0; +} + static int builtin_path_id(UdevEvent *event, int argc, char *argv[]) { sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); _cleanup_(sd_device_unrefp) sd_device *dev_other_branch = NULL; @@ -749,6 +773,10 @@ static int builtin_path_id(UdevEvent *event, int argc, char *argv[]) { path_prepend(&compat_path, "acpi-%s", sysname); parent = skip_subsystem(parent, "acpi"); supported_parent = true; + } else if (device_in_subsystem(parent, "pnp") > 0) { + if (handle_pnp(parent, &path) >= 0) + supported_parent = true; + parent = skip_subsystem(parent, "pnp"); } else if (device_in_subsystem(parent, "xen") > 0) { path_prepend(&path, "xen-%s", sysname); if (compat_path) diff --git a/test/sys-script.py b/test/sys-script.py index be45a211e21..550fb289dfe 100755 --- a/test/sys-script.py +++ b/test/sys-script.py @@ -10584,6 +10584,7 @@ f('sys/devices/pnp0/00:07/rtc/rtc0/name', 0o644, b'rtc_cmos\n') f('sys/devices/pnp0/00:07/rtc/rtc0/time', 0o644, b'02:30:51\n') f('sys/devices/pnp0/00:07/rtc/rtc0/uevent', 0o644, b'''MAJOR=253 MINOR=0 +DEVNAME=rtc0 ''') d('sys/devices/pnp0/00:07/rtc/rtc0/power', 0o755) f('sys/devices/pnp0/00:07/rtc/rtc0/power/wakeup', 0o644, b'\n') diff --git a/test/test-udev.py b/test/test-udev.py index da5d41efe01..c2ee8b1bc14 100755 --- a/test/test-udev.py +++ b/test/test-udev.py @@ -2071,6 +2071,17 @@ SUBSYSTEMS=="scsi", PROGRAM=="/bin/bash -c \"printf %%s 'foo1 foo2' | grep 'foo1 KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}" ''', ), + Rules.new( + 'builtin path_id for PNP device with ACPI firmware node', + Device( + '/devices/pnp0/00:07/rtc/rtc0', + exp_links=['rtc/by-path/acpi-PNP0B00:00'], + ), + rules=r''' + KERNEL=="rtc0", IMPORT{builtin}="path_id" + KERNEL=="rtc0", ENV{ID_PATH}=="?*", SYMLINK+="rtc/by-path/$env{ID_PATH}" + ''', + ), Rules.new( 'add and match tag', Device(