X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Flaunch.c;h=261136d5483fae06827785769039b138add5cd0c;hp=e5bca56e8d3572c34a35fc602ca3fe2797912dc7;hb=4e0cf4dbf8a8a96288f70114fdc3939da0aa7ad1;hpb=06fef60db5c7a96cb59aa92c4708e10333345e90 diff --git a/src/launch.c b/src/launch.c index e5bca56..261136d 100644 --- a/src/launch.c +++ b/src/launch.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -69,6 +70,8 @@ #include "guestfs-internal-actions.h" #include "guestfs_protocol.h" +static int launch_appliance (guestfs_h *g); +static int connect_unix_socket (guestfs_h *g, const char *sock); static int qemu_supports (guestfs_h *g, const char *option); /* Add a string to the current command line. */ @@ -101,6 +104,49 @@ add_cmdline (guestfs_h *g, const char *str) } int +guestfs___checkpoint_cmdline (guestfs_h *g) +{ + return g->cmdline_size; +} + +void +guestfs___rollback_cmdline (guestfs_h *g, int pos) +{ + int i; + + assert (g->cmdline_size >= pos); + + for (i = g->cmdline_size - 1; i >= pos; --i) + free (g->cmdline[i]); + + g->cmdline_size = pos; +} + +/* Internal command to return the command line. */ +char ** +guestfs__debug_cmdline (guestfs_h *g) +{ + int i; + char **r; + + if (g->cmdline == NULL) { + r = safe_malloc (g, sizeof (char *) * 1); + r[0] = NULL; + return r; + } + + r = safe_malloc (g, sizeof (char *) * (g->cmdline_size + 1)); + r[0] = safe_strdup (g, g->qemu); /* g->cmdline[0] is always NULL */ + + for (i = 1; i < g->cmdline_size; ++i) + r[i] = safe_strdup (g, g->cmdline[i]); + + r[g->cmdline_size] = NULL; + + return r; /* caller frees */ +} + +int guestfs__config (guestfs_h *g, const char *qemu_param, const char *qemu_value) { @@ -306,33 +352,19 @@ static int is_openable (guestfs_h *g, const char *path, int flags); int guestfs__launch (guestfs_h *g) { - int r; - int wfd[2], rfd[2]; - int tries; - char unixsock[256]; - struct sockaddr_un addr; - /* Configured? */ - if (!g->cmdline) { - error (g, _("you must call guestfs_add_drive before guestfs_launch")); - return -1; - } - if (g->state != CONFIG) { error (g, _("the libguestfs handle has already been launched")); return -1; } - /* Start the clock ... */ - gettimeofday (&g->launch_t, NULL); - /* Make the temporary directory. */ if (!g->tmpdir) { TMP_TEMPLATE_ON_STACK (dir_template); g->tmpdir = safe_strdup (g, dir_template); if (mkdtemp (g->tmpdir) == NULL) { perrorf (g, _("%s: cannot create temporary directory"), dir_template); - goto cleanup0; + return -1; } } @@ -341,7 +373,39 @@ guestfs__launch (guestfs_h *g) * want. (RHBZ#610880). */ if (chmod (g->tmpdir, 0755) == -1) - fprintf (stderr, "chmod: %s: %m (ignored)\n", g->tmpdir); + warning (g, "chmod: %s: %m (ignored)", g->tmpdir); + + /* Launch the appliance or attach to an existing daemon. */ + switch (g->attach_method) { + case ATTACH_METHOD_APPLIANCE: + return launch_appliance (g); + + case ATTACH_METHOD_UNIX: + return connect_unix_socket (g, g->attach_method_arg); + + default: + abort (); + } +} + +static int +launch_appliance (guestfs_h *g) +{ + int r; + int wfd[2], rfd[2]; + char unixsock[256]; + struct sockaddr_un addr; + + /* At present you must add drives before starting the appliance. In + * future when we enable hotplugging you won't need to do this. + */ + if (!g->cmdline) { + error (g, _("you must call guestfs_add_drive before guestfs_launch")); + return -1; + } + + /* Start the clock ... */ + gettimeofday (&g->launch_t, NULL); /* Locate and/or build the appliance. */ char *kernel = NULL, *initrd = NULL, *appliance = NULL; @@ -705,7 +769,7 @@ guestfs__launch (guestfs_h *g) } if (g->pid > 0) kill (g->pid, 9); if (g->recoverypid > 0) kill (g->recoverypid, 9); - waitpid (g->pid, NULL, 0); + if (g->pid > 0) waitpid (g->pid, NULL, 0); if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0); g->fd[0] = -1; g->fd[1] = -1; @@ -725,8 +789,81 @@ guestfs__launch (guestfs_h *g) return -1; } +/* Alternate attach method: instead of launching the appliance, + * connect to an existing unix socket. + */ +static int +connect_unix_socket (guestfs_h *g, const char *sockpath) +{ + int r; + struct sockaddr_un addr; + + /* Start the clock ... */ + gettimeofday (&g->launch_t, NULL); + + /* Set these to nothing so we don't try to kill random processes or + * read from random file descriptors. + */ + g->pid = 0; + g->recoverypid = 0; + g->fd[0] = -1; + g->fd[1] = -1; + + if (g->verbose) + guestfs___print_timestamped_message (g, "connecting to %s", sockpath); + + g->sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (g->sock == -1) { + perrorf (g, "socket"); + return -1; + } + + addr.sun_family = AF_UNIX; + strncpy (addr.sun_path, sockpath, UNIX_PATH_MAX); + addr.sun_path[UNIX_PATH_MAX-1] = '\0'; + + g->state = LAUNCHING; + + if (connect (g->sock, &addr, sizeof addr) == -1) { + perrorf (g, "bind"); + goto cleanup; + } + + if (fcntl (g->sock, F_SETFL, O_NONBLOCK) == -1) { + perrorf (g, "fcntl"); + goto cleanup; + } + + uint32_t size; + void *buf = NULL; + r = guestfs___recv_from_daemon (g, &size, &buf); + free (buf); + + if (r == -1) return -1; + + if (size != GUESTFS_LAUNCH_FLAG) { + error (g, _("guestfs_launch failed, unexpected initial message from guestfsd")); + goto cleanup; + } + + if (g->verbose) + guestfs___print_timestamped_message (g, "connected"); + + if (g->state != READY) { + error (g, _("contacted guestfsd, but state != READY")); + goto cleanup; + } + + return 0; + + cleanup: + close (g->sock); + return -1; +} + /* Return the location of the tmpdir (eg. "/tmp") and allow users * to override it at runtime using $TMPDIR. + * http://www.pathname.com/fhs/pub/fhs-2.3.html#TMPTEMPORARYFILES */ const char * guestfs_tmpdir (void) @@ -745,6 +882,23 @@ guestfs_tmpdir (void) return tmpdir; } +/* Return the location of the persistent tmpdir (eg. "/var/tmp") and + * allow users to override it at runtime using $TMPDIR. + * http://www.pathname.com/fhs/pub/fhs-2.3.html#VARTMPTEMPORARYFILESPRESERVEDBETWEE + */ +const char * +guestfs___persistent_tmpdir (void) +{ + const char *tmpdir; + + tmpdir = "/var/tmp"; + + const char *t = getenv ("TMPDIR"); + if (t) tmpdir = t; + + return tmpdir; +} + /* Compute Y - X and return the result in milliseconds. * Approximately the same as this code: * http://www.mpp.mpg.de/~huber/util/timevaldiff.c @@ -764,27 +918,40 @@ guestfs___print_timestamped_argv (guestfs_h *g, const char * argv[]) { int i = 0; int needs_quote; + char *buf = NULL; + size_t len; + FILE *fp; + + fp = open_memstream (&buf, &len); + if (fp == NULL) { + warning (g, "open_memstream: %m"); + return; + } struct timeval tv; gettimeofday (&tv, NULL); - fprintf (stderr, "[%05" PRIi64 "ms] ", timeval_diff (&g->launch_t, &tv)); + fprintf (fp, "[%05" PRIi64 "ms] ", timeval_diff (&g->launch_t, &tv)); while (argv[i]) { if (argv[i][0] == '-') /* -option starts a new line */ - fprintf (stderr, " \\\n "); + fprintf (fp, " \\\n "); - if (i > 0) fputc (' ', stderr); + if (i > 0) fputc (' ', fp); /* 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); + if (needs_quote) fputc ('\'', fp); + fprintf (fp, "%s", argv[i]); + if (needs_quote) fputc ('\'', fp); i++; } - fputc ('\n', stderr); + fclose (fp); + + debug (g, "%s", buf); + + free (buf); } void @@ -803,8 +970,7 @@ guestfs___print_timestamped_message (guestfs_h *g, const char *fs, ...) gettimeofday (&tv, NULL); - fprintf (stderr, "[%05" PRIi64 "ms] %s\n", - timeval_diff (&g->launch_t, &tv), msg); + debug (g, "[%05" PRIi64 "ms] %s", timeval_diff (&g->launch_t, &tv), msg); free (msg); } @@ -910,8 +1076,7 @@ is_openable (guestfs_h *g, const char *path, int flags) { int fd = open (path, flags); if (fd == -1) { - if (g->verbose) - perror (path); + debug (g, "is_openable: %s: %m", path); return 0; } close (fd); @@ -940,8 +1105,7 @@ guestfs__kill_subprocess (guestfs_h *g) return -1; } - if (g->verbose) - fprintf (stderr, "sending SIGTERM to process %d\n", g->pid); + debug (g, "sending SIGTERM to process %d", g->pid); if (g->pid > 0) kill (g->pid, SIGTERM); if (g->recoverypid > 0) kill (g->recoverypid, 9);