summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2009-06-23 10:07:46 +0100
committerRichard W.M. Jones <rjones@redhat.com>2009-06-23 10:07:46 +0100
commit675411d34f807420d1b714436fc5a58fc0022dae (patch)
treee64888a39d01147d337713d29d1a5015f4e69c57
parent1d07f1f88a08fc84d91db0931fcf34d1f9db36d3 (diff)
downloadlibguestfs-675411d34f807420d1b714436fc5a58fc0022dae.tar.gz
libguestfs-675411d34f807420d1b714436fc5a58fc0022dae.tar.xz
libguestfs-675411d34f807420d1b714436fc5a58fc0022dae.zip
Command line argument handling.
-rw-r--r--TODO15
-rw-r--r--guestfs.pod3
-rwxr-xr-xsrc/generator.ml2
-rw-r--r--src/guestfs.c109
4 files changed, 110 insertions, 19 deletions
diff --git a/TODO b/TODO
index ad9e6e9b..1d7cb364 100644
--- a/TODO
+++ b/TODO
@@ -54,21 +54,6 @@ ie. CentOS 5.3, Fedora 11, Debian.
----------------------------------------------------------------------
-Qemu options -- After discussion with the KVM developers, they have
-recommended some flags which will improve the safety and reliability
-of KVM. Need to test that these also work under qemu (or at least, do
-no harm):
-
--no-hpet HPET support is broken and should be disabled.
-
--rtc-td-hack Keeps the rtc clock source track time correctly.
-
--drive file=...,if=[ide|virtio],cache=off
- cache=off is necessary to improve reliability in the
- event of a system crash when writing.
-
-----------------------------------------------------------------------
-
"Standalone/local mode"
Instead of running guestfsd (the daemon) inside qemu, there should be
diff --git a/guestfs.pod b/guestfs.pod
index f26880cf..10c6ad8c 100644
--- a/guestfs.pod
+++ b/guestfs.pod
@@ -759,6 +759,9 @@ For example:
LIBGUESTFS_QEMU=/tmp/qemu.wrapper guestfish
+Note that libguestfs also calls qemu with the -help and -version
+options in order to determine features.
+
=head1 ENVIRONMENT VARIABLES
=over 4
diff --git a/src/generator.ml b/src/generator.ml
index 341924f1..f8e3934f 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -373,7 +373,7 @@ for whatever operations you want to perform (ie. read access if you
just want to read the image or write access if you want to modify the
image).
-This is equivalent to the qemu parameter C<-drive file=filename>.
+This is equivalent to the qemu parameter C<-drive file=filename,cache=off>.
Note that this call checks for the existence of C<filename>. This
stops you from specifying other types of drive which are supported
diff --git a/src/guestfs.c b/src/guestfs.c
index f7f64def..02b3ceb3 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -162,6 +162,8 @@ struct guestfs_h
char *tmpdir; /* Temporary directory containing socket. */
+ char *qemu_help, *qemu_version; /* Output of qemu -help, qemu -version. */
+
char **cmdline; /* Qemu command line. */
int cmdline_size;
@@ -346,6 +348,8 @@ guestfs_close (guestfs_h *g)
free (g->path);
free (g->qemu);
free (g->append);
+ free (g->qemu_help);
+ free (g->qemu_version);
free (g);
}
@@ -638,7 +642,6 @@ guestfs_config (guestfs_h *g,
strcmp (qemu_param, "-initrd") == 0 ||
strcmp (qemu_param, "-nographic") == 0 ||
strcmp (qemu_param, "-serial") == 0 ||
- strcmp (qemu_param, "-vnc") == 0 ||
strcmp (qemu_param, "-full-screen") == 0 ||
strcmp (qemu_param, "-std-vga") == 0 ||
strcmp (qemu_param, "-vnc") == 0) {
@@ -671,7 +674,8 @@ guestfs_add_drive (guestfs_h *g, const char *filename)
return -1;
}
- snprintf (buf, len, "file=%s", filename);
+ /* cache=off improves reliability in the event of a host crash. */
+ snprintf (buf, len, "file=%s,cache=off", filename);
return guestfs_config (g, "-drive", buf);
}
@@ -745,6 +749,8 @@ dir_contains_files (const char *dir, ...)
}
static int build_supermin_appliance (guestfs_h *g, const char *path, char **kernel, char **initrd);
+static int test_qemu (guestfs_h *g);
+static int qemu_supports (guestfs_h *g, const char *option);
static const char *kernel_name = "vmlinuz." REPO "." host_cpu;
static const char *initrd_name = "initramfs." REPO "." host_cpu ".img";
@@ -879,12 +885,16 @@ guestfs_launch (guestfs_h *g)
/* Choose a suitable memory size. Previously we tried to choose
* a minimal memory size, but this isn't really necessary since
* recent QEMU and KVM don't do anything nasty like locking
- * memory into core any more. This we can safely choose a
+ * memory into core any more. Thus we can safely choose a
* large, generous amount of memory, and it'll just get swapped
* on smaller systems.
*/
memsize = 384;
+ /* Get qemu help text and version. */
+ if (test_qemu (g) == -1)
+ goto cleanup0;
+
/* Make the vmchannel socket. */
snprintf (unixsock, sizeof unixsock, "%s/sock", g->tmpdir);
unlink (unixsock);
@@ -946,6 +956,15 @@ guestfs_launch (guestfs_h *g)
add_cmdline (g, "user,vlan=0");
add_cmdline (g, "-net");
add_cmdline (g, "nic,model=virtio,vlan=0");
+
+ /* These options recommended by KVM developers to improve reliability. */
+ if (qemu_supports (g, "-no-hpet"))
+ add_cmdline (g, "-no-hpet");
+
+ if (qemu_supports (g, "-rtc-td-hack"))
+ add_cmdline (g, "-rtc-td-hack");
+
+ /* Finish off the command line. */
incr_cmdline_size (g);
g->cmdline[g->cmdline_size-1] = NULL;
@@ -1171,6 +1190,90 @@ build_supermin_appliance (guestfs_h *g, const char *path,
return 0;
}
+static int read_all (guestfs_h *g, FILE *fp, char **ret);
+
+/* Test qemu binary (or wrapper) runs, and do 'qemu -help' and
+ * 'qemu -version' so we know what options this qemu supports and
+ * the version.
+ */
+static int
+test_qemu (guestfs_h *g)
+{
+ char cmd[1024];
+ FILE *fp;
+
+ free (g->qemu_help);
+ free (g->qemu_version);
+ g->qemu_help = NULL;
+ g->qemu_version = NULL;
+
+ snprintf (cmd, sizeof cmd, "'%s' -help", g->qemu);
+
+ fp = popen (cmd, "r");
+ /* qemu -help should always work (qemu -version OTOH wasn't
+ * supported by qemu 0.9). If this command doesn't work then it
+ * probably indicates that the qemu binary is missing.
+ */
+ if (!fp) {
+ /* XXX This error is never printed, even if the qemu binary
+ * doesn't exist. Why?
+ */
+ error:
+ perrorf (g, _("%s: command failed: If qemu is located on a non-standard path, try setting the LIBGUESTFS_QEMU environment variable."), cmd);
+ return -1;
+ }
+
+ if (read_all (g, fp, &g->qemu_help) == -1)
+ goto error;
+
+ if (pclose (fp) == -1)
+ goto error;
+
+ snprintf (cmd, sizeof cmd, "'%s' -version 2>/dev/null", g->qemu);
+
+ fp = popen (cmd, "r");
+ if (fp) {
+ /* Intentionally ignore errors. */
+ read_all (g, fp, &g->qemu_version);
+ pclose (fp);
+ }
+
+ return 0;
+}
+
+static int
+read_all (guestfs_h *g, FILE *fp, char **ret)
+{
+ int r, n = 0;
+ char *p;
+
+ again:
+ if (feof (fp)) {
+ *ret = safe_realloc (g, *ret, n + 1);
+ (*ret)[n] = '\0';
+ return n;
+ }
+
+ *ret = safe_realloc (g, *ret, n + BUFSIZ);
+ p = &(*ret)[n];
+ r = fread (p, 1, BUFSIZ, fp);
+ if (ferror (fp)) {
+ perrorf (g, "read");
+ return -1;
+ }
+ n += r;
+ goto again;
+}
+
+/* Test if option is supported by qemu command line (just by grepping
+ * the help text).
+ */
+static int
+qemu_supports (guestfs_h *g, const char *option)
+{
+ return g->qemu_help && strstr (g->qemu_help, option) != NULL;
+}
+
static void
finish_wait_ready (guestfs_h *g, void *vp)
{