/* libguestfs
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009-2010 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 <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
+#include <stdint.h>
+#include <inttypes.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
+#include "c-ctype.h"
+#include "glthread/lock.h"
+#include "ignore-value.h"
+
#include "guestfs.h"
+#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
#include "guestfs_protocol.h"
-#include "c-ctype.h"
-#include "ignore-value.h"
#ifdef HAVE_GETTEXT
#include "gettext.h"
int sock; /* Daemon communications socket. */
pid_t pid; /* Qemu PID. */
pid_t recoverypid; /* Recovery process PID. */
- time_t start_t; /* The time when we started qemu. */
+
+ struct timeval launch_t; /* The time that we called guestfs_launch. */
char *tmpdir; /* Temporary directory containing socket. */
int msg_next_serial;
};
+gl_lock_define_initialized (static, handles_lock);
static guestfs_h *handles = NULL;
static int atexit_handler_set = 0;
*/
g->msg_next_serial = 0x00123400;
- /* Link the handles onto a global list. This is the one area
- * where the library needs to be made thread-safe. (XXX)
- */
- /* acquire mutex (XXX) */
+ /* Link the handles onto a global list. */
+ gl_lock_lock (handles_lock);
g->next = handles;
handles = g;
if (!atexit_handler_set) {
atexit (close_handles);
atexit_handler_set = 1;
}
- /* release mutex (XXX) */
+ gl_lock_unlock (handles_lock);
if (g->verbose)
fprintf (stderr, "new guestfs handle %p\n", g);
/* Mark the handle as dead before freeing it. */
g->state = NO_HANDLE;
- /* acquire mutex (XXX) */
+ gl_lock_lock (handles_lock);
if (handles == g)
handles = g->next;
else {
;
gg->next = g->next;
}
- /* release mutex (XXX) */
+ gl_lock_unlock (handles_lock);
free (g->last_error);
free (g->path);
return 1;
}
+static void print_timestamped_message (guestfs_h *g, const char *fs, ...);
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);
char unixsock[256];
struct sockaddr_un addr;
+ /* Start the clock ... */
+ gettimeofday (&g->launch_t, NULL);
+
#ifdef P_tmpdir
tmpdir = P_tmpdir;
#else
goto cleanup0;
}
+ if (g->verbose)
+ print_timestamped_message (g, "begin testing qemu features");
+
/* Get qemu help text and version. */
if (test_qemu (g) == -1)
goto cleanup0;
}
}
+ if (g->verbose)
+ print_timestamped_message (g, "finished testing qemu features");
+
r = fork ();
if (r == -1) {
perrorf (g, "fork");
*/
g->cmdline[0] = g->qemu;
- snprintf (buf, sizeof buf, "%d", g->memsize);
- add_cmdline (g, "-m");
- add_cmdline (g, buf);
+ /* Newer versions of qemu (from around 2009/12) changed the
+ * behaviour of monitors so that an implicit '-monitor stdio' is
+ * assumed if we are in -nographic mode and there is no other
+ * -monitor option. Only a single stdio device is allowed, so
+ * this broke the '-serial stdio' option. There is a new flag
+ * called -nodefaults which gets rid of all this default crud, so
+ * let's use that to avoid this and any future surprises.
+ */
+ if (qemu_supports (g, "-nodefaults"))
+ add_cmdline (g, "-nodefaults");
- add_cmdline (g, "-no-reboot"); /* Force exit instead of reboot on panic */
add_cmdline (g, "-nographic");
add_cmdline (g, "-serial");
add_cmdline (g, "stdio");
+ snprintf (buf, sizeof buf, "%d", g->memsize);
+ add_cmdline (g, "-m");
+ add_cmdline (g, buf);
+
+ /* Force exit instead of reboot on panic */
+ add_cmdline (g, "-no-reboot");
+
/* These options recommended by KVM developers to improve reliability. */
if (qemu_supports (g, "-no-hpet"))
add_cmdline (g, "-no-hpet");
g->recoverypid = r;
}
- /* Start the clock ... */
- time (&g->start_t);
-
if (!g->direct) {
/* Close the other ends of the pipe. */
close (wfd[0]);
goto cleanup1;
}
+ if (g->verbose)
+ print_timestamped_message (g, "appliance is up");
+
/* This is possible in some really strange situations, such as
* guestfsd starts up OK but then qemu immediately exits. Check for
* it because the caller is probably expecting to be able to send
g->fd[1] = -1;
g->pid = 0;
g->recoverypid = 0;
- g->start_t = 0;
+ memset (&g->launch_t, 0, sizeof g->launch_t);
cleanup0:
if (g->sock >= 0) {
char cmd[4096];
int r, len;
+ if (g->verbose)
+ print_timestamped_message (g, "begin building supermin appliance");
+
len = strlen (g->tmpdir);
*kernel = safe_malloc (g, len + 8);
snprintf (*kernel, len+8, "%s/kernel", g->tmpdir);
snprintf (cmd, sizeof cmd,
"PATH='%s':$PATH "
- "libguestfs-supermin-helper '%s' %s %s",
+ "libguestfs-supermin-helper '%s' " host_cpu " " REPO " %s %s",
path,
path, *kernel, *initrd);
+ if (g->verbose)
+ print_timestamped_message (g, "%s", cmd);
r = system (cmd);
if (r == -1 || WEXITSTATUS(r) != 0) {
return -1;
}
+ if (g->verbose)
+ print_timestamped_message (g, "finished building supermin appliance");
+
return 0;
}
+/* Compute Y - X and return the result in milliseconds.
+ * Approximately the same as this code:
+ * http://www.mpp.mpg.de/~huber/util/timevaldiff.c
+ */
+static int64_t
+timeval_diff (const struct timeval *x, const struct timeval *y)
+{
+ int64_t msec;
+
+ msec = (y->tv_sec - x->tv_sec) * 1000;
+ msec += (y->tv_usec - x->tv_usec) / 1000;
+ return msec;
+}
+
+static void
+print_timestamped_message (guestfs_h *g, const char *fs, ...)
+{
+ va_list args;
+ char *msg;
+ int err;
+ struct timeval tv, diff;
+
+ va_start (args, fs);
+ err = vasprintf (&msg, fs, args);
+ va_end (args);
+
+ if (err < 0) return;
+
+ gettimeofday (&tv, NULL);
+
+ fprintf (stderr, "[%05" PRIi64 "ms] %s\n",
+ timeval_diff (&g->launch_t, &tv), msg);
+
+ free (msg);
+}
+
static int read_all (guestfs_h *g, FILE *fp, char **ret);
/* Test qemu binary (or wrapper) runs, and do 'qemu -help' and
g->sock = -1;
g->pid = 0;
g->recoverypid = 0;
- g->start_t = 0;
+ memset (&g->launch_t, 0, sizeof g->launch_t);
g->state = CONFIG;
if (g->subprocess_quit_cb)
g->subprocess_quit_cb (g, g->subprocess_quit_cb_data);