]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: derive path ID for PNP devices from ACPI firmware node
authorAndre Eikmeyer <dev@deq.rocks>
Sun, 2 Aug 2026 13:48:41 +0000 (15:48 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 3 Aug 2026 04:54:17 +0000 (13:54 +0900)
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.

src/udev/udev-builtin-path_id.c
test/sys-script.py
test/test-udev.py

index 8ae66b30f2676b344cb9a6e43f53737e4190fdff..32028c83f6b8f8beb9bd107dcb0236b70ba7e7c0 100644 (file)
@@ -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)
index be45a211e214c62910b7278828ea36147edb9d86..550fb289dfec2d4e3dba420b3e489a94e585d662 100755 (executable)
@@ -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')
index da5d41efe0179ba9bf1d6bd986e75de9a0e188ba..c2ee8b1bc1440cefc7a546c7393d72ec854c7e6d 100755 (executable)
@@ -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(