- 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? Ignore it because stdout_watch will get called
- * and will do the cleanup.
- */
- return;
-
- if (n == -1) {
- if (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 (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");
- }
- }
-
- /* 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);
-
- 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;
-
- 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) {
- if (errno != EAGAIN)
- perrorf (g, "write");
- return;
- }
-
- if (g->verbose)
- fprintf (stderr, "sock_write_event: wrote %d bytes\n", n);
-
- g->msg_out_pos += n;
-
- /* More to write? */
- if (g->msg_out_pos < g->msg_out_size)
- return;
-
- if (g->verbose)
- fprintf (stderr, "sock_write_event: done writing, calling send_cb\n");
-
- free (g->msg_out);
- g->msg_out = NULL;
- g->msg_out_pos = g->msg_out_size = 0;
-
- /* Done writing, call the higher layer. */
- if (g->send_cb)
- g->send_cb (g, g->send_cb_data);
-}
-
-void
-guestfs_set_send_callback (guestfs_h *g,
- guestfs_send_cb cb, void *opaque)
-{
- g->send_cb = cb;
- g->send_cb_data = opaque;
-}
-
-void
-guestfs_set_reply_callback (guestfs_h *g,
- guestfs_reply_cb cb, void *opaque)
-{
- g->reply_cb = cb;
- g->reply_cb_data = opaque;
-}
-
-void
-guestfs_set_log_message_callback (guestfs_h *g,
- guestfs_log_message_cb cb, void *opaque)
-{
- g->log_message_cb = cb;
- g->log_message_cb_data = opaque;
-}
-
-void
-guestfs_set_subprocess_quit_callback (guestfs_h *g,
- guestfs_subprocess_quit_cb cb, void *opaque)
-{
- g->subprocess_quit_cb = cb;
- g->subprocess_quit_cb_data = opaque;
-}
-
-void
-guestfs_set_launch_done_callback (guestfs_h *g,
- guestfs_launch_done_cb cb, void *opaque)
-{
- g->launch_done_cb = cb;
- g->launch_done_cb_data = opaque;
-}
-
-/* Access to the handle's main loop and the default main loop. */
-void
-guestfs_set_main_loop (guestfs_h *g, guestfs_main_loop *main_loop)
-{
- g->main_loop = main_loop;
-}
-
-guestfs_main_loop *
-guestfs_get_main_loop (guestfs_h *g)
-{
- return g->main_loop;
-}
-
-guestfs_main_loop *
-guestfs_get_default_main_loop (void)
-{
- return (guestfs_main_loop *) &default_main_loop;
-}
-
-/* Change the daemon socket handler so that we are now writing.
- * This sets the handle to sock_write_event.
- */
-int
-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");
- g->sock_watch = -1;
- return -1;
- }
- }
-
- g->sock_watch =
- g->main_loop->add_handle (g->main_loop, g, g->sock,
- GUESTFS_HANDLE_WRITABLE,
- sock_write_event, NULL);
- if (g->sock_watch == -1) {
- error (g, "add_handle failed");
- return -1;
- }
-
- return 0;
-}
-
-int
-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");
- g->sock_watch = -1;
- return -1;
- }
- }
-
- g->sock_watch =
- g->main_loop->add_handle (g->main_loop, g, g->sock,
- GUESTFS_HANDLE_READABLE,
- sock_read_event, NULL);
- if (g->sock_watch == -1) {
- error (g, "add_handle failed");
- return -1;
- }
-
- return 0;
-}
-
-/* Dispatch a call (len + header + args) to the remote daemon,
- * synchronously (ie. using the guest's main loop to wait until
- * it has been sent). Returns -1 for error, or the serial
- * number of the message.
- */
-static void
-send_cb (guestfs_h *g, void *data)
-{
- guestfs_main_loop *ml = guestfs_get_main_loop (g);
-
- *((int *)data) = 1;
- ml->main_loop_quit (ml, g);
-}
-
-int
-guestfs__send_sync (guestfs_h *g, int proc_nr,
- xdrproc_t xdrp, char *args)
-{
- char buffer[GUESTFS_MESSAGE_MAX];
- struct guestfs_message_header hdr;
- XDR xdr;
- unsigned 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);
- return -1;
- }
-
- /* Serialize the header. */
- hdr.prog = GUESTFS_PROGRAM;
- hdr.vers = GUESTFS_PROTOCOL_VERSION;
- hdr.proc = proc_nr;
- hdr.direction = GUESTFS_DIRECTION_CALL;
- hdr.serial = serial;
- hdr.status = GUESTFS_STATUS_OK;
-
- xdrmem_create (&xdr, buffer, sizeof buffer, XDR_ENCODE);
- if (!xdr_guestfs_message_header (&xdr, &hdr)) {
- error (g, "xdr_guestfs_message_header failed");
- return -1;
- }
-
- /* Serialize the args. If any, because some message types
- * have no parameters.
- */
- if (xdrp) {
- if (!(*xdrp) (&xdr, args)) {
- error (g, "dispatch failed to marshal args");
- return -1;
- }
- }
-
- len = xdr_getpos (&xdr);
- xdr_destroy (&xdr);
-
- /* Allocate the outgoing message buffer. */
- g->msg_out = safe_malloc (g, len + 4);
-
- g->msg_out_size = len + 4;
- g->msg_out_pos = 0;
-
- xdrmem_create (&xdr, g->msg_out, 4, XDR_ENCODE);
- xdr_uint32_t (&xdr, &len);
-
- memcpy (g->msg_out + 4, buffer, len);
-
- if (guestfs__switch_to_sending (g) == -1)
- goto cleanup1;
-
- sent = 0;
- guestfs_set_send_callback (g, send_cb, &sent);
- if (ml->main_loop_run (ml, g) == -1)
- goto cleanup1;
- if (sent != 1) {
- error (g, "send failed, see earlier error messages");
- goto cleanup1;
- }
-
- return serial;
-
- cleanup1:
- free (g->msg_out);
- g->msg_out = NULL;
- g->msg_out_size = 0;
- return -1;
-}
-
-static int cancel = 0; /* XXX Implement file cancellation. */
-static int send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t len);
-static int send_file_data_sync (guestfs_h *g, const char *buf, size_t len);
-static int send_file_cancellation_sync (guestfs_h *g);
-static int send_file_complete_sync (guestfs_h *g);
-
-/* Synchronously send a file.
- * Returns:
- * 0 OK
- * -1 error
- * -2 daemon cancelled (we must read the error message)
- */
-int
-guestfs__send_file_sync (guestfs_h *g, const char *filename)
-{
- char buf[GUESTFS_MAX_CHUNK_SIZE];
- int fd, r, err;
-
- fd = open (filename, O_RDONLY);
- if (fd == -1) {
- perrorf (g, "open: %s", filename);
- send_file_cancellation_sync (g);
- /* Daemon sees cancellation and won't reply, so caller can
- * just return here.
- */
- return -1;
- }
-
- /* Send file in chunked encoding. */
- while (!cancel && (r = read (fd, buf, sizeof buf)) > 0) {
- err = send_file_data_sync (g, buf, r);
- if (err < 0) {
- if (err == -2) /* daemon sent cancellation */
- send_file_cancellation_sync (g);
- return err;
- }
- }
-
- if (cancel) { /* cancel from either end */
- send_file_cancellation_sync (g);
- return -1;
- }
-
- if (r == -1) {
- perrorf (g, "read: %s", filename);
- send_file_cancellation_sync (g);
- return -1;
- }
-
- /* End of file, but before we send that, we need to close
- * the file and check for errors.
- */
- if (close (fd) == -1) {
- perrorf (g, "close: %s", filename);
- send_file_cancellation_sync (g);
- return -1;
- }
-
- return send_file_complete_sync (g);
-}
-
-/* Send a chunk of file data. */
-static int
-send_file_data_sync (guestfs_h *g, const char *buf, size_t len)
-{
- return send_file_chunk_sync (g, 0, buf, len);
-}
-
-/* Send a cancellation message. */
-static int
-send_file_cancellation_sync (guestfs_h *g)
-{
- return send_file_chunk_sync (g, 1, NULL, 0);
-}
-
-/* Send a file complete chunk. */
-static int
-send_file_complete_sync (guestfs_h *g)
-{
- char buf[1];
- return send_file_chunk_sync (g, 0, buf, 0);
-}
-
-/* Send a chunk, cancellation or end of file, synchronously (ie. wait
- * for it to go).
- */
-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 len)