X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Flaunch.c;h=f84a128b77299c37adc608697275ad52466f07c7;hp=9deb0cfa68f54593b5f5c95014d3625def78350c;hb=5c31f6126ba4ea3e9056c34c300f6f5e332ab997;hpb=4b753c62089be663ac722e4a875bb061d259e87d diff --git a/src/launch.c b/src/launch.c index 9deb0cf..f84a128 100644 --- a/src/launch.c +++ b/src/launch.c @@ -224,53 +224,15 @@ guestfs__add_cdrom (guestfs_h *g, const char *filename) return guestfs__config (g, "-cdrom", filename); } -/* Returns true iff file is contained in dir. */ -static int -dir_contains_file (const char *dir, const char *file) -{ - int dirlen = strlen (dir); - int filelen = strlen (file); - int len = dirlen+filelen+2; - char path[len]; - - snprintf (path, len, "%s/%s", dir, file); - return access (path, F_OK) == 0; -} - -/* Returns true iff every listed file is contained in 'dir'. */ -static int -dir_contains_files (const char *dir, ...) -{ - va_list args; - const char *file; - - va_start (args, dir); - while ((file = va_arg (args, const char *)) != NULL) { - if (!dir_contains_file (dir, file)) { - va_end (args); - return 0; - } - } - va_end (args); - return 1; -} - -static int build_supermin_appliance (guestfs_h *g, const char *path, char **kernel, char **initrd); static int is_openable (guestfs_h *g, const char *path, int flags); static void print_cmdline (guestfs_h *g); -static const char *kernel_name = "vmlinuz." REPO "." host_cpu; -static const char *initrd_name = "initramfs." REPO "." host_cpu ".img"; - int guestfs__launch (guestfs_h *g) { - int r, pmore; - size_t len; + int r; int wfd[2], rfd[2]; int tries; - char *path, *pelem, *pend; - char *kernel = NULL, *initrd = NULL; int null_vmchannel_sock; char unixsock[256]; struct sockaddr_un addr; @@ -302,101 +264,17 @@ guestfs__launch (guestfs_h *g) } } - /* Allow anyone to read the temporary directory. There are no - * secrets in the kernel or initrd files. The socket in this + /* Allow anyone to read the temporary directory. The socket in this * directory won't be readable but anyone can see it exists if they * want. (RHBZ#610880). */ if (chmod (g->tmpdir, 0755) == -1) fprintf (stderr, "chmod: %s: %m (ignored)\n", g->tmpdir); - /* First search g->path for the supermin appliance, and try to - * synthesize a kernel and initrd from that. If it fails, we - * try the path search again looking for a backup ordinary - * appliance. - */ - pelem = path = safe_strdup (g, g->path); - do { - pend = strchrnul (pelem, ':'); - pmore = *pend == ':'; - *pend = '\0'; - len = pend - pelem; - - /* Empty element of "." means cwd. */ - if (len == 0 || (len == 1 && *pelem == '.')) { - if (g->verbose) - fprintf (stderr, - "looking for supermin appliance in current directory\n"); - if (dir_contains_files (".", - "supermin.d", "kmod.whitelist", NULL)) { - if (build_supermin_appliance (g, ".", &kernel, &initrd) == -1) - return -1; - break; - } - } - /* Look at /supermin* etc. */ - else { - if (g->verbose) - fprintf (stderr, "looking for supermin appliance in %s\n", pelem); - - if (dir_contains_files (pelem, - "supermin.d", "kmod.whitelist", NULL)) { - if (build_supermin_appliance (g, pelem, &kernel, &initrd) == -1) - return -1; - break; - } - } - - pelem = pend + 1; - } while (pmore); - - free (path); - - if (kernel == NULL || initrd == NULL) { - /* Search g->path for the kernel and initrd. */ - pelem = path = safe_strdup (g, g->path); - do { - pend = strchrnul (pelem, ':'); - pmore = *pend == ':'; - *pend = '\0'; - len = pend - pelem; - - /* Empty element or "." means cwd. */ - if (len == 0 || (len == 1 && *pelem == '.')) { - if (g->verbose) - fprintf (stderr, - "looking for appliance in current directory\n"); - if (dir_contains_files (".", kernel_name, initrd_name, NULL)) { - kernel = safe_strdup (g, kernel_name); - initrd = safe_strdup (g, initrd_name); - break; - } - } - /* Look at /kernel etc. */ - else { - if (g->verbose) - fprintf (stderr, "looking for appliance in %s\n", pelem); - - if (dir_contains_files (pelem, kernel_name, initrd_name, NULL)) { - kernel = safe_malloc (g, len + strlen (kernel_name) + 2); - initrd = safe_malloc (g, len + strlen (initrd_name) + 2); - sprintf (kernel, "%s/%s", pelem, kernel_name); - sprintf (initrd, "%s/%s", pelem, initrd_name); - break; - } - } - - pelem = pend + 1; - } while (pmore); - - free (path); - } - - if (kernel == NULL || initrd == NULL) { - error (g, _("cannot find %s or %s on LIBGUESTFS_PATH (current path = %s)"), - kernel_name, initrd_name, g->path); - goto cleanup0; - } + /* Locate and/or build the appliance. */ + char *kernel = NULL, *initrd = NULL, *appliance = NULL; + if (guestfs___build_appliance (g, &kernel, &initrd, &appliance) == -1) + return -1; if (g->verbose) guestfs___print_timestamped_message (g, "begin testing qemu features"); @@ -614,12 +492,29 @@ guestfs__launch (guestfs_h *g) g->append ? g->append : ""); add_cmdline (g, "-kernel"); - add_cmdline (g, (char *) kernel); + add_cmdline (g, kernel); add_cmdline (g, "-initrd"); - add_cmdline (g, (char *) initrd); + add_cmdline (g, initrd); add_cmdline (g, "-append"); add_cmdline (g, buf); + /* Add the ext2 appliance drive (last of all). */ + if (appliance) { + const char *cachemode = ""; + if (qemu_supports (g, "cache=")) { + if (qemu_supports (g, "unsafe")) + cachemode = ",cache=unsafe"; + else if (qemu_supports (g, "writeback")) + cachemode = ",cache=writeback"; + } + + char buf2[PATH_MAX + 64]; + add_cmdline (g, "-drive"); + snprintf (buf2, sizeof buf2, "file=%s,snapshot=on,if=" DRIVE_IF "%s", + appliance, cachemode); + add_cmdline (g, buf2); + } + /* Finish off the command line. */ incr_cmdline_size (g); g->cmdline[g->cmdline_size-1] = NULL; @@ -866,6 +761,7 @@ guestfs__launch (guestfs_h *g) g->state = CONFIG; free (kernel); free (initrd); + free (appliance); return -1; } @@ -913,60 +809,6 @@ print_cmdline (guestfs_h *g) fputc ('\n', stderr); } -/* This function does the hard work of building the supermin appliance - * on the fly. 'path' is the directory containing the control files. - * 'kernel' and 'initrd' are where we will return the names of the - * kernel and initrd (only initrd is built). The work is done by - * an external script. We just tell it where to put the result. - */ -static int -build_supermin_appliance (guestfs_h *g, const char *path, - char **kernel, char **initrd) -{ - 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); - *initrd = safe_malloc (g, len + 8); - snprintf (*initrd, len+8, "%s/initrd", g->tmpdir); - - /* Set a sensible umask in the subprocess, so kernel and initrd - * output files are world-readable (RHBZ#610880). - */ - snprintf (cmd, sizeof cmd, - "umask 0002; " - "febootstrap-supermin-helper%s " - "-k '%s/kmod.whitelist' " - "'%s/supermin.d' " - host_cpu " " - "%s %s", - g->verbose ? " --verbose" : "", - path, - path, - *kernel, *initrd); - if (g->verbose) - print_timestamped_message (g, "%s", cmd); - - r = system (cmd); - if (r == -1 || WEXITSTATUS(r) != 0) { - error (g, _("external command failed: %s"), cmd); - free (*kernel); - free (*initrd); - *kernel = *initrd = NULL; - 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