+ dev = talloc_zero(handler, struct ramdisk_device);
+ if (!dev) {
+ pb_log("Failed to allocate memory to track %s\n", path);
+ return;
+ }
+
+ dev->path = talloc_strdup(handler, path);
+
+ handler->ramdisks = talloc_realloc(handler, handler->ramdisks,
+ struct ramdisk_device *,
+ handler->n_ramdisks + 1);
+ if (!handler->ramdisks) {
+ pb_log("Failed to reallocate memory"
+ "- ramdisk tracking inconsistent!\n");
+ return;
+ }
+
+ handler->ramdisks[i] = dev;
+ handler->n_ramdisks++;
+}
+
+struct ramdisk_device *device_handler_get_ramdisk(
+ struct device_handler *handler)
+{
+ unsigned int i;
+ char *name;
+ dev_t id;
+
+ /* Check if free ramdisk exists */
+ for (i = 0; i < handler->n_ramdisks; i++)
+ if (!handler->ramdisks[i]->snapshot &&
+ !handler->ramdisks[i]->origin &&
+ !handler->ramdisks[i]->base)
+ return handler->ramdisks[i];
+
+ /* Otherwise create a new one */
+ name = talloc_asprintf(handler, "/dev/ram%d",
+ handler->n_ramdisks);
+ if (!name) {
+ pb_debug("Failed to allocate memory to name /dev/ram%d",
+ handler->n_ramdisks);
+ return NULL;
+ }
+
+ id = makedev(1, handler->n_ramdisks);
+ if (mknod(name, S_IFBLK, id)) {
+ if (errno == EEXIST) {
+ /* We haven't yet received updates for existing
+ * ramdisks - add and use this one */
+ pb_debug("Using untracked ramdisk %s\n", name);
+ } else {
+ pb_log("Failed to create new ramdisk %s: %s\n",
+ name, strerror(errno));
+ return NULL;
+ }
+ }
+ device_handler_add_ramdisk(handler, name);
+ talloc_free(name);
+
+ return handler->ramdisks[i];
+}
+
+void device_handler_release_ramdisk(struct discover_device *device)
+{
+ struct ramdisk_device *ramdisk = device->ramdisk;
+
+ talloc_free(ramdisk->snapshot);
+ talloc_free(ramdisk->origin);
+ talloc_free(ramdisk->base);
+
+ ramdisk->snapshot = ramdisk->origin = ramdisk->base = NULL;
+ ramdisk->sectors = 0;
+
+ device->ramdisk = NULL;
+}
+
+/*
+ * Check if a device name matches the name of an encrypted device that has been
+ * opened. If it matches remove it from the list and remove the original crypt
+ * discover device.
+ */
+bool device_handler_found_crypt_device(struct device_handler *handler,
+ const char *name)
+{
+ struct crypt_info *crypt, *c;
+
+ list_for_each_entry_safe(&handler->crypt_devices, crypt, c, list) {
+ if (!strncmp(crypt->dm_name, name, strlen(crypt->dm_name))) {
+ device_handler_remove(handler, crypt->source_device);
+ list_remove(&crypt->list);
+ talloc_free(crypt);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void cryptsetup_cb(struct process *process)
+{
+ struct device_handler *handler = process->data;
+ struct crypt_info *crypt, *c;
+
+ if (process->exit_status == 0)
+ return;
+ device_handler_status_err(handler,
+ _("Failed to open encrypted device %s"),
+ process->argv[2]);
+
+ /*
+ * Failed to open the device; stop tracking it, but don't remove
+ * the source device.
+ */
+ list_for_each_entry_safe(&handler->crypt_devices, crypt, c, list) {
+ if (!strncmp(crypt->dm_name, process->argv[3],
+ strlen(crypt->dm_name))) {
+ list_remove(&crypt->list);
+ talloc_free(crypt);
+ break;
+ }
+ }
+}
+
+void device_handler_open_encrypted_dev(struct device_handler *handler,
+ char *password, char *device_id)
+{
+ struct discover_device *dev;
+ struct crypt_info *crypt;
+ const char *device_path, **argv;
+ struct process *p;
+ char *name;
+ int result;
+
+ dev = device_lookup_by_id(handler, device_id);
+ if (!dev) {
+ pb_log_fn("Can't find device %s\n", device_id);
+ device_handler_status_err(handler,
+ _("Encrypted device %s does not exist"),
+ device_id);
+ return;
+ }
+
+ device_path = dev->device_path;
+ name = talloc_asprintf(handler, "luks_%s", device_id);
+
+ p = process_create(handler);
+ /* talloc argv under the process so we can access it in cryptsetup_cb */
+ argv = talloc_zero_array(p, const char *, 6);
+ argv[0] = talloc_strdup(argv, pb_system_apps.cryptsetup);
+ argv[1] = talloc_asprintf(argv, "luksOpen");
+ argv[2] = talloc_strdup(argv, device_path);
+ argv[3] = talloc_strdup(argv, name);
+ argv[4] = talloc_asprintf(argv, "-");
+ argv[5] = NULL;
+
+ p->path = pb_system_apps.cryptsetup;
+ p->argv = (const char **)argv;
+ p->exit_cb = cryptsetup_cb;
+ p->data = handler;
+ p->keep_stdout = true;
+ p->pipe_stdin = talloc_asprintf(p, "%s\n", password);
+
+ result = process_run_async(p);
+ if (result) {
+ pb_log("Failed to run cryptsetup\n");
+ return;
+ }
+
+ crypt = talloc(handler, struct crypt_info);
+ crypt->source_device = dev;
+ crypt->dm_name = name;
+ talloc_steal(crypt, name);
+ list_add(&handler->crypt_devices, &crypt->list);
+}
+
+void device_handler_add_encrypted_dev(struct device_handler *handler,
+ struct discover_device *dev)
+{
+ system_info_register_blockdev(dev->device->id, dev->uuid, "");
+ discover_server_notify_device_add(handler->server,
+ dev->device);
+ dev->notified = true;
+ if (!device_lookup_by_uuid(handler, dev->uuid))
+ device_handler_add_device(handler, dev);
+}
+
+/* Start discovery on a hotplugged device. The device will be in our devices
+ * array, but has only just been initialised by the hotplug source.
+ */
+int device_handler_discover(struct device_handler *handler,
+ struct discover_device *dev)
+{
+ struct discover_context *ctx;
+ int rc;
+
+ device_handler_status_dev_info(handler, dev,
+ /*
+ * TRANSLATORS: this string will be passed the type of the
+ * device (eg "disk" or "network"), which will be translated
+ * accordingly.
+ */
+ _("Processing new %s device"),
+ device_type_display_name(dev->device->type));
+
+ /* create our context */
+ ctx = device_handler_discover_context_create(handler, dev);
+
+ rc = mount_device(dev);
+ if (rc)
+ goto out;