X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fguestfs.c;h=3492c624125aa840264f12b86c376a9fa76e6d97;hb=8e570870f577ff0c3db074f88924633b559af5d4;hp=0c0a37fec8d3fc121767c8effb2f1da9b6240dc4;hpb=99bd425a0a8fb02c27e0c22b32dafa804773a7b1;p=libguestfs.git diff --git a/src/guestfs.c b/src/guestfs.c index 0c0a37f..3492c62 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -19,7 +19,7 @@ #include #define _BSD_SOURCE /* for mkdtemp, usleep */ -#define _GNU_SOURCE /* for vasprintf, GNU strerror_r */ +#define _GNU_SOURCE /* for vasprintf, GNU strerror_r, strchrnul */ #include #include @@ -116,6 +116,9 @@ struct guestfs_h int cmdline_size; int verbose; + int autosync; + + const char *path; /* Callbacks. */ guestfs_abort_cb abort_cb; @@ -177,6 +180,10 @@ guestfs_create (void) str = getenv ("LIBGUESTFS_DEBUG"); g->verbose = str != NULL && strcmp (str, "1") == 0; + str = getenv ("LIBGUESTFS_PATH"); + g->path = str != NULL ? str : GUESTFS_DEFAULT_PATH; + /* XXX We should probably make QEMU configurable as well. */ + /* Start with large serial numbers so they are easy to spot * inside the protocol. */ @@ -216,6 +223,10 @@ guestfs_close (guestfs_h *g) if (g->verbose) fprintf (stderr, "closing guestfs handle %p (state %d)\n", g, g->state); + /* Try to sync if autosync flag is set. */ + if (g->autosync && g->state == READY) + guestfs_sync (g); + /* Remove any handlers that might be called back before we kill the * subprocess. */ @@ -378,6 +389,33 @@ guestfs_get_verbose (guestfs_h *g) return g->verbose; } +void +guestfs_set_autosync (guestfs_h *g, int a) +{ + g->autosync = a; +} + +int +guestfs_get_autosync (guestfs_h *g) +{ + return g->autosync; +} + +void +guestfs_set_path (guestfs_h *g, const char *path) +{ + if (path == NULL) + g->path = GUESTFS_DEFAULT_PATH; + else + g->path = path; +} + +const char * +guestfs_get_path (guestfs_h *g) +{ + return g->path; +} + /* Add a string to the current command line. */ static void incr_cmdline_size (guestfs_h *g) @@ -450,6 +488,11 @@ guestfs_add_drive (guestfs_h *g, const char *filename) return -1; } + if (access (filename, F_OK) == -1) { + perrorf (g, "%s", filename); + return -1; + } + snprintf (buf, len, "file=%s", filename); return guestfs_config (g, "-drive", buf); @@ -463,6 +506,11 @@ guestfs_add_cdrom (guestfs_h *g, const char *filename) return -1; } + if (access (filename, F_OK) == -1) { + perrorf (g, "%s", filename); + return -1; + } + return guestfs_config (g, "-cdrom", filename); } @@ -470,19 +518,16 @@ int guestfs_launch (guestfs_h *g) { static const char *dir_template = "/tmp/libguestfsXXXXXX"; - int r, i; + int r, i, len, pmore; int wfd[2], rfd[2]; int tries; - /*const char *qemu = QEMU;*/ /* XXX */ - const char *qemu = "/usr/bin/qemu-system-x86_64"; - const char *kernel = "vmlinuz.fedora-10.x86_64"; - const char *initrd = "initramfs.fedora-10.x86_64.img"; + 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]; struct sockaddr_un addr; - /* XXX Choose which qemu to run. */ - /* XXX Choose initrd, etc. */ - /* Configured? */ if (!g->cmdline) { error (g, "you must call guestfs_add_drive before guestfs_launch"); @@ -494,12 +539,59 @@ guestfs_launch (guestfs_h *g) return -1; } + /* 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 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); + break; + } + } + /* Look at /kernel 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); + + if (access (kernel, F_OK) == 0 && access (initrd, F_OK) == 0) + break; + free (kernel); + free (initrd); + kernel = initrd = NULL; + } + + 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; + } + /* 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); - return -1; + goto cleanup0; } } @@ -508,7 +600,7 @@ guestfs_launch (guestfs_h *g) if (pipe (wfd) == -1 || pipe (rfd) == -1) { perrorf (g, "pipe"); - return -1; + goto cleanup0; } r = fork (); @@ -518,7 +610,7 @@ guestfs_launch (guestfs_h *g) close (wfd[1]); close (rfd[0]); close (rfd[1]); - return -1; + goto cleanup0; } if (r == 0) { /* Child (qemu). */ @@ -528,7 +620,7 @@ guestfs_launch (guestfs_h *g) /* Set up the full command line. Do this in the subprocess so we * don't need to worry about cleaning up. */ - g->cmdline[0] = (char *) qemu; + g->cmdline[0] = (char *) QEMU; /* Construct the -net channel parameter for qemu. */ snprintf (vmchannel, sizeof vmchannel, @@ -561,7 +653,7 @@ guestfs_launch (guestfs_h *g) g->cmdline[g->cmdline_size-1] = NULL; if (g->verbose) { - fprintf (stderr, "%s", qemu); + fprintf (stderr, "%s", QEMU); for (i = 0; g->cmdline[i]; ++i) fprintf (stderr, " %s", g->cmdline[i]); fprintf (stderr, "\n"); @@ -584,8 +676,8 @@ guestfs_launch (guestfs_h *g) setpgid (0, 0); #endif - execv (qemu, g->cmdline); /* Run qemu. */ - perror (qemu); + execv (QEMU, g->cmdline); /* Run qemu. */ + perror (QEMU); _exit (1); } @@ -702,6 +794,10 @@ guestfs_launch (guestfs_h *g) g->start_t = 0; g->stdout_watch = -1; g->sock_watch = -1; + + cleanup0: + free (kernel); + free (initrd); return -1; } @@ -762,7 +858,7 @@ guestfs_kill_subprocess (guestfs_h *g) } if (g->verbose) - fprintf (stderr, "sending SIGTERM to process group %d\n", g->pid); + fprintf (stderr, "sending SIGTERM to process %d\n", g->pid); kill (g->pid, SIGTERM);