+
+static int handle_add_udev_event(struct device_handler *handler,
+ struct event *event)
+{
+ struct discover_context *ctx;
+ const char *devname;
+ int rc;
+
+ /* create our context */
+ ctx = talloc(handler, struct discover_context);
+ ctx->event = event;
+ ctx->mount_path = NULL;
+ ctx->links = NULL;
+ ctx->n_links = 0;
+
+ ctx->id = talloc_strdup(ctx, event->device);
+
+ devname = event_get_param(ctx->event, "DEVNAME");
+ assert(devname);
+ ctx->device_path = talloc_strdup(ctx, devname);
+
+ rc = mount_device(ctx);
+ if (rc) {
+ talloc_free(ctx);
+ return 0;
+ }
+
+ list_add(&handler->contexts, &ctx->list);
+ talloc_set_destructor(ctx, destroy_context);
+
+ /* set up the top-level device */
+ ctx->device = talloc_zero(ctx, struct device);
+ ctx->device->id = talloc_strdup(ctx->device, ctx->id);
+ list_init(&ctx->device->boot_options);
+
+ /* run the parsers */
+ iterate_parsers(ctx);
+
+ /* add device to handler device array */
+ device_handler_add(handler, ctx->device);
+
+ discover_server_notify_add(handler->server, ctx->device);
+
+ return 0;
+}
+
+static int handle_remove_udev_event(struct device_handler *handler,
+ struct event *event)
+{
+ struct discover_context *ctx;
+
+ ctx = find_context(handler, event->device);
+ if (!ctx)
+ return 0;
+
+ discover_server_notify_remove(handler->server, ctx->device);
+
+ /* remove device from handler device array */
+ device_handler_remove(handler, ctx->device);
+
+ talloc_free(ctx);
+
+ return 0;
+}
+
+static int handle_add_user_event(struct device_handler *handler,
+ struct event *event)
+{
+ struct device *device;
+
+ assert(event->device);
+
+ device = talloc_zero(handler, struct device);
+
+ if (!device)
+ goto fail;
+
+ device->id = talloc_strdup(device, event->device);
+ list_init(&device->boot_options);
+
+ parse_user_event(device, event);
+
+ discover_server_notify_add(handler->server, device);
+
+ /* add device to handler device array */
+ device_handler_add(handler, device);
+
+ return 0;
+
+fail:
+ talloc_free(device);
+ return 0;
+}
+
+static int handle_remove_user_event(struct device_handler *handler,
+ struct event *event)
+{
+ struct device *device = device_handler_find(handler, event->device);
+
+ if (!device)
+ return 0;
+
+ discover_server_notify_remove(handler->server, device);
+
+ /* remove device from handler device array */
+ device_handler_remove(handler, device);
+
+ talloc_free(device);
+ return 0;
+}
+
+typedef int (*event_handler)(struct device_handler *, struct event *);
+
+static event_handler handlers[EVENT_TYPE_MAX][EVENT_ACTION_MAX] = {
+ [EVENT_TYPE_UDEV] = {
+ [EVENT_ACTION_ADD] = handle_add_udev_event,
+ [EVENT_ACTION_REMOVE] = handle_remove_udev_event,
+ },
+ [EVENT_TYPE_USER] = {
+ [EVENT_ACTION_ADD] = handle_add_user_event,
+ [EVENT_ACTION_REMOVE] = handle_remove_user_event,
+ }
+};
+
+int device_handler_event(struct device_handler *handler,
+ struct event *event)
+{
+ if (event->type >= EVENT_TYPE_MAX ||
+ event->action >= EVENT_ACTION_MAX ||
+ !handlers[event->type][event->action]) {
+ pb_log("%s unknown type/action: %d/%d\n", __func__,
+ event->type, event->action);
+ return 0;
+ }
+
+ return handlers[event->type][event->action](handler, event);
+}
+
+struct device_handler *device_handler_init(struct discover_server *server)
+{
+ struct device_handler *handler;
+
+ handler = talloc(NULL, struct device_handler);
+ handler->devices = NULL;
+ handler->n_devices = 0;
+ handler->server = server;
+
+ list_init(&handler->contexts);
+
+ /* set up our mount point base */
+ pb_mkdir_recursive(mount_base());
+
+ parser_init();
+
+ return handler;
+}
+
+void device_handler_destroy(struct device_handler *handler)
+{
+ talloc_free(handler);
+}