]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/udev-util.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / shared / udev-util.c
index fdeaf8f613e5c2138ae3cd3e2259923ab8fedcde..4200032b3b6c15aeaddedae3cdc3ae4c35cb0268 100644 (file)
@@ -91,3 +91,81 @@ int udev_parse_config_full(
 
         return 0;
 }
+
+struct DeviceMonitorData {
+        const char *sysname;
+        sd_device *device;
+};
+
+static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) {
+        struct DeviceMonitorData *data = userdata;
+        const char *sysname;
+
+        assert(device);
+        assert(data);
+        assert(data->sysname);
+        assert(!data->device);
+
+        if (sd_device_get_sysname(device, &sysname) >= 0 && streq(sysname, data->sysname)) {
+                data->device = sd_device_ref(device);
+                return sd_event_exit(sd_device_monitor_get_event(monitor), 0);
+        }
+
+        return 0;
+}
+
+int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_device **ret) {
+        _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
+        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
+        struct DeviceMonitorData data = {};
+        int r;
+
+        assert(device);
+        assert(subsystem);
+
+        if (sd_device_get_is_initialized(device) > 0) {
+                if (ret)
+                        *ret = sd_device_ref(device);
+                return 0;
+        }
+
+        assert_se(sd_device_get_sysname(device, &data.sysname) >= 0);
+
+        /* Wait until the device is initialized, so that we can get access to the ID_PATH property */
+
+        r = sd_event_default(&event);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get default event: %m");
+
+        r = sd_device_monitor_new(&monitor);
+        if (r < 0)
+                return log_error_errno(r, "Failed to acquire monitor: %m");
+
+        r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, subsystem, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add %s subsystem match to monitor: %m", subsystem);
+
+        r = sd_device_monitor_attach_event(monitor, event);
+        if (r < 0)
+                return log_error_errno(r, "Failed to attach event to device monitor: %m");
+
+        r = sd_device_monitor_start(monitor, device_monitor_handler, &data);
+        if (r < 0)
+                return log_error_errno(r, "Failed to start device monitor: %m");
+
+        /* Check again, maybe things changed. Udev will re-read the db if the device wasn't initialized
+         * yet. */
+        if (sd_device_get_is_initialized(device) > 0) {
+                if (ret)
+                        *ret = sd_device_ref(device);
+                return 0;
+        }
+
+        r = sd_event_loop(event);
+        if (r < 0)
+                return log_error_errno(r, "Event loop failed: %m");
+
+        if (ret)
+                *ret = TAKE_PTR(data.device);
+        return 0;
+}