+ handler = talloc_zero(NULL, struct device_handler);
+ handler->server = server;
+ handler->waitset = waitset;
+ handler->dry_run = dry_run;
+ handler->autoboot_enabled = config_get()->autoboot_enabled;
+
+ list_init(&handler->unresolved_boot_options);
+
+ /* set up our mount point base */
+ pb_mkdir_recursive(mount_base());
+
+ parser_init();
+
+ if (config_get()->safe_mode)
+ return handler;
+
+ rc = device_handler_init_sources(handler);
+ if (rc) {
+ talloc_free(handler);
+ return NULL;
+ }
+
+ return handler;
+}
+
+void device_handler_reinit(struct device_handler *handler)
+{
+ struct discover_boot_option *opt, *tmp;
+ struct ramdisk_device *ramdisk;
+ unsigned int i;
+
+ device_handler_cancel_default(handler);
+
+ /* free unresolved boot options */
+ list_for_each_entry_safe(&handler->unresolved_boot_options,
+ opt, tmp, list)
+ talloc_free(opt);
+ list_init(&handler->unresolved_boot_options);
+
+ /* drop all devices */
+ for (i = 0; i < handler->n_devices; i++) {
+ discover_server_notify_device_remove(handler->server,
+ handler->devices[i]->device);
+ ramdisk = handler->devices[i]->ramdisk;
+ talloc_free(handler->devices[i]);
+ talloc_free(ramdisk);
+ }
+
+ talloc_free(handler->devices);
+ handler->devices = NULL;
+ handler->n_devices = 0;
+ talloc_free(handler->ramdisks);
+ handler->ramdisks = NULL;
+ handler->n_ramdisks = 0;
+
+ device_handler_reinit_sources(handler);
+}
+
+void device_handler_remove(struct device_handler *handler,
+ struct discover_device *device)
+{
+ struct discover_boot_option *opt, *tmp;
+ unsigned int i;
+
+ for (i = 0; i < handler->n_devices; i++)
+ if (handler->devices[i] == device)
+ break;
+
+ if (i == handler->n_devices) {
+ talloc_free(device);
+ return;
+ }
+
+ /* Free any unresolved options, as they're currently allocated
+ * against the handler */
+ list_for_each_entry_safe(&handler->unresolved_boot_options,
+ opt, tmp, list) {
+ if (opt->device != device)
+ continue;
+ list_remove(&opt->list);
+ talloc_free(opt);
+ }
+
+ /* if this is a network device, we have to unregister it from the
+ * network code */
+ if (device->device->type == DEVICE_TYPE_NETWORK)
+ network_unregister_device(handler->network, device);
+
+ handler->n_devices--;
+ memmove(&handler->devices[i], &handler->devices[i + 1],
+ (handler->n_devices - i) * sizeof(handler->devices[0]));
+ handler->devices = talloc_realloc(handler, handler->devices,
+ struct discover_device *, handler->n_devices);
+
+ if (device->notified)
+ discover_server_notify_device_remove(handler->server,
+ device->device);
+
+ talloc_free(device);
+}
+
+static void boot_status(void *arg, struct boot_status *status)
+{
+ struct device_handler *handler = arg;
+
+ discover_server_notify_boot_status(handler->server, status);
+}
+
+static void countdown_status(struct device_handler *handler,
+ struct discover_boot_option *opt, unsigned int sec)
+{
+ struct boot_status status;
+
+ status.type = BOOT_STATUS_INFO;
+ status.progress = -1;
+ status.detail = NULL;
+ status.message = talloc_asprintf(handler,
+ _("Booting in %d sec: %s"), sec, opt->option->name);
+
+ discover_server_notify_boot_status(handler->server, &status);
+
+ talloc_free(status.message);
+}
+
+static int default_timeout(void *arg)
+{
+ struct device_handler *handler = arg;
+ struct discover_boot_option *opt;
+
+ if (!handler->default_boot_option)
+ return 0;
+
+ if (handler->pending_boot)
+ return 0;
+
+ opt = handler->default_boot_option;
+
+ if (handler->sec_to_boot) {
+ countdown_status(handler, opt, handler->sec_to_boot);
+ handler->sec_to_boot--;
+ handler->timeout_waiter = waiter_register_timeout(
+ handler->waitset, 1000,
+ default_timeout, handler);
+ return 0;
+ }
+
+ handler->timeout_waiter = NULL;
+
+ pb_log("Timeout expired, booting default option %s\n", opt->option->id);
+
+ handler->pending_boot = boot(handler, handler->default_boot_option,
+ NULL, handler->dry_run, boot_status, handler);
+ handler->pending_boot_is_default = true;