X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fguestfs.c;h=f7f64defb7f53d15189f3717dc803352f6455770;hb=1d07f1f88a08fc84d91db0931fcf34d1f9db36d3;hp=fb214c535de1a63b2042d22912d6cf2b53664d3d;hpb=d70248333edf8a5b5f509609cf2c8f7fd77d5e05;p=libguestfs.git diff --git a/src/guestfs.c b/src/guestfs.c index fb214c5..f7f64de 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -309,6 +310,12 @@ guestfs_close (guestfs_h *g) snprintf (filename, sizeof filename, "%s/sock", g->tmpdir); unlink (filename); + snprintf (filename, sizeof filename, "%s/initrd", g->tmpdir); + unlink (filename); + + snprintf (filename, sizeof filename, "%s/kernel", g->tmpdir); + unlink (filename); + rmdir (g->tmpdir); free (g->tmpdir); @@ -418,7 +425,7 @@ void * guestfs_safe_malloc (guestfs_h *g, size_t nbytes) { void *ptr = malloc (nbytes); - if (!ptr) g->abort_cb (); + if (nbytes > 0 && !ptr) g->abort_cb (); return ptr; } @@ -426,7 +433,7 @@ void * guestfs_safe_realloc (guestfs_h *g, void *ptr, int nbytes) { void *p = realloc (ptr, nbytes); - if (!p) g->abort_cb (); + if (nbytes > 0 && !p) g->abort_cb (); return p; } @@ -670,6 +677,27 @@ guestfs_add_drive (guestfs_h *g, const char *filename) } int +guestfs_add_drive_ro (guestfs_h *g, const char *filename) +{ + size_t len = strlen (filename) + 64; + char buf[len]; + + if (strchr (filename, ',') != NULL) { + error (g, _("filename cannot contain ',' (comma) character")); + return -1; + } + + if (access (filename, F_OK) == -1) { + perrorf (g, "%s", filename); + return -1; + } + + snprintf (buf, len, "file=%s,snapshot=on", filename); + + return guestfs_config (g, "-drive", buf); +} + +int guestfs_add_cdrom (guestfs_h *g, const char *filename) { if (strchr (filename, ',') != NULL) { @@ -685,6 +713,46 @@ 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 const char *kernel_name = "vmlinuz." REPO "." host_cpu; +static const char *initrd_name = "initramfs." REPO "." host_cpu ".img"; +static const char *supermin_name = + "initramfs." REPO "." host_cpu ".supermin.img"; +static const char *supermin_hostfiles_name = + "initramfs." REPO "." host_cpu ".supermin.hostfiles"; + int guestfs_launch (guestfs_h *g) { @@ -693,8 +761,6 @@ guestfs_launch (guestfs_h *g) size_t len; int wfd[2], rfd[2]; int tries; - const char *kernel_name = "vmlinuz." REPO "." host_cpu; - const char *initrd_name = "initramfs." REPO "." host_cpu ".img"; char *path, *pelem, *pend; char *kernel = NULL, *initrd = NULL; char unixsock[256]; @@ -711,7 +777,20 @@ guestfs_launch (guestfs_h *g) return -1; } - /* Search g->path for the kernel and initrd. */ + /* Make the temporary directory. */ + if (!g->tmpdir) { + g->tmpdir = safe_strdup (g, dir_template); + if (mkdtemp (g->tmpdir) == NULL) { + perrorf (g, _("%s: cannot create temporary directory"), dir_template); + goto cleanup0; + } + } + + /* 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, ':'); @@ -719,32 +798,31 @@ guestfs_launch (guestfs_h *g) *pend = '\0'; len = pend - pelem; - /* Empty element or "." means cwd. */ + /* Empty element of "." means cwd. */ if (len == 0 || (len == 1 && *pelem == '.')) { if (g->verbose) fprintf (stderr, - "looking for kernel and initrd in current directory\n"); - if (access (kernel_name, F_OK) == 0 && access (initrd_name, F_OK) == 0) { - kernel = safe_strdup (g, kernel_name); - initrd = safe_strdup (g, initrd_name); + "looking for supermin appliance in current directory\n"); + if (dir_contains_files (".", + supermin_name, supermin_hostfiles_name, + "kmod.whitelist", NULL)) { + if (build_supermin_appliance (g, ".", &kernel, &initrd) == -1) + return -1; break; } } - /* Look at /kernel etc. */ + /* Look at /supermin* etc. */ else { - 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); - if (g->verbose) - fprintf (stderr, "looking for %s and %s\n", kernel, initrd); + fprintf (stderr, "looking for supermin appliance in %s\n", pelem); - if (access (kernel, F_OK) == 0 && access (initrd, F_OK) == 0) + if (dir_contains_files (pelem, + supermin_name, supermin_hostfiles_name, + "kmod.whitelist", NULL)) { + if (build_supermin_appliance (g, pelem, &kernel, &initrd) == -1) + return -1; break; - free (kernel); - free (initrd); - kernel = initrd = NULL; + } } pelem = pend + 1; @@ -753,6 +831,46 @@ guestfs_launch (guestfs_h *g) 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; @@ -767,15 +885,7 @@ guestfs_launch (guestfs_h *g) */ memsize = 384; - /* Make the temporary directory containing the socket. */ - if (!g->tmpdir) { - g->tmpdir = safe_strdup (g, dir_template); - if (mkdtemp (g->tmpdir) == NULL) { - perrorf (g, _("%s: cannot create temporary directory"), dir_template); - goto cleanup0; - } - } - + /* Make the vmchannel socket. */ snprintf (unixsock, sizeof unixsock, "%s/sock", g->tmpdir); unlink (unixsock); @@ -820,9 +930,6 @@ guestfs_launch (guestfs_h *g) add_cmdline (g, "-m"); add_cmdline (g, memsize_str); -#if 0 - add_cmdline (g, "-no-kqemu"); /* Avoids a warning. */ -#endif add_cmdline (g, "-no-reboot"); /* Force exit instead of reboot on panic */ add_cmdline (g, "-kernel"); add_cmdline (g, (char *) kernel); @@ -1027,6 +1134,43 @@ guestfs_launch (guestfs_h *g) return -1; } +/* 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; + + 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); + + snprintf (cmd, sizeof cmd, + "PATH='%s':$PATH " + "libguestfs-supermin-helper '%s' %s %s", + path, + path, *kernel, *initrd); + + 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; + } + + return 0; +} + static void finish_wait_ready (guestfs_h *g, void *vp) {