diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index 3307bb9db6..7ec3f6f0d6 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -751,7 +751,7 @@ int device_rename(sd_device *device, const char *name) { int device_shallow_clone(sd_device *old_device, sd_device **new_device) { _cleanup_(sd_device_unrefp) sd_device *ret = NULL; - const char *subsystem; + const char *val; int r; assert(old_device); @@ -765,17 +765,43 @@ int device_shallow_clone(sd_device *old_device, sd_device **new_device) { if (r < 0) return r; - if (sd_device_get_subsystem(old_device, &subsystem) >= 0) { - r = device_set_subsystem(ret, subsystem); + if (sd_device_get_subsystem(old_device, &val) >= 0) { + r = device_set_subsystem(ret, val); if (r < 0) return r; + + if (streq(val, "drivers")) { + ret->driver_subsystem = strdup(old_device->driver_subsystem); + if (!ret->driver_subsystem) + return -ENOMEM; + } } else ret->subsystem_set = true; - ret->devnum = old_device->devnum; + /* The device may be already removed. Let's copy minimal set of information to make + * device_get_device_id() work without uevent file. */ + + if (sd_device_get_property_value(old_device, "IFINDEX", &val) >= 0) { + r = device_set_ifindex(ret, val); + if (r < 0) + return r; + } + + if (sd_device_get_property_value(old_device, "MAJOR", &val) >= 0) { + const char *minor = NULL; + + (void) sd_device_get_property_value(old_device, "MINOR", &minor); + r = device_set_devnum(ret, val, minor); + if (r < 0) + return r; + } + + /* And then read uevent file, but ignore errors, as some devices seem to return a spurious + * error on read, e.g. -ENODEV, and even if ifindex or devnum is set in the above, + * sd_device_get_ifindex() or sd_device_get_devnum() fails. See. #19788. */ + (void) device_read_uevent_file(ret); *new_device = TAKE_PTR(ret); - return 0; }