[5/6] discover: Mount and parse ISO images.
diff mbox

Message ID 20161025034448.28723-5-sam@mendozajonas.com
State Superseded
Headers show

Commit Message

Samuel Mendoza-Jonas Oct. 25, 2016, 3:44 a.m. UTC
Allow users to specify an ISO file via device_handler_process_url(), and
load it asynchronously. The load task makes use of a custom IO callback
in order to relay live progress to the UI. At the moment this is
primarily targeted at the progress meter from programs such as wget.

On a successful load the ISO file is mounted via losetup, and th
resulting loop device is recognised as a mountable device by
discover/udev.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 discover/device-handler.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++
 discover/udev.c           |   8 +++-
 2 files changed, 109 insertions(+), 2 deletions(-)

Patch
diff mbox

diff --git a/discover/device-handler.c b/discover/device-handler.c
index 70e4506..e4a3fc3 100644
--- a/discover/device-handler.c
+++ b/discover/device-handler.c
@@ -1007,6 +1007,51 @@  void device_handler_update_config(struct device_handler *handler,
 	device_handler_reinit(handler);
 }
 
+/*
+ * Process the download of an ISO file. Mount the image with losetup which if
+ * successfull should be noticed as a new udev event.
+ */
+static void device_handler_process_image(struct load_url_result *result,
+					 void *data)
+{
+	struct device_handler *handler = data;
+	struct boot_status *status;
+	struct process *p;
+	int rc;
+
+	if (!result || result->status != LOAD_OK) {
+		pb_log("%s: load failed\n", __func__);
+		return;
+	}
+
+	status = talloc_zero(handler, struct boot_status);
+	status->type = BOOT_STATUS_INFO;
+	status->message = talloc_asprintf(status, _("ISO downloaded to %s"),
+					  result->local);
+	device_handler_boot_status(handler, status);
+
+	const char *argv[] = {
+		pb_system_apps.losetup,
+		"-r", "-f",
+		result->local,
+		NULL
+	};
+
+	p = process_create(handler);
+	p->path = pb_system_apps.losetup;
+	p->argv = argv;
+
+	rc = process_run_sync(p);
+
+	if (rc || p->exit_status) {
+		pb_log("Failed to create loopback device (%d)\n", rc);
+		pb_debug("%s\n", p->stdout_buf);
+	}
+
+	talloc_free(status);
+	talloc_free(p);
+}
+
 static char *device_from_addr(void *ctx, struct pb_url *url)
 {
 	char *ipaddr, *buf, *tok, *dev = NULL;
@@ -1077,9 +1122,46 @@  static char *device_from_addr(void *ctx, struct pb_url *url)
 	return dev;
 }
 
+/*
+ * Callback to retrieve output from a running asynchronous process. If output
+ * exists it is sent as a status update to the UI
+ */
+static int live_stdout_cb(void *arg)
+{
+	struct process_info *procinfo = arg;
+	struct device_handler *handler;
+	struct boot_status *status;
+	struct process *p;
+	char *line = NULL;
+	int rc;
+
+	if (!arg)
+		return -1;
+
+	p = procinfo_get_process(procinfo);
+	handler = load_task_async_data(p);
+
+	status = talloc_zero(arg, struct boot_status);
+
+	rc = process_stdout_custom(procinfo, &line);
+
+	if (rc || !line)
+		return rc;
+
+	status->type = BOOT_STATUS_INFO;
+	status->message = line;
+	device_handler_boot_status(handler, status);
+
+	talloc_free(status);
+	talloc_free(line);
+
+	return rc;
+}
+
 void device_handler_process_url(struct device_handler *handler,
 		const char *url, const char *mac, const char *ip)
 {
+	struct load_url_result *result;
 	struct discover_context *ctx;
 	struct discover_device *dev;
 	struct boot_status *status;
@@ -1143,6 +1225,27 @@  void device_handler_process_url(struct device_handler *handler,
 		goto msg;
 	}
 
+	/*
+	 * An ISO download may take some time - start an asynchronous job and
+	 * watch output to let the user know progress is being made.
+	 */
+	if (pb_url && pb_url->file && strstr(pb_url->file, ".iso")) {
+		result = load_url_async(handler, pb_url,
+				device_handler_process_image, handler,
+				live_stdout_cb);
+		if (!result) {
+			status->message = talloc_asprintf(status,
+						_("Failed to download image \"%s\""),
+						pb_url->file);
+		} else {
+			status->message = talloc_asprintf(status,
+						_("Retrieving image \"%s\""),
+						pb_url->file);
+			status->type = BOOT_STATUS_INFO;
+		}
+		goto msg;
+	}
+
 	dev = discover_device_create(handler, mac, event->device);
 	if (pb_url->scheme == pb_url_file)
 		dev->device->type = DEVICE_TYPE_ANY;
diff --git a/discover/udev.c b/discover/udev.c
index 1e04313..d3824f7 100644
--- a/discover/udev.c
+++ b/discover/udev.c
@@ -104,8 +104,12 @@  static int udev_handle_block_add(struct pb_udev *udev, struct udev_device *dev,
 	node = udev_device_get_devnode(dev);
 	path = udev_device_get_devpath(dev);
 	if (path && strstr(path, "virtual/block/loop")) {
-		pb_log("SKIP: %s: ignored (path=%s)\n", name, path);
-		return 0;
+		type = udev_device_get_property_value(dev, "ID_FS_TYPE");
+		/* Don't skip if an ISO has been mounted on this loop device */
+		if (strcasestr(path, "iso9660") != 0) {
+			pb_log("SKIP: %s: ignored (path=%s)\n", name, path);
+			return 0;
+		}
 	}
 
 	if (path && strstr(path, "virtual/block/ram")) {