protocol: Enhance "unexpected end of file when reading from daemon" error.
[libguestfs.git] / src / proto.c
index cda731e..d8b1048 100644 (file)
@@ -251,8 +251,15 @@ read_log_message_or_eof (guestfs_h *g, int fd, int error_if_eof)
   /* QEMU's console emulates a 16550A serial port.  The real 16550A
    * device has a small FIFO buffer (16 bytes) which means here we see
    * lots of small reads of 1-16 bytes in length, usually single
-   * bytes.
+   * bytes.  Sleeping here for a very brief period groups reads
+   * together (so we usually get a few lines of output at once) and
+   * improves overall throughput, as well as making the event
+   * interface a bit more sane for callers.  With a virtio-serial
+   * based console (not yet implemented) we may be able to remove
+   * this.  XXX
    */
+  usleep (1000);
+
   n = read (fd, buf, sizeof buf);
   if (n == 0) {
     /* Hopefully this indicates the qemu child process has died. */
@@ -278,6 +285,24 @@ read_log_message_or_eof (guestfs_h *g, int fd, int error_if_eof)
   /* It's an actual log message, send it upwards if anyone is listening. */
   guestfs___call_callbacks_message (g, GUESTFS_EVENT_APPLIANCE, buf, n);
 
+  /* This is a gross hack.  See the comment above
+   * guestfs___launch_send_progress.
+   */
+  if (g->state == LAUNCHING) {
+    const char *sentinel;
+    size_t len;
+
+    sentinel = "Linux version"; /* kernel up */
+    len = strlen (sentinel);
+    if (memmem (buf, n, sentinel, len) != NULL)
+      guestfs___launch_send_progress (g, 6);
+
+    sentinel = "Starting /init script"; /* /init running */
+    len = strlen (sentinel);
+    if (memmem (buf, n, sentinel, len) != NULL)
+      guestfs___launch_send_progress (g, 9);
+  }
+
   return 0;
 }
 
@@ -326,8 +351,10 @@ really_read_from_socket (guestfs_h *g, int sock, char *buf, size_t n)
   return (ssize_t) got;
 }
 
-static void
-send_progress_message (guestfs_h *g, const guestfs_progress *message)
+/* Convenient wrapper to generate a progress message callback. */
+void
+guestfs___progress_message_callback (guestfs_h *g,
+                                     const guestfs_progress *message)
 {
   uint64_t array[4];
 
@@ -384,7 +411,7 @@ check_for_daemon_cancellation_or_eof (guestfs_h *g, int fd)
       xdr_guestfs_progress (&xdr, &message);
       xdr_destroy (&xdr);
 
-      send_progress_message (g, &message);
+      guestfs___progress_message_callback (g, &message);
     }
 
     return 0;
@@ -504,6 +531,25 @@ guestfs___send_to_daemon (guestfs_h *g, const void *v_buf, size_t n)
  * will not see GUESTFS_PROGRESS_FLAG.
  */
 
+static inline void
+unexpected_end_of_file_from_daemon_error (guestfs_h *g)
+{
+#define UNEXPEOF_ERROR "unexpected end of file when reading from daemon.\n"
+#define UNEXPEOF_TEST_TOOL \
+  "Or you can run 'libguestfs-test-tool' and post the complete output into\n" \
+  "a bug report or message to the libguestfs mailing list."
+  if (!g->verbose)
+    error (g, _(UNEXPEOF_ERROR
+"This usually means the libguestfs appliance failed to start up.  Please\n"
+"enable debugging (LIBGUESTFS_DEBUG=1) and rerun the command, then look at\n"
+"the debug messages output prior to this error.\n"
+UNEXPEOF_TEST_TOOL));
+  else
+    error (g, _(UNEXPEOF_ERROR
+"See earlier debug messages.\n"
+UNEXPEOF_TEST_TOOL));
+}
+
 int
 guestfs___recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
 {
@@ -569,7 +615,7 @@ guestfs___recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
           return -1;
         }
         if (r == 0) {
-          error (g, _("unexpected end of file when reading from daemon"));
+          unexpected_end_of_file_from_daemon_error (g);
           child_cleanup (g);
           return -1;
         }
@@ -632,7 +678,7 @@ guestfs___recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
         return -1;
       }
       if (r == 0) {
-        error (g, _("unexpected end of file when reading from daemon"));
+        unexpected_end_of_file_from_daemon_error (g);
         child_cleanup (g);
         free (*buf_rtn);
         *buf_rtn = NULL;
@@ -674,7 +720,7 @@ guestfs___recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
       xdr_guestfs_progress (&xdr, &message);
       xdr_destroy (&xdr);
 
-      send_progress_message (g, &message);
+      guestfs___progress_message_callback (g, &message);
     }
 
     free (*buf_rtn);