+ udev_monitor_unref(m);
+ return -1;
+}
+
+/*
+ * udev_process - waiter callback for monitor netlink.
+ */
+
+static int udev_process(void *arg)
+{
+ struct udev_monitor *monitor = arg;
+ struct udev_device *dev;
+ const char *action;
+
+ dev = udev_monitor_receive_device(monitor);
+ if (!dev) {
+ pb_log("udev_monitor_receive_device failed\n");
+ return -1;
+ }
+
+ action = udev_device_get_action(dev);
+
+ if (!action) {
+ pb_log("udev_device_get_action failed\n");
+ } else {
+ udev_handle_dev_action(dev, action);
+ }
+
+ udev_device_unref(dev);
+ return 0;
+}
+
+#ifdef UDEV_LOGGING
+static void udev_log_fn(struct udev __attribute__((unused)) *udev,
+ int __attribute__((unused)) priority, const char *file, int line,
+ const char *fn, const char *format, va_list args)
+{
+ pb_log("libudev: %s %s:%d: ", fn, file, line);
+ vfprintf(pb_log_get_stream(), format, args);
+}
+#endif
+
+struct pb_udev *udev_init(struct device_handler *handler,
+ struct waitset *waitset)
+{
+ struct pb_udev *udev;
+ int result;
+
+ udev = talloc_zero(handler, struct pb_udev);
+ talloc_set_destructor(udev, udev_destructor);
+ udev->handler = handler;
+
+ udev->udev = udev_new();
+
+ if (!udev->udev) {
+ pb_log("udev_new failed\n");
+ goto fail;
+ }
+
+ udev_set_userdata(udev->udev, udev);
+
+#ifdef UDEV_LOGGING
+ udev_set_log_fn(udev->udev, udev_log_fn);
+#endif
+
+ result = udev_setup_monitor(udev->udev, &udev->monitor);
+ if (result)
+ goto fail;
+
+ result = udev_enumerate(udev->udev);
+ if (result)
+ goto fail;
+
+ waiter_register_io(waitset, udev_monitor_get_fd(udev->monitor), WAIT_IN,
+ udev_process, udev->monitor);
+
+ pb_debug("%s: waiting on udev\n", __func__);
+
+ return udev;
+
+fail: