X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fguestfs.c;h=fea8107d18cdb486705b391d83b75aefd3e063d9;hp=05c02f3f42ce71777c2e3d50a55c350ee5cb2d31;hb=bfdc03be234d6d95f18450846433bce4f97e184c;hpb=64a6a828bd318622420cf3018899392fd80c14e7 diff --git a/src/guestfs.c b/src/guestfs.c index 05c02f3..fea8107 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -58,6 +58,15 @@ #include "guestfs.h" #include "guestfs_protocol.h" +#ifdef HAVE_GETTEXT +#include "gettext.h" +#define _(str) dgettext(PACKAGE, (str)) +#define N_(str) dgettext(PACKAGE, (str)) +#else +#define _(str) str +#define N_(str) str +#endif + #define error guestfs_error #define perrorf guestfs_perrorf #define safe_malloc guestfs_safe_malloc @@ -158,8 +167,9 @@ struct guestfs_h int verbose; int autosync; - const char *path; - const char *qemu; + char *path; /* Path to kernel, initrd. */ + char *qemu; /* Qemu binary. */ + char *append; /* Append to kernel command line. */ char *last_error; @@ -220,10 +230,18 @@ guestfs_create (void) g->verbose = str != NULL && strcmp (str, "1") == 0; str = getenv ("LIBGUESTFS_PATH"); - g->path = str != NULL ? str : GUESTFS_DEFAULT_PATH; + g->path = str != NULL ? strdup (str) : strdup (GUESTFS_DEFAULT_PATH); + if (!g->path) goto error; str = getenv ("LIBGUESTFS_QEMU"); - g->qemu = str != NULL ? str : QEMU; + g->qemu = str != NULL ? strdup (str) : strdup (QEMU); + if (!g->qemu) goto error; + + str = getenv ("LIBGUESTFS_APPEND"); + if (str) { + g->append = strdup (str); + if (!g->append) goto error; + } g->main_loop = guestfs_get_default_main_loop (); @@ -248,6 +266,13 @@ guestfs_create (void) fprintf (stderr, "new guestfs handle %p\n", g); return g; + + error: + free (g->path); + free (g->qemu); + free (g->append); + free (g); + return NULL; } void @@ -259,7 +284,7 @@ guestfs_close (guestfs_h *g) if (g->state == NO_HANDLE) { /* Not safe to call 'error' here, so ... */ - fprintf (stderr, "guestfs_close: called twice on the same handle\n"); + fprintf (stderr, _("guestfs_close: called twice on the same handle\n")); return; } @@ -267,8 +292,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. @@ -306,7 +333,12 @@ guestfs_close (guestfs_h *g) } /* release mutex (XXX) */ + free (g->msg_in); + free (g->msg_out); free (g->last_error); + free (g->path); + free (g->qemu); + free (g->append); free (g); } @@ -333,7 +365,7 @@ set_last_error (guestfs_h *g, const char *msg) static void default_error_cb (guestfs_h *g, void *data, const char *msg) { - fprintf (stderr, "libguestfs: error: %s\n", msg); + fprintf (stderr, _("libguestfs: error: %s\n"), msg); } void @@ -386,7 +418,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; } @@ -394,7 +426,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; } @@ -439,8 +471,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; @@ -504,10 +539,12 @@ guestfs_get_autosync (guestfs_h *g) int guestfs_set_path (guestfs_h *g, const char *path) { - if (path == NULL) - g->path = GUESTFS_DEFAULT_PATH; - else - g->path = path; + free (g->path); + g->path = NULL; + + g->path = + path == NULL ? + safe_strdup (g, GUESTFS_DEFAULT_PATH) : safe_strdup (g, path); return 0; } @@ -520,10 +557,10 @@ guestfs_get_path (guestfs_h *g) int guestfs_set_qemu (guestfs_h *g, const char *qemu) { - if (qemu == NULL) - g->qemu = QEMU; - else - g->qemu = qemu; + free (g->qemu); + g->qemu = NULL; + + g->qemu = qemu == NULL ? safe_strdup (g, QEMU) : safe_strdup (g, qemu); return 0; } @@ -533,6 +570,22 @@ guestfs_get_qemu (guestfs_h *g) return g->qemu; } +int +guestfs_set_append (guestfs_h *g, const char *append) +{ + free (g->append); + g->append = NULL; + + g->append = append ? safe_strdup (g, append) : NULL; + return 0; +} + +const char * +guestfs_get_append (guestfs_h *g) +{ + return g->append; +} + /* Add a string to the current command line. */ static void incr_cmdline_size (guestfs_h *g) @@ -552,7 +605,8 @@ static int add_cmdline (guestfs_h *g, const char *str) { if (g->state != CONFIG) { - error (g, "command line cannot be altered after qemu subprocess launched"); + error (g, + _("command line cannot be altered after qemu subprocess launched")); return -1; } @@ -566,7 +620,7 @@ guestfs_config (guestfs_h *g, const char *qemu_param, const char *qemu_value) { if (qemu_param[0] != '-') { - error (g, "guestfs_config: parameter must begin with '-' character"); + error (g, _("guestfs_config: parameter must begin with '-' character")); return -1; } @@ -581,7 +635,7 @@ guestfs_config (guestfs_h *g, strcmp (qemu_param, "-full-screen") == 0 || strcmp (qemu_param, "-std-vga") == 0 || strcmp (qemu_param, "-vnc") == 0) { - error (g, "guestfs_config: parameter '%s' isn't allowed", qemu_param); + error (g, _("guestfs_config: parameter '%s' isn't allowed"), qemu_param); return -1; } @@ -597,11 +651,11 @@ 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) { - error (g, "filename cannot contain ',' (comma) character"); + error (g, _("filename cannot contain ',' (comma) character")); return -1; } @@ -616,10 +670,31 @@ 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) { - error (g, "filename cannot contain ',' (comma) character"); + error (g, _("filename cannot contain ',' (comma) character")); return -1; } @@ -635,7 +710,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,16 +720,15 @@ guestfs_launch (guestfs_h *g) char *kernel = NULL, *initrd = NULL; char unixsock[256]; struct sockaddr_un addr; - struct stat statbuf; /* Configured? */ if (!g->cmdline) { - error (g, "you must call guestfs_add_drive before guestfs_launch"); + error (g, _("you must call guestfs_add_drive before guestfs_launch")); return -1; } if (g->state != CONFIG) { - error (g, "qemu has already been launched"); + error (g, _("qemu has already been launched")); return -1; } @@ -699,50 +774,25 @@ guestfs_launch (guestfs_h *g) free (path); if (kernel == NULL || initrd == NULL) { - error (g, "cannot find %s or %s on LIBGUESTFS_PATH (current path = %s)", + error (g, _("cannot find %s or %s on LIBGUESTFS_PATH (current path = %s)"), kernel_name, initrd_name, g->path); 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) { g->tmpdir = safe_strdup (g, dir_template); if (mkdtemp (g->tmpdir) == NULL) { - perrorf (g, "%s: cannot create temporary directory", dir_template); + perrorf (g, _("%s: cannot create temporary directory"), dir_template); goto cleanup0; } } @@ -773,7 +823,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 *) g->qemu; + g->cmdline[0] = g->qemu; /* Construct the -net channel parameter for qemu. */ snprintf (vmchannel, sizeof vmchannel, @@ -782,9 +832,10 @@ 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%s%s", VMCHANNEL_ADDR, VMCHANNEL_PORT, - g->verbose ? " guestfs_verbose=1" : ""); + g->verbose ? " guestfs_verbose=1" : "", + g->append ? " " : "", g->append ? g->append : ""); snprintf (memsize_str, sizeof memsize_str, "%d", memsize); @@ -793,6 +844,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 +859,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; @@ -843,6 +895,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). */ @@ -918,10 +975,9 @@ guestfs_launch (guestfs_h *g) addr.sun_path[UNIX_PATH_MAX-1] = '\0'; tries = 100; + /* Always sleep at least once to give qemu a small chance to start up. */ + usleep (10000); while (tries > 0) { - /* Always sleep at least once to give qemu a small chance to start up. */ - usleep (10000); - r = connect (g->sock, (struct sockaddr *) &addr, sizeof addr); if ((r == -1 && errno == EINPROGRESS) || r == 0) goto connected; @@ -929,9 +985,10 @@ guestfs_launch (guestfs_h *g) if (errno != ENOENT) perrorf (g, "connect"); tries--; + usleep (100000); } - error (g, "failed to connect to vmchannel socket"); + error (g, _("failed to connect to vmchannel socket")); goto cleanup2; connected: @@ -950,7 +1007,7 @@ guestfs_launch (guestfs_h *g) GUESTFS_HANDLE_READABLE, stdout_event, NULL); if (g->stdout_watch == -1) { - error (g, "could not watch qemu stdout"); + error (g, _("could not watch qemu stdout")); goto cleanup3; } @@ -1009,12 +1066,12 @@ guestfs_wait_ready (guestfs_h *g) if (g->state == READY) return 0; if (g->state == BUSY) { - error (g, "qemu has finished launching already"); + error (g, _("qemu has finished launching already")); return -1; } if (g->state != LAUNCHING) { - error (g, "qemu has not been launched yet"); + error (g, _("qemu has not been launched yet")); return -1; } @@ -1027,7 +1084,7 @@ guestfs_wait_ready (guestfs_h *g) if (r == -1) return -1; if (finished != 1) { - error (g, "guestfs_wait_ready failed, see earlier error messages"); + error (g, _("guestfs_wait_ready failed, see earlier error messages")); return -1; } @@ -1037,7 +1094,7 @@ guestfs_wait_ready (guestfs_h *g) * commands after this function returns. */ if (g->state != READY) { - error (g, "qemu launched and contacted daemon, but state != READY"); + error (g, _("qemu launched and contacted daemon, but state != READY")); return -1; } @@ -1048,7 +1105,7 @@ int guestfs_kill_subprocess (guestfs_h *g) { if (g->state == CONFIG) { - error (g, "no subprocess to kill"); + error (g, _("no subprocess to kill")); return -1; } @@ -1096,7 +1153,8 @@ int guestfs_set_ready (guestfs_h *g) { if (g->state != BUSY) { - error (g, "guestfs_set_ready: called when in state %d != BUSY", g->state); + error (g, _("guestfs_set_ready: called when in state %d != BUSY"), + g->state); return -1; } g->state = READY; @@ -1107,13 +1165,33 @@ int guestfs_set_busy (guestfs_h *g) { if (g->state != READY) { - error (g, "guestfs_set_busy: called when in state %d != READY", g->state); + error (g, _("guestfs_set_busy: called when in state %d != READY"), + g->state); return -1; } g->state = BUSY; 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 +1223,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. @@ -1164,42 +1275,19 @@ stdout_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, #endif if (g->fd[1] != fd) { - error (g, "stdout_event: internal error: %d != %d", g->fd[1], fd); + error (g, _("stdout_event: internal error: %d != %d"), g->fd[1], fd); return; } 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 +1309,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) @@ -1230,7 +1318,7 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, g, g->state, fd, events); if (g->sock != fd) { - error (g, "sock_read_event: internal error: %d != %d", g->sock, fd); + error (g, _("sock_read_event: internal error: %d != %d"), g->sock, fd); return; } @@ -1240,14 +1328,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; } @@ -1260,7 +1348,7 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, xdrmem_create (&xdr, g->msg_in, g->msg_in_size, XDR_DECODE); if (!xdr_uint32_t (&xdr, &len)) { - error (g, "can't decode length word"); + error (g, _("can't decode length word")); goto cleanup; } @@ -1270,10 +1358,10 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, */ if (len == GUESTFS_LAUNCH_FLAG) { if (g->state != LAUNCHING) - error (g, "received magic signature from guestfsd, but in state %d", + error (g, _("received magic signature from guestfsd, but in state %d"), g->state); else if (g->msg_in_size != 4) - error (g, "received magic signature from guestfsd, but msg size is %d", + error (g, _("received magic signature from guestfsd, but msg size is %d"), g->msg_in_size); else { g->state = READY; @@ -1298,7 +1386,7 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, * synchronization. */ if (len > GUESTFS_MESSAGE_MAX) { - error (g, "message length (%u) > maximum possible size (%d)", + error (g, _("message length (%u) > maximum possible size (%d)"), len, GUESTFS_MESSAGE_MAX); goto cleanup; } @@ -1331,7 +1419,7 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, /* Not in the expected state. */ if (g->state != BUSY) - error (g, "state %d != BUSY", g->state); + error (g, _("state %d != BUSY"), g->state); /* Push the message up to the higher layer. */ if (g->reply_cb) @@ -1371,12 +1459,12 @@ sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, g, g->state, fd, events); if (g->sock != fd) { - error (g, "sock_write_event: internal error: %d != %d", g->sock, fd); + error (g, _("sock_write_event: internal error: %d != %d"), g->sock, fd); return; } if (g->state != BUSY) { - error (g, "sock_write_event: state %d != BUSY", g->state); + error (g, _("sock_write_event: state %d != BUSY"), g->state); return; } @@ -1480,7 +1568,7 @@ guestfs__switch_to_sending (guestfs_h *g) { if (g->sock_watch >= 0) { if (g->main_loop->remove_handle (g->main_loop, g, g->sock_watch) == -1) { - error (g, "remove_handle failed"); + error (g, _("remove_handle failed")); g->sock_watch = -1; return -1; } @@ -1491,7 +1579,7 @@ guestfs__switch_to_sending (guestfs_h *g) GUESTFS_HANDLE_WRITABLE, sock_write_event, NULL); if (g->sock_watch == -1) { - error (g, "add_handle failed"); + error (g, _("add_handle failed")); return -1; } @@ -1503,7 +1591,7 @@ guestfs__switch_to_receiving (guestfs_h *g) { if (g->sock_watch >= 0) { if (g->main_loop->remove_handle (g->main_loop, g, g->sock_watch) == -1) { - error (g, "remove_handle failed"); + error (g, _("remove_handle failed")); g->sock_watch = -1; return -1; } @@ -1514,7 +1602,7 @@ guestfs__switch_to_receiving (guestfs_h *g) GUESTFS_HANDLE_READABLE, sock_read_event, NULL); if (g->sock_watch == -1) { - error (g, "add_handle failed"); + error (g, _("add_handle failed")); return -1; } @@ -1541,13 +1629,13 @@ 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); if (g->state != BUSY) { - error (g, "guestfs__send_sync: state %d != BUSY", g->state); + error (g, _("guestfs__send_sync: state %d != BUSY"), g->state); return -1; } @@ -1555,7 +1643,7 @@ guestfs__send_sync (guestfs_h *g, int proc_nr, * free the buffer anyway? */ if (g->msg_out != NULL) { - error (g, "guestfs__send_sync: msg_out should be NULL"); + error (g, _("guestfs__send_sync: msg_out should be NULL")); return -1; } @@ -1577,7 +1665,7 @@ guestfs__send_sync (guestfs_h *g, int proc_nr, hdr.status = GUESTFS_STATUS_OK; if (!xdr_guestfs_message_header (&xdr, &hdr)) { - error (g, "xdr_guestfs_message_header failed"); + error (g, _("xdr_guestfs_message_header failed")); goto cleanup1; } @@ -1586,7 +1674,7 @@ guestfs__send_sync (guestfs_h *g, int proc_nr, */ if (xdrp) { if (!(*xdrp) (&xdr, args)) { - error (g, "dispatch failed to marshal args"); + error (g, _("dispatch failed to marshal args")); goto cleanup1; } } @@ -1612,7 +1700,7 @@ guestfs__send_sync (guestfs_h *g, int proc_nr, if (ml->main_loop_run (ml, g) == -1) goto cleanup1; if (sent != 1) { - error (g, "send failed, see earlier error messages"); + error (g, _("send failed, see earlier error messages")); goto cleanup1; } @@ -1654,7 +1742,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,14 +1808,14 @@ 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; guestfs_main_loop *ml = guestfs_get_main_loop (g); if (g->state != BUSY) { - error (g, "send_file_chunk_sync: state %d != READY", g->state); + error (g, _("send_file_chunk_sync: state %d != READY"), g->state); return -1; } @@ -1731,7 +1823,7 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen) * free the buffer anyway? */ if (g->msg_out != NULL) { - error (g, "guestfs__send_sync: msg_out should be NULL"); + error (g, _("guestfs__send_sync: msg_out should be NULL")); return -1; } @@ -1754,7 +1846,7 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen) chunk.data.data_val = (char *) buf; if (!xdr_guestfs_chunk (&xdr, &chunk)) { - error (g, "xdr_guestfs_chunk failed (buf = %p, buflen = %zu)", + error (g, _("xdr_guestfs_chunk failed (buf = %p, buflen = %zu)"), buf, buflen); xdr_destroy (&xdr); goto cleanup1; @@ -1779,7 +1871,7 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen) if (ml->main_loop_run (ml, g) == -1) goto cleanup1; if (sent != 1) { - error (g, "send file chunk failed, see earlier error messages"); + error (g, _("send file chunk failed, see earlier error messages")); goto cleanup1; } @@ -1830,7 +1922,7 @@ check_for_daemon_cancellation (guestfs_h *g) xdr_destroy (&xdr); if (flag != GUESTFS_CANCEL_FLAG) { - error (g, "check_for_daemon_cancellation: read 0x%x from daemon, expected 0x%x\n", + error (g, _("check_for_daemon_cancellation: read 0x%x from daemon, expected 0x%x\n"), flag, GUESTFS_CANCEL_FLAG); return 0; } @@ -1841,13 +1933,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) { @@ -1867,7 +1960,7 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename) } if (r == -1) { - error (g, "%s: error in chunked encoding", filename); + error (g, _("%s: error in chunked encoding"), filename); return -1; } @@ -1891,7 +1984,7 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename) xdr_destroy (&xdr); if (xwrite (g->sock, fbuf, sizeof fbuf) == -1) { - perrorf (g, "write to daemon socket"); + perrorf (g, _("write to daemon socket")); return -1; } @@ -1938,7 +2031,7 @@ receive_file_cb (guestfs_h *g, void *data, XDR *xdr) memset (&chunk, 0, sizeof chunk); if (!xdr_guestfs_chunk (xdr, &chunk)) { - error (g, "failed to parse file chunk"); + error (g, _("failed to parse file chunk")); free_chunks (ctx); ctx->chunks = NULL; ctx->count = -1; @@ -1955,11 +2048,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; @@ -1969,12 +2063,12 @@ receive_file_data_sync (guestfs_h *g, void **buf, int *len_r) guestfs_set_reply_callback (g, NULL, NULL); if (ctx.count == 0) { - error (g, "receive_file_data_sync: reply callback not called\n"); + error (g, _("receive_file_data_sync: reply callback not called\n")); return -1; } if (ctx.count == -1) { - error (g, "receive_file_data_sync: parse error in reply callback\n"); + error (g, _("receive_file_data_sync: parse error in reply callback\n")); /* callback already freed the chunks */ return -1; } @@ -1988,7 +2082,7 @@ receive_file_data_sync (guestfs_h *g, void **buf, int *len_r) for (i = 0; i < ctx.count; ++i) { if (ctx.chunks[i].cancel) { - error (g, "file receive cancelled by daemon"); + error (g, _("file receive cancelled by daemon")); free_chunks (&ctx); if (buf) free (*buf); if (len_r) *len_r = 0; @@ -2023,7 +2117,7 @@ select_add_handle (guestfs_main_loop *mlv, guestfs_h *g, int fd, int events, struct select_main_loop *ml = (struct select_main_loop *) mlv; if (fd < 0 || fd >= FD_SETSIZE) { - error (g, "fd %d is out of range", fd); + error (g, _("fd %d is out of range"), fd); return -1; } @@ -2031,24 +2125,24 @@ select_add_handle (guestfs_main_loop *mlv, guestfs_h *g, int fd, int events, GUESTFS_HANDLE_WRITABLE | GUESTFS_HANDLE_HANGUP | GUESTFS_HANDLE_ERROR)) != 0) { - error (g, "set of events (0x%x) contains unknown events", events); + error (g, _("set of events (0x%x) contains unknown events"), events); return -1; } if (events == 0) { - error (g, "set of events is empty"); + error (g, _("set of events is empty")); return -1; } if (FD_ISSET (fd, &ml->rset) || FD_ISSET (fd, &ml->wset) || FD_ISSET (fd, &ml->xset)) { - error (g, "fd %d is already registered", fd); + error (g, _("fd %d is already registered"), fd); return -1; } if (cb == NULL) { - error (g, "callback is NULL"); + error (g, _("callback is NULL")); return -1; } @@ -2081,14 +2175,14 @@ select_remove_handle (guestfs_main_loop *mlv, guestfs_h *g, int fd) struct select_main_loop *ml = (struct select_main_loop *) mlv; if (fd < 0 || fd >= FD_SETSIZE) { - error (g, "fd %d is out of range", fd); + error (g, _("fd %d is out of range"), fd); return -1; } if (!FD_ISSET (fd, &ml->rset) && !FD_ISSET (fd, &ml->wset) && !FD_ISSET (fd, &ml->xset)) { - error (g, "fd %d was not registered", fd); + error (g, _("fd %d was not registered"), fd); return -1; } @@ -2137,7 +2231,7 @@ select_main_loop_run (guestfs_main_loop *mlv, guestfs_h *g) fd_set rset2, wset2, xset2; if (ml->is_running) { - error (g, "select_main_loop_run: this cannot be called recursively"); + error (g, _("select_main_loop_run: this cannot be called recursively")); return -1; } @@ -2152,6 +2246,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;