X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fguestfs.c;h=be7b0c794e6117b904419d31b2bf49f55e1c145a;hp=05c02f3f42ce71777c2e3d50a55c350ee5cb2d31;hb=33377fc61d4356a0e83cf7ef39d545842647481c;hpb=64a6a828bd318622420cf3018899392fd80c14e7 diff --git a/src/guestfs.c b/src/guestfs.c index 05c02f3..be7b0c7 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -267,8 +267,10 @@ guestfs_close (guestfs_h *g) 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) + if (g->autosync && g->state == READY) { + guestfs_umount_all (g); guestfs_sync (g); + } /* Remove any handlers that might be called back before we kill the * subprocess. @@ -439,8 +441,11 @@ xread (int fd, void *buf, size_t len) while (len > 0) { r = read (fd, buf, len); - if (r == -1) + if (r == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; return -1; + } buf += r; len -= r; @@ -597,7 +602,7 @@ guestfs_config (guestfs_h *g, int guestfs_add_drive (guestfs_h *g, const char *filename) { - int len = strlen (filename) + 64; + size_t len = strlen (filename) + 64; char buf[len]; if (strchr (filename, ',') != NULL) { @@ -635,7 +640,8 @@ int guestfs_launch (guestfs_h *g) { static const char *dir_template = "/tmp/libguestfsXXXXXX"; - int r, i, len, pmore, memsize; + int r, i, pmore, memsize; + size_t len; int wfd[2], rfd[2]; int tries; const char *kernel_name = "vmlinuz." REPO "." host_cpu; @@ -644,7 +650,6 @@ guestfs_launch (guestfs_h *g) char *kernel = NULL, *initrd = NULL; char unixsock[256]; struct sockaddr_un addr; - struct stat statbuf; /* Configured? */ if (!g->cmdline) { @@ -704,39 +709,14 @@ guestfs_launch (guestfs_h *g) goto cleanup0; } - /* Choose a suitable memory size (in MB). This is more art - * than science, but you can help by doing - * ./configure --enable-debug-command - * and then running: - * debug sh free - * debug mem '' - * and seeing how much free memory is left for particular - * configurations. - * - * It's also helpful to report both the compressed and uncompressed - * size of the initramfs (ls -lh initramfs*.img; du -sh initramfs). - * - * XXX KVM virtio balloon driver? + /* Choose a suitable memory size. Previously we tried to choose + * a minimal memory size, but this isn't really necessary since + * recent QEMU and KVM don't do anything nasty like locking + * memory into core any more. This we can safely choose a + * large, generous amount of memory, and it'll just get swapped + * on smaller systems. */ - if (stat (initrd, &statbuf) != -1) { - /* Approximate size of the initramfs after it is decompressed - * in kernel memory. The compression factor is ~2.5-3. - */ - memsize = 3 * statbuf.st_size / 1024 / 1024; - - /* Approximate size used by the kernel. */ - memsize += 10; - - /* Want to give userspace some room, so: */ - memsize += 128; - -#if SIZEOF_LONG == 8 - /* On 64 bit, assume some overhead. */ - memsize += 64; -#endif - } else - memsize = 512; - + memsize = 384; /* Make the temporary directory containing the socket. */ if (!g->tmpdir) { @@ -782,7 +762,7 @@ guestfs_launch (guestfs_h *g) /* Linux kernel command line. */ snprintf (append, sizeof append, - "console=ttyS0 guestfs=%s:%d%s", + "panic=1 console=ttyS0 guestfs=%s:%d%s", VMCHANNEL_ADDR, VMCHANNEL_PORT, g->verbose ? " guestfs_verbose=1" : ""); @@ -793,6 +773,7 @@ guestfs_launch (guestfs_h *g) #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); add_cmdline (g, "-initrd"); @@ -807,7 +788,7 @@ guestfs_launch (guestfs_h *g) add_cmdline (g, "-net"); add_cmdline (g, "user,vlan=0"); add_cmdline (g, "-net"); - add_cmdline (g, "nic,model=rtl8139,vlan=0"); + add_cmdline (g, "nic,model=virtio,vlan=0"); incr_cmdline_size (g); g->cmdline[g->cmdline_size-1] = NULL; @@ -1114,6 +1095,25 @@ guestfs_set_busy (guestfs_h *g) return 0; } +int +guestfs_end_busy (guestfs_h *g) +{ + switch (g->state) + { + case BUSY: + g->state = READY; + break; + case CONFIG: + case READY: + break; + case LAUNCHING: + case NO_HANDLE: + error (g, "guestfs_end_busy: called when in state %d", g->state); + return -1; + } + return 0; +} + /* Structure-freeing functions. These rely on the fact that the * structure format is identical to the XDR format. See note in * generator.ml. @@ -1145,6 +1145,39 @@ guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *x) free (x); } +/* We don't know if stdout_event or sock_read_event will be the + * first to receive EOF if the qemu process dies. This function + * has the common cleanup code for both. + */ +static void +child_cleanup (guestfs_h *g) +{ + if (g->verbose) + fprintf (stderr, "stdout_event: %p: child process died\n", g); + /*kill (g->pid, SIGTERM);*/ + if (g->recoverypid > 0) kill (g->recoverypid, 9); + waitpid (g->pid, NULL, 0); + if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0); + if (g->stdout_watch >= 0) + g->main_loop->remove_handle (g->main_loop, g, g->stdout_watch); + if (g->sock_watch >= 0) + g->main_loop->remove_handle (g->main_loop, g, g->sock_watch); + close (g->fd[0]); + close (g->fd[1]); + close (g->sock); + g->fd[0] = -1; + g->fd[1] = -1; + g->sock = -1; + g->pid = 0; + g->recoverypid = 0; + g->start_t = 0; + g->stdout_watch = -1; + g->sock_watch = -1; + g->state = CONFIG; + if (g->subprocess_quit_cb) + g->subprocess_quit_cb (g, g->subprocess_quit_cb_data); +} + /* This function is called whenever qemu prints something on stdout. * Qemu's stdout is also connected to the guest's serial console, so * we see kernel messages here too. @@ -1171,35 +1204,12 @@ stdout_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, n = read (fd, buf, sizeof buf); if (n == 0) { /* Hopefully this indicates the qemu child process has died. */ - if (g->verbose) - fprintf (stderr, "stdout_event: %p: child process died\n", g); - /*kill (g->pid, SIGTERM);*/ - if (g->recoverypid > 0) kill (g->recoverypid, 9); - waitpid (g->pid, NULL, 0); - if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0); - if (g->stdout_watch >= 0) - g->main_loop->remove_handle (g->main_loop, g, g->stdout_watch); - if (g->sock_watch >= 0) - g->main_loop->remove_handle (g->main_loop, g, g->sock_watch); - close (g->fd[0]); - close (g->fd[1]); - close (g->sock); - g->fd[0] = -1; - g->fd[1] = -1; - g->sock = -1; - g->pid = 0; - g->recoverypid = 0; - g->start_t = 0; - g->stdout_watch = -1; - g->sock_watch = -1; - g->state = CONFIG; - if (g->subprocess_quit_cb) - g->subprocess_quit_cb (g, g->subprocess_quit_cb_data); + child_cleanup (g); return; } if (n == -1) { - if (errno != EAGAIN) + if (errno != EINTR && errno != EAGAIN) perrorf (g, "read"); return; } @@ -1221,7 +1231,7 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, int watch, int fd, int events) { XDR xdr; - unsigned len; + u_int32_t len; int n; if (g->verbose) @@ -1240,14 +1250,14 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, } n = read (g->sock, g->msg_in + g->msg_in_size, g->msg_in_allocated - g->msg_in_size); - if (n == 0) - /* Disconnected? Ignore it because stdout_watch will get called - * and will do the cleanup. - */ + if (n == 0) { + /* Disconnected. */ + child_cleanup (g); return; + } if (n == -1) { - if (errno != EAGAIN) + if (errno != EINTR && errno != EAGAIN) perrorf (g, "read"); return; } @@ -1541,7 +1551,7 @@ guestfs__send_sync (guestfs_h *g, int proc_nr, { struct guestfs_message_header hdr; XDR xdr; - unsigned len; + u_int32_t len; int serial = g->msg_next_serial++; int sent; guestfs_main_loop *ml = guestfs_get_main_loop (g); @@ -1654,7 +1664,11 @@ guestfs__send_file_sync (guestfs_h *g, const char *filename) } /* Send file in chunked encoding. */ - while (!cancel && (r = read (fd, buf, sizeof buf)) > 0) { + while (!cancel) { + r = read (fd, buf, sizeof buf); + if (r == -1 && (errno == EINTR || errno == EAGAIN)) + continue; + if (r <= 0) break; err = send_file_data_sync (g, buf, r); if (err < 0) { if (err == -2) /* daemon sent cancellation */ @@ -1716,7 +1730,7 @@ static int check_for_daemon_cancellation (guestfs_h *g); static int send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen) { - unsigned len; + u_int32_t len; int sent; guestfs_chunk chunk; XDR xdr; @@ -1841,13 +1855,14 @@ check_for_daemon_cancellation (guestfs_h *g) /* Synchronously receive a file. */ /* Returns -1 = error, 0 = EOF, 1 = more data */ -static int receive_file_data_sync (guestfs_h *g, void **buf, int *len); +static int receive_file_data_sync (guestfs_h *g, void **buf, size_t *len); int guestfs__receive_file_sync (guestfs_h *g, const char *filename) { void *buf; - int fd, r, len; + int fd, r; + size_t len; fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666); if (fd == -1) { @@ -1955,11 +1970,12 @@ receive_file_cb (guestfs_h *g, void *data, XDR *xdr) /* Receive a chunk of file data. */ /* Returns -1 = error, 0 = EOF, 1 = more data */ static int -receive_file_data_sync (guestfs_h *g, void **buf, int *len_r) +receive_file_data_sync (guestfs_h *g, void **buf, size_t *len_r) { struct receive_file_ctx ctx; guestfs_main_loop *ml = guestfs_get_main_loop (g); - int i, len; + int i; + size_t len; ctx.count = 0; ctx.chunks = NULL;