+ }
+ return 0;
+}
+
+/* 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.
+ */
+static void
+stdout_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
+ int watch, int fd, int events)
+{
+ char buf[4096];
+ int n;
+
+#if 0
+ if (g->verbose)
+ fprintf (stderr,
+ "stdout_event: %p g->state = %d, fd = %d, events = 0x%x\n",
+ g, g->state, fd, events);
+#endif
+
+ if (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. */
+ child_cleanup (g);
+ return;
+ }
+
+ if (n == -1) {
+ if (errno != EINTR && errno != EAGAIN)
+ perrorf (g, "read");
+ return;
+ }
+
+ /* In verbose mode, copy all log messages to stderr. */
+ if (g->verbose)
+ write (2, buf, n);
+
+ /* It's an actual log message, send it upwards if anyone is listening. */
+ if (g->log_message_cb)
+ g->log_message_cb (g, g->log_message_cb_data, buf, n);
+}
+
+/* The function is called whenever we can read something on the
+ * guestfsd (daemon inside the guest) communication socket.
+ */
+static void
+sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
+ int watch, int fd, int events)
+{
+ XDR xdr;
+ u_int32_t len;
+ int n;
+
+ if (g->verbose)
+ fprintf (stderr,
+ "sock_read_event: %p g->state = %d, fd = %d, events = 0x%x\n",
+ g, g->state, fd, events);
+
+ if (g->sock != fd) {
+ error (g, _("sock_read_event: internal error: %d != %d"), g->sock, fd);
+ return;
+ }
+
+ if (g->msg_in_size <= g->msg_in_allocated) {
+ g->msg_in_allocated += 4096;
+ g->msg_in = safe_realloc (g, g->msg_in, g->msg_in_allocated);
+ }
+ n = read (g->sock, g->msg_in + g->msg_in_size,
+ g->msg_in_allocated - g->msg_in_size);
+ if (n == 0) {
+ /* Disconnected. */
+ child_cleanup (g);
+ return;
+ }
+
+ if (n == -1) {
+ if (errno != EINTR && errno != EAGAIN)
+ perrorf (g, "read");
+ return;
+ }
+
+ g->msg_in_size += n;
+
+ /* Have we got enough of a message to be able to process it yet? */
+ again:
+ if (g->msg_in_size < 4) return;
+
+ 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"));
+ goto cleanup;
+ }
+
+ /* Length is normally the length of the message, but when guestfsd
+ * starts up it sends a "magic" value (longer than any possible
+ * message). Check for this.
+ */
+ if (len == GUESTFS_LAUNCH_FLAG) {
+ if (g->state != LAUNCHING)
+ 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"),
+ g->msg_in_size);
+ else {
+ g->state = READY;
+ if (g->launch_done_cb)
+ g->launch_done_cb (g, g->launch_done_cb_data);
+ }
+
+ goto cleanup;
+ }
+
+ /* This can happen if a cancellation happens right at the end
+ * of us sending a FileIn parameter to the daemon. Discard. The
+ * daemon should send us an error message next.
+ */
+ if (len == GUESTFS_CANCEL_FLAG) {
+ g->msg_in_size -= 4;
+ memmove (g->msg_in, g->msg_in+4, g->msg_in_size);
+ goto again;
+ }
+
+ /* If this happens, it's pretty bad and we've probably lost
+ * synchronization.
+ */
+ if (len > GUESTFS_MESSAGE_MAX) {
+ error (g, _("message length (%u) > maximum possible size (%d)"),
+ len, GUESTFS_MESSAGE_MAX);
+ goto cleanup;
+ }
+
+ if (g->msg_in_size-4 < len) return; /* Need more of this message. */
+
+ /* Got the full message, begin processing it. */
+#if 0
+ if (g->verbose) {
+ int i, j;
+
+ for (i = 0; i < g->msg_in_size; i += 16) {
+ printf ("%04x: ", i);
+ for (j = i; j < MIN (i+16, g->msg_in_size); ++j)
+ printf ("%02x ", (unsigned char) g->msg_in[j]);
+ for (; j < i+16; ++j)
+ printf (" ");
+ printf ("|");
+ for (j = i; j < MIN (i+16, g->msg_in_size); ++j)
+ if (isprint (g->msg_in[j]))
+ printf ("%c", g->msg_in[j]);
+ else
+ printf (".");
+ for (; j < i+16; ++j)
+ printf (" ");
+ printf ("|\n");
+ }
+ }
+#endif
+
+ /* Not in the expected state. */
+ if (g->state != BUSY)
+ error (g, _("state %d != BUSY"), g->state);
+
+ /* Push the message up to the higher layer. */
+ if (g->reply_cb)
+ g->reply_cb (g, g->reply_cb_data, &xdr);
+ else
+ /* This message (probably) should never be printed. */
+ fprintf (stderr, "libguesfs: sock_read_event: !!! dropped message !!!\n");
+
+ g->msg_in_size -= len + 4;
+ memmove (g->msg_in, g->msg_in+len+4, g->msg_in_size);
+ if (g->msg_in_size > 0) goto again;
+
+ cleanup:
+ /* Free the message buffer if it's grown excessively large. */
+ if (g->msg_in_allocated > 65536) {
+ free (g->msg_in);
+ g->msg_in = NULL;
+ g->msg_in_size = g->msg_in_allocated = 0;
+ } else
+ g->msg_in_size = 0;
+
+ xdr_destroy (&xdr);
+}
+
+/* The function is called whenever we can write something on the
+ * guestfsd (daemon inside the guest) communication socket.
+ */
+static void
+sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
+ int watch, int fd, int events)
+{
+ int n, err;
+
+ if (g->verbose)
+ fprintf (stderr,
+ "sock_write_event: %p g->state = %d, fd = %d, events = 0x%x\n",
+ g, g->state, fd, events);
+
+ if (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);
+ return;
+ }
+
+ if (g->verbose)
+ fprintf (stderr, "sock_write_event: writing %d bytes ...\n",
+ g->msg_out_size - g->msg_out_pos);
+
+ n = write (g->sock, g->msg_out + g->msg_out_pos,
+ g->msg_out_size - g->msg_out_pos);
+ if (n == -1) {
+ err = errno;
+ if (err != EAGAIN)
+ perrorf (g, "write");
+ if (err == EPIPE) /* Disconnected from guest (RHBZ#508713). */
+ child_cleanup (g);
+ return;