X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fguestfs.c;h=612ac000c2ec2a9e6ceb257630f693a4cd890760;hb=f0a5cd69f92f734b94e2361a939e4a1eb01dad9c;hp=c1fb01d117a9a5e3fba68d5f8e529a9a3b326b54;hpb=bb349b05333aa5bf87a3882f15458d8f7341d807;p=libguestfs.git diff --git a/src/guestfs.c b/src/guestfs.c index c1fb01d..612ac00 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -308,6 +308,8 @@ guestfs_close (guestfs_h *g) } /* release mutex (XXX) */ + free (g->msg_in); + free (g->msg_out); free (g->last_error); free (g); } @@ -602,7 +604,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) { @@ -640,7 +642,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; @@ -649,7 +652,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) { @@ -709,39 +711,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) { @@ -787,7 +764,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" : ""); @@ -798,6 +775,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"); @@ -848,6 +826,11 @@ guestfs_launch (guestfs_h *g) /* Parent (library). */ g->pid = r; + free (kernel); + kernel = NULL; + free (initrd); + initrd = NULL; + /* Fork the recovery process off which will kill qemu if the parent * process fails to do so (eg. if the parent segfaults). */ @@ -1119,6 +1102,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. @@ -1150,6 +1152,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. @@ -1176,30 +1211,7 @@ 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; } @@ -1226,7 +1238,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) @@ -1245,11 +1257,11 @@ 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 != EINTR && errno != EAGAIN) @@ -1546,7 +1558,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); @@ -1725,7 +1737,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; @@ -1850,13 +1862,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) { @@ -1964,11 +1977,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; @@ -2161,6 +2175,8 @@ select_main_loop_run (guestfs_main_loop *mlv, guestfs_h *g) xset2 = ml->xset; r = select (ml->max_fd+1, &rset2, &wset2, &xset2, NULL); if (r == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; perrorf (g, "select"); ml->is_running = 0; return -1;