]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
libudev: cache the errno for a failed parent lookup main
authorDaniel28972897 <danyboy28sep@gmail.com>
Wed, 29 Jul 2026 04:23:05 +0000 (22:23 -0600)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 29 Jul 2026 22:24:17 +0000 (07:24 +0900)
udev_device_get_parent() caches the result of device_new_from_parent()
in udev_device->parent on first call. device_new_from_parent() sets
errno correctly via return_with_errno() when it fails, so a caller
gets the right errno on the first invocation. But on any subsequent
call for the same object, the cached NULL is returned directly without
recomputing anything, so errno reflects whatever happened in between
rather than the original failure reason.

Cache the errno alongside the parent pointer (new parent_errno field,
zero-initialized like the rest of the struct via udev_device_new()'s
compound literal) and restore it whenever the cached parent is NULL.

src/libudev/libudev-device.c

index 22ff6075e856672a137c6e0825cf6bbe9c6f8939..0216d56ae32e25e8d9fceeee4a9e1cb6c85260fd 100644 (file)
@@ -38,6 +38,7 @@ struct udev_device {
 
         struct udev_device *parent;
         bool parent_set;
+        int parent_errno;
 
         struct udev_list *properties;
         uint64_t properties_generation;
@@ -393,9 +394,12 @@ _public_ struct udev_device* udev_device_get_parent(struct udev_device *udev_dev
         if (!udev_device->parent_set) {
                 udev_device->parent_set = true;
                 udev_device->parent = device_new_from_parent(udev_device);
+                udev_device->parent_errno = udev_device->parent ? 0 : errno;
         }
 
-        /* TODO: errno will differ here in case parent == NULL */
+        if (!udev_device->parent)
+                errno = udev_device->parent_errno;
+
         return udev_device->parent;
 }