---
lib/Makefile.am | 3 +
lib/launch-direct.c | 498 ++++++++++++++++++++++++++++++----------------------
lib/qemu.c | 4 +
3 files changed, 292 insertions(+), 213 deletions(-)
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 063706f..b22fbd1 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -56,6 +56,7 @@ lib_LTLIBRARIES = libguestfs.la
libguestfs_la_SOURCES = \
../common/errnostring/errnostring.h \
../common/protocol/guestfs_protocol.h \
+ ../common/qemuopts/qemuopts.h \
../common/utils/guestfs-internal-frontend.h \
../common/utils/guestfs-internal-frontend-cleanups.h \
guestfs.h \
@@ -136,6 +137,7 @@ libguestfs_la_CPPFLAGS = \
-DLIBOSINFO_DB_PATH='"$(datadir)/libosinfo/db"' \
-I$(top_srcdir)/common/errnostring -I$(top_builddir)/common/errnostring \
-I$(top_srcdir)/common/protocol -I$(top_builddir)/common/protocol \
+ -I$(top_srcdir)/common/qemuopts -I$(top_builddir)/common/qemuopts \
-I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \
-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib
@@ -151,6 +153,7 @@ libguestfs_la_CFLAGS = \
libguestfs_la_LIBADD = \
../common/errnostring/liberrnostring.la \
../common/protocol/libprotocol.la \
+ ../common/qemuopts/libqemuopts.la \
../common/utils/libutils.la \
$(PCRE_LIBS) $(MAGIC_LIBS) \
$(LIBVIRT_LIBS) $(LIBXML2_LIBS) \
diff --git a/lib/launch-direct.c b/lib/launch-direct.c
index aa9c292..4d5d6b9 100644
--- a/lib/launch-direct.c
+++ b/lib/launch-direct.c
@@ -47,6 +47,7 @@
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs_protocol.h"
+#include "qemuopts.h"
/* Per-handle data. */
struct backend_direct_data {
@@ -61,7 +62,6 @@ struct backend_direct_data {
static int is_openable (guestfs_h *g, const char *path, int flags);
static char *make_appliance_dev (guestfs_h *g);
-static void print_qemu_command_line (guestfs_h *g, char **argv);
static char *
create_cow_overlay_direct (guestfs_h *g, void *datav, struct drive *drv)
@@ -157,11 +157,181 @@ debian_kvm_warning (guestfs_h *g)
#endif /* __linux__ */
}
+/* Some macros which make using qemuopts a bit easier. */
+#define flag(flag) \
+ do { \
+ if (qemuopts_add_flag (qopts, (flag)) == -1) goto qemuopts_error; \
+ } while (0)
+#define arg(flag, value) \
+ do { \
+ if (qemuopts_add_arg (qopts, (flag), (value)) == -1) goto qemuopts_error; \
+ } while (0)
+#define arg_format(flag, fs, ...) \
+ do { \
+ if (qemuopts_add_arg_format (qopts, (flag), (fs), ##__VA_ARGS__) == -1) \
+ goto qemuopts_error; \
+ } while (0)
+#define arg_noquote(flag, value) \
+ do { \
+ if (qemuopts_add_arg_noquote (qopts, (flag), (value)) == -1) \
+ goto qemuopts_error; \
+ } while (0)
+#define start_list(flag) \
+ if (qemuopts_start_arg_list (qopts, (flag)) == -1) goto qemuopts_error; \
+ do
+#define append_list(value) \
+ do { \
+ if (qemuopts_append_arg_list (qopts, (value)) == -1) \
+ goto qemuopts_error; \
+ } while (0)
+#define append_list_format(fs, ...) \
+ do { \
+ if (qemuopts_append_arg_list_format (qopts, (fs), ##__VA_ARGS__) == -1) \
+ goto qemuopts_error; \
+ } while (0)
+#define end_list() \
+ while (0); \
+ do { \
+ if (qemuopts_end_arg_list (qopts) == -1) goto qemuopts_error; \
+ } while (0)
+
+/**
+ * Add the standard elements of the C<-drive> parameter.
+ */
+static int
+add_drive_standard_params (guestfs_h *g, struct backend_direct_data *data,
+ struct qemuopts *qopts,
+ size_t i, struct drive *drv)
+{
+ if (!drv->overlay) {
+ CLEANUP_FREE char *file = NULL;
+
+ /* file= parameter. */
+ file = guestfs_int_drive_source_qemu_param (g, &drv->src);
+ append_list_format ("file=%s", file);
+
+ if (drv->readonly)
+ append_list ("snapshot=on");
+ append_list_format ("cache=%s",
+ drv->cachemode ? drv->cachemode : "writeback");
+ if (drv->src.format)
+ append_list_format ("format=%s", drv->src.format);
+ if (drv->disk_label)
+ append_list_format ("serial=%s", drv->disk_label);
+ if (drv->copyonread)
+ append_list ("copy-on-read=on");
+
+ /* Discard mode. */
+ switch (drv->discard) {
+ case discard_disable:
+ /* Since the default is always discard=ignore, don't specify it
+ * on the command line. This also avoids unnecessary breakage
+ * with qemu < 1.5 which didn't have the option at all.
+ */
+ break;
+ case discard_enable:
+ if (!guestfs_int_discard_possible (g, drv, &data->qemu_version))
+ return -1;
+ /*FALLTHROUGH*/
+ case discard_besteffort:
+ /* I believe from reading the code that this is always safe as
+ * long as qemu >= 1.5.
+ */
+ if (guestfs_int_version_ge (&data->qemu_version, 1, 5, 0))
+ append_list ("discard=unmap");
+ break;
+ }
+ }
+ else {
+ /* Writable qcow2 overlay on top of read-only drive. */
+ append_list_format ("file=%s", drv->overlay);
+ append_list ("cache=unsafe");
+ append_list ("format=qcow2");
+ if (drv->disk_label)
+ append_list_format ("serial=%s", drv->disk_label);
+ }
+
+ append_list_format ("id=hd%zu", i);
+
+ return 0;
+
+ /* This label is called implicitly from the qemuopts macros on error. */
+ qemuopts_error:
+ perrorf (g, "qemuopts");
+ return -1;
+}
+
+static int
+add_drive (guestfs_h *g, struct backend_direct_data *data,
+ struct qemuopts *qopts, size_t i, struct drive *drv)
+{
+ /* If there's an explicit 'iface', use it. Otherwise default to
+ * virtio-scsi.
+ */
+ if (drv->iface && STREQ (drv->iface, "virtio")) { /* virtio-blk
*/
+ start_list ("-drive") {
+ if (add_drive_standard_params (g, data, qopts, i, drv) == -1)
+ return -1;
+ append_list ("if=none");
+ } end_list ();
+ start_list ("-device") {
+ append_list (VIRTIO_BLK);
+ append_list_format ("drive=hd%zu", i);
+ } end_list ();
+ }
+#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__)
+ else if (drv->iface && STREQ (drv->iface, "ide")) {
+ error (g, "'ide' interface does not work on ARM or PowerPC");
+ return -1;
+ }
+#endif
+ else if (drv->iface) {
+ start_list ("-drive") {
+ if (add_drive_standard_params (g, data, qopts, i, drv) == -1)
+ return -1;
+ append_list_format ("if=%s", drv->iface);
+ } end_list ();
+ }
+ else /* default case: virtio-scsi */ {
+ start_list ("-drive") {
+ if (add_drive_standard_params (g, data, qopts, i, drv) == -1)
+ return -1;
+ append_list ("if=none");
+ } end_list ();
+ start_list ("-device") {
+ append_list ("scsi-hd");
+ append_list_format ("drive=hd%zu", i);
+ } end_list ();
+ }
+
+ return 0;
+
+ /* This label is called implicitly from the qemuopts macros on error. */
+ qemuopts_error:
+ perrorf (g, "qemuopts");
+ return -1;
+}
+
+static int
+add_drives (guestfs_h *g, struct backend_direct_data *data,
+ struct qemuopts *qopts)
+{
+ size_t i;
+ struct drive *drv;
+
+ ITER_DRIVES (g, i, drv) {
+ if (add_drive (g, data, qopts, i, drv) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
static int
launch_direct (guestfs_h *g, void *datav, const char *arg)
{
struct backend_direct_data *data = datav;
- CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (cmdline);
+ struct qemuopts *qopts = NULL;
int daemon_accept_sock = -1, console_sock = -1;
int r;
int flags;
@@ -174,12 +344,12 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
CLEANUP_FREE char *appliance_dev = NULL;
uint32_t size;
CLEANUP_FREE void *buf = NULL;
- struct drive *drv;
- size_t i;
struct hv_param *hp;
bool has_kvm;
int force_tcg;
const char *cpu_model;
+ CLEANUP_FREE char *append = NULL;
+ CLEANUP_FREE_STRING_LIST char **argv = NULL;
/* At present you must add drives before starting the appliance. In
* future when we enable hotplugging you won't need to do this.
@@ -267,30 +437,28 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
* forking, because after fork we are not allowed to use
* non-signal-safe functions such as malloc.
*/
-#define ADD_CMDLINE(str) \
- guestfs_int_add_string (g, &cmdline, (str))
-#define ADD_CMDLINE_STRING_NODUP(str) \
- guestfs_int_add_string_nodup (g, &cmdline, (str))
-#define ADD_CMDLINE_PRINTF(fs,...) \
- guestfs_int_add_sprintf (g, &cmdline, (fs), ##__VA_ARGS__)
-
- ADD_CMDLINE (g->hv);
+ qopts = qemuopts_create ();
+ if (qopts == NULL) {
+ qemuopts_error:
+ perrorf (g, "qemuopts");
+ goto cleanup0;
+ }
+ if (qemuopts_set_binary (qopts, g->hv) == -1) goto qemuopts_error;
/* CVE-2011-4127 mitigation: Disable SCSI ioctls on virtio-blk
* devices.
*/
- ADD_CMDLINE ("-global");
- ADD_CMDLINE (VIRTIO_BLK ".scsi=off");
+ arg ("-global", VIRTIO_BLK ".scsi=off");
if (guestfs_int_qemu_supports (g, data->qemu_data, "-nodefconfig"))
- ADD_CMDLINE ("-nodefconfig");
+ flag ("-nodefconfig");
/* This oddly named option doesn't actually enable FIPS. It just
* causes qemu to do the right thing if FIPS is enabled in the
* kernel. So like libvirt, we pass it unconditionally.
*/
if (guestfs_int_qemu_supports (g, data->qemu_data, "-enable-fips"))
- ADD_CMDLINE ("-enable-fips");
+ flag ("-enable-fips");
/* Newer versions of qemu (from around 2009/12) changed the
* behaviour of monitors so that an implicit '-monitor stdio' is
@@ -301,60 +469,47 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
* let's use that to avoid this and any future surprises.
*/
if (guestfs_int_qemu_supports (g, data->qemu_data, "-nodefaults"))
- ADD_CMDLINE ("-nodefaults");
+ flag ("-nodefaults");
/* This disables the host-side display (SDL, Gtk). */
- ADD_CMDLINE ("-display");
- ADD_CMDLINE ("none");
+ arg ("-display", "none");
/* See guestfs.pod / gdb */
if (guestfs_int_get_backend_setting_bool (g, "gdb") > 0) {
- ADD_CMDLINE ("-S");
- ADD_CMDLINE ("-s");
+ flag ("-S");
+ flag ("-s");
warning (g, "qemu debugging is enabled, connect gdb to tcp::1234 to
begin");
}
- ADD_CMDLINE ("-machine");
- ADD_CMDLINE_PRINTF (
+ start_list ("-machine") {
#ifdef MACHINE_TYPE
- MACHINE_TYPE ","
+ append_list (MACHINE_TYPE);
#endif
#ifdef __aarch64__
- "%s" /* gic-version */
+ if (has_kvm && !force_tcg)
+ append_list ("gic-version=host");
#endif
- "accel=%s",
-#ifdef __aarch64__
- has_kvm && !force_tcg ? "gic-version=host," :
"",
-#endif
- !force_tcg ? "kvm:tcg" : "tcg");
+ append_list_format ("accel=%s", !force_tcg ? "kvm:tcg" :
"tcg");
+ } end_list ();
cpu_model = guestfs_int_get_cpu_model (has_kvm && !force_tcg);
- if (cpu_model) {
- ADD_CMDLINE ("-cpu");
- ADD_CMDLINE (cpu_model);
- }
+ if (cpu_model)
+ arg ("-cpu", cpu_model);
- if (g->smp > 1) {
- ADD_CMDLINE ("-smp");
- ADD_CMDLINE_PRINTF ("%d", g->smp);
- }
+ if (g->smp > 1)
+ arg_format ("-smp", "%d", g->smp);
- ADD_CMDLINE ("-m");
- ADD_CMDLINE_PRINTF ("%d", g->memsize);
+ arg_format ("-m", "%d", g->memsize);
/* Force exit instead of reboot on panic */
- ADD_CMDLINE ("-no-reboot");
+ flag ("-no-reboot");
/* These are recommended settings, see RHBZ#1053847. */
- ADD_CMDLINE ("-rtc");
- ADD_CMDLINE ("driftfix=slew");
- if (guestfs_int_qemu_supports (g, data->qemu_data, "-no-hpet")) {
- ADD_CMDLINE ("-no-hpet");
- }
- if (guestfs_int_version_ge (&data->qemu_version, 1, 3, 0)) {
- ADD_CMDLINE ("-global");
- ADD_CMDLINE ("kvm-pit.lost_tick_policy=discard");
- }
+ arg ("-rtc", "driftfix=slew");
+ if (guestfs_int_qemu_supports (g, data->qemu_data, "-no-hpet"))
+ flag ("-no-hpet");
+ if (guestfs_int_version_ge (&data->qemu_version, 1, 3, 0))
+ arg ("-global", "kvm-pit.lost_tick_policy=discard");
/* UEFI (firmware) if required. */
if (guestfs_int_get_uefi (g, &uefi_code, &uefi_vars, &uefi_flags) == -1)
@@ -372,19 +527,24 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
goto cleanup0;
}
if (uefi_code) {
- ADD_CMDLINE ("-drive");
- ADD_CMDLINE_PRINTF ("if=pflash,format=raw,file=%s,readonly", uefi_code);
+ start_list ("-drive") {
+ append_list ("if=pflash");
+ append_list ("format=raw");
+ append_list_format ("file=%s", uefi_code);
+ append_list ("readonly");
+ } end_list ();
if (uefi_vars) {
- ADD_CMDLINE ("-drive");
- ADD_CMDLINE_PRINTF ("if=pflash,format=raw,file=%s", uefi_vars);
+ start_list ("-drive") {
+ append_list ("if=pflash");
+ append_list ("format=raw");
+ append_list_format ("file=%s", uefi_vars);
+ } end_list ();
}
}
/* Kernel and initrd. */
- ADD_CMDLINE ("-kernel");
- ADD_CMDLINE (kernel);
- ADD_CMDLINE ("-initrd");
- ADD_CMDLINE (initrd);
+ arg ("-kernel", kernel);
+ arg ("-initrd", initrd);
/* Add a random number generator (backend for virtio-rng). This
* isn't strictly necessary but means we won't need to hang around
@@ -392,121 +552,50 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
*/
if (guestfs_int_qemu_supports_device (g, data->qemu_data,
"virtio-rng-pci")) {
- ADD_CMDLINE ("-object");
- ADD_CMDLINE ("rng-random,filename=/dev/urandom,id=rng0");
- ADD_CMDLINE ("-device");
- ADD_CMDLINE ("virtio-rng-pci,rng=rng0");
+ start_list ("-object") {
+ append_list ("rng-random");
+ append_list ("filename=/dev/urandom");
+ append_list ("id=rng0");
+ } end_list ();
+ start_list ("-device") {
+ append_list ("virtio-rng-pci");
+ append_list ("rng=rng0");
+ } end_list ();
}
/* Create the virtio-scsi bus. */
- ADD_CMDLINE ("-device");
- ADD_CMDLINE (VIRTIO_SCSI ",id=scsi");
-
- /* Add drives */
- ITER_DRIVES (g, i, drv) {
- CLEANUP_FREE char *file = NULL, *escaped_file = NULL, *param = NULL;
-
- if (!drv->overlay) {
- const char *discard_mode = "";
-
- switch (drv->discard) {
- case discard_disable:
- /* Since the default is always discard=ignore, don't specify it
- * on the command line. This also avoids unnecessary breakage
- * with qemu < 1.5 which didn't have the option at all.
- */
- break;
- case discard_enable:
- if (!guestfs_int_discard_possible (g, drv, &data->qemu_version))
- goto cleanup0;
- /*FALLTHROUGH*/
- case discard_besteffort:
- /* I believe from reading the code that this is always safe as
- * long as qemu >= 1.5.
- */
- if (guestfs_int_version_ge (&data->qemu_version, 1, 5, 0))
- discard_mode = ",discard=unmap";
- break;
- }
-
- /* Make the file= parameter. */
- file = guestfs_int_drive_source_qemu_param (g, &drv->src);
- escaped_file = guestfs_int_qemu_escape_param (g, file);
-
- /* Make the first part of the -drive parameter, everything up to
- * the if=... at the end.
- */
- param = safe_asprintf
- (g, "file=%s%s,cache=%s%s%s%s%s%s%s,id=hd%zu",
- escaped_file,
- drv->readonly ? ",snapshot=on" : "",
- drv->cachemode ? drv->cachemode : "writeback",
- discard_mode,
- drv->src.format ? ",format=" : "",
- drv->src.format ? drv->src.format : "",
- drv->disk_label ? ",serial=" : "",
- drv->disk_label ? drv->disk_label : "",
- drv->copyonread ? ",copy-on-read=on" : "",
- i);
- }
- else {
- /* Writable qcow2 overlay on top of read-only drive. */
- escaped_file = guestfs_int_qemu_escape_param (g, drv->overlay);
- param = safe_asprintf
- (g, "file=%s,cache=unsafe,format=qcow2%s%s,id=hd%zu",
- escaped_file,
- drv->disk_label ? ",serial=" : "",
- drv->disk_label ? drv->disk_label : "",
- i);
- }
-
- /* If there's an explicit 'iface', use it. Otherwise default to
- * virtio-scsi.
- */
- if (drv->iface && STREQ (drv->iface, "virtio")) { /*
virtio-blk */
- ADD_CMDLINE ("-drive");
- ADD_CMDLINE_PRINTF ("%s,if=none" /* sic */, param);
- ADD_CMDLINE ("-device");
- ADD_CMDLINE_PRINTF (VIRTIO_BLK ",drive=hd%zu", i);
- }
-#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__)
- else if (drv->iface && STREQ (drv->iface, "ide")) {
- error (g, "'ide' interface does not work on ARM or PowerPC");
- goto cleanup0;
- }
-#endif
- else if (drv->iface) {
- ADD_CMDLINE ("-drive");
- ADD_CMDLINE_PRINTF ("%s,if=%s", param, drv->iface);
- }
- else /* virtio-scsi */ {
- ADD_CMDLINE ("-drive");
- ADD_CMDLINE_PRINTF ("%s,if=none" /* sic */, param);
- ADD_CMDLINE ("-device");
- ADD_CMDLINE_PRINTF ("scsi-hd,drive=hd%zu", i);
- }
- }
+ start_list ("-device") {
+ append_list (VIRTIO_SCSI);
+ append_list ("id=scsi");
+ } end_list ();
+
+ /* Add drives (except for the appliance drive). */
+ if (add_drives (g, data, qopts) == -1)
+ goto cleanup0;
/* Add the ext2 appliance drive (after all the drives). */
if (has_appliance_drive) {
- ADD_CMDLINE ("-drive");
- ADD_CMDLINE_PRINTF ("file=%s,snapshot=on,id=appliance,"
- "cache=unsafe,if=none,format=raw",
- appliance);
-
- ADD_CMDLINE ("-device");
- ADD_CMDLINE ("scsi-hd,drive=appliance");
+ start_list ("-drive") {
+ append_list_format ("file=%s", appliance);
+ append_list ("snapshot=on");
+ append_list ("id=appliance");
+ append_list ("cache=unsafe");
+ append_list ("if=none");
+ append_list ("format=raw");
+ } end_list ();
+ start_list ("-device") {
+ append_list ("scsi-hd");
+ append_list ("drive=appliance");
+ } end_list ();
appliance_dev = make_appliance_dev (g);
}
/* Create the virtio serial bus. */
- ADD_CMDLINE ("-device");
- ADD_CMDLINE (VIRTIO_SERIAL);
+ arg ("-device", VIRTIO_SERIAL);
/* Create the serial console. */
- ADD_CMDLINE ("-serial");
- ADD_CMDLINE ("stdio");
+ arg ("-serial", "stdio");
if (g->verbose &&
guestfs_int_qemu_supports_device (g, data->qemu_data,
@@ -517,30 +606,39 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
*
https://bugs.launchpad.net/qemu/+bug/1021649
* QEmu has included sgabios upstream since just before 1.0.
*/
- ADD_CMDLINE ("-device");
- ADD_CMDLINE ("sga");
+ arg ("-device", "sga");
}
/* Set up virtio-serial for the communications channel. */
- ADD_CMDLINE ("-chardev");
- ADD_CMDLINE_PRINTF ("socket,path=%s,id=channel0", data->guestfsd_sock);
- ADD_CMDLINE ("-device");
- ADD_CMDLINE
("virtserialport,chardev=channel0,name=org.libguestfs.channel.0");
+ start_list ("-chardev") {
+ append_list ("socket");
+ append_list_format ("path=%s", data->guestfsd_sock);
+ append_list ("id=channel0");
+ } end_list ();
+ start_list ("-device") {
+ append_list ("virtserialport");
+ append_list ("chardev=channel0");
+ append_list ("name=org.libguestfs.channel.0");
+ } end_list ();
/* Enable user networking. */
if (g->enable_network) {
- ADD_CMDLINE ("-netdev");
- ADD_CMDLINE ("user,id=usernet,net=169.254.0.0/16");
- ADD_CMDLINE ("-device");
- ADD_CMDLINE (VIRTIO_NET ",netdev=usernet");
+ start_list ("-netdev") {
+ append_list ("user");
+ append_list ("id=usernet");
+ append_list ("net=169.254.0.0/16");
+ } end_list ();
+ start_list ("-device") {
+ append_list (VIRTIO_NET);
+ append_list ("netdev=usernet");
+ } end_list ();
}
- ADD_CMDLINE ("-append");
flags = 0;
if (!has_kvm || force_tcg)
flags |= APPLIANCE_COMMAND_LINE_IS_TCG;
- ADD_CMDLINE_STRING_NODUP
- (guestfs_int_appliance_command_line (g, appliance_dev, flags));
+ append = guestfs_int_appliance_command_line (g, appliance_dev, flags);
+ arg ("-append", append);
/* Note: custom command line parameters must come last so that
* qemu -set parameters can modify previously added options.
@@ -548,13 +646,14 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
/* Add any qemu parameters. */
for (hp = g->hv_params; hp; hp = hp->next) {
- ADD_CMDLINE (hp->hv_param);
- if (hp->hv_value)
- ADD_CMDLINE (hp->hv_value);
+ if (!hp->hv_value)
+ flag (hp->hv_param);
+ else
+ arg_noquote (hp->hv_param, hp->hv_value);
}
- /* Finish off the command line. */
- guestfs_int_end_stringsbuf (g, &cmdline);
+ /* Get the argv list from the command line. */
+ argv = qemuopts_to_argv (qopts);
r = fork ();
if (r == -1) {
@@ -609,7 +708,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
/* Dump the command line (after setting up stderr above). */
if (g->verbose)
- print_qemu_command_line (g, cmdline.argv);
+ qemuopts_to_channel (qopts, stderr);
/* Put qemu in a new process group. */
if (g->pgroup)
@@ -620,7 +719,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
TRACE0 (launch_run_qemu);
- execv (g->hv, cmdline.argv); /* Run qemu. */
+ execv (g->hv, argv); /* Run qemu. */
perror (g->hv);
_exit (EXIT_FAILURE);
}
@@ -628,6 +727,9 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
/* Parent (library). */
data->pid = r;
+ qemuopts_free (qopts);
+ qopts = NULL;
+
/* Fork the recovery process off which will kill qemu if the parent
* process fails to do so (eg. if the parent segfaults).
*/
@@ -635,6 +737,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
if (g->recovery_proc) {
r = fork ();
if (r == 0) {
+ size_t i;
struct sigaction sa;
pid_t qemu_pid = data->pid;
pid_t parent_pid = getppid ();
@@ -774,6 +877,8 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
data->qemu_data = NULL;
cleanup0:
+ if (qopts != NULL)
+ qemuopts_free (qopts);
if (daemon_accept_sock >= 0)
close (daemon_accept_sock);
if (console_sock >= 0)
@@ -813,39 +918,6 @@ make_appliance_dev (guestfs_h *g)
return safe_strdup (g, dev); /* Caller frees. */
}
-/* This is called from the forked subprocess just before qemu runs, so
- * it can just print the message straight to stderr, where it will be
- * picked up and funnelled through the usual appliance event API.
- */
-static void
-print_qemu_command_line (guestfs_h *g, char **argv)
-{
- int i = 0;
- int needs_quote;
-
- struct timeval tv;
- gettimeofday (&tv, NULL);
- fprintf (stderr, "[%05" PRIi64 "ms] ",
- guestfs_int_timeval_diff (&g->launch_t, &tv));
-
- while (argv[i]) {
- if (argv[i][0] == '-') /* -option starts a new line */
- fprintf (stderr, " \\\n ");
-
- if (i > 0) fputc (' ', stderr);
-
- /* Does it need shell quoting? This only deals with simple cases. */
- needs_quote = strcspn (argv[i], " ") != strlen (argv[i]);
-
- if (needs_quote) fputc ('\'', stderr);
- fprintf (stderr, "%s", argv[i]);
- if (needs_quote) fputc ('\'', stderr);
- i++;
- }
-
- fputc ('\n', stderr);
-}
-
/* Check if a file can be opened. */
static int
is_openable (guestfs_h *g, const char *path, int flags)
diff --git a/lib/qemu.c b/lib/qemu.c
index 8bec6ba..41098a2 100644
--- a/lib/qemu.c
+++ b/lib/qemu.c
@@ -304,6 +304,10 @@ guestfs_int_qemu_supports_device (guestfs_h *g,
* Escape a qemu parameter.
*
* Every C<,> becomes C<,,>. The caller must free the returned string.
+ *
+ * XXX This functionality is now only used when constructing a
+ * qemu-img command in F<lib/create.c>. We should extend the qemuopts
+ * library to cover this use case.
*/
char *
guestfs_int_qemu_escape_param (guestfs_h *g, const char *param)
--
2.9.3