/* libguestfs
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <stddef.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
char *qemu; /* Qemu binary. */
char *append; /* Append to kernel command line. */
+ int memsize; /* Size of RAM (megabytes). */
+
char *last_error;
/* Callbacks. */
if (!g->append) goto error;
}
+ /* 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. Thus we can safely choose a
+ * large, generous amount of memory, and it'll just get swapped
+ * on smaller systems.
+ */
+ str = getenv ("LIBGUESTFS_MEMSIZE");
+ if (str) {
+ if (sscanf (str, "%d", &g->memsize) != 1 || g->memsize <= 256) {
+ fprintf (stderr, "libguestfs: non-numeric or too small value for LIBGUESTFS_MEMSIZE\n");
+ goto error;
+ }
+ } else
+ g->memsize = 500;
+
g->main_loop = guestfs_get_default_main_loop ();
/* Start with large serial numbers so they are easy to spot
if (g->state != CONFIG)
guestfs_kill_subprocess (g);
+ /* Close any sockets and deregister any handlers. */
+ if (g->stdout_watch >= 0)
+ g->main_loop->remove_handle (g->main_loop, g, g->stdout_watch);
+ if (g->sock_watch >= 0)
+ g->main_loop->remove_handle (g->main_loop, g, g->sock_watch);
+ g->stdout_watch = -1;
+ g->sock_watch = -1;
+
+ if (g->fd[0] >= 0)
+ close (g->fd[0]);
+ if (g->fd[1] >= 0)
+ close (g->fd[1]);
+ if (g->sock >= 0)
+ close (g->sock);
+ g->fd[0] = -1;
+ g->fd[1] = -1;
+ g->sock = -1;
+
+ /* Remove tmpfiles. */
if (g->tmpdir) {
snprintf (filename, sizeof filename, "%s/sock", g->tmpdir);
unlink (filename);
char *msg;
va_start (args, fs);
- vasprintf (&msg, fs, args);
+ int err = vasprintf (&msg, fs, args);
va_end (args);
+ if (err < 0) return;
+
if (g->error_cb) g->error_cb (g, g->error_cb_data, msg);
set_last_error (g, msg);
return ptr;
}
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+ to size arithmetic overflow. S must be positive and N must be
+ nonnegative. This is a macro, not an inline function, so that it
+ works correctly even when SIZE_MAX < N.
+
+ By gnulib convention, SIZE_MAX represents overflow in size
+ calculations, so the conservative dividend to use here is
+ SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+ However, malloc (SIZE_MAX) fails on all known hosts where
+ sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+ exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+ branch when S is known to be 1. */
+# define xalloc_oversized(n, s) \
+ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
+
+/* Technically we should add an autoconf test for this, testing for the desired
+ functionality, like what's done in gnulib, but for now, this is fine. */
+#define HAVE_GNU_CALLOC (__GLIBC__ >= 2)
+
+/* Allocate zeroed memory for N elements of S bytes, with error
+ checking. S must be nonzero. */
+void *
+guestfs_safe_calloc (guestfs_h *g, size_t n, size_t s)
+{
+ /* From gnulib's calloc function in xmalloc.c. */
+ void *p;
+ /* Test for overflow, since some calloc implementations don't have
+ proper overflow checks. But omit overflow and size-zero tests if
+ HAVE_GNU_CALLOC, since GNU calloc catches overflow and never
+ returns NULL if successful. */
+ if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s))
+ || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0)))
+ g->abort_cb ();
+ return p;
+}
+
void *
guestfs_safe_realloc (guestfs_h *g, void *ptr, int nbytes)
{
return g->append;
}
+int
+guestfs_set_memsize (guestfs_h *g, int memsize)
+{
+ g->memsize = memsize;
+ return 0;
+}
+
+int
+guestfs_get_memsize (guestfs_h *g)
+{
+ return g->memsize;
+}
+
+int
+guestfs_get_pid (guestfs_h *g)
+{
+ if (g->pid > 0)
+ return g->pid;
+ else {
+ error (g, "get_pid: no qemu subprocess");
+ return -1;
+ }
+}
+
+struct guestfs_version *
+guestfs_version (guestfs_h *g)
+{
+ struct guestfs_version *r;
+
+ r = safe_malloc (g, sizeof *r);
+ r->major = PACKAGE_VERSION_MAJOR;
+ r->minor = PACKAGE_VERSION_MINOR;
+ r->release = PACKAGE_VERSION_RELEASE;
+ r->extra = safe_strdup (g, PACKAGE_VERSION_EXTRA);
+ return r;
+}
+
/* Add a string to the current command line. */
static void
incr_cmdline_size (guestfs_h *g)
}
/* cache=off improves reliability in the event of a host crash. */
- snprintf (buf, len, "file=%s,cache=off", filename);
+ snprintf (buf, len, "file=%s,cache=off,if=%s", filename, DRIVE_IF);
return guestfs_config (g, "-drive", buf);
}
return -1;
}
- snprintf (buf, len, "file=%s,snapshot=on", filename);
+ snprintf (buf, len, "file=%s,snapshot=on,if=%s", filename, DRIVE_IF);
return guestfs_config (g, "-drive", buf);
}
guestfs_launch (guestfs_h *g)
{
static const char *dir_template = "/tmp/libguestfsXXXXXX";
- int r, i, pmore, memsize;
+ int r, i, pmore;
size_t len;
int wfd[2], rfd[2];
int tries;
goto cleanup0;
}
- /* 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. Thus we can safely choose a
- * large, generous amount of memory, and it'll just get swapped
- * on smaller systems.
- */
- memsize = 500;
-
/* Get qemu help text and version. */
if (test_qemu (g) == -1)
goto cleanup0;
g->verbose ? " guestfs_verbose=1" : "",
g->append ? " " : "", g->append ? g->append : "");
- snprintf (memsize_str, sizeof memsize_str, "%d", memsize);
+ snprintf (memsize_str, sizeof memsize_str, "%d", g->memsize);
add_cmdline (g, "-m");
add_cmdline (g, memsize_str);
return 0;
}
-/* Structure-freeing functions. These rely on the fact that the
- * structure format is identical to the XDR format. See note in
- * generator.ml.
- */
-void
-guestfs_free_int_bool (struct guestfs_int_bool *x)
-{
- free (x);
-}
-
-void
-guestfs_free_lvm_pv_list (struct guestfs_lvm_pv_list *x)
-{
- xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_pv_list, (char *) x);
- free (x);
-}
-
-void
-guestfs_free_lvm_vg_list (struct guestfs_lvm_vg_list *x)
-{
- xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_vg_list, (char *) x);
- free (x);
-}
-
-void
-guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *x)
-{
- xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_lv_list, (char *) x);
- free (x);
-}
-
/* We don't know if stdout_event or sock_read_event will be the
* first to receive EOF if the qemu process dies. This function
* has the common cleanup code for both.
sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
int watch, int fd, int events)
{
- int n;
+ int n, err;
if (g->verbose)
fprintf (stderr,
n = write (g->sock, g->msg_out + g->msg_out_pos,
g->msg_out_size - g->msg_out_pos);
if (n == -1) {
- if (errno != EAGAIN)
+ err = errno;
+ if (err != EAGAIN)
perrorf (g, "write");
+ if (err == EPIPE) /* Disconnected from guest (RHBZ#508713). */
+ child_cleanup (g);
return;
}
char fbuf[4];
uint32_t flag = GUESTFS_CANCEL_FLAG;
+ if (g->verbose)
+ fprintf (stderr, "%s: waiting for daemon to acknowledge cancellation\n",
+ __func__);
+
xdrmem_create (&xdr, fbuf, sizeof fbuf, XDR_ENCODE);
xdr_uint32_t (&xdr, &flag);
xdr_destroy (&xdr);