Include <stdarg.h> in public header.
[libguestfs.git] / src / proto.c
index fc1fedc..5d924e8 100644 (file)
@@ -299,7 +299,7 @@ check_for_daemon_cancellation_or_eof (guestfs_h *g, int fd)
  * child_cleanup function above.
  */
 int
-guestfs__send_to_daemon (guestfs_h *g, const void *v_buf, size_t n)
+guestfs___send_to_daemon (guestfs_h *g, const void *v_buf, size_t n)
 {
   const char *buf = v_buf;
   fd_set rset, rset2;
@@ -373,9 +373,17 @@ guestfs__send_to_daemon (guestfs_h *g, const void *v_buf, size_t n)
  *
  * It also checks for EOF (qemu died) and passes that up through the
  * child_cleanup function above.
+ *
+ * Progress notifications are handled transparently by this function.
+ * If the callback exists, it is called.  The caller of this function
+ * will not see GUESTFS_PROGRESS_FLAG.
  */
+
+/* Size of guestfs_progress message on the wire. */
+#define PROGRESS_MESSAGE_SIZE 24
+
 int
-guestfs__recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
+guestfs___recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
 {
   fd_set rset, rset2;
 
@@ -400,7 +408,13 @@ guestfs__recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
    */
   ssize_t nr = -4;
 
-  while (nr < (ssize_t) *size_rtn) {
+  for (;;) {
+    ssize_t message_size =
+      *size_rtn != GUESTFS_PROGRESS_FLAG ?
+      *size_rtn : PROGRESS_MESSAGE_SIZE;
+    if (nr >= message_size)
+      break;
+
     rset2 = rset;
     int r = select (max_fd+1, &rset2, NULL, NULL, NULL);
     if (r == -1) {
@@ -450,6 +464,11 @@ guestfs__recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
         xdr_uint32_t (&xdr, size_rtn);
         xdr_destroy (&xdr);
 
+        /* *size_rtn changed, recalculate message_size */
+        message_size =
+          *size_rtn != GUESTFS_PROGRESS_FLAG ?
+          *size_rtn : PROGRESS_MESSAGE_SIZE;
+
         if (*size_rtn == GUESTFS_LAUNCH_FLAG) {
           if (g->state != LAUNCHING)
             error (g, _("received magic signature from guestfsd, but in state %d"),
@@ -463,6 +482,8 @@ guestfs__recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
         }
         else if (*size_rtn == GUESTFS_CANCEL_FLAG)
           return 0;
+        else if (*size_rtn == GUESTFS_PROGRESS_FLAG)
+          /*FALLTHROUGH*/;
         /* If this happens, it's pretty bad and we've probably lost
          * synchronization.
          */
@@ -473,11 +494,11 @@ guestfs__recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
         }
 
         /* Allocate the complete buffer, size now known. */
-        *buf_rtn = safe_malloc (g, *size_rtn);
+        *buf_rtn = safe_malloc (g, message_size);
         /*FALLTHROUGH*/
       }
 
-      size_t sizetoread = *size_rtn - nr;
+      size_t sizetoread = message_size - nr;
       if (sizetoread > BUFSIZ) sizetoread = BUFSIZ;
 
       r = read (g->sock, (char *) (*buf_rtn) + nr, sizetoread);
@@ -524,6 +545,26 @@ guestfs__recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
   }
 #endif
 
+  if (*size_rtn == GUESTFS_PROGRESS_FLAG) {
+    if (g->state == BUSY && g->progress_cb) {
+      guestfs_progress message;
+      XDR xdr;
+      xdrmem_create (&xdr, *buf_rtn, PROGRESS_MESSAGE_SIZE, XDR_DECODE);
+      xdr_guestfs_progress (&xdr, &message);
+      xdr_destroy (&xdr);
+
+      g->progress_cb (g, g->progress_cb_data,
+                      message.proc, message.serial,
+                      message.position, message.total);
+    }
+
+    free (*buf_rtn);
+    *buf_rtn = NULL;
+
+    /* Process next message. */
+    return guestfs___recv_from_daemon (g, size_rtn, buf_rtn);
+  }
+
   return 0;
 }
 
@@ -533,7 +574,7 @@ guestfs__recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
  * accepted socket.
  */
 int
-guestfs__accept_from_daemon (guestfs_h *g)
+guestfs___accept_from_daemon (guestfs_h *g)
 {
   fd_set rset, rset2;
 
@@ -646,7 +687,7 @@ guestfs___send (guestfs_h *g, int proc_nr, xdrproc_t xdrp, char *args)
   xdr_uint32_t (&xdr, &len);
 
  again:
-  r = guestfs__send_to_daemon (g, msg_out, msg_out_size);
+  r = guestfs___send_to_daemon (g, msg_out, msg_out_size);
   if (r == -2)                  /* Ignore stray daemon cancellations. */
     goto again;
   if (r == -1)
@@ -790,7 +831,7 @@ send_file_chunk (guestfs_h *g, int cancel, const char *buf, size_t buflen)
   xdrmem_create (&xdr, msg_out, 4, XDR_ENCODE);
   xdr_uint32_t (&xdr, &len);
 
-  r = guestfs__send_to_daemon (g, msg_out, msg_out_size);
+  r = guestfs___send_to_daemon (g, msg_out, msg_out_size);
 
   /* Did the daemon send a cancellation message? */
   if (r == -2) {
@@ -824,7 +865,7 @@ guestfs___recv (guestfs_h *g, const char *fn,
   int r;
 
  again:
-  r = guestfs__recv_from_daemon (g, &size, &buf);
+  r = guestfs___recv_from_daemon (g, &size, &buf);
   if (r == -1)
     return -1;
 
@@ -946,7 +987,7 @@ receive_file_data (guestfs_h *g, void **buf_r)
   XDR xdr;
   guestfs_chunk chunk;
 
-  r = guestfs__recv_from_daemon (g, &len, &buf);
+  r = guestfs___recv_from_daemon (g, &len, &buf);
   if (r == -1) {
     error (g, _("receive_file_data: parse error in reply callback"));
     return -1;