---
v2v/Makefile.am | 8 +-
v2v/output_qemu.ml | 88 +++++++-------
v2v/qemu_command.ml | 101 ---------------
v2v/qemuopts-c.c | 216 +++++++++++++++++++++++++++++++++
v2v/qemuopts.ml | 35 ++++++
v2v/{qemu_command.mli => qemuopts.mli} | 24 ++--
6 files changed, 318 insertions(+), 154 deletions(-)
delete mode 100644 v2v/qemu_command.ml
create mode 100644 v2v/qemuopts-c.c
create mode 100644 v2v/qemuopts.ml
rename v2v/{qemu_command.mli => qemuopts.mli} (75%)
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 8df8ca0..5b6618a 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -57,7 +57,7 @@ SOURCES_MLI = \
parse_ovf_from_ova.mli \
parse_libvirt_xml.mli \
parse_vmx.mli \
- qemu_command.mli \
+ qemuopts.mli \
target_bus_assignment.mli \
types.mli \
uefi.mli \
@@ -85,7 +85,7 @@ SOURCES_ML = \
parse_vmx.ml \
parse_libvirt_xml.ml \
create_libvirt_xml.ml \
- qemu_command.ml \
+ qemuopts.ml \
input_libvirtxml.ml \
input_libvirt_other.ml \
input_libvirt_vcenter_https.ml \
@@ -111,6 +111,7 @@ SOURCES_ML = \
SOURCES_C = \
libvirt_utils-c.c \
+ qemuopts-c.c \
utils-c.c
if HAVE_OCAML
@@ -122,6 +123,7 @@ virt_v2v_CPPFLAGS = \
-I. \
-I$(top_builddir) \
-I$(shell $(OCAMLC) -where) \
+ -I$(top_srcdir)/common/qemuopts \
-I$(top_srcdir)/common/utils \
-I$(top_srcdir)/lib
virt_v2v_CFLAGS = \
@@ -140,6 +142,7 @@ XOBJECTS = $(BOBJECTS:.cmo=.cmx)
OCAMLPACKAGES = \
-package str,unix \
-I $(top_builddir)/common/utils/.libs \
+ -I $(top_builddir)/common/qemuopts/.libs \
-I $(top_builddir)/lib/.libs \
-I $(top_builddir)/gnulib/lib/.libs \
-I $(top_builddir)/ocaml \
@@ -151,6 +154,7 @@ endif
OCAMLCLIBS = \
-lutils \
+ -lqemuopts \
$(LIBVIRT_LIBS) \
$(LIBXML2_LIBS) \
$(LIBINTL) \
diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml
index 7721f0b..031279c 100644
--- a/v2v/output_qemu.ml
+++ b/v2v/output_qemu.ml
@@ -69,29 +69,31 @@ object
let machine_q35 = secure_boot_required in
let smm = secure_boot_required in
- (* Construct the command line. Note that the [Qemu_command]
+ (* Construct the command line. Note that the [Qemuopts]
* module deals with shell and qemu comma quoting.
*)
- let cmd = Qemu_command.create ~arch:guestcaps.gcaps_arch () in
- let flag = Qemu_command.flag cmd
- and arg = Qemu_command.arg cmd
- and arg_noquote = Qemu_command.arg_noquote cmd
- and commas = Qemu_command.commas cmd in
+ let cmd = Qemuopts.create () in
+ Qemuopts.set_binary_by_arch cmd (Some guestcaps.gcaps_arch);
+
+ let flag = Qemuopts.flag cmd
+ and arg = Qemuopts.arg cmd
+ and arg_noquote = Qemuopts.arg_noquote cmd
+ and arg_list = Qemuopts.arg_list cmd in
flag "-no-user-config"; flag "-nodefaults";
arg "-name" source.s_name;
- commas "-machine" (if machine_q35 then ["q35"] else [] @
- if smm then ["smm=on"] else [] @
- ["accel=kvm:tcg"]);
+ arg_list "-machine" (if machine_q35 then ["q35"] else [] @
+ if smm then ["smm=on"] else [] @
+ ["accel=kvm:tcg"]);
(match uefi_firmware with
| None -> ()
| Some { Uefi.code = code } ->
if secure_boot_required then
- commas "-global"
- ["driver=cfi.pflash01"; "property=secure";
"value=on"];
- commas "-drive"
- ["if=pflash"; "format=raw"; "file=" ^ code;
"readonly"];
+ arg_list "-global"
+ ["driver=cfi.pflash01"; "property=secure";
"value=on"];
+ arg_list "-drive"
+ ["if=pflash"; "format=raw"; "file=" ^
code; "readonly"];
arg_noquote "-drive"
"if=pflash,format=raw,file=\"$uefi_vars\"";
);
@@ -113,7 +115,7 @@ object
(match source.s_cpu_threads with
| None -> 1
| Some v -> v));
- commas "-smp" !a
+ arg_list "-smp" !a
)
else
arg "-smp" (string_of_int source.s_vcpu);
@@ -123,17 +125,17 @@ object
| BusSlotEmpty -> ()
| BusSlotTarget t ->
- commas "-drive" ["file=" ^ t.target_file; "format="
^ t.target_format;
- "if=" ^ if_name; "index=" ^ string_of_int i;
- "media=disk"]
+ arg_list "-drive" ["file=" ^ t.target_file;
"format=" ^ t.target_format;
+ "if=" ^ if_name; "index=" ^ string_of_int
i;
+ "media=disk"]
| BusSlotRemovable { s_removable_type = CDROM } ->
- commas "-drive" ["format=raw"; "if=" ^ if_name;
- "index=" ^ string_of_int i; "media=cdrom"]
+ arg_list "-drive" ["format=raw"; "if=" ^ if_name;
+ "index=" ^ string_of_int i; "media=cdrom"]
| BusSlotRemovable { s_removable_type = Floppy } ->
- commas "-drive" ["format=raw"; "if=" ^ if_name;
- "index=" ^ string_of_int i; "media=floppy"]
+ arg_list "-drive" ["format=raw"; "if=" ^ if_name;
+ "index=" ^ string_of_int i;
"media=floppy"]
in
Array.iteri (make_disk "virtio") target_buses.target_virtio_blk_bus;
Array.iteri (make_disk "ide") target_buses.target_ide_bus;
@@ -142,17 +144,17 @@ object
| BusSlotEmpty -> ()
| BusSlotTarget t ->
- commas "-drive" ["file=" ^ t.target_file; "format="
^ t.target_format;
- "if=scsi"; "bus=0"; "unit=" ^
string_of_int i;
- "media=disk"]
+ arg_list "-drive" ["file=" ^ t.target_file;
"format=" ^ t.target_format;
+ "if=scsi"; "bus=0"; "unit=" ^
string_of_int i;
+ "media=disk"]
| BusSlotRemovable { s_removable_type = CDROM } ->
- commas "-drive" ["format=raw"; "if=scsi";
"bus=0";
- "unit=" ^ string_of_int i; "media=cdrom"]
+ arg_list "-drive" ["format=raw"; "if=scsi";
"bus=0";
+ "unit=" ^ string_of_int i; "media=cdrom"]
| BusSlotRemovable { s_removable_type = Floppy } ->
- commas "-drive" ["format=raw"; "if=scsi";
"bus=0";
- "unit=" ^ string_of_int i; "media=floppy"]
+ arg_list "-drive" ["format=raw"; "if=scsi";
"bus=0";
+ "unit=" ^ string_of_int i; "media=floppy"]
in
Array.iteri make_scsi target_buses.target_scsi_bus;
@@ -167,12 +169,12 @@ object
| RTL8139 -> "rtl8139" in
iteri (
fun i nic ->
- commas "-netdev" ["user"; "id=net" ^ string_of_int
i];
- commas "-device" [net_bus;
- sprintf "netdev=net%d%s" i
- (match nic.s_mac with
- | None -> ""
- | Some mac -> "mac=" ^ mac)]
+ arg_list "-netdev" ["user"; "id=net" ^
string_of_int i];
+ arg_list "-device" [net_bus;
+ sprintf "netdev=net%d%s" i
+ (match nic.s_mac with
+ | None -> ""
+ | Some mac -> "mac=" ^ mac)]
) source.s_nics;
(* Add a display. *)
@@ -185,11 +187,11 @@ object
| VNC ->
arg "-display" "vnc=:0"
| Spice ->
- commas "-spice" [sprintf "port=%d"
- (match display.s_port with
- | None -> 5900
- | Some p -> p);
- "addr=127.0.0.1"]
+ arg_list "-spice" [sprintf "port=%d"
+ (match display.s_port with
+ | None -> 5900
+ | Some p -> p);
+ "addr=127.0.0.1"]
);
arg "-vga"
(match guestcaps.gcaps_video with Cirrus -> "cirrus" | QXL ->
"qxl")
@@ -215,15 +217,15 @@ object
(* Add the miscellaneous KVM devices. *)
if guestcaps.gcaps_virtio_rng then (
- commas "-object" ["rng-random";
"filename=/dev/urandom"; "id=rng0"];
- commas "-device" ["virtio-rng-pci"; "rng=rng0"];
+ arg_list "-object" ["rng-random";
"filename=/dev/urandom"; "id=rng0"];
+ arg_list "-device" ["virtio-rng-pci"; "rng=rng0"];
);
if guestcaps.gcaps_virtio_balloon then
arg "-balloon" "virtio"
else
arg "-balloon" "none";
if guestcaps.gcaps_isa_pvpanic then
- commas "-device" ["pvpanic"; "ioport=0x505"];
+ arg_list "-device" ["pvpanic"; "ioport=0x505"];
(* Add a serial console to Linux guests. *)
if inspect.i_type = "linux" then
@@ -244,7 +246,7 @@ object
fpf "\n"
);
- Qemu_command.to_chan cmd chan;
+ Qemuopts.to_chan cmd chan;
close_out chan;
Unix.chmod file 0o755;
diff --git a/v2v/qemu_command.ml b/v2v/qemu_command.ml
deleted file mode 100644
index ccdda8a..0000000
--- a/v2v/qemu_command.ml
+++ /dev/null
@@ -1,101 +0,0 @@
-(* virt-v2v
- * Copyright (C) 2009-2017 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *)
-
-(** Generate a qemu command line, dealing with quoting. *)
-
-open Printf
-
-open Common_utils
-
-type t = {
- cmd : string;
- mutable args : arg list; (* list constructed in reverse order *)
-}
-and arg =
- | Flag of string
- | Arg of string * string * bool
- | Commas of string * string list
-
-let create ?(arch = "x86_64") () =
- { cmd = "qemu-system-" ^ arch; args = [] }
-
-let flag t k =
- assert (String.is_prefix k "-");
- t.args <- Flag k :: t.args
-
-let arg t k v =
- assert (String.is_prefix k "-");
- t.args <- Arg (k, v, true) :: t.args
-
-let arg_noquote t k v =
- assert (String.is_prefix k "-");
- t.args <- Arg (k, v, false) :: t.args
-
-let commas t k vs =
- assert (String.is_prefix k "-");
- List.iter (fun v -> assert (v <> "")) vs;
- t.args <- Commas (k, vs) :: t.args
-
-let nl = " \\\n\t"
-
-(* If the value contains only simple characters then it doesn't
- * need quoting. This keeps the output as similar as possible
- * to the old code.
- *)
-let do_quoting str =
- let len = String.length str in
- let ret = ref false in
- for i = 0 to len-1 do
- let c = String.unsafe_get str i in
- if not (Char.isalnum c) &&
- c <> '.' && c <> '-' && c <>
'_' &&
- c <> '=' && c <> ',' && c <>
':' && c <> '/'
- then
- ret := true
- done;
- !ret
-
-let print_quoted_param chan k v =
- if not (do_quoting v) then
- fprintf chan "%s%s %s" nl k v
- else
- fprintf chan "%s%s %s" nl k (quote v)
-
-let to_chan t chan =
- fprintf chan "%s" t.cmd;
- List.iter (
- function
- | Flag k ->
- fprintf chan "%s%s" nl k
- | Arg (k, v, true) ->
- print_quoted_param chan k v
- | Arg (k, v, false) ->
- fprintf chan "%s%s %s" nl k v
- | Commas (k, vs) ->
- let vs = List.map (fun s -> String.replace s "," ",,") vs
in
- let v = String.concat "," vs in
- print_quoted_param chan k v
- ) (List.rev t.args);
- fprintf chan "\n"
-
-let to_script t filename =
- let chan = open_out filename in
- fprintf chan "#!/bin/sh -\n";
- to_chan t chan;
- close_out chan;
- Unix.chmod filename 0o755
diff --git a/v2v/qemuopts-c.c b/v2v/qemuopts-c.c
new file mode 100644
index 0000000..cfdb5f6
--- /dev/null
+++ b/v2v/qemuopts-c.c
@@ -0,0 +1,216 @@
+/* virt-v2v
+ * Copyright (C) 2009-2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <caml/alloc.h>
+#include <caml/custom.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+
+#ifdef HAVE_CAML_UNIXSUPPORT_H
+#include <caml/unixsupport.h>
+#else
+#define Nothing ((value) 0)
+extern void unix_error (int errcode, char * cmdname, value arg) Noreturn;
+#endif
+
+#include "qemuopts.h"
+
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+
+#define Qopts_val(v) (*((struct qemuopts **)Data_custom_val(v)))
+
+static void
+qopts_finalize (value qoptsv)
+{
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+
+ if (qopts)
+ qemuopts_free (qopts);
+}
+
+static struct custom_operations qemuopts_custom_operations = {
+ (char *) "qemuopts_custom_operations",
+ qopts_finalize,
+ custom_compare_default,
+ custom_hash_default,
+ custom_serialize_default,
+ custom_deserialize_default
+};
+
+value
+guestfs_int_qemuopts_create (value unitv)
+{
+ CAMLparam1 (unitv);
+ CAMLlocal1 (qoptsv);
+ struct qemuopts *qopts;
+
+ qopts = qemuopts_create ();
+ if (qopts == NULL)
+ unix_error (errno, (char *) "qemuopts_create", Nothing);
+
+ qoptsv = caml_alloc_custom (&qemuopts_custom_operations,
+ sizeof (struct qemuopts *), 0, 1);
+ Qopts_val (qoptsv) = qopts;
+
+ CAMLreturn (qoptsv);
+}
+
+value
+guestfs_int_qemuopts_set_binary (value qoptsv, value strv)
+{
+ CAMLparam2 (qoptsv, strv);
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+
+ if (qemuopts_set_binary (qopts, String_val (strv)) == -1)
+ unix_error (errno, (char *) "qemuopts_set_binary", strv);
+
+ CAMLreturn (Val_unit);
+}
+
+value
+guestfs_int_qemuopts_set_binary_by_arch (value qoptsv, value ostrv)
+{
+ CAMLparam2 (qoptsv, ostrv);
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+ int r;
+
+ if (ostrv != Val_int (0))
+ r = qemuopts_set_binary_by_arch (qopts, NULL);
+ else
+ r = qemuopts_set_binary_by_arch (qopts, String_val (Field (ostrv, 0)));
+
+ if (r == -1)
+ unix_error (errno, (char *) "qemuopts_set_binary_by_arch", Nothing);
+
+ CAMLreturn (Val_unit);
+}
+
+value
+guestfs_int_qemuopts_flag (value qoptsv, value flagv)
+{
+ CAMLparam2 (qoptsv, flagv);
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+
+ if (qemuopts_add_flag (qopts, String_val (flagv)) == -1)
+ unix_error (errno, (char *) "qemuopts_add_flag", flagv);
+
+ CAMLreturn (Val_unit);
+}
+
+value
+guestfs_int_qemuopts_arg (value qoptsv, value flagv, value valv)
+{
+ CAMLparam3 (qoptsv, flagv, valv);
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+
+ if (qemuopts_add_arg (qopts, String_val (flagv), String_val (valv)) == -1)
+ unix_error (errno, (char *) "qemuopts_add_arg", flagv);
+
+ CAMLreturn (Val_unit);
+}
+
+value
+guestfs_int_qemuopts_arg_noquote (value qoptsv, value flagv, value valv)
+{
+ CAMLparam3 (qoptsv, flagv, valv);
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+
+ if (qemuopts_add_arg_noquote (qopts,
+ String_val (flagv), String_val (valv)) == -1)
+ unix_error (errno, (char *) "qemuopts_add_arg_noquote", flagv);
+
+ CAMLreturn (Val_unit);
+}
+
+value
+guestfs_int_qemuopts_arg_list (value qoptsv, value flagv, value valuesv)
+{
+ CAMLparam3 (qoptsv, flagv, valuesv);
+ CAMLlocal1 (hd);
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+
+ if (qemuopts_start_arg_list (qopts, String_val (flagv)) == -1)
+ unix_error (errno, (char *) "qemuopts_start_arg_list", flagv);
+
+ while (valuesv != Val_emptylist) {
+ hd = Field (valuesv, 0);
+ if (qemuopts_append_arg_list (qopts, String_val (hd)) == -1)
+ unix_error (errno, (char *) "qemuopts_append_arg_list", flagv);
+ valuesv = Field (valuesv, 1);
+ }
+
+ if (qemuopts_end_arg_list (qopts) == -1)
+ unix_error (errno, (char *) "qemuopts_end_arg_list", flagv);
+
+ CAMLreturn (Val_unit);
+}
+
+value
+guestfs_int_qemuopts_to_script (value qoptsv, value strv)
+{
+ CAMLparam2 (qoptsv, strv);
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+
+ if (qemuopts_to_script (qopts, String_val (strv)) == -1)
+ unix_error (errno, (char *) "qemuopts_to_script", strv);
+
+ CAMLreturn (Val_unit);
+}
+
+value
+guestfs_int_qemuopts_to_chan (value qoptsv, value fdv)
+{
+ CAMLparam2 (qoptsv, fdv);
+ struct qemuopts *qopts = Qopts_val (qoptsv);
+ /* Note that Unix.file_descr is really just an int. */
+ int fd = Int_val (fdv);
+ int fd2;
+ FILE *fp;
+ int saved_errno;
+
+ /* Dup the file descriptor so we don't lose it in fclose. */
+ fd2 = dup (fd);
+ if (fd2 == -1)
+ unix_error (errno, (char *) "qemuopts_to_channel: dup", Nothing);
+
+ fp = fdopen (fd2, "w");
+ if (fp == NULL) {
+ saved_errno = errno;
+ close (fd2);
+ unix_error (saved_errno, (char *) "qemuopts_to_channel: fdopen", Nothing);
+ }
+
+ if (qemuopts_to_channel (qopts, fp) == -1) {
+ saved_errno = errno;
+ fclose (fp);
+ unix_error (saved_errno, (char *) "qemuopts_to_channel", Nothing);
+ }
+
+ if (fclose (fp) == EOF)
+ unix_error (errno, (char *) "qemuopts_to_channel: fclose", Nothing);
+
+ CAMLreturn (Val_unit);
+}
diff --git a/v2v/qemuopts.ml b/v2v/qemuopts.ml
new file mode 100644
index 0000000..752e4d6
--- /dev/null
+++ b/v2v/qemuopts.ml
@@ -0,0 +1,35 @@
+(* virt-v2v
+ * Copyright (C) 2009-2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+type t
+
+external create : unit -> t = "guestfs_int_qemuopts_create"
+external set_binary : t -> string -> unit =
"guestfs_int_qemuopts_set_binary"
+external set_binary_by_arch : t -> string option -> unit =
"guestfs_int_qemuopts_set_binary_by_arch"
+external flag : t -> string -> unit = "guestfs_int_qemuopts_flag"
+external arg : t -> string -> string -> unit =
"guestfs_int_qemuopts_arg"
+external arg_noquote : t -> string -> string -> unit =
"guestfs_int_qemuopts_arg_noquote"
+external arg_list : t -> string -> string list -> unit =
"guestfs_int_qemuopts_arg_list"
+external to_script : t -> string -> unit =
"guestfs_int_qemuopts_to_script"
+
+external _to_chan : t -> Unix.file_descr -> unit =
"guestfs_int_qemuopts_to_chan"
+
+let to_chan t chan =
+ flush chan;
+ let fd = Unix.descr_of_out_channel chan in
+ _to_chan t fd
diff --git a/v2v/qemu_command.mli b/v2v/qemuopts.mli
similarity index 75%
rename from v2v/qemu_command.mli
rename to v2v/qemuopts.mli
index d993bd2..695acab 100644
--- a/v2v/qemu_command.mli
+++ b/v2v/qemuopts.mli
@@ -16,14 +16,22 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
-(** Generate a qemu command line, dealing with quoting. *)
+(** OCaml bindings for the [common/qemuopts] library. *)
type t
-val create : ?arch:string -> unit -> t
-(** Create an empty qemu command. If the optional [?arch] parameter
- is supplied then the command will be [qemu-system-<arch>],
- otherwise it will be [qemu-system-x86_64]. *)
+val create : unit -> t
+(** Create an empty qemu command line.
+
+ In case of error, all these functions raise [Unix_error]. *)
+
+val set_binary : t -> string -> unit
+(** Set the qemu binary name. *)
+
+val set_binary_by_arch : t -> string option -> unit
+(** Set the qemu binary to [qemu-system-<arch>]. If [arch] is [None],
+ then this picks the right KVM binary for the current host
+ architecture. *)
val flag : t -> string -> unit
(** [flag t "-foo"] adds a parameter to the command line with no argument. *)
@@ -34,13 +42,13 @@ val arg : t -> string -> string -> unit
The value will shell-quoted if required, so you do not need to quote
the string. However if the value is a comma-separated list
(eg. [-drive file=foo,if=ide]) then do {b not} use this function, call
- {!commas} instead. *)
+ {!arg_list} instead. *)
val arg_noquote : t -> string -> string -> unit
(** Like {!arg} except no quoting is done on the value. *)
-val commas : t -> string -> string list -> unit
-(** [commas t "-drive" ["file=foo"; "if=ide"]] adds a
comma-separated
+val arg_list : t -> string -> string list -> unit
+(** [arg_list t "-drive" ["file=foo"; "if=ide"]] adds a
comma-separated
list of parameters to the command line [-drive file=foo,if=ide].
This does both qemu comma-quoting and shell-quoting as required. *)
--
2.9.3