Implement upload and download commands.
authorRichard Jones <rjones@redhat.com>
Sun, 19 Apr 2009 23:22:02 +0000 (00:22 +0100)
committerRichard Jones <rjones@redhat.com>
Sun, 19 Apr 2009 23:22:02 +0000 (00:22 +0100)
23 files changed:
daemon/blockdev.c
daemon/daemon.h
daemon/guestfsd.c
daemon/proto.c
daemon/upload.c
guestfs-actions.pod
guestfs.pod
ocaml/guestfs.ml
ocaml/guestfs.mli
ocaml/guestfs_c_actions.c
perl/Guestfs.xs
perl/lib/Sys/Guestfs.pm
python/guestfs-py.c
python/guestfs.py
ruby/ext/guestfs/_guestfs.c
src/generator.ml
src/guestfs-actions.c
src/guestfs-actions.h
src/guestfs.c
src/guestfs.h
src/guestfs_protocol.h
src/guestfs_protocol.x
tests.c

index 094ad5e..2c075ef 100644 (file)
@@ -68,7 +68,7 @@ call_blockdev (const char *device, const char *switc, int extraarg, int prints)
 
   if (prints) {
     if (sscanf (out, "%" SCNi64, &rv) != 1) {
-      reply_with_error ("%s: expected output, but got nothing");
+      reply_with_error ("%s: expected output, but got nothing", argv[0]);
       free (out);
       return -1;
     }
index b2b8152..bd14b12 100644 (file)
@@ -44,6 +44,8 @@ extern int command (char **stdoutput, char **stderror, const char *name, ...);
 extern int commandv (char **stdoutput, char **stderror,
                     char * const* const argv);
 
+extern int verbose;
+
 /*-- in proto.c --*/
 extern int proc_nr;
 extern int serial;
@@ -61,22 +63,29 @@ extern guestfs_lvm_int_lv_list *parse_command_line_lvs (void);
 extern void main_loop (int sock);
 
 /* ordinary daemon functions use these to indicate errors */
-extern void reply_with_error (const char *fs, ...);
-extern void reply_with_perror (const char *fs, ...);
+extern void reply_with_error (const char *fs, ...)
+  __attribute__((format (printf,1,2)));
+extern void reply_with_perror (const char *fs, ...)
+  __attribute__((format (printf,1,2)));
 
 /* daemon functions that receive files (FileIn) should call
  * receive_file for each FileIn parameter.
  */
-#if 0
-extern void receive_file ();
-#endif
+typedef int (*receive_cb) (void *opaque, const void *buf, int len);
+extern int receive_file (receive_cb cb, void *opaque);
+
+/* daemon functions that receive files (FileIn) can call this
+ * to cancel incoming transfers (eg. if there is a local error),
+ * but they MUST then call reply_with_error or reply_with_perror.
+ */
+extern void cancel_receive (void);
 
 /* daemon functions that return files (FileOut) should call
- * reply, then send_file for each FileOut parameter.
+ * reply, then send_file_* for each FileOut parameter.
+ * Note max write size if GUESTFS_MAX_CHUNK_SIZE.
  */
-#if 0
-extern void send_file ();
-#endif
+extern int send_file_write (const void *buf, int len);
+extern void send_file_end (int cancel);
 
 /* only call this if there is a FileOut parameter */
 extern void reply (xdrproc_t xdrp, char *ret);
@@ -122,7 +131,7 @@ extern void reply (xdrproc_t xdrp, char *ret);
     if (strncmp ((path), "/dev/", 5) == 0)                             \
       IS_DEVICE ((path),(errcode));                                    \
     else {                                                             \
-      NEED_ROOT ((path),(errcode));                                    \
+      NEED_ROOT ((errcode));                                           \
       ABS_PATH ((path),(errcode));                                     \
     }                                                                  \
   } while (0)
index c3f5e82..2553ea2 100644 (file)
@@ -41,6 +41,8 @@ static void usage (void);
 #define VMCHANNEL_PORT "6666"
 #define VMCHANNEL_ADDR "10.0.2.4"
 
+int verbose = 0;
+
 int
 main (int argc, char *argv[])
 {
@@ -108,6 +110,14 @@ main (int argc, char *argv[])
     fclose (fp);
     buf[n] = '\0';
 
+    /* Set the verbose flag.  Not quite right because this will only
+     * set the flag if host and port aren't set on the command line.
+     * Don't worry about this for now. (XXX)
+     */
+    verbose = strstr (buf, "guestfs_verbose=1") != NULL;
+    if (verbose)
+      printf ("verbose daemon enabled\n");
+
     p = strstr (buf, "guestfs=");
 
     if (p) {
@@ -359,10 +369,12 @@ commandv (char **stdoutput, char **stderror, char * const* const argv)
   if (stdoutput) *stdoutput = NULL;
   if (stderror) *stderror = NULL;
 
-  printf ("%s", argv[0]);
-  for (i = 1; argv[i] != NULL; ++i)
-    printf (" %s", argv[i]);
-  printf ("\n");
+  if (verbose) {
+    printf ("%s", argv[0]);
+    for (i = 1; argv[i] != NULL; ++i)
+      printf (" %s", argv[i]);
+    printf ("\n");
+  }
 
   if (pipe (so_fd) == -1 || pipe (se_fd) == -1) {
     perror ("pipe");
index 76dce98..cd61f18 100644 (file)
 #include "daemon.h"
 #include "../src/guestfs_protocol.h"
 
-/* XXX We should make this configurable from /proc/cmdline so that the
- * verbose setting of the guestfs_h can be inherited here.
- */
-#define DEBUG 0
-
 /* The message currently being processed. */
 int proc_nr;
 int serial;
@@ -76,26 +71,26 @@ main_loop (int _sock)
 
     xread (sock, buf, len);
 
-#if DEBUG
-    int i, j;
-
-    for (i = 0; i < len; i += 16) {
-      printf ("%04x: ", i);
-      for (j = i; j < MIN (i+16, len); ++j)
-       printf ("%02x ", (unsigned char) buf[j]);
-      for (; j < i+16; ++j)
-       printf ("   ");
-      printf ("|");
-      for (j = i; j < MIN (i+16, len); ++j)
-       if (isprint (buf[j]))
-         printf ("%c", buf[j]);
-       else
-         printf (".");
-      for (; j < i+16; ++j)
-       printf (" ");
-      printf ("|\n");
+    if (verbose) {
+      int i, j;
+
+      for (i = 0; i < len; i += 16) {
+       printf ("%04x: ", i);
+       for (j = i; j < MIN (i+16, len); ++j)
+         printf ("%02x ", (unsigned char) buf[j]);
+       for (; j < i+16; ++j)
+         printf ("   ");
+       printf ("|");
+       for (j = i; j < MIN (i+16, len); ++j)
+         if (isprint (buf[j]))
+           printf ("%c", buf[j]);
+         else
+           printf (".");
+       for (; j < i+16; ++j)
+         printf (" ");
+       printf ("|\n");
+      }
     }
-#endif
 
     /* Decode the message header. */
     xdrmem_create (&xdr, buf, len, XDR_DECODE);
@@ -250,3 +245,210 @@ reply (xdrproc_t xdrp, char *ret)
   (void) xwrite (sock, lenbuf, 4);
   (void) xwrite (sock, buf, len);
 }
+
+/* Receive file chunks, repeatedly calling 'cb'. */
+int
+receive_file (receive_cb cb, void *opaque)
+{
+  guestfs_chunk chunk;
+  char lenbuf[4];
+  char *buf;
+  XDR xdr;
+  int r;
+  uint32_t len;
+
+  for (;;) {
+    /* Read the length word. */
+    xread (sock, lenbuf, 4);
+    xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
+    xdr_uint32_t (&xdr, &len);
+    xdr_destroy (&xdr);
+
+    if (len == GUESTFS_CANCEL_FLAG)
+      continue;                        /* Just ignore it. */
+
+    if (len > GUESTFS_MESSAGE_MAX) {
+      fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
+              len);
+      exit (1);
+    }
+
+    buf = malloc (len);
+    if (!buf) {
+      perror ("malloc");
+      return -1;
+    }
+
+    xread (sock, buf, len);
+
+    xdrmem_create (&xdr, buf, len, XDR_DECODE);
+    memset (&chunk, 0, sizeof chunk);
+    if (!xdr_guestfs_chunk (&xdr, &chunk)) {
+      xdr_destroy (&xdr);
+      free (buf);
+      return -1;
+    }
+    xdr_destroy (&xdr);
+    free (buf);
+
+    if (verbose)
+      printf ("receive_file: got chunk: cancel = %d, len = %d, buf = %p\n",
+             chunk.cancel, chunk.data.data_len, chunk.data.data_val);
+
+    if (chunk.cancel) {
+      fprintf (stderr, "receive_file: received cancellation from library\n");
+      xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
+      return -2;
+    }
+    if (chunk.data.data_len == 0) {
+      xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
+      return 0;                        /* end of file */
+    }
+
+    if (cb)
+      r = cb (opaque, chunk.data.data_val, chunk.data.data_len);
+    else
+      r = 0;
+
+    xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
+    if (r == -1)               /* write error */
+      return -1;
+  }
+}
+
+/* Send a cancellation flag back to the library. */
+void
+cancel_receive (void)
+{
+  XDR xdr;
+  char fbuf[4];
+  uint32_t flag = GUESTFS_CANCEL_FLAG;
+
+  xdrmem_create (&xdr, fbuf, sizeof fbuf, XDR_ENCODE);
+  xdr_uint32_t (&xdr, &flag);
+  xdr_destroy (&xdr);
+
+  if (xwrite (sock, fbuf, sizeof fbuf) == -1) {
+    perror ("write to socket");
+    return;
+  }
+
+  /* Keep receiving chunks and discarding, until library sees cancel. */
+  (void) receive_file (NULL, NULL);
+}
+
+static int check_for_library_cancellation (void);
+static int send_chunk (const guestfs_chunk *);
+
+/* Also check if the library sends us a cancellation message. */
+int
+send_file_write (const void *buf, int len)
+{
+  guestfs_chunk chunk;
+  int cancel;
+
+  if (len > GUESTFS_MAX_CHUNK_SIZE) {
+    fprintf (stderr, "send_file_write: len (%d) > GUESTFS_MAX_CHUNK_SIZE (%d)\n",
+            len, GUESTFS_MAX_CHUNK_SIZE);
+    return -1;
+  }
+
+  cancel = check_for_library_cancellation ();
+
+  if (cancel) {
+    chunk.cancel = 1;
+    chunk.data.data_len = 0;
+    chunk.data.data_val = NULL;
+  } else {
+    chunk.cancel = 0;
+    chunk.data.data_len = len;
+    chunk.data.data_val = (char *) buf;
+  }
+
+  if (send_chunk (&chunk) == -1)
+    return -1;
+
+  if (cancel) return -2;
+  return 0;
+}
+
+static int
+check_for_library_cancellation (void)
+{
+  fd_set rset;
+  struct timeval tv;
+  int r;
+  char buf[4];
+  uint32_t flag;
+  XDR xdr;
+
+  FD_ZERO (&rset);
+  FD_SET (sock, &rset);
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+  r = select (sock+1, &rset, NULL, NULL, &tv);
+  if (r == -1) {
+    perror ("select");
+    return 0;
+  }
+  if (r == 0)
+    return 0;
+
+  /* Read the message from the daemon. */
+  r = xread (sock, buf, sizeof buf);
+  if (r == -1) {
+    perror ("read");
+    return 0;
+  }
+
+  xdrmem_create (&xdr, buf, sizeof buf, XDR_DECODE);
+  xdr_uint32_t (&xdr, &flag);
+  xdr_destroy (&xdr);
+
+  if (flag != GUESTFS_CANCEL_FLAG) {
+    fprintf (stderr, "check_for_library_cancellation: read 0x%x from library, expected 0x%x\n",
+            flag, GUESTFS_CANCEL_FLAG);
+    return 0;
+  }
+
+  return 1;
+}
+
+void
+send_file_end (int cancel)
+{
+  guestfs_chunk chunk;
+
+  chunk.cancel = cancel;
+  chunk.data.data_len = 0;
+  chunk.data.data_val = NULL;
+  send_chunk (&chunk);
+}
+
+static int
+send_chunk (const guestfs_chunk *chunk)
+{
+  char buf[GUESTFS_MAX_CHUNK_SIZE + 48];
+  char lenbuf[4];
+  XDR xdr;
+  uint32_t len;
+
+  xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
+  if (!xdr_guestfs_chunk (&xdr, (guestfs_chunk *) chunk)) {
+    fprintf (stderr, "send_chunk: failed to encode chunk\n");
+    xdr_destroy (&xdr);
+    return -1;
+  }
+
+  len = xdr_getpos (&xdr);
+  xdr_destroy (&xdr);
+
+  xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
+  xdr_uint32_t (&xdr, &len);
+  xdr_destroy (&xdr);
+
+  (void) xwrite (sock, lenbuf, 4);
+  (void) xwrite (sock, buf, len);
+
+  return 0;
+}
index d2feb02..b457695 100644 (file)
 #include "daemon.h"
 #include "actions.h"
 
+static int
+write_cb (void *fd_ptr, const void *buf, int len)
+{
+  int fd = *(int *)fd_ptr;
+  return xwrite (fd, buf, len);
+}
+
+/* Has one FileIn parameter. */
 int
-do_upload (const char *remote_filename)
+do_upload (const char *filename)
 {
-  XXX_NOT_IMPL (-1);
+  int err, fd, r, is_dev;
+
+  NEED_ROOT_OR_IS_DEVICE (filename, -1);
+
+  is_dev = strncmp (filename, "/dev/", 5) == 0;
+
+  if (!is_dev) CHROOT_IN;
+  fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
+  if (!is_dev) CHROOT_OUT;
+  if (fd == -1) {
+    err = errno;
+    cancel_receive ();
+    errno = err;
+    reply_with_perror ("%s", filename);
+    return -1;
+  }
+
+  r = receive_file (write_cb, &fd);
+  if (r == -1) {               /* write error */
+    err = errno;
+    cancel_receive ();
+    errno = err;
+    reply_with_perror ("write: %s", filename);
+    return -1;
+  }
+  if (r == -2) {               /* cancellation from library */
+    close (fd);
+    /* Do NOT send any error. */
+    return -1;
+  }
+
+  if (close (fd) == -1) {
+    err = errno;
+    cancel_receive ();
+    errno = err;
+    reply_with_perror ("close: %s", filename);
+    return -1;
+  }
+
+  return 0;
 }
 
+/* Has one FileOut parameter. */
 int
-do_download (const char *remote_filename)
+do_download (const char *filename)
 {
-  XXX_NOT_IMPL (-1);
+  int fd, r, is_dev;
+  char buf[GUESTFS_MAX_CHUNK_SIZE];
+
+  NEED_ROOT_OR_IS_DEVICE (filename, -1);
+
+  is_dev = strncmp (filename, "/dev/", 5) == 0;
+
+  if (!is_dev) CHROOT_IN;
+  fd = open (filename, O_RDONLY);
+  if (!is_dev) CHROOT_OUT;
+  if (fd == -1) {
+    reply_with_perror ("%s", filename);
+    return -1;
+  }
+
+  /* Now we must send the reply message, before the file contents.  After
+   * this there is no opportunity in the protocol to send any error
+   * message back.  Instead we can only cancel the transfer.
+   */
+  reply (NULL, NULL);
+
+  while ((r = read (fd, buf, sizeof buf)) > 0) {
+    if (send_file_write (buf, r) < 0)
+      return -1;
+  }
+
+  if (r == -1) {
+    perror (filename);
+    send_file_end (1);         /* Cancel. */
+    return -1;
+  }
+
+  if (close (fd) == -1) {
+    perror (filename);
+    send_file_end (1);         /* Cancel. */
+    return -1;
+  }
+
+  send_file_end (0);           /* Normal end of file. */
+  return 0;
 }
index 21f424f..d57dae3 100644 (file)
@@ -938,6 +938,17 @@ best effort attempt to run C<guestfs_sync> when the handle is closed
 
 This function returns 0 on success or -1 on error.
 
+=head2 guestfs_set_busy
+
+ int guestfs_set_busy (guestfs_h *handle);
+
+This sets the state to C<BUSY>.  This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L<guestfs(3)>.
+
+This function returns 0 on success or -1 on error.
+
 =head2 guestfs_set_path
 
  int guestfs_set_path (guestfs_h *handle,
@@ -955,6 +966,17 @@ Setting C<path> to C<NULL> restores the default path.
 
 This function returns 0 on success or -1 on error.
 
+=head2 guestfs_set_ready
+
+ int guestfs_set_ready (guestfs_h *handle);
+
+This sets the state to C<READY>.  This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L<guestfs(3)>.
+
+This function returns 0 on success or -1 on error.
+
 =head2 guestfs_set_verbose
 
  int guestfs_set_verbose (guestfs_h *handle,
index db8887e..dc059c4 100644 (file)
@@ -518,8 +518,8 @@ For ordinary functions, the request message is:
 
  total length (header + arguments,
       but not including the length word itself)
- struct guestfs_message_header
- struct guestfs_<foo>_args
+ struct guestfs_message_header (encoded as XDR)
+ struct guestfs_<foo>_args (encoded as XDR)
 
 The total length field allows the daemon to allocate a fixed size
 buffer into which it slurps the rest of the message.  As a result, the
@@ -538,8 +538,8 @@ The reply message for ordinary functions is:
 
  total length (header + ret,
       but not including the length word itself)
- struct guestfs_message_header
- struct guestfs_<foo>_ret
+ struct guestfs_message_header (encoded as XDR)
+ struct guestfs_<foo>_ret (encoded as XDR)
 
 As above the C<guestfs_I<foo>_ret> structure may be completely omitted
 for functions that return no formal return values.
@@ -552,8 +552,8 @@ message is slightly changed:
 
  total length (header + error,
       but not including the length word itself)
- struct guestfs_message_header
- struct guestfs_message_error
+ struct guestfs_message_header (encoded as XDR)
+ struct guestfs_message_error (encoded as XDR)
 
 The C<guestfs_message_error> structure contains the error message as a
 string.
@@ -567,19 +567,29 @@ is followed by a sequence of file chunks.
  total length (header + arguments,
       but not including the length word itself,
       and not including the chunks)
- struct guestfs_message_header
- struct guestfs_<foo>_args
+ struct guestfs_message_header (encoded as XDR)
+ struct guestfs_<foo>_args (encoded as XDR)
  sequence of chunks for FileIn param #0
  sequence of chunks for FileIn param #1 etc.
 
-The sequence of chunks is a sequence of C<struct guestfs_chunk>.  A
+The "sequence of chunks" is:
+
+ length of chunk (not including length word itself)
+ struct guestfs_chunk (encoded as XDR)
+ length of chunk
+ struct guestfs_chunk (encoded as XDR)
+   ...
+ length of chunk
+ struct guestfs_chunk (with data.data_len == 0)
+
+The final chunk has the C<data_len> field set to zero.  Additionally a
 flag is set in the final chunk to indicate either successful
 completion or early cancellation.
 
 At time of writing there are no functions that have more than one
 FileIn parameter.  However this is (theoretically) supported, by
-sending the chunks for each FileIn parameter one after another (from
-left to right).
+sending the sequence of chunks for each FileIn parameter one after
+another (from left to right).
 
 Both the library (sender) I<and> the daemon (receiver) may cancel the
 transfer.  The library does this by sending a chunk with a special
@@ -610,8 +620,8 @@ parameters, but with the roles of daemon and library reversed.
  total length (header + ret,
       but not including the length word itself,
       and not including the chunks)
- struct guestfs_message_header
- struct guestfs_<foo>_ret
+ struct guestfs_message_header (encoded as XDR)
+ struct guestfs_<foo>_ret (encoded as XDR)
  sequence of chunks for FileOut param #0
  sequence of chunks for FileOut param #1 etc.
 
index f45533b..09b12b1 100644 (file)
@@ -132,6 +132,8 @@ external is_config : t -> bool = "ocaml_guestfs_is_config"
 external is_launching : t -> bool = "ocaml_guestfs_is_launching"
 external is_busy : t -> bool = "ocaml_guestfs_is_busy"
 external get_state : t -> int = "ocaml_guestfs_get_state"
+external set_busy : t -> unit = "ocaml_guestfs_set_busy"
+external set_ready : t -> unit = "ocaml_guestfs_set_ready"
 external mount : t -> string -> string -> unit = "ocaml_guestfs_mount"
 external sync : t -> unit = "ocaml_guestfs_sync"
 external touch : t -> string -> unit = "ocaml_guestfs_touch"
index 2257fc0..dfc1784 100644 (file)
@@ -175,6 +175,12 @@ val is_busy : t -> bool
 val get_state : t -> int
 (** get the current state *)
 
+val set_busy : t -> unit
+(** set state to busy *)
+
+val set_ready : t -> unit
+(** set state to ready *)
+
 val mount : t -> string -> string -> unit
 (** mount a guest disk at a position in the filesystem *)
 
index 4d7b350..138f0fd 100644 (file)
@@ -711,6 +711,50 @@ ocaml_guestfs_get_state (value gv)
 }
 
 CAMLprim value
+ocaml_guestfs_set_busy (value gv)
+{
+  CAMLparam1 (gv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("set_busy: used handle after closing it");
+
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_set_busy (g);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "set_busy");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_set_ready (value gv)
+{
+  CAMLparam1 (gv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("set_ready: used handle after closing it");
+
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_set_ready (g);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "set_ready");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
+CAMLprim value
 ocaml_guestfs_mount (value gv, value devicev, value mountpointv)
 {
   CAMLparam3 (gv, devicev, mountpointv);
index e498842..235c3a7 100644 (file)
@@ -305,6 +305,26 @@ PREINIT:
       RETVAL
 
 void
+set_busy (g)
+      guestfs_h *g;
+PREINIT:
+      int r;
+ PPCODE:
+      r = guestfs_set_busy (g);
+      if (r == -1)
+        croak ("set_busy: %s", guestfs_last_error (g));
+
+void
+set_ready (g)
+      guestfs_h *g;
+PREINIT:
+      int r;
+ PPCODE:
+      r = guestfs_set_ready (g);
+      if (r == -1)
+        croak ("set_ready: %s", guestfs_last_error (g));
+
+void
 mount (g, device, mountpoint)
       guestfs_h *g;
       char *device;
index f624c24..bd8da0f 100644 (file)
@@ -657,6 +657,13 @@ If C<autosync> is true, this enables autosync.  Libguestfs will make a
 best effort attempt to run C<$h-E<gt>sync> when the handle is closed
 (also if the program exits without closing handles).
 
+=item $h->set_busy ();
+
+This sets the state to C<BUSY>.  This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L<guestfs(3)>.
+
 =item $h->set_path ($path);
 
 Set the path that libguestfs searches for kernel and initrd.img.
@@ -669,6 +676,13 @@ must make sure it remains valid for the lifetime of the handle.
 
 Setting C<path> to C<NULL> restores the default path.
 
+=item $h->set_ready ();
+
+This sets the state to C<READY>.  This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L<guestfs(3)>.
+
 =item $h->set_verbose ($verbose);
 
 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
index 69446ae..9969c53 100644 (file)
@@ -796,6 +796,54 @@ py_guestfs_get_state (PyObject *self, PyObject *args)
 }
 
 static PyObject *
+py_guestfs_set_busy (PyObject *self, PyObject *args)
+{
+  PyObject *py_g;
+  guestfs_h *g;
+  PyObject *py_r;
+  int r;
+
+  if (!PyArg_ParseTuple (args, (char *) "O:guestfs_set_busy",
+                         &py_g))
+    return NULL;
+  g = get_handle (py_g);
+
+  r = guestfs_set_busy (g);
+  if (r == -1) {
+    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+    return NULL;
+  }
+
+  Py_INCREF (Py_None);
+  py_r = Py_None;
+  return py_r;
+}
+
+static PyObject *
+py_guestfs_set_ready (PyObject *self, PyObject *args)
+{
+  PyObject *py_g;
+  guestfs_h *g;
+  PyObject *py_r;
+  int r;
+
+  if (!PyArg_ParseTuple (args, (char *) "O:guestfs_set_ready",
+                         &py_g))
+    return NULL;
+  g = get_handle (py_g);
+
+  r = guestfs_set_ready (g);
+  if (r == -1) {
+    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+    return NULL;
+  }
+
+  Py_INCREF (Py_None);
+  py_r = Py_None;
+  return py_r;
+}
+
+static PyObject *
 py_guestfs_mount (PyObject *self, PyObject *args)
 {
   PyObject *py_g;
@@ -2508,6 +2556,8 @@ static PyMethodDef methods[] = {
   { (char *) "is_launching", py_guestfs_is_launching, METH_VARARGS, NULL },
   { (char *) "is_busy", py_guestfs_is_busy, METH_VARARGS, NULL },
   { (char *) "get_state", py_guestfs_get_state, METH_VARARGS, NULL },
+  { (char *) "set_busy", py_guestfs_set_busy, METH_VARARGS, NULL },
+  { (char *) "set_ready", py_guestfs_set_ready, METH_VARARGS, NULL },
   { (char *) "mount", py_guestfs_mount, METH_VARARGS, NULL },
   { (char *) "sync", py_guestfs_sync, METH_VARARGS, NULL },
   { (char *) "touch", py_guestfs_touch, METH_VARARGS, NULL },
index fd495fd..416404b 100644 (file)
@@ -234,6 +234,22 @@ class GuestFS:
         """
         return libguestfsmod.get_state (self._o)
 
+    def set_busy (self):
+        u"""This sets the state to "BUSY". This is only used when
+        implementing actions using the low-level API.
+        
+        For more information on states, see guestfs(3).
+        """
+        return libguestfsmod.set_busy (self._o)
+
+    def set_ready (self):
+        u"""This sets the state to "READY". This is only used when
+        implementing actions using the low-level API.
+        
+        For more information on states, see guestfs(3).
+        """
+        return libguestfsmod.set_ready (self._o)
+
     def mount (self, device, mountpoint):
         u"""Mount a guest disk at a position in the filesystem.
         Block devices are named "/dev/sda", "/dev/sdb" and so
index f73a3b7..0104017 100644 (file)
@@ -374,6 +374,40 @@ static VALUE ruby_guestfs_get_state (VALUE gv)
   return INT2NUM (r);
 }
 
+static VALUE ruby_guestfs_set_busy (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "set_busy");
+
+
+  int r;
+
+  r = guestfs_set_busy (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_set_ready (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "set_ready");
+
+
+  int r;
+
+  r = guestfs_set_ready (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
 static VALUE ruby_guestfs_mount (VALUE gv, VALUE devicev, VALUE mountpointv)
 {
   guestfs_h *g;
@@ -2076,6 +2110,10 @@ void Init__guestfs ()
         ruby_guestfs_is_busy, 0);
   rb_define_method (c_guestfs, "get_state",
         ruby_guestfs_get_state, 0);
+  rb_define_method (c_guestfs, "set_busy",
+        ruby_guestfs_set_busy, 0);
+  rb_define_method (c_guestfs, "set_ready",
+        ruby_guestfs_set_ready, 0);
   rb_define_method (c_guestfs, "mount",
         ruby_guestfs_mount, 2);
   rb_define_method (c_guestfs, "sync",
index 8c75b93..34b2241 100755 (executable)
@@ -380,6 +380,25 @@ This returns the current state as an opaque integer.  This is
 only useful for printing debug and internal error messages.
 
 For more information on states, see L<guestfs(3)>.");
+
+  ("set_busy", (RErr, []), -1, [NotInFish],
+   [],
+   "set state to busy",
+   "\
+This sets the state to C<BUSY>.  This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L<guestfs(3)>.");
+
+  ("set_ready", (RErr, []), -1, [NotInFish],
+   [],
+   "set state to ready",
+   "\
+This sets the state to C<READY>.  This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L<guestfs(3)>.");
+
 ]
 
 let daemon_functions = [
@@ -1932,7 +1951,7 @@ const GUESTFS_PROGRAM = 0x2000F5F5;
 const GUESTFS_PROTOCOL_VERSION = 1;
 
 /* These constants must be larger than any possible message length. */
-const GUESTFS_LAUNCH_FLAG = 0xf5f55f5f;
+const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
 
 enum guestfs_message_direction {
@@ -2210,6 +2229,7 @@ check_state (guestfs_h *g, const char *caller)
       pr "  int serial;\n";
       pr "\n";
       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
+      pr "  guestfs_set_busy (g);\n";
       pr "\n";
       pr "  memset (&ctx, 0, sizeof ctx);\n";
       pr "\n";
@@ -2240,21 +2260,33 @@ check_state (guestfs_h *g, const char *caller)
           pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
             name;
       );
-      pr "  if (serial == -1)\n";
+      pr "  if (serial == -1) {\n";
+      pr "    guestfs_set_ready (g);\n";
       pr "    return %s;\n" error_code;
+      pr "  }\n";
       pr "\n";
 
       (* Send any additional files (FileIn) requested. *)
       List.iter (
        function
        | FileIn n ->
-           pr "  if (guestfs__send_file_sync (g, %s) == -1)\n" n;
-           pr "    return %s;\n" error_code;
+           pr "  {\n";
+           pr "    int r;\n";
+           pr "\n";
+           pr "    r = guestfs__send_file_sync (g, %s);\n" n;
+           pr "    if (r == -1) {\n";
+           pr "      guestfs_set_ready (g);\n";
+           pr "      return %s;\n" error_code;
+           pr "    }\n";
+           pr "    if (r == -2) /* daemon cancelled */\n";
+           pr "      goto read_reply;\n";
+           pr "  }\n";
            pr "\n";
        | _ -> ()
       ) (snd style);
 
       (* Wait for the reply from the remote end. *)
+      pr " read_reply:\n";
       pr "  guestfs__switch_to_receiving (g);\n";
       pr "  ctx.cb_sequence = 0;\n";
       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
@@ -2262,17 +2294,21 @@ check_state (guestfs_h *g, const char *caller)
       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
       pr "  if (ctx.cb_sequence != 1001) {\n";
       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
+      pr "    guestfs_set_ready (g);\n";
       pr "    return %s;\n" error_code;
       pr "  }\n";
       pr "\n";
 
-      pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
+      pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
        (String.uppercase shortname);
+      pr "    guestfs_set_ready (g);\n";
       pr "    return %s;\n" error_code;
+      pr "  }\n";
       pr "\n";
 
       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
+      pr "    guestfs_set_ready (g);\n";
       pr "    return %s;\n" error_code;
       pr "  }\n";
       pr "\n";
@@ -2281,12 +2317,16 @@ check_state (guestfs_h *g, const char *caller)
       List.iter (
        function
        | FileOut n ->
-           pr "  if (guestfs__receive_file_sync (g, %s) == -1)\n" n;
+           pr "  if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
+           pr "    guestfs_set_ready (g);\n";
            pr "    return %s;\n" error_code;
+           pr "  }\n";
            pr "\n";
        | _ -> ()
       ) (snd style);
 
+      pr "  guestfs_set_ready (g);\n";
+
       (match fst style with
        | RErr -> pr "  return 0;\n"
        | RInt n | RInt64 n | RBool n ->
index d76010d..1a63236 100644 (file)
@@ -126,6 +126,7 @@ int guestfs_mount (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_mount") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -133,9 +134,12 @@ int guestfs_mount (guestfs_h *g,
   args.mountpoint = (char *) mountpoint;
   serial = guestfs__send_sync (g, GUESTFS_PROC_MOUNT,
         (xdrproc_t) xdr_guestfs_mount_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, mount_reply_cb, &ctx);
@@ -143,17 +147,22 @@ int guestfs_mount (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_mount");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNT, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNT, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -197,13 +206,17 @@ int guestfs_sync (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_sync") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_SYNC, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, sync_reply_cb, &ctx);
@@ -211,17 +224,22 @@ int guestfs_sync (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_sync");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SYNC, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SYNC, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -267,15 +285,19 @@ int guestfs_touch (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_touch") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_TOUCH,
         (xdrproc_t) xdr_guestfs_touch_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, touch_reply_cb, &ctx);
@@ -283,17 +305,22 @@ int guestfs_touch (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_touch");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TOUCH, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TOUCH, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -344,15 +371,19 @@ char *guestfs_cat (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_cat") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_CAT,
         (xdrproc_t) xdr_guestfs_cat_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, cat_reply_cb, &ctx);
@@ -360,17 +391,22 @@ char *guestfs_cat (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_cat");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CAT, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CAT, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.content; /* caller will free */
 }
 
@@ -421,15 +457,19 @@ char *guestfs_ll (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_ll") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.directory = (char *) directory;
   serial = guestfs__send_sync (g, GUESTFS_PROC_LL,
         (xdrproc_t) xdr_guestfs_ll_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, ll_reply_cb, &ctx);
@@ -437,17 +477,22 @@ char *guestfs_ll (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_ll");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LL, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LL, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.listing; /* caller will free */
 }
 
@@ -498,15 +543,19 @@ char **guestfs_ls (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_ls") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.directory = (char *) directory;
   serial = guestfs__send_sync (g, GUESTFS_PROC_LS,
         (xdrproc_t) xdr_guestfs_ls_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, ls_reply_cb, &ctx);
@@ -514,17 +563,22 @@ char **guestfs_ls (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_ls");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LS, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.listing.listing_val =
     safe_realloc (g, ctx.ret.listing.listing_val,
@@ -578,13 +632,17 @@ char **guestfs_list_devices (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_list_devices") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_LIST_DEVICES, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, list_devices_reply_cb, &ctx);
@@ -592,17 +650,22 @@ char **guestfs_list_devices (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_list_devices");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LIST_DEVICES, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LIST_DEVICES, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.devices.devices_val =
     safe_realloc (g, ctx.ret.devices.devices_val,
@@ -656,13 +719,17 @@ char **guestfs_list_partitions (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_list_partitions") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_LIST_PARTITIONS, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, list_partitions_reply_cb, &ctx);
@@ -670,17 +737,22 @@ char **guestfs_list_partitions (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_list_partitions");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LIST_PARTITIONS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LIST_PARTITIONS, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.partitions.partitions_val =
     safe_realloc (g, ctx.ret.partitions.partitions_val,
@@ -734,13 +806,17 @@ char **guestfs_pvs (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_pvs") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_PVS, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, pvs_reply_cb, &ctx);
@@ -748,17 +824,22 @@ char **guestfs_pvs (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_pvs");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVS, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.physvols.physvols_val =
     safe_realloc (g, ctx.ret.physvols.physvols_val,
@@ -812,13 +893,17 @@ char **guestfs_vgs (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_vgs") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_VGS, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, vgs_reply_cb, &ctx);
@@ -826,17 +911,22 @@ char **guestfs_vgs (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_vgs");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGS, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.volgroups.volgroups_val =
     safe_realloc (g, ctx.ret.volgroups.volgroups_val,
@@ -890,13 +980,17 @@ char **guestfs_lvs (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_lvs") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_LVS, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, lvs_reply_cb, &ctx);
@@ -904,17 +998,22 @@ char **guestfs_lvs (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_lvs");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVS, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.logvols.logvols_val =
     safe_realloc (g, ctx.ret.logvols.logvols_val,
@@ -968,13 +1067,17 @@ struct guestfs_lvm_pv_list *guestfs_pvs_full (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_pvs_full") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_PVS_FULL, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, pvs_full_reply_cb, &ctx);
@@ -982,17 +1085,22 @@ struct guestfs_lvm_pv_list *guestfs_pvs_full (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_pvs_full");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVS_FULL, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVS_FULL, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this */
   return safe_memdup (g, &ctx.ret.physvols, sizeof (ctx.ret.physvols));
 }
@@ -1042,13 +1150,17 @@ struct guestfs_lvm_vg_list *guestfs_vgs_full (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_vgs_full") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_VGS_FULL, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, vgs_full_reply_cb, &ctx);
@@ -1056,17 +1168,22 @@ struct guestfs_lvm_vg_list *guestfs_vgs_full (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_vgs_full");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGS_FULL, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGS_FULL, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this */
   return safe_memdup (g, &ctx.ret.volgroups, sizeof (ctx.ret.volgroups));
 }
@@ -1116,13 +1233,17 @@ struct guestfs_lvm_lv_list *guestfs_lvs_full (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_lvs_full") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_LVS_FULL, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, lvs_full_reply_cb, &ctx);
@@ -1130,17 +1251,22 @@ struct guestfs_lvm_lv_list *guestfs_lvs_full (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_lvs_full");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVS_FULL, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVS_FULL, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this */
   return safe_memdup (g, &ctx.ret.logvols, sizeof (ctx.ret.logvols));
 }
@@ -1192,15 +1318,19 @@ char **guestfs_read_lines (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_read_lines") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_READ_LINES,
         (xdrproc_t) xdr_guestfs_read_lines_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, read_lines_reply_cb, &ctx);
@@ -1208,17 +1338,22 @@ char **guestfs_read_lines (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_read_lines");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_READ_LINES, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_READ_LINES, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.lines.lines_val =
     safe_realloc (g, ctx.ret.lines.lines_val,
@@ -1270,6 +1405,7 @@ int guestfs_aug_init (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_init") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -1277,9 +1413,12 @@ int guestfs_aug_init (guestfs_h *g,
   args.flags = flags;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_INIT,
         (xdrproc_t) xdr_guestfs_aug_init_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_init_reply_cb, &ctx);
@@ -1287,17 +1426,22 @@ int guestfs_aug_init (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_init");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_INIT, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_INIT, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -1341,13 +1485,17 @@ int guestfs_aug_close (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_aug_close") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_CLOSE, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_close_reply_cb, &ctx);
@@ -1355,17 +1503,22 @@ int guestfs_aug_close (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_close");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_CLOSE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_CLOSE, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -1417,6 +1570,7 @@ int guestfs_aug_defvar (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_defvar") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -1424,9 +1578,12 @@ int guestfs_aug_defvar (guestfs_h *g,
   args.expr = expr ? (char **) &expr : NULL;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_DEFVAR,
         (xdrproc_t) xdr_guestfs_aug_defvar_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_defvar_reply_cb, &ctx);
@@ -1434,17 +1591,22 @@ int guestfs_aug_defvar (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_defvar");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_DEFVAR, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_DEFVAR, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.nrnodes;
 }
 
@@ -1497,6 +1659,7 @@ struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_defnode") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -1505,9 +1668,12 @@ struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
   args.val = (char *) val;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_DEFNODE,
         (xdrproc_t) xdr_guestfs_aug_defnode_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_defnode_reply_cb, &ctx);
@@ -1515,17 +1681,22 @@ struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_defnode");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_DEFNODE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_DEFNODE, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller with free this */
   return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));
 }
@@ -1577,15 +1748,19 @@ char *guestfs_aug_get (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_get") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_GET,
         (xdrproc_t) xdr_guestfs_aug_get_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_get_reply_cb, &ctx);
@@ -1593,17 +1768,22 @@ char *guestfs_aug_get (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_get");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_GET, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_GET, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.val; /* caller will free */
 }
 
@@ -1650,6 +1830,7 @@ int guestfs_aug_set (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_set") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -1657,9 +1838,12 @@ int guestfs_aug_set (guestfs_h *g,
   args.val = (char *) val;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_SET,
         (xdrproc_t) xdr_guestfs_aug_set_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_set_reply_cb, &ctx);
@@ -1667,17 +1851,22 @@ int guestfs_aug_set (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_set");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_SET, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_SET, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -1725,6 +1914,7 @@ int guestfs_aug_insert (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_insert") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -1733,9 +1923,12 @@ int guestfs_aug_insert (guestfs_h *g,
   args.before = before;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_INSERT,
         (xdrproc_t) xdr_guestfs_aug_insert_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_insert_reply_cb, &ctx);
@@ -1743,17 +1936,22 @@ int guestfs_aug_insert (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_insert");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_INSERT, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_INSERT, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -1804,15 +2002,19 @@ int guestfs_aug_rm (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_rm") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_RM,
         (xdrproc_t) xdr_guestfs_aug_rm_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_rm_reply_cb, &ctx);
@@ -1820,17 +2022,22 @@ int guestfs_aug_rm (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_rm");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_RM, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_RM, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.nrnodes;
 }
 
@@ -1877,6 +2084,7 @@ int guestfs_aug_mv (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_mv") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -1884,9 +2092,12 @@ int guestfs_aug_mv (guestfs_h *g,
   args.dest = (char *) dest;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_MV,
         (xdrproc_t) xdr_guestfs_aug_mv_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_mv_reply_cb, &ctx);
@@ -1894,17 +2105,22 @@ int guestfs_aug_mv (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_mv");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_MV, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_MV, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -1955,15 +2171,19 @@ char **guestfs_aug_match (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_match") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_MATCH,
         (xdrproc_t) xdr_guestfs_aug_match_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_match_reply_cb, &ctx);
@@ -1971,17 +2191,22 @@ char **guestfs_aug_match (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_match");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_MATCH, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_MATCH, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.matches.matches_val =
     safe_realloc (g, ctx.ret.matches.matches_val,
@@ -2030,13 +2255,17 @@ int guestfs_aug_save (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_aug_save") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_SAVE, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_save_reply_cb, &ctx);
@@ -2044,17 +2273,22 @@ int guestfs_aug_save (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_save");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_SAVE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_SAVE, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2098,13 +2332,17 @@ int guestfs_aug_load (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_aug_load") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_LOAD, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_load_reply_cb, &ctx);
@@ -2112,17 +2350,22 @@ int guestfs_aug_load (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_load");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_LOAD, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_LOAD, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2173,15 +2416,19 @@ char **guestfs_aug_ls (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_aug_ls") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_LS,
         (xdrproc_t) xdr_guestfs_aug_ls_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, aug_ls_reply_cb, &ctx);
@@ -2189,17 +2436,22 @@ char **guestfs_aug_ls (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_aug_ls");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_LS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_LS, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.matches.matches_val =
     safe_realloc (g, ctx.ret.matches.matches_val,
@@ -2250,15 +2502,19 @@ int guestfs_rm (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_rm") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_RM,
         (xdrproc_t) xdr_guestfs_rm_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, rm_reply_cb, &ctx);
@@ -2266,17 +2522,22 @@ int guestfs_rm (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_rm");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RM, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RM, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2322,15 +2583,19 @@ int guestfs_rmdir (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_rmdir") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_RMDIR,
         (xdrproc_t) xdr_guestfs_rmdir_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, rmdir_reply_cb, &ctx);
@@ -2338,17 +2603,22 @@ int guestfs_rmdir (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_rmdir");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RMDIR, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RMDIR, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2394,15 +2664,19 @@ int guestfs_rm_rf (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_rm_rf") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_RM_RF,
         (xdrproc_t) xdr_guestfs_rm_rf_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, rm_rf_reply_cb, &ctx);
@@ -2410,17 +2684,22 @@ int guestfs_rm_rf (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_rm_rf");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RM_RF, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RM_RF, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2466,15 +2745,19 @@ int guestfs_mkdir (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_mkdir") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_MKDIR,
         (xdrproc_t) xdr_guestfs_mkdir_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, mkdir_reply_cb, &ctx);
@@ -2482,17 +2765,22 @@ int guestfs_mkdir (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_mkdir");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKDIR, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKDIR, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2538,15 +2826,19 @@ int guestfs_mkdir_p (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_mkdir_p") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_MKDIR_P,
         (xdrproc_t) xdr_guestfs_mkdir_p_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, mkdir_p_reply_cb, &ctx);
@@ -2554,17 +2846,22 @@ int guestfs_mkdir_p (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_mkdir_p");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKDIR_P, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKDIR_P, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2611,6 +2908,7 @@ int guestfs_chmod (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_chmod") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -2618,9 +2916,12 @@ int guestfs_chmod (guestfs_h *g,
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_CHMOD,
         (xdrproc_t) xdr_guestfs_chmod_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, chmod_reply_cb, &ctx);
@@ -2628,17 +2929,22 @@ int guestfs_chmod (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_chmod");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CHMOD, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CHMOD, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2686,6 +2992,7 @@ int guestfs_chown (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_chown") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -2694,9 +3001,12 @@ int guestfs_chown (guestfs_h *g,
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_CHOWN,
         (xdrproc_t) xdr_guestfs_chown_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, chown_reply_cb, &ctx);
@@ -2704,17 +3014,22 @@ int guestfs_chown (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_chown");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CHOWN, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CHOWN, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -2765,15 +3080,19 @@ int guestfs_exists (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_exists") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_EXISTS,
         (xdrproc_t) xdr_guestfs_exists_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, exists_reply_cb, &ctx);
@@ -2781,17 +3100,22 @@ int guestfs_exists (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_exists");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_EXISTS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_EXISTS, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.existsflag;
 }
 
@@ -2842,15 +3166,19 @@ int guestfs_is_file (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_is_file") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_IS_FILE,
         (xdrproc_t) xdr_guestfs_is_file_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, is_file_reply_cb, &ctx);
@@ -2858,17 +3186,22 @@ int guestfs_is_file (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_is_file");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_IS_FILE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_IS_FILE, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.fileflag;
 }
 
@@ -2919,15 +3252,19 @@ int guestfs_is_dir (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_is_dir") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_IS_DIR,
         (xdrproc_t) xdr_guestfs_is_dir_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, is_dir_reply_cb, &ctx);
@@ -2935,17 +3272,22 @@ int guestfs_is_dir (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_is_dir");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_IS_DIR, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_IS_DIR, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.dirflag;
 }
 
@@ -2991,15 +3333,19 @@ int guestfs_pvcreate (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_pvcreate") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_PVCREATE,
         (xdrproc_t) xdr_guestfs_pvcreate_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, pvcreate_reply_cb, &ctx);
@@ -3007,17 +3353,22 @@ int guestfs_pvcreate (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_pvcreate");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVCREATE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVCREATE, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3064,6 +3415,7 @@ int guestfs_vgcreate (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_vgcreate") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -3072,9 +3424,12 @@ int guestfs_vgcreate (guestfs_h *g,
   for (args.physvols.physvols_len = 0; physvols[args.physvols.physvols_len]; args.physvols.physvols_len++) ;
   serial = guestfs__send_sync (g, GUESTFS_PROC_VGCREATE,
         (xdrproc_t) xdr_guestfs_vgcreate_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, vgcreate_reply_cb, &ctx);
@@ -3082,17 +3437,22 @@ int guestfs_vgcreate (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_vgcreate");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGCREATE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGCREATE, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3140,6 +3500,7 @@ int guestfs_lvcreate (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_lvcreate") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -3148,9 +3509,12 @@ int guestfs_lvcreate (guestfs_h *g,
   args.mbytes = mbytes;
   serial = guestfs__send_sync (g, GUESTFS_PROC_LVCREATE,
         (xdrproc_t) xdr_guestfs_lvcreate_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, lvcreate_reply_cb, &ctx);
@@ -3158,17 +3522,22 @@ int guestfs_lvcreate (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_lvcreate");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVCREATE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVCREATE, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3215,6 +3584,7 @@ int guestfs_mkfs (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_mkfs") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -3222,9 +3592,12 @@ int guestfs_mkfs (guestfs_h *g,
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_MKFS,
         (xdrproc_t) xdr_guestfs_mkfs_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, mkfs_reply_cb, &ctx);
@@ -3232,17 +3605,22 @@ int guestfs_mkfs (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_mkfs");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKFS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKFS, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3292,6 +3670,7 @@ int guestfs_sfdisk (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_sfdisk") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -3303,9 +3682,12 @@ int guestfs_sfdisk (guestfs_h *g,
   for (args.lines.lines_len = 0; lines[args.lines.lines_len]; args.lines.lines_len++) ;
   serial = guestfs__send_sync (g, GUESTFS_PROC_SFDISK,
         (xdrproc_t) xdr_guestfs_sfdisk_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, sfdisk_reply_cb, &ctx);
@@ -3313,17 +3695,22 @@ int guestfs_sfdisk (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3371,6 +3758,7 @@ int guestfs_write_file (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_write_file") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -3379,9 +3767,12 @@ int guestfs_write_file (guestfs_h *g,
   args.size = size;
   serial = guestfs__send_sync (g, GUESTFS_PROC_WRITE_FILE,
         (xdrproc_t) xdr_guestfs_write_file_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, write_file_reply_cb, &ctx);
@@ -3389,17 +3780,22 @@ int guestfs_write_file (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_write_file");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_WRITE_FILE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_WRITE_FILE, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3445,15 +3841,19 @@ int guestfs_umount (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_umount") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.pathordevice = (char *) pathordevice;
   serial = guestfs__send_sync (g, GUESTFS_PROC_UMOUNT,
         (xdrproc_t) xdr_guestfs_umount_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, umount_reply_cb, &ctx);
@@ -3461,17 +3861,22 @@ int guestfs_umount (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_umount");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UMOUNT, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UMOUNT, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3520,13 +3925,17 @@ char **guestfs_mounts (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_mounts") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_MOUNTS, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, mounts_reply_cb, &ctx);
@@ -3534,17 +3943,22 @@ char **guestfs_mounts (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_mounts");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNTS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNTS, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.devices.devices_val =
     safe_realloc (g, ctx.ret.devices.devices_val,
@@ -3593,13 +4007,17 @@ int guestfs_umount_all (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_umount_all") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_UMOUNT_ALL, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, umount_all_reply_cb, &ctx);
@@ -3607,17 +4025,22 @@ int guestfs_umount_all (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_umount_all");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UMOUNT_ALL, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UMOUNT_ALL, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3661,13 +4084,17 @@ int guestfs_lvm_remove_all (guestfs_h *g)
   int serial;
 
   if (check_state (g, "guestfs_lvm_remove_all") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   serial = guestfs__send_sync (g, GUESTFS_PROC_LVM_REMOVE_ALL, NULL, NULL);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, lvm_remove_all_reply_cb, &ctx);
@@ -3675,17 +4102,22 @@ int guestfs_lvm_remove_all (guestfs_h *g)
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_lvm_remove_all");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVM_REMOVE_ALL, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVM_REMOVE_ALL, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -3736,15 +4168,19 @@ char *guestfs_file (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_file") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_FILE,
         (xdrproc_t) xdr_guestfs_file_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, file_reply_cb, &ctx);
@@ -3752,17 +4188,22 @@ char *guestfs_file (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_file");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_FILE, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_FILE, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.description; /* caller will free */
 }
 
@@ -3813,6 +4254,7 @@ char *guestfs_command (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_command") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -3820,9 +4262,12 @@ char *guestfs_command (guestfs_h *g,
   for (args.arguments.arguments_len = 0; arguments[args.arguments.arguments_len]; args.arguments.arguments_len++) ;
   serial = guestfs__send_sync (g, GUESTFS_PROC_COMMAND,
         (xdrproc_t) xdr_guestfs_command_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, command_reply_cb, &ctx);
@@ -3830,17 +4275,22 @@ char *guestfs_command (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_command");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_COMMAND, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_COMMAND, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.output; /* caller will free */
 }
 
@@ -3891,6 +4341,7 @@ char **guestfs_command_lines (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_command_lines") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -3898,9 +4349,12 @@ char **guestfs_command_lines (guestfs_h *g,
   for (args.arguments.arguments_len = 0; arguments[args.arguments.arguments_len]; args.arguments.arguments_len++) ;
   serial = guestfs__send_sync (g, GUESTFS_PROC_COMMAND_LINES,
         (xdrproc_t) xdr_guestfs_command_lines_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, command_lines_reply_cb, &ctx);
@@ -3908,17 +4362,22 @@ char **guestfs_command_lines (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_command_lines");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_COMMAND_LINES, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_COMMAND_LINES, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.lines.lines_val =
     safe_realloc (g, ctx.ret.lines.lines_val,
@@ -3974,15 +4433,19 @@ struct guestfs_stat *guestfs_stat (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_stat") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_STAT,
         (xdrproc_t) xdr_guestfs_stat_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, stat_reply_cb, &ctx);
@@ -3990,17 +4453,22 @@ struct guestfs_stat *guestfs_stat (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_stat");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_STAT, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_STAT, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this */
   return safe_memdup (g, &ctx.ret.statbuf, sizeof (ctx.ret.statbuf));
 }
@@ -4052,15 +4520,19 @@ struct guestfs_stat *guestfs_lstat (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_lstat") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_LSTAT,
         (xdrproc_t) xdr_guestfs_lstat_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, lstat_reply_cb, &ctx);
@@ -4068,17 +4540,22 @@ struct guestfs_stat *guestfs_lstat (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_lstat");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LSTAT, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LSTAT, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this */
   return safe_memdup (g, &ctx.ret.statbuf, sizeof (ctx.ret.statbuf));
 }
@@ -4130,15 +4607,19 @@ struct guestfs_statvfs *guestfs_statvfs (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_statvfs") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.path = (char *) path;
   serial = guestfs__send_sync (g, GUESTFS_PROC_STATVFS,
         (xdrproc_t) xdr_guestfs_statvfs_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, statvfs_reply_cb, &ctx);
@@ -4146,17 +4627,22 @@ struct guestfs_statvfs *guestfs_statvfs (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_statvfs");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_STATVFS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_STATVFS, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this */
   return safe_memdup (g, &ctx.ret.statbuf, sizeof (ctx.ret.statbuf));
 }
@@ -4208,15 +4694,19 @@ char **guestfs_tune2fs_l (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_tune2fs_l") == -1) return NULL;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_TUNE2FS_L,
         (xdrproc_t) xdr_guestfs_tune2fs_l_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, tune2fs_l_reply_cb, &ctx);
@@ -4224,17 +4714,22 @@ char **guestfs_tune2fs_l (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_tune2fs_l");
+    guestfs_set_ready (g);
     return NULL;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TUNE2FS_L, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TUNE2FS_L, serial) == -1) {
+    guestfs_set_ready (g);
     return NULL;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return NULL;
   }
 
+  guestfs_set_ready (g);
   /* caller will free this, but we need to add a NULL entry */
   ctx.ret.superblock.superblock_val =
     safe_realloc (g, ctx.ret.superblock.superblock_val,
@@ -4285,15 +4780,19 @@ int guestfs_blockdev_setro (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_setro") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_SETRO,
         (xdrproc_t) xdr_guestfs_blockdev_setro_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_setro_reply_cb, &ctx);
@@ -4301,17 +4800,22 @@ int guestfs_blockdev_setro (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setro");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETRO, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETRO, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -4357,15 +4861,19 @@ int guestfs_blockdev_setrw (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_setrw") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_SETRW,
         (xdrproc_t) xdr_guestfs_blockdev_setrw_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_setrw_reply_cb, &ctx);
@@ -4373,17 +4881,22 @@ int guestfs_blockdev_setrw (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setrw");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETRW, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETRW, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -4434,15 +4947,19 @@ int guestfs_blockdev_getro (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_getro") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETRO,
         (xdrproc_t) xdr_guestfs_blockdev_getro_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_getro_reply_cb, &ctx);
@@ -4450,17 +4967,22 @@ int guestfs_blockdev_getro (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getro");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETRO, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETRO, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.ro;
 }
 
@@ -4511,15 +5033,19 @@ int guestfs_blockdev_getss (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_getss") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETSS,
         (xdrproc_t) xdr_guestfs_blockdev_getss_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_getss_reply_cb, &ctx);
@@ -4527,17 +5053,22 @@ int guestfs_blockdev_getss (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getss");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSS, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.sectorsize;
 }
 
@@ -4588,15 +5119,19 @@ int guestfs_blockdev_getbsz (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_getbsz") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETBSZ,
         (xdrproc_t) xdr_guestfs_blockdev_getbsz_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_getbsz_reply_cb, &ctx);
@@ -4604,17 +5139,22 @@ int guestfs_blockdev_getbsz (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getbsz");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETBSZ, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETBSZ, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.blocksize;
 }
 
@@ -4661,6 +5201,7 @@ int guestfs_blockdev_setbsz (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_setbsz") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
@@ -4668,9 +5209,12 @@ int guestfs_blockdev_setbsz (guestfs_h *g,
   args.blocksize = blocksize;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_SETBSZ,
         (xdrproc_t) xdr_guestfs_blockdev_setbsz_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_setbsz_reply_cb, &ctx);
@@ -4678,17 +5222,22 @@ int guestfs_blockdev_setbsz (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setbsz");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETBSZ, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETBSZ, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -4739,15 +5288,19 @@ int64_t guestfs_blockdev_getsz (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_getsz") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETSZ,
         (xdrproc_t) xdr_guestfs_blockdev_getsz_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_getsz_reply_cb, &ctx);
@@ -4755,17 +5308,22 @@ int64_t guestfs_blockdev_getsz (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getsz");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSZ, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSZ, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.sizeinsectors;
 }
 
@@ -4816,15 +5374,19 @@ int64_t guestfs_blockdev_getsize64 (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_getsize64") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETSIZE64,
         (xdrproc_t) xdr_guestfs_blockdev_getsize64_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_getsize64_reply_cb, &ctx);
@@ -4832,17 +5394,22 @@ int64_t guestfs_blockdev_getsize64 (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getsize64");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSIZE64, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSIZE64, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return ctx.ret.sizeinbytes;
 }
 
@@ -4888,15 +5455,19 @@ int guestfs_blockdev_flushbufs (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_flushbufs") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS,
         (xdrproc_t) xdr_guestfs_blockdev_flushbufs_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_flushbufs_reply_cb, &ctx);
@@ -4904,17 +5475,22 @@ int guestfs_blockdev_flushbufs (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_flushbufs");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -4960,15 +5536,19 @@ int guestfs_blockdev_rereadpt (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_blockdev_rereadpt") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.device = (char *) device;
   serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_REREADPT,
         (xdrproc_t) xdr_guestfs_blockdev_rereadpt_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, blockdev_rereadpt_reply_cb, &ctx);
@@ -4976,17 +5556,22 @@ int guestfs_blockdev_rereadpt (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_rereadpt");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_REREADPT, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_REREADPT, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -5033,18 +5618,31 @@ int guestfs_upload (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_upload") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.remotefilename = (char *) remotefilename;
   serial = guestfs__send_sync (g, GUESTFS_PROC_UPLOAD,
         (xdrproc_t) xdr_guestfs_upload_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
-  if (guestfs__send_file_sync (g, filename) == -1)
-    return -1;
+  {
+    int r;
+
+    r = guestfs__send_file_sync (g, filename);
+    if (r == -1) {
+      guestfs_set_ready (g);
+      return -1;
+    }
+    if (r == -2) /* daemon cancelled */
+      goto read_reply;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, upload_reply_cb, &ctx);
@@ -5052,17 +5650,22 @@ int guestfs_upload (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_upload");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UPLOAD, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UPLOAD, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
@@ -5109,15 +5712,19 @@ int guestfs_download (guestfs_h *g,
   int serial;
 
   if (check_state (g, "guestfs_download") == -1) return -1;
+  guestfs_set_busy (g);
 
   memset (&ctx, 0, sizeof ctx);
 
   args.remotefilename = (char *) remotefilename;
   serial = guestfs__send_sync (g, GUESTFS_PROC_DOWNLOAD,
         (xdrproc_t) xdr_guestfs_download_args, (char *) &args);
-  if (serial == -1)
+  if (serial == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+ read_reply:
   guestfs__switch_to_receiving (g);
   ctx.cb_sequence = 0;
   guestfs_set_reply_callback (g, download_reply_cb, &ctx);
@@ -5125,20 +5732,27 @@ int guestfs_download (guestfs_h *g,
   guestfs_set_reply_callback (g, NULL, NULL);
   if (ctx.cb_sequence != 1001) {
     error (g, "%s reply failed, see earlier error messages", "guestfs_download");
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DOWNLOAD, serial) == -1)
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DOWNLOAD, serial) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
   if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
     error (g, "%s", ctx.err.error_message);
+    guestfs_set_ready (g);
     return -1;
   }
 
-  if (guestfs__receive_file_sync (g, filename) == -1)
+  if (guestfs__receive_file_sync (g, filename) == -1) {
+    guestfs_set_ready (g);
     return -1;
+  }
 
+  guestfs_set_ready (g);
   return 0;
 }
 
index 2ec2d40..e3c3cf8 100644 (file)
@@ -36,6 +36,8 @@ extern int guestfs_is_config (guestfs_h *handle);
 extern int guestfs_is_launching (guestfs_h *handle);
 extern int guestfs_is_busy (guestfs_h *handle);
 extern int guestfs_get_state (guestfs_h *handle);
+extern int guestfs_set_busy (guestfs_h *handle);
+extern int guestfs_set_ready (guestfs_h *handle);
 extern int guestfs_mount (guestfs_h *handle, const char *device, const char *mountpoint);
 extern int guestfs_sync (guestfs_h *handle);
 extern int guestfs_touch (guestfs_h *handle, const char *path);
index cad2cad..1b7d61c 100644 (file)
 #include "guestfs.h"
 #include "guestfs_protocol.h"
 
-void guestfs_error (guestfs_h *g, const char *fs, ...);
-void guestfs_perrorf (guestfs_h *g, const char *fs, ...);
-void *guestfs_safe_malloc (guestfs_h *g, size_t nbytes);
-void *guestfs_safe_realloc (guestfs_h *g, void *ptr, int nbytes);
-char *guestfs_safe_strdup (guestfs_h *g, const char *str);
-void *guestfs_safe_memdup (guestfs_h *g, void *ptr, size_t size);
-
 #define error guestfs_error
 #define perrorf guestfs_perrorf
 #define safe_malloc guestfs_safe_malloc
@@ -423,10 +416,26 @@ xwrite (int fd, const void *buf, size_t len)
 
   while (len > 0) {
     r = write (fd, buf, len);
-    if (r == -1) {
-      perror ("write");
+    if (r == -1)
       return -1;
-    }
+
+    buf += r;
+    len -= r;
+  }
+
+  return 0;
+}
+
+static int
+xread (int fd, void *buf, size_t len)
+{
+  int r;
+
+  while (len > 0) {
+    r = read (fd, buf, len);
+    if (r == -1)
+      return -1;
+
     buf += r;
     len -= r;
   }
@@ -715,7 +724,9 @@ guestfs_launch (guestfs_h *g)
 
     /* Linux kernel command line. */
     snprintf (append, sizeof append,
-             "console=ttyS0 guestfs=%s:%d", VMCHANNEL_ADDR, VMCHANNEL_PORT);
+             "console=ttyS0 guestfs=%s:%d%s",
+             VMCHANNEL_ADDR, VMCHANNEL_PORT,
+             g->verbose ? " guestfs_verbose=1" : "");
 
     add_cmdline (g, "-m");
     add_cmdline (g, "384");      /* XXX Choose best size. */
@@ -981,6 +992,28 @@ guestfs_get_state (guestfs_h *g)
   return g->state;
 }
 
+int
+guestfs_set_ready (guestfs_h *g)
+{
+  if (g->state != BUSY) {
+    error (g, "guestfs_set_ready: called when in state %d != BUSY", g->state);
+    return -1;
+  }
+  g->state = READY;
+  return 0;
+}
+
+int
+guestfs_set_busy (guestfs_h *g)
+{
+  if (g->state != READY) {
+    error (g, "guestfs_set_busy: called when in state %d != READY", g->state);
+    return -1;
+  }
+  g->state = BUSY;
+  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.
@@ -1119,6 +1152,7 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
   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);
@@ -1131,7 +1165,7 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
    * starts up it sends a "magic" value (longer than any possible
    * message).  Check for this.
    */
-  if (len == 0xf5f55ff5) {
+  if (len == GUESTFS_LAUNCH_FLAG) {
     if (g->state != LAUNCHING)
       error (g, "received magic signature from guestfsd, but in state %d",
             g->state);
@@ -1147,7 +1181,19 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
     goto cleanup;
   }
 
-  /* If this happens, it's pretty bad and we've probably lost synchronization.*/
+  /* 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);
@@ -1156,14 +1202,6 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
 
   if (g->msg_in_size-4 < len) return; /* Need more of this message. */
 
-  /* This should not happen, and if it does it probably means we've
-   * lost all hope of synchronization.
-   */
-  if (g->msg_in_size-4 > len) {
-    error (g, "len = %d, but msg_in_size-4 = %d", len, g->msg_in_size-4);
-    goto cleanup;
-  }
-
   /* Got the full message, begin processing it. */
   if (g->verbose) {
     int i, j;
@@ -1191,10 +1229,13 @@ sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
     error (g, "state %d != BUSY", g->state);
 
   /* Push the message up to the higher layer. */
-  g->state = READY;
   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) {
@@ -1253,7 +1294,7 @@ sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
     return;
 
   if (g->verbose)
-    fprintf (stderr, "sock_write_event: done writing, switching back to reading events\n");
+    fprintf (stderr, "sock_write_event: done writing, calling send_cb\n");
 
   free (g->msg_out);
   g->msg_out = NULL;
@@ -1398,8 +1439,8 @@ guestfs__send_sync (guestfs_h *g, int proc_nr,
   int sent;
   guestfs_main_loop *ml = guestfs_get_main_loop (g);
 
-  if (g->state != READY) {
-    error (g, "dispatch: state %d != READY", g->state);
+  if (g->state != BUSY) {
+    error (g, "guestfs__send_sync: state %d != BUSY", g->state);
     return -1;
   }
 
@@ -1435,13 +1476,9 @@ guestfs__send_sync (guestfs_h *g, int proc_nr,
 
   g->msg_out_size = len + 4;
   g->msg_out_pos = 0;
-  g->state = BUSY;
 
   xdrmem_create (&xdr, g->msg_out, 4, XDR_ENCODE);
-  if (!xdr_uint32_t (&xdr, &len)) {
-    error (g, "xdr_uint32_t failed in dispatch");
-    goto cleanup1;
-  }
+  xdr_uint32_t (&xdr, &len);
 
   memcpy (g->msg_out + 4, buffer, len);
 
@@ -1463,7 +1500,6 @@ guestfs__send_sync (guestfs_h *g, int proc_nr,
   free (g->msg_out);
   g->msg_out = NULL;
   g->msg_out_size = 0;
-  g->state = READY;
   return -1;
 }
 
@@ -1473,12 +1509,17 @@ 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. */
+/* 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;
+  int fd, r, err;
 
   fd = open (filename, O_RDONLY);
   if (fd == -1) {
@@ -1492,8 +1533,9 @@ guestfs__send_file_sync (guestfs_h *g, const char *filename)
 
   /* Send file in chunked encoding. */
   while (!cancel && (r = read (fd, buf, sizeof buf)) > 0) {
-    if (send_file_data_sync (g, buf, r) == -1)
-      return -1;
+    err = send_file_data_sync (g, buf, r);
+    if (err < 0)
+      return err;
   }
 
   if (cancel) {
@@ -1530,8 +1572,7 @@ send_file_data_sync (guestfs_h *g, const char *buf, size_t len)
 static int
 send_file_cancellation_sync (guestfs_h *g)
 {
-  char buf[1];
-  return send_file_chunk_sync (g, 1, buf, 0);
+  return send_file_chunk_sync (g, 1, NULL, 0);
 }
 
 /* Send a file complete chunk. */
@@ -1545,10 +1586,12 @@ send_file_complete_sync (guestfs_h *g)
 /* 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)
 {
-  void *data;
+  char data[GUESTFS_MAX_CHUNK_SIZE + 48];
   unsigned datalen;
   int sent;
   guestfs_chunk chunk;
@@ -1556,31 +1599,39 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t len)
   guestfs_main_loop *ml = guestfs_get_main_loop (g);
 
   if (g->state != BUSY) {
-    error (g, "send_file_chunk: state %d != READY", g->state);
+    error (g, "send_file_chunk_sync: state %d != READY", g->state);
     return -1;
   }
 
+  /* Did the daemon send a cancellation message? */
+  if (check_for_daemon_cancellation (g))
+    return -2;
+
   /* Serialize the chunk. */
   chunk.cancel = cancel;
   chunk.data.data_len = len;
   chunk.data.data_val = (char *) buf;
 
-  data = safe_malloc (g, GUESTFS_MAX_CHUNK_SIZE + 48);
-  xdrmem_create (&xdr, data, GUESTFS_MAX_CHUNK_SIZE + 48, XDR_ENCODE);
-  if (xdr_guestfs_chunk (&xdr, &chunk)) {
-    error (g, "xdr_guestfs_chunk failed");
-    free (data);
+  xdrmem_create (&xdr, data, sizeof data, XDR_ENCODE);
+  if (!xdr_guestfs_chunk (&xdr, &chunk)) {
+    error (g, "xdr_guestfs_chunk failed (buf = %p, len = %zu)", buf, len);
+    xdr_destroy (&xdr);
     return -1;
   }
 
   datalen = xdr_getpos (&xdr);
   xdr_destroy (&xdr);
 
-  data = safe_realloc (g, data, datalen);
-  g->msg_out = data;
-  g->msg_out_size = datalen;
+  /* Allocate outgoing message buffer. */
+  g->msg_out = safe_malloc (g, datalen + 4);
+  g->msg_out_size = datalen + 4;
   g->msg_out_pos = 0;
 
+  xdrmem_create (&xdr, g->msg_out, 4, XDR_ENCODE);
+  xdr_uint32_t (&xdr, &datalen);
+
+  memcpy (g->msg_out + 4, data, datalen);
+
   if (guestfs__switch_to_sending (g) == -1)
     goto cleanup1;
 
@@ -1599,14 +1650,57 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t len)
   free (g->msg_out);
   g->msg_out = NULL;
   g->msg_out_size = 0;
-  g->state = READY;
   return -1;
 }
 
-/* Synchronously receive a file.
- * XXX No way to cancel file receives.  We would need to send an
- * error to the daemon and have it see this and stop sending.
+/* At this point we are sending FileIn file(s) to the guest, and not
+ * expecting to read anything, so if we do read anything, it must be
+ * a cancellation message.  This checks for this case without blocking.
  */
+static int
+check_for_daemon_cancellation (guestfs_h *g)
+{
+  fd_set rset;
+  struct timeval tv;
+  int r;
+  char buf[4];
+  uint32_t flag;
+  XDR xdr;
+
+  FD_ZERO (&rset);
+  FD_SET (g->sock, &rset);
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+  r = select (g->sock+1, &rset, NULL, NULL, &tv);
+  if (r == -1) {
+    perrorf (g, "select");
+    return 0;
+  }
+  if (r == 0)
+    return 0;
+
+  /* Read the message from the daemon. */
+  r = xread (g->sock, buf, sizeof buf);
+  if (r == -1) {
+    perrorf (g, "read");
+    return 0;
+  }
+
+  xdrmem_create (&xdr, buf, sizeof buf, XDR_DECODE);
+  xdr_uint32_t (&xdr, &flag);
+  xdr_destroy (&xdr);
+
+  if (flag != GUESTFS_CANCEL_FLAG) {
+    error (g, "check_for_daemon_cancellation: read 0x%x from daemon, expected 0x%x\n",
+          flag, GUESTFS_CANCEL_FLAG);
+    return 0;
+  }
+
+  return 1;
+}
+
+/* Synchronously receive a file. */
+
 static int receive_file_data_sync (guestfs_h *g, void **buf);
 
 int
@@ -1615,17 +1709,18 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename)
   void *buf;
   int fd, r;
 
-  fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY);
+  fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
   if (fd == -1) {
     perrorf (g, "open: %s", filename);
-    return -1;
+    goto cancel;
   }
 
   /* Receive the file in chunked encoding. */
   while ((r = receive_file_data_sync (g, &buf)) > 0) {
     if (xwrite (fd, buf, r) == -1) {
+      perrorf (g, "%s: write", filename);
       free (buf);
-      return -1;
+      goto cancel;
     }
     free (buf);
   }
@@ -1641,6 +1736,28 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename)
   }
 
   return 0;
+
+ cancel: ;
+  /* Send cancellation message to daemon, then wait until it
+   * cancels (just throwing away data).
+   */
+  XDR xdr;
+  char fbuf[4];
+  uint32_t flag = GUESTFS_CANCEL_FLAG;
+
+  xdrmem_create (&xdr, fbuf, sizeof fbuf, XDR_ENCODE);
+  xdr_uint32_t (&xdr, &flag);
+  xdr_destroy (&xdr);
+
+  if (xwrite (g->sock, fbuf, sizeof fbuf) == -1) {
+    perrorf (g, "write to daemon socket");
+    return -1;
+  }
+
+  while ((r = receive_file_data_sync (g, &buf)) > 0)
+    free (buf);                        /* just discard it */
+
+  return -1;
 }
 
 struct receive_file_ctx {
@@ -1657,6 +1774,8 @@ receive_file_cb (guestfs_h *g, void *data, XDR *xdr)
 
   ml->main_loop_quit (ml, g);
 
+  memset (&chunk, 0, sizeof chunk);
+
   if (!xdr_guestfs_chunk (xdr, &chunk)) {
     error (g, "failed to parse file chunk");
     ctx->code = -1;
@@ -1689,6 +1808,10 @@ receive_file_data_sync (guestfs_h *g, void **buf)
   guestfs_set_reply_callback (g, receive_file_cb, &ctx);
   (void) ml->main_loop_run (ml, g);
   guestfs_set_reply_callback (g, NULL, NULL);
+
+  if (g->verbose)
+    fprintf (stderr, "receive_file_data_sync: code %d\n", ctx.code);
+
   switch (ctx.code) {
   case 0:                      /* end of file */
     return 0;
@@ -1872,10 +1995,9 @@ select_main_loop_quit (guestfs_main_loop *mlv, guestfs_h *g)
 {
   struct select_main_loop *ml = (struct select_main_loop *) mlv;
 
-  if (!ml->is_running) {
-    error (g, "cannot quit, we are not running in a main loop");
-    return -1;
-  }
+  /* Note that legitimately ml->is_running can be zero when
+   * this function is called.
+   */
 
   ml->is_running = 0;
   return 0;
index 8a349df..823fefe 100644 (file)
@@ -67,8 +67,10 @@ extern void guestfs_set_log_message_callback (guestfs_h *g, guestfs_log_message_
 extern void guestfs_set_subprocess_quit_callback (guestfs_h *g, guestfs_subprocess_quit_cb cb, void *opaque);
 extern void guestfs_set_launch_done_callback (guestfs_h *g, guestfs_launch_done_cb cb, void *opaque);
 
-extern void guestfs_error (guestfs_h *g, const char *fs, ...);
-extern void guestfs_perrorf (guestfs_h *g, const char *fs, ...);
+extern void guestfs_error (guestfs_h *g, const char *fs, ...)
+  __attribute__((format (printf,2,3)));
+extern void guestfs_perrorf (guestfs_h *g, const char *fs, ...)
+  __attribute__((format (printf,2,3)));
 extern void *guestfs_safe_malloc (guestfs_h *g, size_t nbytes);
 extern void *guestfs_safe_realloc (guestfs_h *g, void *ptr, int nbytes);
 extern char *guestfs_safe_strdup (guestfs_h *g, const char *str);
index 0747a38..4c3f1cd 100644 (file)
@@ -700,6 +700,8 @@ typedef enum guestfs_procedure guestfs_procedure;
 #define GUESTFS_MESSAGE_MAX 4194304
 #define GUESTFS_PROGRAM 0x2000F5F5
 #define GUESTFS_PROTOCOL_VERSION 1
+#define GUESTFS_LAUNCH_FLAG 0xf5f55ff5
+#define GUESTFS_CANCEL_FLAG 0xffffeeee
 
 enum guestfs_message_direction {
        GUESTFS_DIRECTION_CALL = 0,
index 4291809..ff4713f 100644 (file)
@@ -556,9 +556,17 @@ enum guestfs_procedure {
 
 const GUESTFS_MESSAGE_MAX = 4194304;
 
+/* The communication protocol is now documented in the guestfs(3)
+ * manpage.
+ */
+
 const GUESTFS_PROGRAM = 0x2000F5F5;
 const GUESTFS_PROTOCOL_VERSION = 1;
 
+/* These constants must be larger than any possible message length. */
+const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
+const GUESTFS_CANCEL_FLAG = 0xffffeeee;
+
 enum guestfs_message_direction {
   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
@@ -575,19 +583,6 @@ struct guestfs_message_error {
   string error_message<GUESTFS_ERROR_LEN>;
 };
 
-/* For normal requests and replies (not involving any FileIn or
- * FileOut parameters), the protocol is:
- *
- * For requests:
- *   total length (header + args, but not including length word itself)
- *   header
- *   guestfs_foo_args struct
- * For replies:
- *   total length (as above)
- *   header
- *   guestfs_foo_ret struct
- */
-
 struct guestfs_message_header {
   unsigned prog;                     /* GUESTFS_PROGRAM */
   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
@@ -597,23 +592,6 @@ struct guestfs_message_header {
   guestfs_message_status status;
 };
 
-/* Chunked encoding used to transfer files, for FileIn and FileOut
- * parameters.
- *
- * For requests which have >= 1 FileIn parameter:
- *   length of header + args (but not length word itself, and not chunks)
- *   header
- *   guestfs_foo_args struct
- *   sequence of chunks for FileIn param #0
- *   sequence of chunks for FileIn param #1 etc
- *
- * For replies which have >= 1 FileOut parameter:
- *   length of header + ret (but not length word itself, and not chunks)
- *   header
- *   guestfs_foo_ret struct
- *   sequence of chunks for FileOut param #0
- *   sequence of chunks for FileOut param #1 etc
- */
 const GUESTFS_MAX_CHUNK_SIZE = 8192;
 
 struct guestfs_chunk {
diff --git a/tests.c b/tests.c
index f1cf32a..bd541be 100644 (file)
--- a/tests.c
+++ b/tests.c
@@ -74,6 +74,8 @@ static void no_test_warnings (void)
   fprintf (stderr, "warning: \"guestfs_is_launching\" has no tests\n");
   fprintf (stderr, "warning: \"guestfs_is_busy\" has no tests\n");
   fprintf (stderr, "warning: \"guestfs_get_state\" has no tests\n");
+  fprintf (stderr, "warning: \"guestfs_set_busy\" has no tests\n");
+  fprintf (stderr, "warning: \"guestfs_set_ready\" has no tests\n");
   fprintf (stderr, "warning: \"guestfs_ll\" has no tests\n");
   fprintf (stderr, "warning: \"guestfs_pvs_full\" has no tests\n");
   fprintf (stderr, "warning: \"guestfs_vgs_full\" has no tests\n");