Rewrite of main loop impl, start of FileIn/FileOut support.
authorRichard Jones <rjones@redhat.com>
Sat, 18 Apr 2009 12:17:12 +0000 (13:17 +0100)
committerRichard Jones <rjones@redhat.com>
Sat, 18 Apr 2009 12:17:12 +0000 (13:17 +0100)
17 files changed:
daemon/Makefile.am
daemon/daemon.h
daemon/upload.c [new file with mode: 0644]
fish/cmds.c
guestfish-actions.pod
guestfs-actions.pod
guestfs.pod
perl/lib/Sys/Guestfs.pm
python/guestfs-py.c
python/guestfs.py
src/generator.ml
src/guestfs-actions.c
src/guestfs.c
src/guestfs.h
src/guestfs_protocol.c
src/guestfs_protocol.h
src/guestfs_protocol.x

index 75de066..1c1609d 100644 (file)
@@ -36,6 +36,7 @@ guestfsd_SOURCES = \
        stubs.c \
        sync.c \
        tune2fs.c \
+       upload.c \
        ../src/guestfs_protocol.h \
        ../src/guestfs_protocol.c
 
index 27d86c9..ca71265 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "../src/guestfs_protocol.h"
 
-/* in guestfsd.c */
+/*-- in guestfsd.c --*/
 extern int xwrite (int sock, const void *buf, size_t len);
 extern int xread (int sock, void *buf, size_t len);
 
@@ -44,25 +44,37 @@ extern int command (char **stdoutput, char **stderror, const char *name, ...);
 extern int commandv (char **stdoutput, char **stderror,
                     char * const* const argv);
 
-/* in proto.c */
+/*-- in proto.c --*/
 extern int proc_nr;
 extern int serial;
 
-/* in mount.c */
+/*-- in mount.c --*/
 extern int root_mounted;
 
-/* in stubs.c (auto-generated) */
+/*-- in stubs.c (auto-generated) --*/
 extern void dispatch_incoming_message (XDR *);
 extern guestfs_lvm_int_pv_list *parse_command_line_pvs (void);
 extern guestfs_lvm_int_vg_list *parse_command_line_vgs (void);
 extern guestfs_lvm_int_lv_list *parse_command_line_lvs (void);
 
-/* in proto.c */
+/*-- in proto.c --*/
 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, ...);
+
+/* daemon functions that return files (FileOut) should call
+ * reply, then send_file for each FileOut parameter.
+ */
+#if 0
+extern void send_file ();
+#endif
+
+/* only call this if there is a FileOut parameter */
 extern void reply (xdrproc_t xdrp, char *ret);
 
+/* Helper for functions that need a root filesystem mounted. */
 #define NEED_ROOT(errcode)                                             \
   do {                                                                 \
     if (!root_mounted) {                                               \
@@ -72,6 +84,7 @@ extern void reply (xdrproc_t xdrp, char *ret);
   }                                                                    \
   while (0)
 
+/* Helper for functions that need an argument ("path") that is absolute. */
 #define ABS_PATH(path,errcode)                                         \
   do {                                                                 \
     if ((path)[0] != '/') {                                            \
@@ -80,6 +93,7 @@ extern void reply (xdrproc_t xdrp, char *ret);
     }                                                                  \
   } while (0)
 
+/* Helper for functions that need an argument ("path") that is a device. */
 #define IS_DEVICE(path,errcode)                                                \
   do {                                                                 \
     struct stat statbuf;                                               \
@@ -104,6 +118,7 @@ extern void reply (xdrproc_t xdrp, char *ret);
 #define CHROOT_OUT \
   do { int old_errno = errno; chroot ("."); errno = old_errno; } while (0)
 
+/* Marks functions which are not implemented. */
 #define XXX_NOT_IMPL(errcode)                                          \
   do {                                                                 \
     reply_with_error ("%s: function not implemented", __func__);       \
diff --git a/daemon/upload.c b/daemon/upload.c
new file mode 100644 (file)
index 0000000..d2feb02
--- /dev/null
@@ -0,0 +1,40 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 Red Hat Inc. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "../src/guestfs_protocol.h"
+#include "daemon.h"
+#include "actions.h"
+
+int
+do_upload (const char *remote_filename)
+{
+  XXX_NOT_IMPL (-1);
+}
+
+int
+do_download (const char *remote_filename)
+{
+  XXX_NOT_IMPL (-1);
+}
index 8ee72d2..c197ece 100644 (file)
@@ -155,7 +155,7 @@ void display_command (const char *cmd)
     pod2text ("touch - update file timestamps or create a new file", " touch <path>\n\nTouch acts like the L<touch(1)> command.  It can be used to\nupdate the timestamps on a file, or, if the file does not exist,\nto create a new zero-length file.");
   else
   if (strcasecmp (cmd, "cat") == 0)
-    pod2text ("cat - list the contents of a file", " cat <path>\n\nReturn the contents of the file named C<path>.\n\nNote that this function cannot correctly handle binary files\n(specifically, files containing C<\\0> character which is treated\nas end of string).  For those you need to use the C<read_file>\nfunction which has a more complex interface.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB.  To transfer large files you should use\nFTP.");
+    pod2text ("cat - list the contents of a file", " cat <path>\n\nReturn the contents of the file named C<path>.\n\nNote that this function cannot correctly handle binary files\n(specifically, files containing C<\\0> character which is treated\nas end of string).  For those you need to use the C<download>\nfunction which has a more complex interface.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB.  To transfer large files you should use\nFTP.");
   else
   if (strcasecmp (cmd, "ll") == 0)
     pod2text ("ll - list the files in a directory (long format)", " ll <directory>\n\nList the files in C<directory> (relative to the root directory,\nthere is no cwd) in the format of 'ls -la'.\n\nThis command is mostly useful for interactive sessions.  It\nis I<not> intended that you try to parse the output string.");
index d4c0401..116878d 100644 (file)
@@ -289,7 +289,7 @@ Return the contents of the file named C<path>.
 
 Note that this function cannot correctly handle binary files
 (specifically, files containing C<\0> character which is treated
-as end of string).  For those you need to use the C<read_file>
+as end of string).  For those you need to use the C<download>
 function which has a more complex interface.
 
 Because of the message protocol, there is a transfer limit 
index cb2415c..520425c 100644 (file)
@@ -378,7 +378,7 @@ Return the contents of the file named C<path>.
 
 Note that this function cannot correctly handle binary files
 (specifically, files containing C<\0> character which is treated
-as end of string).  For those you need to use the C<guestfs_read_file>
+as end of string).  For those you need to use the C<guestfs_download>
 function which has a more complex interface.
 
 This function returns a string, or NULL on error.
index 6c01600..cce7b90 100644 (file)
@@ -86,9 +86,8 @@ C<guestfs_h> is the opaque type representing a connection handle.
 Create a handle by calling C<guestfs_create>.  Call C<guestfs_close>
 to free the handle and release all resources used.
 
-Handles and operations on handles are not thread safe.  However you
-can use a separate handle for each thread (but not on the same disk
-image).
+For information on using multiple handles and threads, see the section
+MULTIPLE HANDLES AND MULTIPLE THREADS below.
 
 =head2 guestfs_create
 
@@ -312,34 +311,21 @@ this function with C<cb> set to C<NULL>.
 
 =head2 NON-BLOCKING ACTIONS
 
-XXX NOT IMPLEMENTED YET XXX
+XXX This section was documented in previous versions but never
+implemented in a way which matched the documentation.  For now I have
+removed the documentation, pending a working implementation.  See also
+C<src/guestfs-actions.c> in the source.
 
-C<guestfs_set_reply_callback> is the most interesting callback to
-play with, since it allows you to perform actions without blocking.
 
-For example:
+=head2 guestfs_set_send_callback
 
- do_it ()
- {
-   start_call ();
-   guestfs_main_loop_run (); /* --> blocks, then calls my_cb */
- }
+ typedef void (*guestfs_send_cb) (guestfs_h *g, void *opaque);
+ void guestfs_set_send_callback (guestfs_h *handle,
+                                 guestfs_send_cb cb,
+                                 void *opaque);
 
- start_call ()
- {
-   guestfs_set_reply_callback (handle, my_cb, data);
-   guestfs_nb_[action] (handle, [other parameters ...]);
-   /* returns immediately */
- }
- my_cb (guestfs_h *handle, void *data, XDR *xdr)
- {
-   retval = guestfs_nb_[action]_r (handle, xdr);
-   /* ... */
- }
-
-There are C<guestfs_nb_*> and C<guestfs_nb_*_r> functions
-corresponding to every C<guestfs_*> action in the high-level API.
+The callback function C<cb> will be called whenever a message
+which is queued for sending, has been sent.
 
 =head2 guestfs_set_reply_callback
 
@@ -400,9 +386,10 @@ non-blocking wait for the child process to finish booting up.
 
 =head2 EVENT MAIN LOOP
 
-To use the low-level event API, you have to provide an event "main
-loop".  You can write your own, but if you don't want to write one,
-two are provided for you:
+To use the low-level event API and/or to use handles from multiple
+threads, you have to provide an event "main loop".  You can write your
+own, but if you don't want to write one, two types are provided for
+you:
 
 =over 4
 
@@ -410,8 +397,8 @@ two are provided for you:
 
 A simple main loop that is implemented using L<select(2)>.
 
-This is the default main loop unless you call C<guestfs_set_main_loop>
-or C<guestfs_glib_set_main_loop>.
+This is the default main loop for new guestfs handles, unless you
+call C<guestfs_set_main_loop> after a handle is created.
 
 =item libguestfs-glib
 
@@ -421,67 +408,83 @@ without hanging during long or slow operations.
 
 =back
 
-=head2 guestfs_set_main_loop
+=head2 MULTIPLE HANDLES AND MULTIPLE THREADS
+
+The support for multiple handles and multiple threads is modelled
+after glib (although doesn't require glib, if you use the select-based
+main loop).
+
+L<http://library.gnome.org/devel/glib/unstable/glib-The-Main-Event-Loop.html>
+
+You will need to create one main loop for each thread that wants to
+use libguestfs.  Each guestfs handle should be confined to one thread.
+If you try to pass guestfs handles between threads, you will get
+undefined results.
+
+If you only want to use guestfs handles from one thread in your
+program, but your program has other threads doing other things, then
+you don't need to do anything special.
 
- void guestfs_set_main_loop (guestfs_main_loop *);
+=head2 SINGLE THREAD CASE
 
-This call sets the current main loop to the list of callbacks
-contained in the C<guestfs_main_loop> structure.
+In the single thread case, there is a single select-based main loop
+created for you.  All guestfs handles will use this main loop to
+execute high level API actions.
 
-Only one main loop implementation can be used by libguestfs, so
-calling this replaces the previous one.  (So this is something that
-has to be done by the main program, but only the main program "knows"
-that it is a GTK+ program or whatever).
+=head2 MULTIPLE THREADS CASE
+
+In the multiple threads case, you will need to create a main loop for
+each thread that wants to use libguestfs.
+
+To create main loops for other threads, use
+C<guestfs_create_main_loop> or C<guestfs_glib_create_main_loop>.
+
+Then you will need to attach each handle to the thread-specific main
+loop by calling:
+
+ handle = guestfs_create ();
+ guestfs_set_main_loop (handle, main_loop_of_current_thread);
+
+=head2 guestfs_set_main_loop
 
-You should call this early in the main program, certainly before
-calling C<guestfs_create>.
+ void guestfs_set_main_loop (guestfs_h *handle,
+                             guestfs_main_loop *main_loop);
 
-=head2 guestfs_glib_set_main_loop
+Sets the main loop used by high level API actions for this handle.  By
+default, the select-based main loop is used (see
+C<guestfs_get_default_main_loop>).
 
- void guestfs_glib_set_main_loop (GMainLoop *);
+You only need to use this in multi-threaded programs, where multiple
+threads want to use libguestfs.  Create a main loop for each thread,
+then call this function.
 
-This helper calls C<guestfs_set_main_loop> with the correct callbacks
-for integrating with the GLib main loop.
+You cannot pass guestfs handles between threads.
 
-The libguestfs-glib main loop is contained in a separate library, so
-that libguestfs doesn't depend on the whole of GLib:
+=head2 guestfs_get_main_loop
 
- #include <glib.h>
- #include <guestfs-glib.h>
+ guestfs_main_loop *guestfs_get_main_loop (guestfs_h *handle);
 
- main ()
- {
-   GMainLoop *loop =
-     g_main_loop_new (g_main_context_default (), 1);
-   ...
-   guestfs_glib_set_main_loop (loop);
-   ...
-   g_main_loop_run (loop);
- }
+Return the main loop used by C<handle>.
 
-To use this main loop you must link with C<-lguestfs-glib>.  (See also
-the GLib and GTK+ documentation).
+=head2 guestfs_get_default_main_loop
 
-=head2 guestfs_main_loop_run
+ guestfs_main_loop *guestfs_get_default_main_loop (void);
 
- void guestfs_main_loop_run (void);
+Return the default select-based main loop.
 
-This calls the main loop.
+=head2 guestfs_create_main_loop
 
-For some types of main loop you may want or prefer to call another
-function, eg. C<g_main_loop_run>, or the main loop may already be
-invoked by another part of your program.  In those cases, ignore this
-call.
+ guestfs_main_loop *guestfs_create_main_loop (void);
 
-=head2 guestfs_main_loop_quit
+This creates a select-based main loop.  You should create one main
+loop for each additional thread that needs to use libguestfs.
 
- void guestfs_main_loop_quit (void);
+=head2 guestfs_free_main_loop
 
-This instructs the main loop to quit.  In other words,
-C<guestfs_main_loop_run> will return.
+ void guestfs_free_main_loop (guestfs_main_loop *);
 
-For some types of main loop you may want or prefer to call another
-function, eg. C<g_main_loop_quit>.  In those cases, ignore this call.
+Free the select-based main loop which was previously allocated with
+C<guestfs_create_main_loop>.
 
 =head2 WRITING A CUSTOM MAIN LOOP
 
index a351d57..28d2b0f 100644 (file)
@@ -330,7 +330,7 @@ Return the contents of the file named C<path>.
 
 Note that this function cannot correctly handle binary files
 (specifically, files containing C<\0> character which is treated
-as end of string).  For those you need to use the C<$h-E<gt>read_file>
+as end of string).  For those you need to use the C<$h-E<gt>download>
 function which has a more complex interface.
 
 Because of the message protocol, there is a transfer limit 
index c8df178..09d4270 100644 (file)
@@ -103,7 +103,6 @@ put_table (char * const * const argv)
 
   list = PyList_New (argc >> 1);
   for (i = 0; i < argc; i += 2) {
-    PyObject *item;
     item = PyTuple_New (2);
     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
index 9739fa5..0a4c396 100644 (file)
@@ -236,7 +236,7 @@ class GuestFS:
         Note that this function cannot correctly handle binary
         files (specifically, files containing "\\0" character
         which is treated as end of string). For those you need
-        to use the "g.read_file" function which has a more
+        to use the "g.download" function which has a more
         complex interface.
         
         Because of the message protocol, there is a transfer
index c0a4740..77bcc47 100755 (executable)
@@ -98,6 +98,16 @@ and argt =
   | StringList of string(* list of strings (each string cannot be NULL) *)
   | Bool of string     (* boolean *)
   | Int of string      (* int (smallish ints, signed, <= 31 bits) *)
+    (* These are treated as filenames (simple string parameters) in
+     * the C API and bindings.  But in the RPC protocol, we transfer
+     * the actual file content up to or down from the daemon.
+     * FileIn: local machine -> daemon (in request)
+     * FileOut: daemon -> local machine (in reply)
+     * In guestfish (only), the special name "-" means read from
+     * stdin or write to stdout.
+     *)
+  | FileIn of string
+  | FileOut of string
 
 type flags =
   | ProtocolLimitWarning  (* display warning about protocol size limits *)
@@ -384,7 +394,7 @@ Return the contents of the file named C<path>.
 
 Note that this function cannot correctly handle binary files
 (specifically, files containing C<\\0> character which is treated
-as end of string).  For those you need to use the C<guestfs_read_file>
+as end of string).  For those you need to use the C<guestfs_download>
 function which has a more complex interface.");
 
   ("ll", (RString "listing", [String "directory"]), 5, [],
@@ -1198,6 +1208,30 @@ Reread the partition table on C<device>.
 
 This uses the L<blockdev(8)> command.");
 
+(*
+  ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
+   [],
+   "upload a file from the local machine",
+   "\
+Upload local file C<filename> to C<remotefilename> on the
+filesystem.
+
+C<filename> can also be a named pipe.
+
+See also C<guestfs_upload>.");
+
+  ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
+   [],
+   "download a file to the local machine",
+   "\
+Download file C<remotefilename> and save it as C<filename>
+on the local machine.
+
+C<filename> can also be a named pipe.
+
+See also C<guestfs_download>, C<guestfs_cat>.");
+*)
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
@@ -1410,7 +1444,8 @@ let mapi f xs =
   loop 0 xs
 
 let name_of_argt = function
-  | String n | OptString n | StringList n | Bool n | Int n -> n
+  | String n | OptString n | StringList n | Bool n | Int n
+  | FileIn n | FileOut n -> n
 
 let seq_of_test = function
   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
@@ -1765,6 +1800,7 @@ and generate_xdr () =
             | StringList n -> pr "  str %s<>;\n" n
             | Bool n -> pr "  bool %s;\n" n
             | Int n -> pr "  int %s;\n" n
+            | FileIn _ | FileOut _ -> ()
           ) args;
           pr "};\n\n"
       );
@@ -1830,7 +1866,7 @@ and generate_xdr () =
     fun (shortname, _, proc_nr, _, _, _, _) ->
       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
   ) daemon_functions;
-  pr "  GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
+  pr "  GUESTFS_PROC_NR_PROCS\n";
   pr "};\n";
   pr "\n";
 
@@ -1864,6 +1900,19 @@ struct guestfs_message_error {
   string error<GUESTFS_ERROR_LEN>;   /* error message */
 };
 
+/* 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 */
@@ -1872,6 +1921,31 @@ struct guestfs_message_header {
   unsigned serial;                   /* message serial number */
   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 {
+  int cancel;                       /* if non-zero, transfer is cancelled */
+  /* data size is 0 bytes if the transfer has finished successfully */
+  opaque data<GUESTFS_MAX_CHUNK_SIZE>;
+};
 "
 
 (* Generate the guestfs-structs.h file. *)
@@ -1953,9 +2027,14 @@ and generate_client_actions () =
     fun (shortname, style, _, _, _, _, _) ->
       let name = "guestfs_" ^ shortname in
 
-      (* Generate the return value struct. *)
-      pr "struct %s_rv {\n" shortname;
-      pr "  int cb_done;  /* flag to indicate callback was called */\n";
+      (* Generate the state struct which stores the high-level
+       * state between callback functions.  The callback(s) are:
+       *   <name>_cb_header_sent      header was sent
+       *   <name>_cb_file_sent        FileIn file was sent
+       *   <name>_cb_reply_received   reply received
+       *)
+      pr "struct %s_state {\n" shortname;
+      pr "  int cb_done;\n";
       pr "  struct guestfs_message_header hdr;\n";
       pr "  struct guestfs_message_error err;\n";
       (match fst style with
@@ -1970,19 +2049,20 @@ and generate_client_actions () =
        | RHashtable _ ->
           pr "  struct %s_ret ret;\n" name
       );
-      pr "};\n\n";
+      pr "};\n";
+      pr "\n";
 
       (* Generate the callback function. *)
       pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
       pr "{\n";
-      pr "  struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
+      pr "  struct %s_state *state = (struct %s_state *) data;\n" shortname shortname;
       pr "\n";
-      pr "  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n";
+      pr "  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {\n";
       pr "    error (g, \"%s: failed to parse reply header\");\n" name;
       pr "    return;\n";
       pr "  }\n";
-      pr "  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n";
-      pr "    if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n";
+      pr "  if (state->hdr.status == GUESTFS_STATUS_ERROR) {\n";
+      pr "    if (!xdr_guestfs_message_error (xdr, &state->err)) {\n";
       pr "      error (g, \"%s: failed to parse reply error\");\n" name;
       pr "      return;\n";
       pr "    }\n";
@@ -1999,15 +2079,15 @@ and generate_client_actions () =
        | RPVList _ | RVGList _ | RLVList _
        | RStat _ | RStatVFS _
        | RHashtable _ ->
-           pr "  if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
+           pr "  if (!xdr_%s_ret (xdr, &state->ret)) {\n" name;
            pr "    error (g, \"%s: failed to parse reply\");\n" name;
            pr "    return;\n";
            pr "  }\n";
       );
 
       pr " done:\n";
-      pr "  rv->cb_done = 1;\n";
-      pr "  main_loop.main_loop_quit (g);\n";
+      pr "  state->cb_done = 1;\n";
+      pr "  g->main_loop->main_loop_quit (g->main_loop, g);\n";
       pr "}\n\n";
 
       (* Generate the action stub. *)
@@ -2032,19 +2112,26 @@ and generate_client_actions () =
        | _ -> pr "  struct %s_args args;\n" name
       );
 
-      pr "  struct %s_rv rv;\n" shortname;
+      pr "  struct %s_state state;\n" shortname;
       pr "  int serial;\n";
       pr "\n";
       pr "  if (g->state != READY) {\n";
-      pr "    error (g, \"%s called from the wrong state, %%d != READY\",\n"
-       name;
-      pr "      g->state);\n";
+      pr "    if (g->state == CONFIG)\n";
+      pr "      error (g, \"%%s: call launch() before using this function\",\n";
+      pr "        \"%s\");\n" name;
+      pr "    else if (g->state == LAUNCHING)\n";
+      pr "      error (g, \"%%s: call wait_ready() before using this function\",\n";
+      pr "        \"%s\");\n" name;
+      pr "    else\n";
+      pr "      error (g, \"%%s called from the wrong state, %%d != READY\",\n";
+      pr "        \"%s\", g->state);\n" name;
       pr "    return %s;\n" error_code;
       pr "  }\n";
       pr "\n";
-      pr "  memset (&rv, 0, sizeof rv);\n";
+      pr "  memset (&state, 0, sizeof state);\n";
       pr "\n";
 
+      (* Dispatch the main header and arguments. *)
       (match snd style with
        | [] ->
           pr "  serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
@@ -2063,6 +2150,7 @@ and generate_client_actions () =
                 pr "  args.%s = %s;\n" n n
             | Int n ->
                 pr "  args.%s = %s;\n" n n
+            | FileIn _ | FileOut _ -> ()
           ) args;
           pr "  serial = dispatch (g, GUESTFS_PROC_%s,\n"
             (String.uppercase shortname);
@@ -2073,52 +2161,73 @@ and generate_client_actions () =
       pr "    return %s;\n" error_code;
       pr "\n";
 
-      pr "  rv.cb_done = 0;\n";
+      (* Send any additional files requested. *)
+      List.iter (
+       function
+       | FileIn n ->
+           pr "  if (send_file (g, %s) == -1)\n" n;
+           pr "    return %s;\n" error_code;
+           pr "\n";
+       | _ -> ()
+      ) (snd style);
+
+      (* Wait for the reply from the remote end. *)
+      pr "  state.cb_done = 0;\n";
       pr "  g->reply_cb_internal = %s_cb;\n" shortname;
-      pr "  g->reply_cb_internal_data = &rv;\n";
-      pr "  main_loop.main_loop_run (g);\n";
+      pr "  g->reply_cb_internal_data = &state;\n";
+      pr "  (void) g->main_loop->main_loop_run (g->main_loop, g);\n";
       pr "  g->reply_cb_internal = NULL;\n";
       pr "  g->reply_cb_internal_data = NULL;\n";
-      pr "  if (!rv.cb_done) {\n";
+      pr "  if (!state.cb_done) {\n";
       pr "    error (g, \"%s failed, see earlier error messages\");\n" name;
       pr "    return %s;\n" error_code;
       pr "  }\n";
       pr "\n";
 
-      pr "  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
+      pr "  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
        (String.uppercase shortname);
       pr "    return %s;\n" error_code;
       pr "\n";
 
-      pr "  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n";
-      pr "    error (g, \"%%s\", rv.err.error);\n";
+      pr "  if (state.hdr.status == GUESTFS_STATUS_ERROR) {\n";
+      pr "    error (g, \"%%s\", state.err.error);\n";
       pr "    return %s;\n" error_code;
       pr "  }\n";
       pr "\n";
 
+      (* Expecting to receive further files (FileOut)? *)
+      List.iter (
+       function
+       | FileOut n ->
+           pr "  if (receive_file (g, %s) == -1)\n" n;
+           pr "    return %s;\n" error_code;
+           pr "\n";
+       | _ -> ()
+      ) (snd style);
+
       (match fst style with
        | RErr -> pr "  return 0;\n"
        | RInt n | RInt64 n | RBool n ->
-          pr "  return rv.ret.%s;\n" n
+          pr "  return state.ret.%s;\n" n
        | RConstString _ ->
           failwithf "RConstString cannot be returned from a daemon function"
        | RString n ->
-          pr "  return rv.ret.%s; /* caller will free */\n" n
+          pr "  return state.ret.%s; /* caller will free */\n" n
        | RStringList n | RHashtable n ->
           pr "  /* caller will free this, but we need to add a NULL entry */\n";
-          pr "  rv.ret.%s.%s_val =" n n;
-          pr "    safe_realloc (g, rv.ret.%s.%s_val,\n" n n;
-          pr "                  sizeof (char *) * (rv.ret.%s.%s_len + 1));\n"
+          pr "  state.ret.%s.%s_val =" n n;
+          pr "    safe_realloc (g, state.ret.%s.%s_val,\n" n n;
+          pr "                  sizeof (char *) * (state.ret.%s.%s_len + 1));\n"
             n n;
-          pr "  rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
-          pr "  return rv.ret.%s.%s_val;\n" n n
+          pr "  state.ret.%s.%s_val[state.ret.%s.%s_len] = NULL;\n" n n n n;
+          pr "  return state.ret.%s.%s_val;\n" n n
        | RIntBool _ ->
           pr "  /* caller with free this */\n";
-          pr "  return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
+          pr "  return safe_memdup (g, &state.ret, sizeof (state.ret));\n"
        | RPVList n | RVGList n | RLVList n
        | RStat n | RStatVFS n ->
           pr "  /* caller will free this */\n";
-          pr "  return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
+          pr "  return safe_memdup (g, &state.ret.%s, sizeof (state.ret.%s));\n" n n
       );
 
       pr "}\n\n"
@@ -2189,6 +2298,7 @@ and generate_daemon_actions () =
             | StringList n -> pr "  char **%s;\n" n
             | Bool n -> pr "  int %s;\n" n
             | Int n -> pr "  int %s;\n" n
+            | FileIn _ | FileOut _ -> ()
           ) args
       );
       pr "\n";
@@ -2212,12 +2322,19 @@ and generate_daemon_actions () =
                 pr "  %s = args.%s.%s_val;\n" n n n
             | Bool n -> pr "  %s = args.%s;\n" n n
             | Int n -> pr "  %s = args.%s;\n" n n
+            | FileIn _ | FileOut _ -> ()
           ) args;
           pr "\n"
       );
 
+      (* Don't want to call the impl with any FileIn or FileOut
+       * parameters, since these go "outside" the RPC protocol.
+       *)
+      let argsnofile =
+       List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
+         (snd style) in
       pr "  r = do_%s " name;
-      generate_call_args style;
+      generate_call_args argsnofile;
       pr ";\n";
 
       pr "  if (r == %s)\n" error_code;
@@ -2225,34 +2342,48 @@ and generate_daemon_actions () =
       pr "    goto done;\n";
       pr "\n";
 
-      (match fst style with
-       | RErr -> pr "  reply (NULL, NULL);\n"
-       | RInt n | RInt64 n | RBool n ->
-          pr "  struct guestfs_%s_ret ret;\n" name;
-          pr "  ret.%s = r;\n" n;
-          pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
-       | RConstString _ ->
-          failwithf "RConstString cannot be returned from a daemon function"
-       | RString n ->
-          pr "  struct guestfs_%s_ret ret;\n" name;
-          pr "  ret.%s = r;\n" n;
-          pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
-          pr "  free (r);\n"
-       | RStringList n | RHashtable n ->
-          pr "  struct guestfs_%s_ret ret;\n" name;
-          pr "  ret.%s.%s_len = count_strings (r);\n" n n;
-          pr "  ret.%s.%s_val = r;\n" n n;
-          pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
-          pr "  free_strings (r);\n"
-       | RIntBool _ ->
-          pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
-          pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
-       | RPVList n | RVGList n | RLVList n
-       | RStat n | RStatVFS n ->
-          pr "  struct guestfs_%s_ret ret;\n" name;
-          pr "  ret.%s = *r;\n" n;
-          pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
-          pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
+      (* If there are any FileOut parameters, then the impl must
+       * send its own reply.
+       *)
+      let no_reply =
+       List.exists (function FileOut _ -> true | _ -> false) (snd style) in
+      if no_reply then
+       pr "  /* do_%s has already sent a reply */\n" name
+      else (
+       match fst style with
+       | RErr -> pr "  reply (NULL, NULL);\n"
+       | RInt n | RInt64 n | RBool n ->
+           pr "  struct guestfs_%s_ret ret;\n" name;
+           pr "  ret.%s = r;\n" n;
+           pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
+             name
+       | RConstString _ ->
+           failwithf "RConstString cannot be returned from a daemon function"
+       | RString n ->
+           pr "  struct guestfs_%s_ret ret;\n" name;
+           pr "  ret.%s = r;\n" n;
+           pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
+             name;
+           pr "  free (r);\n"
+       | RStringList n | RHashtable n ->
+           pr "  struct guestfs_%s_ret ret;\n" name;
+           pr "  ret.%s.%s_len = count_strings (r);\n" n n;
+           pr "  ret.%s.%s_val = r;\n" n n;
+           pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
+             name;
+           pr "  free_strings (r);\n"
+       | RIntBool _ ->
+           pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n"
+             name;
+           pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
+       | RPVList n | RVGList n | RLVList n
+       | RStat n | RStatVFS n ->
+           pr "  struct guestfs_%s_ret ret;\n" name;
+           pr "  ret.%s = *r;\n" n;
+           pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
+             name;
+           pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
+             name
       );
 
       (* Free the args. *)
@@ -2890,6 +3021,7 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
        | OptString _, _
        | Int _, _
        | Bool _, _ -> ()
+       | FileIn _, _ | FileOut _, _ -> ()
        | StringList n, arg ->
            pr "    char *%s[] = {\n" n;
            let strs = string_split " " arg in
@@ -2929,7 +3061,9 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
       (* Generate the parameters. *)
       List.iter (
        function
-       | String _, arg -> pr ", \"%s\"" (c_quote arg)
+       | String _, arg
+       | FileIn _, arg | FileOut _, arg ->
+           pr ", \"%s\"" (c_quote arg)
        | OptString _, arg ->
            if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
        | StringList n, _ ->
@@ -3151,7 +3285,9 @@ and generate_fish_cmds () =
       List.iter (
        function
        | String n
-       | OptString n -> pr "  const char *%s;\n" n
+       | OptString n
+       | FileIn n
+       | FileOut n -> pr "  const char *%s;\n" n
        | StringList n -> pr "  char **%s;\n" n
        | Bool n -> pr "  int %s;\n" n
        | Int n -> pr "  int %s;\n" n
@@ -3172,6 +3308,12 @@ and generate_fish_cmds () =
          | OptString name ->
              pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
                name i i
+         | FileIn name ->
+             pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
+               name i i
+         | FileOut name ->
+             pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
+               name i i
          | StringList name ->
              pr "  %s = parse_string_list (argv[%d]);\n" name i
          | Bool name ->
@@ -3185,7 +3327,7 @@ and generate_fish_cmds () =
        try find_map (function FishAction n -> Some n | _ -> None) flags
        with Not_found -> sprintf "guestfs_%s" name in
       pr "  r = %s " fn;
-      generate_call_args ~handle:"g" style;
+      generate_call_args ~handle:"g" (snd style);
       pr ";\n";
 
       (* Check return value for errors and display command results. *)
@@ -3394,11 +3536,16 @@ and generate_fish_actions_pod () =
        | StringList n -> pr " %s,..." n
        | Bool _ -> pr " true|false"
        | Int n -> pr " %s" n
+       | FileIn n | FileOut n -> pr " (%s|-)" n
       ) (snd style);
       pr "\n";
       pr "\n";
       pr "%s\n\n" longdesc;
 
+      if List.exists (function FileIn _ | FileOut _ -> true
+                     | _ -> false) (snd style) then
+       pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
+
       if List.mem ProtocolLimitWarning flags then
        pr "%s\n\n" protocol_limit_warning;
 
@@ -3457,11 +3604,14 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
     in
     List.iter (
       function
-      | String n -> next (); pr "const char *%s" n
+      | String n
       | OptString n -> next (); pr "const char *%s" n
       | StringList n -> next (); pr "char * const* const %s" n
       | Bool n -> next (); pr "int %s" n
       | Int n -> next (); pr "int %s" n
+      | FileIn n
+      | FileOut n ->
+         if not in_daemon then (next (); pr "const char *%s" n)
     ) (snd style);
   );
   pr ")";
@@ -3469,7 +3619,7 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
   if newline then pr "\n"
 
 (* Generate C call arguments, eg "(handle, foo, bar)" *)
-and generate_call_args ?handle style =
+and generate_call_args ?handle args =
   pr "(";
   let comma = ref false in
   (match handle with
@@ -3480,13 +3630,8 @@ and generate_call_args ?handle style =
     fun arg ->
       if !comma then pr ", ";
       comma := true;
-      match arg with
-      | String n
-      | OptString n
-      | StringList n
-      | Bool n
-      | Int n -> pr "%s" n
-  ) (snd style);
+      pr "%s" (name_of_argt arg)
+  ) args;
   pr ")"
 
 (* Generate the OCaml bindings interface. *)
@@ -3715,7 +3860,9 @@ copy_table (char * const * argv)
 
       List.iter (
        function
-       | String n ->
+       | String n
+       | FileIn n
+       | FileOut n ->
            pr "  const char *%s = String_val (%sv);\n" n n
        | OptString n ->
            pr "  const char *%s =\n" n;
@@ -3760,7 +3907,7 @@ copy_table (char * const * argv)
 
       pr "  caml_enter_blocking_section ();\n";
       pr "  r = guestfs_%s " name;
-      generate_call_args ~handle:"g" style;
+      generate_call_args ~handle:"g" (snd style);
       pr ";\n";
       pr "  caml_leave_blocking_section ();\n";
 
@@ -3768,7 +3915,7 @@ copy_table (char * const * argv)
        function
        | StringList n ->
            pr "  ocaml_guestfs_free_strings (%s);\n" n;
-       | String _ | OptString _ | Bool _ | Int _ -> ()
+       | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
       ) (snd style);
 
       pr "  if (r == %s)\n" error_code;
@@ -3864,7 +4011,7 @@ and generate_ocaml_prototype ?(is_external = false) name style =
   pr "%s : t -> " name;
   List.iter (
     function
-    | String _ -> pr "string -> "
+    | String _ | FileIn _ | FileOut _ -> pr "string -> "
     | OptString _ -> pr "string option -> "
     | StringList _ -> pr "string array -> "
     | Bool _ -> pr "bool -> "
@@ -4003,12 +4150,12 @@ DESTROY (g)
       );
       (* Call and arguments. *)
       pr "%s " name;
-      generate_call_args ~handle:"g" style;
+      generate_call_args ~handle:"g" (snd style);
       pr "\n";
       pr "      guestfs_h *g;\n";
       List.iter (
        function
-       | String n -> pr "      char *%s;\n" n
+       | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
        | OptString n -> pr "      char *%s;\n" n
        | StringList n -> pr "      char **%s;\n" n
        | Bool n -> pr "      int %s;\n" n
@@ -4018,10 +4165,8 @@ DESTROY (g)
       let do_cleanups () =
        List.iter (
          function
-         | String _
-         | OptString _
-         | Bool _
-         | Int _ -> ()
+         | String _ | OptString _ | Bool _ | Int _
+         | FileIn _ | FileOut _ -> ()
          | StringList n -> pr "      free (%s);\n" n
        ) (snd style)
       in
@@ -4033,7 +4178,7 @@ DESTROY (g)
           pr "      int r;\n";
           pr " PPCODE:\n";
           pr "      r = guestfs_%s " name;
-          generate_call_args ~handle:"g" style;
+          generate_call_args ~handle:"g" (snd style);
           pr ";\n";
           do_cleanups ();
           pr "      if (r == -1)\n";
@@ -4044,7 +4189,7 @@ DESTROY (g)
           pr "      int %s;\n" n;
           pr "   CODE:\n";
           pr "      %s = guestfs_%s " n name;
-          generate_call_args ~handle:"g" style;
+          generate_call_args ~handle:"g" (snd style);
           pr ";\n";
           do_cleanups ();
           pr "      if (%s == -1)\n" n;
@@ -4057,7 +4202,7 @@ DESTROY (g)
           pr "      int64_t %s;\n" n;
           pr "   CODE:\n";
           pr "      %s = guestfs_%s " n name;
-          generate_call_args ~handle:"g" style;
+          generate_call_args ~handle:"g" (snd style);
           pr ";\n";
           do_cleanups ();
           pr "      if (%s == -1)\n" n;
@@ -4070,7 +4215,7 @@ DESTROY (g)
           pr "      const char *%s;\n" n;
           pr "   CODE:\n";
           pr "      %s = guestfs_%s " n name;
-          generate_call_args ~handle:"g" style;
+          generate_call_args ~handle:"g" (snd style);
           pr ";\n";
           do_cleanups ();
           pr "      if (%s == NULL)\n" n;
@@ -4083,7 +4228,7 @@ DESTROY (g)
           pr "      char *%s;\n" n;
           pr "   CODE:\n";
           pr "      %s = guestfs_%s " n name;
-          generate_call_args ~handle:"g" style;
+          generate_call_args ~handle:"g" (snd style);
           pr ";\n";
           do_cleanups ();
           pr "      if (%s == NULL)\n" n;
@@ -4098,7 +4243,7 @@ DESTROY (g)
           pr "      int i, n;\n";
           pr " PPCODE:\n";
           pr "      %s = guestfs_%s " n name;
-          generate_call_args ~handle:"g" style;
+          generate_call_args ~handle:"g" (snd style);
           pr ";\n";
           do_cleanups ();
           pr "      if (%s == NULL)\n" n;
@@ -4115,7 +4260,7 @@ DESTROY (g)
           pr "      struct guestfs_int_bool *r;\n";
           pr " PPCODE:\n";
           pr "      r = guestfs_%s " name;
-          generate_call_args ~handle:"g" style;
+          generate_call_args ~handle:"g" (snd style);
           pr ";\n";
           do_cleanups ();
           pr "      if (r == NULL)\n";
@@ -4147,7 +4292,7 @@ and generate_perl_lvm_code typ cols name style n do_cleanups =
   pr "      HV *hv;\n";
   pr " PPCODE:\n";
   pr "      %s = guestfs_%s " n name;
-  generate_call_args ~handle:"g" style;
+  generate_call_args ~handle:"g" (snd style);
   pr ";\n";
   do_cleanups ();
   pr "      if (%s == NULL)\n" n;
@@ -4182,7 +4327,7 @@ and generate_perl_stat_code typ cols name style n do_cleanups =
   pr "      struct guestfs_%s *%s;\n" typ n;
   pr " PPCODE:\n";
   pr "      %s = guestfs_%s " n name;
-  generate_call_args ~handle:"g" style;
+  generate_call_args ~handle:"g" (snd style);
   pr ";\n";
   do_cleanups ();
   pr "      if (%s == NULL)\n" n;
@@ -4338,7 +4483,7 @@ and generate_perl_prototype name style =
       if !comma then pr ", ";
       comma := true;
       match arg with
-      | String n | OptString n | Bool n | Int n ->
+      | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
          pr "$%s" n
       | StringList n ->
          pr "\\@%s" n
@@ -4434,7 +4579,6 @@ put_table (char * const * const argv)
 
   list = PyList_New (argc >> 1);
   for (i = 0; i < argc; i += 2) {
-    PyObject *item;
     item = PyTuple_New (2);
     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
@@ -4590,7 +4734,7 @@ py_guestfs_close (PyObject *self, PyObject *args)
 
       List.iter (
        function
-       | String n -> pr "  const char *%s;\n" n
+       | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
        | OptString n -> pr "  const char *%s;\n" n
        | StringList n ->
            pr "  PyObject *py_%s;\n" n;
@@ -4605,7 +4749,7 @@ py_guestfs_close (PyObject *self, PyObject *args)
       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
       List.iter (
        function
-       | String _ -> pr "s"
+       | String _ | FileIn _ | FileOut _ -> pr "s"
        | OptString _ -> pr "z"
        | StringList _ -> pr "O"
        | Bool _ -> pr "i" (* XXX Python has booleans? *)
@@ -4615,7 +4759,7 @@ py_guestfs_close (PyObject *self, PyObject *args)
       pr "                         &py_g";
       List.iter (
        function
-       | String n -> pr ", &%s" n
+       | String n | FileIn n | FileOut n -> pr ", &%s" n
        | OptString n -> pr ", &%s" n
        | StringList n -> pr ", &py_%s" n
        | Bool n -> pr ", &%s" n
@@ -4628,7 +4772,7 @@ py_guestfs_close (PyObject *self, PyObject *args)
       pr "  g = get_handle (py_g);\n";
       List.iter (
        function
-       | String _ | OptString _ | Bool _ | Int _ -> ()
+       | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
        | StringList n ->
            pr "  %s = get_string_list (py_%s);\n" n n;
            pr "  if (!%s) return NULL;\n" n
@@ -4637,12 +4781,12 @@ py_guestfs_close (PyObject *self, PyObject *args)
       pr "\n";
 
       pr "  r = guestfs_%s " name;
-      generate_call_args ~handle:"g" style;
+      generate_call_args ~handle:"g" (snd style);
       pr ";\n";
 
       List.iter (
        function
-       | String _ | OptString _ | Bool _ | Int _ -> ()
+       | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
        | StringList n ->
            pr "  free (%s);\n" n
       ) (snd style);
@@ -4826,11 +4970,11 @@ class GuestFS:
       let doc = String.concat "\n        " doc in
 
       pr "    def %s " name;
-      generate_call_args ~handle:"self" style;
+      generate_call_args ~handle:"self" (snd style);
       pr ":\n";
       pr "        u\"\"\"%s\"\"\"\n" doc;
       pr "        return libguestfsmod.%s " name;
-      generate_call_args ~handle:"self._o" style;
+      generate_call_args ~handle:"self._o" (snd style);
       pr "\n";
       pr "\n";
   ) all_functions
@@ -4932,7 +5076,7 @@ static VALUE ruby_guestfs_close (VALUE gv)
 
       List.iter (
        function
-       | String n ->
+       | String n | FileIn n | FileOut n ->
            pr "  const char *%s = StringValueCStr (%sv);\n" n n;
            pr "  if (!%s)\n" n;
            pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
@@ -4972,12 +5116,12 @@ static VALUE ruby_guestfs_close (VALUE gv)
       pr "\n";
 
       pr "  r = guestfs_%s " name;
-      generate_call_args ~handle:"g" style;
+      generate_call_args ~handle:"g" (snd style);
       pr ";\n";
 
       List.iter (
        function
-       | String _ | OptString _ | Bool _ | Int _ -> ()
+       | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
        | StringList n ->
            pr "  free (%s);\n" n
       ) (snd style);
index f516979..6f01f9f 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-struct mount_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct mount_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void mount_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct mount_rv *rv = (struct mount_rv *) data;
+  struct mount_state *state = (struct mount_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_mount: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_mount: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_mount (guestfs_h *g,
@@ -50,16 +50,23 @@ int guestfs_mount (guestfs_h *g,
                const char *mountpoint)
 {
   struct guestfs_mount_args args;
-  struct mount_rv rv;
+  struct mount_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_mount called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_mount");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_mount");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_mount", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   args.mountpoint = (char *) mountpoint;
@@ -68,133 +75,147 @@ int guestfs_mount (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = mount_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_mount failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MOUNT, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_MOUNT, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct sync_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct sync_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void sync_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct sync_rv *rv = (struct sync_rv *) data;
+  struct sync_state *state = (struct sync_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_sync: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_sync: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_sync (guestfs_h *g)
 {
-  struct sync_rv rv;
+  struct sync_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_sync called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_sync");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_sync");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_sync", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_SYNC, NULL, NULL);
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = sync_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_sync failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_SYNC, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_SYNC, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct touch_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct touch_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void touch_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct touch_rv *rv = (struct touch_rv *) data;
+  struct touch_state *state = (struct touch_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_touch: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_touch: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_touch (guestfs_h *g,
                const char *path)
 {
   struct guestfs_touch_args args;
-  struct touch_rv rv;
+  struct touch_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_touch called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_touch");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_touch");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_touch", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_TOUCH,
@@ -202,30 +223,30 @@ int guestfs_touch (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = touch_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_touch failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_TOUCH, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_TOUCH, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct cat_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct cat_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_cat_ret ret;
@@ -233,42 +254,49 @@ struct cat_rv {
 
 static void cat_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct cat_rv *rv = (struct cat_rv *) data;
+  struct cat_state *state = (struct cat_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_cat: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_cat: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_cat_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_cat_ret (xdr, &state->ret)) {
     error (g, "guestfs_cat: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char *guestfs_cat (guestfs_h *g,
                const char *path)
 {
   struct guestfs_cat_args args;
-  struct cat_rv rv;
+  struct cat_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_cat called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_cat");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_cat");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_cat", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_CAT,
@@ -276,30 +304,30 @@ char *guestfs_cat (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = cat_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_cat failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_CAT, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_CAT, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
-  return rv.ret.content; /* caller will free */
+  return state.ret.content; /* caller will free */
 }
 
-struct ll_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct ll_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_ll_ret ret;
@@ -307,42 +335,49 @@ struct ll_rv {
 
 static void ll_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct ll_rv *rv = (struct ll_rv *) data;
+  struct ll_state *state = (struct ll_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_ll: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_ll: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_ll_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_ll_ret (xdr, &state->ret)) {
     error (g, "guestfs_ll: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char *guestfs_ll (guestfs_h *g,
                const char *directory)
 {
   struct guestfs_ll_args args;
-  struct ll_rv rv;
+  struct ll_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_ll called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_ll");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_ll");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_ll", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.directory = (char *) directory;
   serial = dispatch (g, GUESTFS_PROC_LL,
@@ -350,30 +385,30 @@ char *guestfs_ll (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = ll_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_ll failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LL, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LL, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
-  return rv.ret.listing; /* caller will free */
+  return state.ret.listing; /* caller will free */
 }
 
-struct ls_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct ls_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_ls_ret ret;
@@ -381,42 +416,49 @@ struct ls_rv {
 
 static void ls_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct ls_rv *rv = (struct ls_rv *) data;
+  struct ls_state *state = (struct ls_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_ls: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_ls: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_ls_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_ls_ret (xdr, &state->ret)) {
     error (g, "guestfs_ls: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_ls (guestfs_h *g,
                const char *directory)
 {
   struct guestfs_ls_args args;
-  struct ls_rv rv;
+  struct ls_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_ls called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_ls");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_ls");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_ls", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.directory = (char *) directory;
   serial = dispatch (g, GUESTFS_PROC_LS,
@@ -424,34 +466,34 @@ char **guestfs_ls (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = ls_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_ls failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LS, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.listing.listing_val =    safe_realloc (g, rv.ret.listing.listing_val,
-                  sizeof (char *) * (rv.ret.listing.listing_len + 1));
-  rv.ret.listing.listing_val[rv.ret.listing.listing_len] = NULL;
-  return rv.ret.listing.listing_val;
+  state.ret.listing.listing_val =    safe_realloc (g, state.ret.listing.listing_val,
+                  sizeof (char *) * (state.ret.listing.listing_len + 1));
+  state.ret.listing.listing_val[state.ret.listing.listing_len] = NULL;
+  return state.ret.listing.listing_val;
 }
 
-struct list_devices_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct list_devices_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_list_devices_ret ret;
@@ -459,73 +501,80 @@ struct list_devices_rv {
 
 static void list_devices_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct list_devices_rv *rv = (struct list_devices_rv *) data;
+  struct list_devices_state *state = (struct list_devices_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_list_devices: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_list_devices: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_list_devices_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_list_devices_ret (xdr, &state->ret)) {
     error (g, "guestfs_list_devices: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_list_devices (guestfs_h *g)
 {
-  struct list_devices_rv rv;
+  struct list_devices_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_list_devices called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_list_devices");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_list_devices");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_list_devices", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_LIST_DEVICES, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = list_devices_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_list_devices failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LIST_DEVICES, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LIST_DEVICES, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.devices.devices_val =    safe_realloc (g, rv.ret.devices.devices_val,
-                  sizeof (char *) * (rv.ret.devices.devices_len + 1));
-  rv.ret.devices.devices_val[rv.ret.devices.devices_len] = NULL;
-  return rv.ret.devices.devices_val;
+  state.ret.devices.devices_val =    safe_realloc (g, state.ret.devices.devices_val,
+                  sizeof (char *) * (state.ret.devices.devices_len + 1));
+  state.ret.devices.devices_val[state.ret.devices.devices_len] = NULL;
+  return state.ret.devices.devices_val;
 }
 
-struct list_partitions_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct list_partitions_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_list_partitions_ret ret;
@@ -533,73 +582,80 @@ struct list_partitions_rv {
 
 static void list_partitions_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct list_partitions_rv *rv = (struct list_partitions_rv *) data;
+  struct list_partitions_state *state = (struct list_partitions_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_list_partitions: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_list_partitions: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_list_partitions_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_list_partitions_ret (xdr, &state->ret)) {
     error (g, "guestfs_list_partitions: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_list_partitions (guestfs_h *g)
 {
-  struct list_partitions_rv rv;
+  struct list_partitions_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_list_partitions called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_list_partitions");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_list_partitions");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_list_partitions", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_LIST_PARTITIONS, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = list_partitions_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_list_partitions failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LIST_PARTITIONS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LIST_PARTITIONS, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.partitions.partitions_val =    safe_realloc (g, rv.ret.partitions.partitions_val,
-                  sizeof (char *) * (rv.ret.partitions.partitions_len + 1));
-  rv.ret.partitions.partitions_val[rv.ret.partitions.partitions_len] = NULL;
-  return rv.ret.partitions.partitions_val;
+  state.ret.partitions.partitions_val =    safe_realloc (g, state.ret.partitions.partitions_val,
+                  sizeof (char *) * (state.ret.partitions.partitions_len + 1));
+  state.ret.partitions.partitions_val[state.ret.partitions.partitions_len] = NULL;
+  return state.ret.partitions.partitions_val;
 }
 
-struct pvs_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct pvs_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_pvs_ret ret;
@@ -607,73 +663,80 @@ struct pvs_rv {
 
 static void pvs_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct pvs_rv *rv = (struct pvs_rv *) data;
+  struct pvs_state *state = (struct pvs_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_pvs: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_pvs: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_pvs_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_pvs_ret (xdr, &state->ret)) {
     error (g, "guestfs_pvs: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_pvs (guestfs_h *g)
 {
-  struct pvs_rv rv;
+  struct pvs_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_pvs called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_pvs");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_pvs");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_pvs", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_PVS, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = pvs_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_pvs failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_PVS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_PVS, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.physvols.physvols_val =    safe_realloc (g, rv.ret.physvols.physvols_val,
-                  sizeof (char *) * (rv.ret.physvols.physvols_len + 1));
-  rv.ret.physvols.physvols_val[rv.ret.physvols.physvols_len] = NULL;
-  return rv.ret.physvols.physvols_val;
+  state.ret.physvols.physvols_val =    safe_realloc (g, state.ret.physvols.physvols_val,
+                  sizeof (char *) * (state.ret.physvols.physvols_len + 1));
+  state.ret.physvols.physvols_val[state.ret.physvols.physvols_len] = NULL;
+  return state.ret.physvols.physvols_val;
 }
 
-struct vgs_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct vgs_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_vgs_ret ret;
@@ -681,73 +744,80 @@ struct vgs_rv {
 
 static void vgs_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct vgs_rv *rv = (struct vgs_rv *) data;
+  struct vgs_state *state = (struct vgs_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_vgs: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_vgs: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_vgs_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_vgs_ret (xdr, &state->ret)) {
     error (g, "guestfs_vgs: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_vgs (guestfs_h *g)
 {
-  struct vgs_rv rv;
+  struct vgs_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_vgs called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_vgs");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_vgs");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_vgs", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_VGS, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = vgs_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_vgs failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_VGS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_VGS, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.volgroups.volgroups_val =    safe_realloc (g, rv.ret.volgroups.volgroups_val,
-                  sizeof (char *) * (rv.ret.volgroups.volgroups_len + 1));
-  rv.ret.volgroups.volgroups_val[rv.ret.volgroups.volgroups_len] = NULL;
-  return rv.ret.volgroups.volgroups_val;
+  state.ret.volgroups.volgroups_val =    safe_realloc (g, state.ret.volgroups.volgroups_val,
+                  sizeof (char *) * (state.ret.volgroups.volgroups_len + 1));
+  state.ret.volgroups.volgroups_val[state.ret.volgroups.volgroups_len] = NULL;
+  return state.ret.volgroups.volgroups_val;
 }
 
-struct lvs_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct lvs_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_lvs_ret ret;
@@ -755,73 +825,80 @@ struct lvs_rv {
 
 static void lvs_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct lvs_rv *rv = (struct lvs_rv *) data;
+  struct lvs_state *state = (struct lvs_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_lvs: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_lvs: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_lvs_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_lvs_ret (xdr, &state->ret)) {
     error (g, "guestfs_lvs: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_lvs (guestfs_h *g)
 {
-  struct lvs_rv rv;
+  struct lvs_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_lvs called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_lvs");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_lvs");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_lvs", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_LVS, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = lvs_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_lvs failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LVS, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.logvols.logvols_val =    safe_realloc (g, rv.ret.logvols.logvols_val,
-                  sizeof (char *) * (rv.ret.logvols.logvols_len + 1));
-  rv.ret.logvols.logvols_val[rv.ret.logvols.logvols_len] = NULL;
-  return rv.ret.logvols.logvols_val;
+  state.ret.logvols.logvols_val =    safe_realloc (g, state.ret.logvols.logvols_val,
+                  sizeof (char *) * (state.ret.logvols.logvols_len + 1));
+  state.ret.logvols.logvols_val[state.ret.logvols.logvols_len] = NULL;
+  return state.ret.logvols.logvols_val;
 }
 
-struct pvs_full_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct pvs_full_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_pvs_full_ret ret;
@@ -829,70 +906,77 @@ struct pvs_full_rv {
 
 static void pvs_full_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct pvs_full_rv *rv = (struct pvs_full_rv *) data;
+  struct pvs_full_state *state = (struct pvs_full_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_pvs_full: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_pvs_full: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_pvs_full_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_pvs_full_ret (xdr, &state->ret)) {
     error (g, "guestfs_pvs_full: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 struct guestfs_lvm_pv_list *guestfs_pvs_full (guestfs_h *g)
 {
-  struct pvs_full_rv rv;
+  struct pvs_full_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_pvs_full called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_pvs_full");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_pvs_full");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_pvs_full", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_PVS_FULL, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = pvs_full_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_pvs_full failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_PVS_FULL, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_PVS_FULL, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this */
-  return safe_memdup (g, &rv.ret.physvols, sizeof (rv.ret.physvols));
+  return safe_memdup (g, &state.ret.physvols, sizeof (state.ret.physvols));
 }
 
-struct vgs_full_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct vgs_full_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_vgs_full_ret ret;
@@ -900,70 +984,77 @@ struct vgs_full_rv {
 
 static void vgs_full_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct vgs_full_rv *rv = (struct vgs_full_rv *) data;
+  struct vgs_full_state *state = (struct vgs_full_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_vgs_full: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_vgs_full: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_vgs_full_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_vgs_full_ret (xdr, &state->ret)) {
     error (g, "guestfs_vgs_full: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 struct guestfs_lvm_vg_list *guestfs_vgs_full (guestfs_h *g)
 {
-  struct vgs_full_rv rv;
+  struct vgs_full_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_vgs_full called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_vgs_full");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_vgs_full");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_vgs_full", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_VGS_FULL, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = vgs_full_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_vgs_full failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_VGS_FULL, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_VGS_FULL, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this */
-  return safe_memdup (g, &rv.ret.volgroups, sizeof (rv.ret.volgroups));
+  return safe_memdup (g, &state.ret.volgroups, sizeof (state.ret.volgroups));
 }
 
-struct lvs_full_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct lvs_full_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_lvs_full_ret ret;
@@ -971,70 +1062,77 @@ struct lvs_full_rv {
 
 static void lvs_full_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct lvs_full_rv *rv = (struct lvs_full_rv *) data;
+  struct lvs_full_state *state = (struct lvs_full_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_lvs_full: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_lvs_full: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_lvs_full_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_lvs_full_ret (xdr, &state->ret)) {
     error (g, "guestfs_lvs_full: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 struct guestfs_lvm_lv_list *guestfs_lvs_full (guestfs_h *g)
 {
-  struct lvs_full_rv rv;
+  struct lvs_full_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_lvs_full called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_lvs_full");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_lvs_full");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_lvs_full", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_LVS_FULL, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = lvs_full_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_lvs_full failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVS_FULL, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LVS_FULL, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this */
-  return safe_memdup (g, &rv.ret.logvols, sizeof (rv.ret.logvols));
+  return safe_memdup (g, &state.ret.logvols, sizeof (state.ret.logvols));
 }
 
-struct read_lines_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct read_lines_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_read_lines_ret ret;
@@ -1042,42 +1140,49 @@ struct read_lines_rv {
 
 static void read_lines_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct read_lines_rv *rv = (struct read_lines_rv *) data;
+  struct read_lines_state *state = (struct read_lines_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_read_lines: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_read_lines: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_read_lines_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_read_lines_ret (xdr, &state->ret)) {
     error (g, "guestfs_read_lines: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_read_lines (guestfs_h *g,
                const char *path)
 {
   struct guestfs_read_lines_args args;
-  struct read_lines_rv rv;
+  struct read_lines_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_read_lines called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_read_lines");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_read_lines");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_read_lines", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_READ_LINES,
@@ -1085,56 +1190,56 @@ char **guestfs_read_lines (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = read_lines_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_read_lines failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_READ_LINES, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_READ_LINES, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.lines.lines_val =    safe_realloc (g, rv.ret.lines.lines_val,
-                  sizeof (char *) * (rv.ret.lines.lines_len + 1));
-  rv.ret.lines.lines_val[rv.ret.lines.lines_len] = NULL;
-  return rv.ret.lines.lines_val;
+  state.ret.lines.lines_val =    safe_realloc (g, state.ret.lines.lines_val,
+                  sizeof (char *) * (state.ret.lines.lines_len + 1));
+  state.ret.lines.lines_val[state.ret.lines.lines_len] = NULL;
+  return state.ret.lines.lines_val;
 }
 
-struct aug_init_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_init_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void aug_init_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_init_rv *rv = (struct aug_init_rv *) data;
+  struct aug_init_state *state = (struct aug_init_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_init: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_init: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_init (guestfs_h *g,
@@ -1142,16 +1247,23 @@ int guestfs_aug_init (guestfs_h *g,
                int flags)
 {
   struct guestfs_aug_init_args args;
-  struct aug_init_rv rv;
+  struct aug_init_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_init called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_init");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_init");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_init", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.root = (char *) root;
   args.flags = flags;
@@ -1160,95 +1272,102 @@ int guestfs_aug_init (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_init_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_init failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_INIT, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_INIT, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct aug_close_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_close_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void aug_close_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_close_rv *rv = (struct aug_close_rv *) data;
+  struct aug_close_state *state = (struct aug_close_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_close: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_close: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_close (guestfs_h *g)
 {
-  struct aug_close_rv rv;
+  struct aug_close_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_close called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_close");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_close");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_close", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_AUG_CLOSE, NULL, NULL);
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_close_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_close failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_CLOSE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_CLOSE, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct aug_defvar_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_defvar_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_aug_defvar_ret ret;
@@ -1256,26 +1375,26 @@ struct aug_defvar_rv {
 
 static void aug_defvar_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_defvar_rv *rv = (struct aug_defvar_rv *) data;
+  struct aug_defvar_state *state = (struct aug_defvar_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_defvar: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_defvar: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_aug_defvar_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_aug_defvar_ret (xdr, &state->ret)) {
     error (g, "guestfs_aug_defvar: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_defvar (guestfs_h *g,
@@ -1283,16 +1402,23 @@ int guestfs_aug_defvar (guestfs_h *g,
                const char *expr)
 {
   struct guestfs_aug_defvar_args args;
-  struct aug_defvar_rv rv;
+  struct aug_defvar_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_defvar called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_defvar");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_defvar");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_defvar", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.name = (char *) name;
   args.expr = expr ? (char **) &expr : NULL;
@@ -1301,30 +1427,30 @@ int guestfs_aug_defvar (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_defvar_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_defvar failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_DEFVAR, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_DEFVAR, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.nrnodes;
+  return state.ret.nrnodes;
 }
 
-struct aug_defnode_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_defnode_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_aug_defnode_ret ret;
@@ -1332,26 +1458,26 @@ struct aug_defnode_rv {
 
 static void aug_defnode_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_defnode_rv *rv = (struct aug_defnode_rv *) data;
+  struct aug_defnode_state *state = (struct aug_defnode_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_defnode: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_defnode: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_aug_defnode_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_aug_defnode_ret (xdr, &state->ret)) {
     error (g, "guestfs_aug_defnode: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
@@ -1360,16 +1486,23 @@ struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
                const char *val)
 {
   struct guestfs_aug_defnode_args args;
-  struct aug_defnode_rv rv;
+  struct aug_defnode_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_defnode called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_defnode");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_defnode");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_defnode", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.name = (char *) name;
   args.expr = (char *) expr;
@@ -1379,31 +1512,31 @@ struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_defnode_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_defnode failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_DEFNODE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_DEFNODE, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller with free this */
-  return safe_memdup (g, &rv.ret, sizeof (rv.ret));
+  return safe_memdup (g, &state.ret, sizeof (state.ret));
 }
 
-struct aug_get_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_get_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_aug_get_ret ret;
@@ -1411,42 +1544,49 @@ struct aug_get_rv {
 
 static void aug_get_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_get_rv *rv = (struct aug_get_rv *) data;
+  struct aug_get_state *state = (struct aug_get_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_get: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_get: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_aug_get_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_aug_get_ret (xdr, &state->ret)) {
     error (g, "guestfs_aug_get: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char *guestfs_aug_get (guestfs_h *g,
                const char *path)
 {
   struct guestfs_aug_get_args args;
-  struct aug_get_rv rv;
+  struct aug_get_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_get called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_get");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_get");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_get", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_AUG_GET,
@@ -1454,52 +1594,52 @@ char *guestfs_aug_get (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_get_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_get failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_GET, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_GET, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
-  return rv.ret.val; /* caller will free */
+  return state.ret.val; /* caller will free */
 }
 
-struct aug_set_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_set_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void aug_set_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_set_rv *rv = (struct aug_set_rv *) data;
+  struct aug_set_state *state = (struct aug_set_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_set: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_set: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_set (guestfs_h *g,
@@ -1507,16 +1647,23 @@ int guestfs_aug_set (guestfs_h *g,
                const char *val)
 {
   struct guestfs_aug_set_args args;
-  struct aug_set_rv rv;
+  struct aug_set_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_set called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_set");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_set");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_set", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   args.val = (char *) val;
@@ -1525,52 +1672,52 @@ int guestfs_aug_set (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_set_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_set failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_SET, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_SET, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct aug_insert_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_insert_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void aug_insert_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_insert_rv *rv = (struct aug_insert_rv *) data;
+  struct aug_insert_state *state = (struct aug_insert_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_insert: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_insert: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_insert (guestfs_h *g,
@@ -1579,16 +1726,23 @@ int guestfs_aug_insert (guestfs_h *g,
                int before)
 {
   struct guestfs_aug_insert_args args;
-  struct aug_insert_rv rv;
+  struct aug_insert_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_insert called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_insert");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_insert");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_insert", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   args.label = (char *) label;
@@ -1598,30 +1752,30 @@ int guestfs_aug_insert (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_insert_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_insert failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_INSERT, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_INSERT, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct aug_rm_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_rm_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_aug_rm_ret ret;
@@ -1629,42 +1783,49 @@ struct aug_rm_rv {
 
 static void aug_rm_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_rm_rv *rv = (struct aug_rm_rv *) data;
+  struct aug_rm_state *state = (struct aug_rm_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_rm: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_rm: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_aug_rm_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_aug_rm_ret (xdr, &state->ret)) {
     error (g, "guestfs_aug_rm: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_rm (guestfs_h *g,
                const char *path)
 {
   struct guestfs_aug_rm_args args;
-  struct aug_rm_rv rv;
+  struct aug_rm_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_rm called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_rm");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_rm");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_rm", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_AUG_RM,
@@ -1672,52 +1833,52 @@ int guestfs_aug_rm (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_rm_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_rm failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_RM, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_RM, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.nrnodes;
+  return state.ret.nrnodes;
 }
 
-struct aug_mv_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_mv_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void aug_mv_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_mv_rv *rv = (struct aug_mv_rv *) data;
+  struct aug_mv_state *state = (struct aug_mv_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_mv: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_mv: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_mv (guestfs_h *g,
@@ -1725,16 +1886,23 @@ int guestfs_aug_mv (guestfs_h *g,
                const char *dest)
 {
   struct guestfs_aug_mv_args args;
-  struct aug_mv_rv rv;
+  struct aug_mv_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_mv called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_mv");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_mv");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_mv", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.src = (char *) src;
   args.dest = (char *) dest;
@@ -1743,30 +1911,30 @@ int guestfs_aug_mv (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_mv_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_mv failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_MV, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_MV, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct aug_match_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_match_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_aug_match_ret ret;
@@ -1774,42 +1942,49 @@ struct aug_match_rv {
 
 static void aug_match_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_match_rv *rv = (struct aug_match_rv *) data;
+  struct aug_match_state *state = (struct aug_match_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_match: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_match: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_aug_match_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_aug_match_ret (xdr, &state->ret)) {
     error (g, "guestfs_aug_match: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_aug_match (guestfs_h *g,
                const char *path)
 {
   struct guestfs_aug_match_args args;
-  struct aug_match_rv rv;
+  struct aug_match_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_match called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_match");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_match");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_match", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_AUG_MATCH,
@@ -1817,164 +1992,178 @@ char **guestfs_aug_match (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_match_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_match failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_MATCH, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_MATCH, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.matches.matches_val =    safe_realloc (g, rv.ret.matches.matches_val,
-                  sizeof (char *) * (rv.ret.matches.matches_len + 1));
-  rv.ret.matches.matches_val[rv.ret.matches.matches_len] = NULL;
-  return rv.ret.matches.matches_val;
+  state.ret.matches.matches_val =    safe_realloc (g, state.ret.matches.matches_val,
+                  sizeof (char *) * (state.ret.matches.matches_len + 1));
+  state.ret.matches.matches_val[state.ret.matches.matches_len] = NULL;
+  return state.ret.matches.matches_val;
 }
 
-struct aug_save_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_save_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void aug_save_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_save_rv *rv = (struct aug_save_rv *) data;
+  struct aug_save_state *state = (struct aug_save_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_save: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_save: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_save (guestfs_h *g)
 {
-  struct aug_save_rv rv;
+  struct aug_save_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_save called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_save");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_save");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_save", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_AUG_SAVE, NULL, NULL);
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_save_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_save failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_SAVE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_SAVE, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct aug_load_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_load_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void aug_load_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_load_rv *rv = (struct aug_load_rv *) data;
+  struct aug_load_state *state = (struct aug_load_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_load: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_load: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_aug_load (guestfs_h *g)
 {
-  struct aug_load_rv rv;
+  struct aug_load_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_load called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_load");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_load");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_load", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_AUG_LOAD, NULL, NULL);
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_load_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_load failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_LOAD, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_LOAD, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct aug_ls_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct aug_ls_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_aug_ls_ret ret;
@@ -1982,42 +2171,49 @@ struct aug_ls_rv {
 
 static void aug_ls_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct aug_ls_rv *rv = (struct aug_ls_rv *) data;
+  struct aug_ls_state *state = (struct aug_ls_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_aug_ls: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_aug_ls: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_aug_ls_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_aug_ls_ret (xdr, &state->ret)) {
     error (g, "guestfs_aug_ls: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_aug_ls (guestfs_h *g,
                const char *path)
 {
   struct guestfs_aug_ls_args args;
-  struct aug_ls_rv rv;
+  struct aug_ls_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_aug_ls called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_aug_ls");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_aug_ls");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_aug_ls", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_AUG_LS,
@@ -2025,72 +2221,79 @@ char **guestfs_aug_ls (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = aug_ls_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_aug_ls failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_AUG_LS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_AUG_LS, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.matches.matches_val =    safe_realloc (g, rv.ret.matches.matches_val,
-                  sizeof (char *) * (rv.ret.matches.matches_len + 1));
-  rv.ret.matches.matches_val[rv.ret.matches.matches_len] = NULL;
-  return rv.ret.matches.matches_val;
+  state.ret.matches.matches_val =    safe_realloc (g, state.ret.matches.matches_val,
+                  sizeof (char *) * (state.ret.matches.matches_len + 1));
+  state.ret.matches.matches_val[state.ret.matches.matches_len] = NULL;
+  return state.ret.matches.matches_val;
 }
 
-struct rm_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct rm_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void rm_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct rm_rv *rv = (struct rm_rv *) data;
+  struct rm_state *state = (struct rm_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_rm: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_rm: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_rm (guestfs_h *g,
                const char *path)
 {
   struct guestfs_rm_args args;
-  struct rm_rv rv;
+  struct rm_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_rm called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_rm");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_rm");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_rm", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_RM,
@@ -2098,68 +2301,75 @@ int guestfs_rm (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = rm_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_rm failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_RM, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_RM, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct rmdir_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct rmdir_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void rmdir_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct rmdir_rv *rv = (struct rmdir_rv *) data;
+  struct rmdir_state *state = (struct rmdir_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_rmdir: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_rmdir: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_rmdir (guestfs_h *g,
                const char *path)
 {
   struct guestfs_rmdir_args args;
-  struct rmdir_rv rv;
+  struct rmdir_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_rmdir called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_rmdir");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_rmdir");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_rmdir", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_RMDIR,
@@ -2167,68 +2377,75 @@ int guestfs_rmdir (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = rmdir_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_rmdir failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_RMDIR, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_RMDIR, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct rm_rf_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct rm_rf_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void rm_rf_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct rm_rf_rv *rv = (struct rm_rf_rv *) data;
+  struct rm_rf_state *state = (struct rm_rf_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_rm_rf: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_rm_rf: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_rm_rf (guestfs_h *g,
                const char *path)
 {
   struct guestfs_rm_rf_args args;
-  struct rm_rf_rv rv;
+  struct rm_rf_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_rm_rf called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_rm_rf");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_rm_rf");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_rm_rf", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_RM_RF,
@@ -2236,68 +2453,75 @@ int guestfs_rm_rf (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = rm_rf_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_rm_rf failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_RM_RF, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_RM_RF, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct mkdir_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct mkdir_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void mkdir_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct mkdir_rv *rv = (struct mkdir_rv *) data;
+  struct mkdir_state *state = (struct mkdir_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_mkdir: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_mkdir: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_mkdir (guestfs_h *g,
                const char *path)
 {
   struct guestfs_mkdir_args args;
-  struct mkdir_rv rv;
+  struct mkdir_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_mkdir called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_mkdir");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_mkdir");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_mkdir", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_MKDIR,
@@ -2305,68 +2529,75 @@ int guestfs_mkdir (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = mkdir_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_mkdir failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MKDIR, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_MKDIR, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct mkdir_p_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct mkdir_p_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void mkdir_p_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct mkdir_p_rv *rv = (struct mkdir_p_rv *) data;
+  struct mkdir_p_state *state = (struct mkdir_p_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_mkdir_p: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_mkdir_p: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_mkdir_p (guestfs_h *g,
                const char *path)
 {
   struct guestfs_mkdir_p_args args;
-  struct mkdir_p_rv rv;
+  struct mkdir_p_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_mkdir_p called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_mkdir_p");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_mkdir_p");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_mkdir_p", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_MKDIR_P,
@@ -2374,52 +2605,52 @@ int guestfs_mkdir_p (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = mkdir_p_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_mkdir_p failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MKDIR_P, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_MKDIR_P, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct chmod_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct chmod_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void chmod_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct chmod_rv *rv = (struct chmod_rv *) data;
+  struct chmod_state *state = (struct chmod_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_chmod: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_chmod: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_chmod (guestfs_h *g,
@@ -2427,16 +2658,23 @@ int guestfs_chmod (guestfs_h *g,
                const char *path)
 {
   struct guestfs_chmod_args args;
-  struct chmod_rv rv;
+  struct chmod_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_chmod called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_chmod");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_chmod");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_chmod", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.mode = mode;
   args.path = (char *) path;
@@ -2445,52 +2683,52 @@ int guestfs_chmod (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = chmod_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_chmod failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_CHMOD, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_CHMOD, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct chown_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct chown_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void chown_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct chown_rv *rv = (struct chown_rv *) data;
+  struct chown_state *state = (struct chown_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_chown: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_chown: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_chown (guestfs_h *g,
@@ -2499,16 +2737,23 @@ int guestfs_chown (guestfs_h *g,
                const char *path)
 {
   struct guestfs_chown_args args;
-  struct chown_rv rv;
+  struct chown_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_chown called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_chown");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_chown");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_chown", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.owner = owner;
   args.group = group;
@@ -2518,30 +2763,30 @@ int guestfs_chown (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = chown_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_chown failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_CHOWN, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_CHOWN, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct exists_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct exists_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_exists_ret ret;
@@ -2549,42 +2794,49 @@ struct exists_rv {
 
 static void exists_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct exists_rv *rv = (struct exists_rv *) data;
+  struct exists_state *state = (struct exists_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_exists: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_exists: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_exists_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_exists_ret (xdr, &state->ret)) {
     error (g, "guestfs_exists: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_exists (guestfs_h *g,
                const char *path)
 {
   struct guestfs_exists_args args;
-  struct exists_rv rv;
+  struct exists_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_exists called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_exists");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_exists");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_exists", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_EXISTS,
@@ -2592,30 +2844,30 @@ int guestfs_exists (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = exists_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_exists failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_EXISTS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_EXISTS, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.existsflag;
+  return state.ret.existsflag;
 }
 
-struct is_file_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct is_file_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_is_file_ret ret;
@@ -2623,42 +2875,49 @@ struct is_file_rv {
 
 static void is_file_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct is_file_rv *rv = (struct is_file_rv *) data;
+  struct is_file_state *state = (struct is_file_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_is_file: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_is_file: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_is_file_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_is_file_ret (xdr, &state->ret)) {
     error (g, "guestfs_is_file: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_is_file (guestfs_h *g,
                const char *path)
 {
   struct guestfs_is_file_args args;
-  struct is_file_rv rv;
+  struct is_file_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_is_file called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_is_file");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_is_file");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_is_file", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_IS_FILE,
@@ -2666,30 +2925,30 @@ int guestfs_is_file (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = is_file_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_is_file failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_IS_FILE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_IS_FILE, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.fileflag;
+  return state.ret.fileflag;
 }
 
-struct is_dir_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct is_dir_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_is_dir_ret ret;
@@ -2697,42 +2956,49 @@ struct is_dir_rv {
 
 static void is_dir_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct is_dir_rv *rv = (struct is_dir_rv *) data;
+  struct is_dir_state *state = (struct is_dir_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_is_dir: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_is_dir: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_is_dir_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_is_dir_ret (xdr, &state->ret)) {
     error (g, "guestfs_is_dir: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_is_dir (guestfs_h *g,
                const char *path)
 {
   struct guestfs_is_dir_args args;
-  struct is_dir_rv rv;
+  struct is_dir_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_is_dir called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_is_dir");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_is_dir");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_is_dir", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_IS_DIR,
@@ -2740,68 +3006,75 @@ int guestfs_is_dir (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = is_dir_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_is_dir failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_IS_DIR, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_IS_DIR, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.dirflag;
+  return state.ret.dirflag;
 }
 
-struct pvcreate_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct pvcreate_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void pvcreate_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct pvcreate_rv *rv = (struct pvcreate_rv *) data;
+  struct pvcreate_state *state = (struct pvcreate_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_pvcreate: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_pvcreate: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_pvcreate (guestfs_h *g,
                const char *device)
 {
   struct guestfs_pvcreate_args args;
-  struct pvcreate_rv rv;
+  struct pvcreate_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_pvcreate called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_pvcreate");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_pvcreate");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_pvcreate", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_PVCREATE,
@@ -2809,52 +3082,52 @@ int guestfs_pvcreate (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = pvcreate_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_pvcreate failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_PVCREATE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_PVCREATE, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct vgcreate_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct vgcreate_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void vgcreate_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct vgcreate_rv *rv = (struct vgcreate_rv *) data;
+  struct vgcreate_state *state = (struct vgcreate_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_vgcreate: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_vgcreate: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_vgcreate (guestfs_h *g,
@@ -2862,16 +3135,23 @@ int guestfs_vgcreate (guestfs_h *g,
                char * const* const physvols)
 {
   struct guestfs_vgcreate_args args;
-  struct vgcreate_rv rv;
+  struct vgcreate_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_vgcreate called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_vgcreate");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_vgcreate");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_vgcreate", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.volgroup = (char *) volgroup;
   args.physvols.physvols_val = (char **) physvols;
@@ -2881,52 +3161,52 @@ int guestfs_vgcreate (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = vgcreate_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_vgcreate failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_VGCREATE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_VGCREATE, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct lvcreate_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct lvcreate_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void lvcreate_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct lvcreate_rv *rv = (struct lvcreate_rv *) data;
+  struct lvcreate_state *state = (struct lvcreate_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_lvcreate: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_lvcreate: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_lvcreate (guestfs_h *g,
@@ -2935,16 +3215,23 @@ int guestfs_lvcreate (guestfs_h *g,
                int mbytes)
 {
   struct guestfs_lvcreate_args args;
-  struct lvcreate_rv rv;
+  struct lvcreate_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_lvcreate called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_lvcreate");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_lvcreate");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_lvcreate", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.logvol = (char *) logvol;
   args.volgroup = (char *) volgroup;
@@ -2954,52 +3241,52 @@ int guestfs_lvcreate (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = lvcreate_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_lvcreate failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVCREATE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LVCREATE, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct mkfs_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct mkfs_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void mkfs_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct mkfs_rv *rv = (struct mkfs_rv *) data;
+  struct mkfs_state *state = (struct mkfs_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_mkfs: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_mkfs: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_mkfs (guestfs_h *g,
@@ -3007,16 +3294,23 @@ int guestfs_mkfs (guestfs_h *g,
                const char *device)
 {
   struct guestfs_mkfs_args args;
-  struct mkfs_rv rv;
+  struct mkfs_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_mkfs called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_mkfs");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_mkfs");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_mkfs", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.fstype = (char *) fstype;
   args.device = (char *) device;
@@ -3025,52 +3319,52 @@ int guestfs_mkfs (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = mkfs_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_mkfs failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MKFS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_MKFS, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct sfdisk_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct sfdisk_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void sfdisk_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct sfdisk_rv *rv = (struct sfdisk_rv *) data;
+  struct sfdisk_state *state = (struct sfdisk_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_sfdisk: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_sfdisk: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_sfdisk (guestfs_h *g,
@@ -3081,16 +3375,23 @@ int guestfs_sfdisk (guestfs_h *g,
                char * const* const lines)
 {
   struct guestfs_sfdisk_args args;
-  struct sfdisk_rv rv;
+  struct sfdisk_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_sfdisk called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_sfdisk");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_sfdisk");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_sfdisk", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   args.cyls = cyls;
@@ -3103,52 +3404,52 @@ int guestfs_sfdisk (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = sfdisk_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_sfdisk failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_SFDISK, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_SFDISK, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct write_file_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct write_file_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void write_file_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct write_file_rv *rv = (struct write_file_rv *) data;
+  struct write_file_state *state = (struct write_file_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_write_file: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_write_file: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_write_file (guestfs_h *g,
@@ -3157,16 +3458,23 @@ int guestfs_write_file (guestfs_h *g,
                int size)
 {
   struct guestfs_write_file_args args;
-  struct write_file_rv rv;
+  struct write_file_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_write_file called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_write_file");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_write_file");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_write_file", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   args.content = (char *) content;
@@ -3176,68 +3484,75 @@ int guestfs_write_file (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = write_file_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_write_file failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_WRITE_FILE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_WRITE_FILE, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct umount_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct umount_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void umount_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct umount_rv *rv = (struct umount_rv *) data;
+  struct umount_state *state = (struct umount_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_umount: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_umount: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_umount (guestfs_h *g,
                const char *pathordevice)
 {
   struct guestfs_umount_args args;
-  struct umount_rv rv;
+  struct umount_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_umount called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_umount");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_umount");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_umount", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.pathordevice = (char *) pathordevice;
   serial = dispatch (g, GUESTFS_PROC_UMOUNT,
@@ -3245,30 +3560,30 @@ int guestfs_umount (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = umount_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_umount failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_UMOUNT, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_UMOUNT, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct mounts_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct mounts_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_mounts_ret ret;
@@ -3276,203 +3591,224 @@ struct mounts_rv {
 
 static void mounts_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct mounts_rv *rv = (struct mounts_rv *) data;
+  struct mounts_state *state = (struct mounts_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_mounts: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_mounts: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_mounts_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_mounts_ret (xdr, &state->ret)) {
     error (g, "guestfs_mounts: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_mounts (guestfs_h *g)
 {
-  struct mounts_rv rv;
+  struct mounts_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_mounts called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_mounts");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_mounts");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_mounts", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_MOUNTS, NULL, NULL);
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = mounts_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_mounts failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MOUNTS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_MOUNTS, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.devices.devices_val =    safe_realloc (g, rv.ret.devices.devices_val,
-                  sizeof (char *) * (rv.ret.devices.devices_len + 1));
-  rv.ret.devices.devices_val[rv.ret.devices.devices_len] = NULL;
-  return rv.ret.devices.devices_val;
+  state.ret.devices.devices_val =    safe_realloc (g, state.ret.devices.devices_val,
+                  sizeof (char *) * (state.ret.devices.devices_len + 1));
+  state.ret.devices.devices_val[state.ret.devices.devices_len] = NULL;
+  return state.ret.devices.devices_val;
 }
 
-struct umount_all_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct umount_all_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void umount_all_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct umount_all_rv *rv = (struct umount_all_rv *) data;
+  struct umount_all_state *state = (struct umount_all_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_umount_all: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_umount_all: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_umount_all (guestfs_h *g)
 {
-  struct umount_all_rv rv;
+  struct umount_all_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_umount_all called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_umount_all");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_umount_all");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_umount_all", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_UMOUNT_ALL, NULL, NULL);
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = umount_all_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_umount_all failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_UMOUNT_ALL, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_UMOUNT_ALL, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct lvm_remove_all_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct lvm_remove_all_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void lvm_remove_all_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct lvm_remove_all_rv *rv = (struct lvm_remove_all_rv *) data;
+  struct lvm_remove_all_state *state = (struct lvm_remove_all_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_lvm_remove_all: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_lvm_remove_all: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_lvm_remove_all (guestfs_h *g)
 {
-  struct lvm_remove_all_rv rv;
+  struct lvm_remove_all_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_lvm_remove_all called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_lvm_remove_all");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_lvm_remove_all");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_lvm_remove_all", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   serial = dispatch (g, GUESTFS_PROC_LVM_REMOVE_ALL, NULL, NULL);
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = lvm_remove_all_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_lvm_remove_all failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVM_REMOVE_ALL, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LVM_REMOVE_ALL, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct file_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct file_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_file_ret ret;
@@ -3480,42 +3816,49 @@ struct file_rv {
 
 static void file_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct file_rv *rv = (struct file_rv *) data;
+  struct file_state *state = (struct file_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_file: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_file: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_file_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_file_ret (xdr, &state->ret)) {
     error (g, "guestfs_file: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char *guestfs_file (guestfs_h *g,
                const char *path)
 {
   struct guestfs_file_args args;
-  struct file_rv rv;
+  struct file_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_file called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_file");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_file");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_file", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_FILE,
@@ -3523,30 +3866,30 @@ char *guestfs_file (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = file_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_file failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_FILE, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_FILE, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
-  return rv.ret.description; /* caller will free */
+  return state.ret.description; /* caller will free */
 }
 
-struct command_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct command_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_command_ret ret;
@@ -3554,42 +3897,49 @@ struct command_rv {
 
 static void command_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct command_rv *rv = (struct command_rv *) data;
+  struct command_state *state = (struct command_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_command: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_command: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_command_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_command_ret (xdr, &state->ret)) {
     error (g, "guestfs_command: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char *guestfs_command (guestfs_h *g,
                char * const* const arguments)
 {
   struct guestfs_command_args args;
-  struct command_rv rv;
+  struct command_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_command called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_command");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_command");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_command", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.arguments.arguments_val = (char **) arguments;
   for (args.arguments.arguments_len = 0; arguments[args.arguments.arguments_len]; args.arguments.arguments_len++) ;
@@ -3598,30 +3948,30 @@ char *guestfs_command (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = command_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_command failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_COMMAND, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_COMMAND, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
-  return rv.ret.output; /* caller will free */
+  return state.ret.output; /* caller will free */
 }
 
-struct command_lines_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct command_lines_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_command_lines_ret ret;
@@ -3629,42 +3979,49 @@ struct command_lines_rv {
 
 static void command_lines_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct command_lines_rv *rv = (struct command_lines_rv *) data;
+  struct command_lines_state *state = (struct command_lines_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_command_lines: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_command_lines: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_command_lines_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_command_lines_ret (xdr, &state->ret)) {
     error (g, "guestfs_command_lines: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_command_lines (guestfs_h *g,
                char * const* const arguments)
 {
   struct guestfs_command_lines_args args;
-  struct command_lines_rv rv;
+  struct command_lines_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_command_lines called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_command_lines");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_command_lines");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_command_lines", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.arguments.arguments_val = (char **) arguments;
   for (args.arguments.arguments_len = 0; arguments[args.arguments.arguments_len]; args.arguments.arguments_len++) ;
@@ -3673,34 +4030,34 @@ char **guestfs_command_lines (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = command_lines_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_command_lines failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_COMMAND_LINES, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_COMMAND_LINES, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.lines.lines_val =    safe_realloc (g, rv.ret.lines.lines_val,
-                  sizeof (char *) * (rv.ret.lines.lines_len + 1));
-  rv.ret.lines.lines_val[rv.ret.lines.lines_len] = NULL;
-  return rv.ret.lines.lines_val;
+  state.ret.lines.lines_val =    safe_realloc (g, state.ret.lines.lines_val,
+                  sizeof (char *) * (state.ret.lines.lines_len + 1));
+  state.ret.lines.lines_val[state.ret.lines.lines_len] = NULL;
+  return state.ret.lines.lines_val;
 }
 
-struct stat_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct stat_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_stat_ret ret;
@@ -3708,42 +4065,49 @@ struct stat_rv {
 
 static void stat_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct stat_rv *rv = (struct stat_rv *) data;
+  struct stat_state *state = (struct stat_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_stat: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_stat: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_stat_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_stat_ret (xdr, &state->ret)) {
     error (g, "guestfs_stat: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 struct guestfs_stat *guestfs_stat (guestfs_h *g,
                const char *path)
 {
   struct guestfs_stat_args args;
-  struct stat_rv rv;
+  struct stat_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_stat called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_stat");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_stat");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_stat", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_STAT,
@@ -3751,31 +4115,31 @@ struct guestfs_stat *guestfs_stat (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = stat_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_stat failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_STAT, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_STAT, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this */
-  return safe_memdup (g, &rv.ret.statbuf, sizeof (rv.ret.statbuf));
+  return safe_memdup (g, &state.ret.statbuf, sizeof (state.ret.statbuf));
 }
 
-struct lstat_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct lstat_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_lstat_ret ret;
@@ -3783,42 +4147,49 @@ struct lstat_rv {
 
 static void lstat_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct lstat_rv *rv = (struct lstat_rv *) data;
+  struct lstat_state *state = (struct lstat_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_lstat: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_lstat: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_lstat_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_lstat_ret (xdr, &state->ret)) {
     error (g, "guestfs_lstat: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 struct guestfs_stat *guestfs_lstat (guestfs_h *g,
                const char *path)
 {
   struct guestfs_lstat_args args;
-  struct lstat_rv rv;
+  struct lstat_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_lstat called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_lstat");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_lstat");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_lstat", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_LSTAT,
@@ -3826,31 +4197,31 @@ struct guestfs_stat *guestfs_lstat (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = lstat_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_lstat failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LSTAT, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_LSTAT, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this */
-  return safe_memdup (g, &rv.ret.statbuf, sizeof (rv.ret.statbuf));
+  return safe_memdup (g, &state.ret.statbuf, sizeof (state.ret.statbuf));
 }
 
-struct statvfs_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct statvfs_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_statvfs_ret ret;
@@ -3858,42 +4229,49 @@ struct statvfs_rv {
 
 static void statvfs_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct statvfs_rv *rv = (struct statvfs_rv *) data;
+  struct statvfs_state *state = (struct statvfs_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_statvfs: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_statvfs: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_statvfs_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_statvfs_ret (xdr, &state->ret)) {
     error (g, "guestfs_statvfs: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 struct guestfs_statvfs *guestfs_statvfs (guestfs_h *g,
                const char *path)
 {
   struct guestfs_statvfs_args args;
-  struct statvfs_rv rv;
+  struct statvfs_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_statvfs called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_statvfs");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_statvfs");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_statvfs", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.path = (char *) path;
   serial = dispatch (g, GUESTFS_PROC_STATVFS,
@@ -3901,31 +4279,31 @@ struct guestfs_statvfs *guestfs_statvfs (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = statvfs_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_statvfs failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_STATVFS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_STATVFS, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this */
-  return safe_memdup (g, &rv.ret.statbuf, sizeof (rv.ret.statbuf));
+  return safe_memdup (g, &state.ret.statbuf, sizeof (state.ret.statbuf));
 }
 
-struct tune2fs_l_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct tune2fs_l_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_tune2fs_l_ret ret;
@@ -3933,42 +4311,49 @@ struct tune2fs_l_rv {
 
 static void tune2fs_l_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct tune2fs_l_rv *rv = (struct tune2fs_l_rv *) data;
+  struct tune2fs_l_state *state = (struct tune2fs_l_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_tune2fs_l: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_tune2fs_l: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_tune2fs_l_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_tune2fs_l_ret (xdr, &state->ret)) {
     error (g, "guestfs_tune2fs_l: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 char **guestfs_tune2fs_l (guestfs_h *g,
                const char *device)
 {
   struct guestfs_tune2fs_l_args args;
-  struct tune2fs_l_rv rv;
+  struct tune2fs_l_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_tune2fs_l called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_tune2fs_l");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_tune2fs_l");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_tune2fs_l", g->state);
     return NULL;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_TUNE2FS_L,
@@ -3976,72 +4361,79 @@ char **guestfs_tune2fs_l (guestfs_h *g,
   if (serial == -1)
     return NULL;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = tune2fs_l_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_tune2fs_l failed, see earlier error messages");
     return NULL;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_TUNE2FS_L, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_TUNE2FS_L, serial) == -1)
     return NULL;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return NULL;
   }
 
   /* caller will free this, but we need to add a NULL entry */
-  rv.ret.superblock.superblock_val =    safe_realloc (g, rv.ret.superblock.superblock_val,
-                  sizeof (char *) * (rv.ret.superblock.superblock_len + 1));
-  rv.ret.superblock.superblock_val[rv.ret.superblock.superblock_len] = NULL;
-  return rv.ret.superblock.superblock_val;
+  state.ret.superblock.superblock_val =    safe_realloc (g, state.ret.superblock.superblock_val,
+                  sizeof (char *) * (state.ret.superblock.superblock_len + 1));
+  state.ret.superblock.superblock_val[state.ret.superblock.superblock_len] = NULL;
+  return state.ret.superblock.superblock_val;
 }
 
-struct blockdev_setro_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_setro_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void blockdev_setro_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_setro_rv *rv = (struct blockdev_setro_rv *) data;
+  struct blockdev_setro_state *state = (struct blockdev_setro_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_setro: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_setro: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_blockdev_setro (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_setro_args args;
-  struct blockdev_setro_rv rv;
+  struct blockdev_setro_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_setro called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_setro");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_setro");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_setro", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_SETRO,
@@ -4049,68 +4441,75 @@ int guestfs_blockdev_setro (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_setro_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_setro failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_SETRO, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_SETRO, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct blockdev_setrw_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_setrw_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void blockdev_setrw_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_setrw_rv *rv = (struct blockdev_setrw_rv *) data;
+  struct blockdev_setrw_state *state = (struct blockdev_setrw_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_setrw: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_setrw: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_blockdev_setrw (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_setrw_args args;
-  struct blockdev_setrw_rv rv;
+  struct blockdev_setrw_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_setrw called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_setrw");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_setrw");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_setrw", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_SETRW,
@@ -4118,30 +4517,30 @@ int guestfs_blockdev_setrw (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_setrw_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_setrw failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_SETRW, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_SETRW, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct blockdev_getro_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_getro_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_blockdev_getro_ret ret;
@@ -4149,42 +4548,49 @@ struct blockdev_getro_rv {
 
 static void blockdev_getro_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_getro_rv *rv = (struct blockdev_getro_rv *) data;
+  struct blockdev_getro_state *state = (struct blockdev_getro_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_getro: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_getro: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_blockdev_getro_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_blockdev_getro_ret (xdr, &state->ret)) {
     error (g, "guestfs_blockdev_getro: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_blockdev_getro (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_getro_args args;
-  struct blockdev_getro_rv rv;
+  struct blockdev_getro_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_getro called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_getro");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_getro");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_getro", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_GETRO,
@@ -4192,30 +4598,30 @@ int guestfs_blockdev_getro (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_getro_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_getro failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_GETRO, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_GETRO, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.ro;
+  return state.ret.ro;
 }
 
-struct blockdev_getss_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_getss_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_blockdev_getss_ret ret;
@@ -4223,42 +4629,49 @@ struct blockdev_getss_rv {
 
 static void blockdev_getss_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_getss_rv *rv = (struct blockdev_getss_rv *) data;
+  struct blockdev_getss_state *state = (struct blockdev_getss_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_getss: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_getss: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_blockdev_getss_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_blockdev_getss_ret (xdr, &state->ret)) {
     error (g, "guestfs_blockdev_getss: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_blockdev_getss (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_getss_args args;
-  struct blockdev_getss_rv rv;
+  struct blockdev_getss_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_getss called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_getss");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_getss");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_getss", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_GETSS,
@@ -4266,30 +4679,30 @@ int guestfs_blockdev_getss (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_getss_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_getss failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_GETSS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_GETSS, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.sectorsize;
+  return state.ret.sectorsize;
 }
 
-struct blockdev_getbsz_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_getbsz_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_blockdev_getbsz_ret ret;
@@ -4297,42 +4710,49 @@ struct blockdev_getbsz_rv {
 
 static void blockdev_getbsz_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_getbsz_rv *rv = (struct blockdev_getbsz_rv *) data;
+  struct blockdev_getbsz_state *state = (struct blockdev_getbsz_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_getbsz: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_getbsz: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_blockdev_getbsz_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_blockdev_getbsz_ret (xdr, &state->ret)) {
     error (g, "guestfs_blockdev_getbsz: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_blockdev_getbsz (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_getbsz_args args;
-  struct blockdev_getbsz_rv rv;
+  struct blockdev_getbsz_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_getbsz called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_getbsz");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_getbsz");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_getbsz", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_GETBSZ,
@@ -4340,52 +4760,52 @@ int guestfs_blockdev_getbsz (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_getbsz_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_getbsz failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_GETBSZ, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_GETBSZ, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.blocksize;
+  return state.ret.blocksize;
 }
 
-struct blockdev_setbsz_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_setbsz_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void blockdev_setbsz_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_setbsz_rv *rv = (struct blockdev_setbsz_rv *) data;
+  struct blockdev_setbsz_state *state = (struct blockdev_setbsz_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_setbsz: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_setbsz: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_blockdev_setbsz (guestfs_h *g,
@@ -4393,16 +4813,23 @@ int guestfs_blockdev_setbsz (guestfs_h *g,
                int blocksize)
 {
   struct guestfs_blockdev_setbsz_args args;
-  struct blockdev_setbsz_rv rv;
+  struct blockdev_setbsz_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_setbsz called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_setbsz");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_setbsz");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_setbsz", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   args.blocksize = blocksize;
@@ -4411,30 +4838,30 @@ int guestfs_blockdev_setbsz (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_setbsz_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_setbsz failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_SETBSZ, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_SETBSZ, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct blockdev_getsz_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_getsz_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_blockdev_getsz_ret ret;
@@ -4442,42 +4869,49 @@ struct blockdev_getsz_rv {
 
 static void blockdev_getsz_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_getsz_rv *rv = (struct blockdev_getsz_rv *) data;
+  struct blockdev_getsz_state *state = (struct blockdev_getsz_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_getsz: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_getsz: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_blockdev_getsz_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_blockdev_getsz_ret (xdr, &state->ret)) {
     error (g, "guestfs_blockdev_getsz: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int64_t guestfs_blockdev_getsz (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_getsz_args args;
-  struct blockdev_getsz_rv rv;
+  struct blockdev_getsz_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_getsz called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_getsz");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_getsz");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_getsz", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_GETSZ,
@@ -4485,30 +4919,30 @@ int64_t guestfs_blockdev_getsz (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_getsz_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_getsz failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_GETSZ, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_GETSZ, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.sizeinsectors;
+  return state.ret.sizeinsectors;
 }
 
-struct blockdev_getsize64_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_getsize64_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
   struct guestfs_blockdev_getsize64_ret ret;
@@ -4516,42 +4950,49 @@ struct blockdev_getsize64_rv {
 
 static void blockdev_getsize64_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_getsize64_rv *rv = (struct blockdev_getsize64_rv *) data;
+  struct blockdev_getsize64_state *state = (struct blockdev_getsize64_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_getsize64: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_getsize64: failed to parse reply error");
       return;
     }
     goto done;
   }
-  if (!xdr_guestfs_blockdev_getsize64_ret (xdr, &rv->ret)) {
+  if (!xdr_guestfs_blockdev_getsize64_ret (xdr, &state->ret)) {
     error (g, "guestfs_blockdev_getsize64: failed to parse reply");
     return;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int64_t guestfs_blockdev_getsize64 (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_getsize64_args args;
-  struct blockdev_getsize64_rv rv;
+  struct blockdev_getsize64_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_getsize64 called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_getsize64");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_getsize64");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_getsize64", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_GETSIZE64,
@@ -4559,68 +5000,75 @@ int64_t guestfs_blockdev_getsize64 (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_getsize64_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_getsize64 failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_GETSIZE64, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_GETSIZE64, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
-  return rv.ret.sizeinbytes;
+  return state.ret.sizeinbytes;
 }
 
-struct blockdev_flushbufs_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_flushbufs_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void blockdev_flushbufs_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_flushbufs_rv *rv = (struct blockdev_flushbufs_rv *) data;
+  struct blockdev_flushbufs_state *state = (struct blockdev_flushbufs_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_flushbufs: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_flushbufs: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_blockdev_flushbufs (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_flushbufs_args args;
-  struct blockdev_flushbufs_rv rv;
+  struct blockdev_flushbufs_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_flushbufs called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_flushbufs");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_flushbufs");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_flushbufs", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS,
@@ -4628,68 +5076,75 @@ int guestfs_blockdev_flushbufs (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_flushbufs_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_flushbufs failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
   return 0;
 }
 
-struct blockdev_rereadpt_rv {
-  int cb_done;  /* flag to indicate callback was called */
+struct blockdev_rereadpt_state {
+  int cb_done;
   struct guestfs_message_header hdr;
   struct guestfs_message_error err;
 };
 
 static void blockdev_rereadpt_cb (guestfs_h *g, void *data, XDR *xdr)
 {
-  struct blockdev_rereadpt_rv *rv = (struct blockdev_rereadpt_rv *) data;
+  struct blockdev_rereadpt_state *state = (struct blockdev_rereadpt_state *) data;
 
-  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+  if (!xdr_guestfs_message_header (xdr, &state->hdr)) {
     error (g, "guestfs_blockdev_rereadpt: failed to parse reply header");
     return;
   }
-  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
-    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+  if (state->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &state->err)) {
       error (g, "guestfs_blockdev_rereadpt: failed to parse reply error");
       return;
     }
     goto done;
   }
  done:
-  rv->cb_done = 1;
-  main_loop.main_loop_quit (g);
+  state->cb_done = 1;
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int guestfs_blockdev_rereadpt (guestfs_h *g,
                const char *device)
 {
   struct guestfs_blockdev_rereadpt_args args;
-  struct blockdev_rereadpt_rv rv;
+  struct blockdev_rereadpt_state state;
   int serial;
 
   if (g->state != READY) {
-    error (g, "guestfs_blockdev_rereadpt called from the wrong state, %d != READY",
-      g->state);
+    if (g->state == CONFIG)
+      error (g, "%s: call launch() before using this function",
+        "guestfs_blockdev_rereadpt");
+    else if (g->state == LAUNCHING)
+      error (g, "%s: call wait_ready() before using this function",
+        "guestfs_blockdev_rereadpt");
+    else
+      error (g, "%s called from the wrong state, %d != READY",
+        "guestfs_blockdev_rereadpt", g->state);
     return -1;
   }
 
-  memset (&rv, 0, sizeof rv);
+  memset (&state, 0, sizeof state);
 
   args.device = (char *) device;
   serial = dispatch (g, GUESTFS_PROC_BLOCKDEV_REREADPT,
@@ -4697,22 +5152,22 @@ int guestfs_blockdev_rereadpt (guestfs_h *g,
   if (serial == -1)
     return -1;
 
-  rv.cb_done = 0;
+  state.cb_done = 0;
   g->reply_cb_internal = blockdev_rereadpt_cb;
-  g->reply_cb_internal_data = &rv;
-  main_loop.main_loop_run (g);
+  g->reply_cb_internal_data = &state;
+  (void) g->main_loop->main_loop_run (g->main_loop, g);
   g->reply_cb_internal = NULL;
   g->reply_cb_internal_data = NULL;
-  if (!rv.cb_done) {
+  if (!state.cb_done) {
     error (g, "guestfs_blockdev_rereadpt failed, see earlier error messages");
     return -1;
   }
 
-  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_BLOCKDEV_REREADPT, serial) == -1)
+  if (check_reply_header (g, &state.hdr, GUESTFS_PROC_BLOCKDEV_REREADPT, serial) == -1)
     return -1;
 
-  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
-    error (g, "%s", rv.err.error);
+  if (state.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", state.err.error);
     return -1;
   }
 
index e104633..6c49e90 100644 (file)
@@ -64,35 +64,71 @@ static char *safe_strdup (guestfs_h *g, const char *str);
 static void *safe_memdup (guestfs_h *g, void *ptr, size_t size);
 
 static void default_error_cb (guestfs_h *g, void *data, const char *msg);
-static void stdout_event (void *data, int watch, int fd, int events);
-static void sock_read_event (void *data, int watch, int fd, int events);
-static void sock_write_event (void *data, int watch, int fd, int events);
+static void stdout_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, int watch, int fd, int events);
+static void sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, int watch, int fd, int events);
+static void sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, int watch, int fd, int events);
 
 static void close_handles (void);
 
-static int select_add_handle (guestfs_h *g, int fd, int events, guestfs_handle_event_cb cb, void *data);
-static int select_remove_handle (guestfs_h *g, int watch);
-static int select_add_timeout (guestfs_h *g, int interval, guestfs_handle_timeout_cb cb, void *data);
-static int select_remove_timeout (guestfs_h *g, int timer);
-static void select_main_loop_run (guestfs_h *g);
-static void select_main_loop_quit (guestfs_h *g);
+static int select_add_handle (guestfs_main_loop *ml, guestfs_h *g, int fd, int events, guestfs_handle_event_cb cb, void *data);
+static int select_remove_handle (guestfs_main_loop *ml, guestfs_h *g, int watch);
+static int select_add_timeout (guestfs_main_loop *ml, guestfs_h *g, int interval, guestfs_handle_timeout_cb cb, void *data);
+static int select_remove_timeout (guestfs_main_loop *ml, guestfs_h *g, int timer);
+static int select_main_loop_run (guestfs_main_loop *ml, guestfs_h *g);
+static int select_main_loop_quit (guestfs_main_loop *ml, guestfs_h *g);
 
-#define UNIX_PATH_MAX 108
+/* Default select-based main loop. */
+struct select_handle_cb_data {
+  guestfs_handle_event_cb cb;
+  guestfs_h *g;
+  void *data;
+};
 
-/* Also in guestfsd.c */
-#define VMCHANNEL_PORT 6666
-#define VMCHANNEL_ADDR "10.0.2.4"
+struct select_main_loop {
+  /* NB. These fields must be the same as in struct guestfs_main_loop: */
+  guestfs_add_handle_cb add_handle;
+  guestfs_remove_handle_cb remove_handle;
+  guestfs_add_timeout_cb add_timeout;
+  guestfs_remove_timeout_cb remove_timeout;
+  guestfs_main_loop_run_cb main_loop_run;
+  guestfs_main_loop_quit_cb main_loop_quit;
+
+  /* Additional private data: */
+  int is_running;
+
+  fd_set rset;
+  fd_set wset;
+  fd_set xset;
+
+  int max_fd;
+  int nr_fds;
+  struct select_handle_cb_data *handle_cb_data;
+};
 
-/* Current main loop. */
-static guestfs_main_loop main_loop = {
+/* Default main loop. */
+static struct select_main_loop default_main_loop = {
   .add_handle = select_add_handle,
   .remove_handle = select_remove_handle,
   .add_timeout = select_add_timeout,
   .remove_timeout = select_remove_timeout,
   .main_loop_run = select_main_loop_run,
   .main_loop_quit = select_main_loop_quit,
+
+  /* XXX hopefully .rset, .wset, .xset are initialized to the empty
+   * set by the normal action of everything being initialized to zero.
+   */
+  .is_running = 0,
+  .max_fd = -1,
+  .nr_fds = 0,
+  .handle_cb_data = NULL,
 };
 
+#define UNIX_PATH_MAX 108
+
+/* Also in guestfsd.c */
+#define VMCHANNEL_PORT 6666
+#define VMCHANNEL_ADDR "10.0.2.4"
+
 /* GuestFS handle and connection. */
 enum state { CONFIG, LAUNCHING, READY, BUSY, NO_HANDLE };
 
@@ -127,6 +163,8 @@ struct guestfs_h
   guestfs_abort_cb           abort_cb;
   guestfs_error_handler_cb   error_cb;
   void *                     error_cb_data;
+  guestfs_send_cb            send_cb;
+  void *                     send_cb_data;
   guestfs_reply_cb           reply_cb;
   void *                     reply_cb_data;
   guestfs_log_message_cb     log_message_cb;
@@ -136,15 +174,21 @@ struct guestfs_h
   guestfs_launch_done_cb     launch_done_cb;
   void *                     launch_done_cb_data;
 
-  /* These callbacks are called before reply_cb and launch_done_cb,
-   * and are used to implement the high-level API without needing to
-   * interfere with callbacks that the user might have set.
+  /* These callbacks are called before send_cb, reply_cb and
+   * launch_done_cb, and are used to implement the high-level
+   * API without needing to interfere with callbacks that the
+   * user might have set.
    */
+  guestfs_send_cb            send_cb_internal;
+  void *                     send_cb_internal_data;
   guestfs_reply_cb           reply_cb_internal;
   void *                     reply_cb_internal_data;
   guestfs_launch_done_cb     launch_done_cb_internal;
   void *                     launch_done_cb_internal_data;
 
+  /* Main loop used by this handle. */
+  guestfs_main_loop *main_loop;
+
   /* Messages sent and received from the daemon. */
   char *msg_in;
   int msg_in_size, msg_in_allocated;
@@ -187,6 +231,8 @@ guestfs_create (void)
   g->path = str != NULL ? str : GUESTFS_DEFAULT_PATH;
   /* XXX We should probably make QEMU configurable as well. */
 
+  g->main_loop = (guestfs_main_loop *) &default_main_loop;
+
   /* Start with large serial numbers so they are easy to spot
    * inside the protocol.
    */
@@ -780,18 +826,18 @@ guestfs_launch (guestfs_h *g)
   g->msg_out_pos = 0;
 
   g->stdout_watch =
-    main_loop.add_handle (g, g->fd[1],
-                         GUESTFS_HANDLE_READABLE,
-                         stdout_event, g);
+    g->main_loop->add_handle (g->main_loop, g, g->fd[1],
+                             GUESTFS_HANDLE_READABLE,
+                             stdout_event, NULL);
   if (g->stdout_watch == -1) {
     error (g, "could not watch qemu stdout");
     goto cleanup3;
   }
 
   g->sock_watch =
-    main_loop.add_handle (g, g->sock,
-                         GUESTFS_HANDLE_READABLE,
-                         sock_read_event, g);
+    g->main_loop->add_handle (g->main_loop, g, g->sock,
+                             GUESTFS_HANDLE_READABLE,
+                             sock_read_event, NULL);
   if (g->sock_watch == -1) {
     error (g, "could not watch daemon communications socket");
     goto cleanup3;
@@ -802,9 +848,9 @@ guestfs_launch (guestfs_h *g)
 
  cleanup3:
   if (g->stdout_watch >= 0)
-    main_loop.remove_handle (g, g->stdout_watch);
+    g->main_loop->remove_handle (g->main_loop, g, g->stdout_watch);
   if (g->sock_watch >= 0)
-    main_loop.remove_handle (g, g->sock_watch);
+    g->main_loop->remove_handle (g->main_loop, g, g->sock_watch);
 
  cleanup2:
   close (g->sock);
@@ -831,14 +877,17 @@ guestfs_launch (guestfs_h *g)
 static void
 finish_wait_ready (guestfs_h *g, void *vp)
 {
+  if (g->verbose)
+    fprintf (stderr, "finish_wait_ready called, %p, vp = %p\n", g, vp);
+
   *((int *)vp) = 1;
-  main_loop.main_loop_quit (g);
+  g->main_loop->main_loop_quit (g->main_loop, g);
 }
 
 int
 guestfs_wait_ready (guestfs_h *g)
 {
-  int r = 0;
+  int finished = 0, r;
 
   if (g->state == READY) return 0;
 
@@ -853,12 +902,14 @@ guestfs_wait_ready (guestfs_h *g)
   }
 
   g->launch_done_cb_internal = finish_wait_ready;
-  g->launch_done_cb_internal_data = &r;
-  main_loop.main_loop_run (g);
+  g->launch_done_cb_internal_data = &finished;
+  r = g->main_loop->main_loop_run (g->main_loop, g);
   g->launch_done_cb_internal = NULL;
   g->launch_done_cb_internal_data = NULL;
 
-  if (r != 1) {
+  if (r == -1) return -1;
+
+  if (finished != 1) {
     error (g, "guestfs_wait_ready failed, see earlier error messages");
     return -1;
   }
@@ -897,9 +948,9 @@ guestfs_kill_subprocess (guestfs_h *g)
  * we see kernel messages here too.
  */
 static void
-stdout_event (void *data, int watch, int fd, int events)
+stdout_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
+             int watch, int fd, int events)
 {
-  guestfs_h *g = (guestfs_h *) data;
   char buf[4096];
   int n;
 
@@ -923,9 +974,9 @@ stdout_event (void *data, int watch, int fd, int events)
     /*kill (g->pid, SIGTERM);*/
     waitpid (g->pid, NULL, 0);
     if (g->stdout_watch >= 0)
-      main_loop.remove_handle (g, g->stdout_watch);
+      g->main_loop->remove_handle (g->main_loop, g, g->stdout_watch);
     if (g->sock_watch >= 0)
-      main_loop.remove_handle (g, g->sock_watch);
+      g->main_loop->remove_handle (g->main_loop, g, g->sock_watch);
     close (g->fd[0]);
     close (g->fd[1]);
     close (g->sock);
@@ -961,9 +1012,9 @@ stdout_event (void *data, int watch, int fd, int events)
  * guestfsd (daemon inside the guest) communication socket.
  */
 static void
-sock_read_event (void *data, int watch, int fd, int events)
+sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
+                int watch, int fd, int events)
 {
-  guestfs_h *g = (guestfs_h *) data;
   XDR xdr;
   unsigned len;
   int n;
@@ -1098,9 +1149,9 @@ sock_read_event (void *data, int watch, int fd, int events)
  * guestfsd (daemon inside the guest) communication socket.
  */
 static void
-sock_write_event (void *data, int watch, int fd, int events)
+sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
+                 int watch, int fd, int events)
 {
-  guestfs_h *g = (guestfs_h *) data;
   int n;
 
   if (g->verbose)
@@ -1145,14 +1196,14 @@ sock_write_event (void *data, int watch, int fd, int events)
   free (g->msg_out);
   g->msg_out_pos = g->msg_out_size = 0;
 
-  if (main_loop.remove_handle (g, g->sock_watch) == -1) {
+  if (g->main_loop->remove_handle (g->main_loop, g, g->sock_watch) == -1) {
     error (g, "remove_handle failed in sock_write_event");
     return;
   }
   g->sock_watch =
-    main_loop.add_handle (g, g->sock,
-                         GUESTFS_HANDLE_READABLE,
-                         sock_read_event, g);
+    g->main_loop->add_handle (g->main_loop, g, g->sock,
+                             GUESTFS_HANDLE_READABLE,
+                             sock_read_event, NULL);
   if (g->sock_watch == -1) {
     error (g, "add_handle failed in sock_write_event");
     return;
@@ -1220,14 +1271,14 @@ dispatch (guestfs_h *g, int proc_nr, xdrproc_t xdrp, char *args)
   memcpy (g->msg_out + 4, buffer, len);
 
   /* Change the handle to sock_write_event. */
-  if (main_loop.remove_handle (g, g->sock_watch) == -1) {
+  if (g->main_loop->remove_handle (g->main_loop, g, g->sock_watch) == -1) {
     error (g, "remove_handle failed in dispatch");
     goto cleanup1;
   }
   g->sock_watch =
-    main_loop.add_handle (g, g->sock,
-                         GUESTFS_HANDLE_WRITABLE,
-                         sock_write_event, g);
+    g->main_loop->add_handle (g->main_loop, g, g->sock,
+                             GUESTFS_HANDLE_WRITABLE,
+                             sock_write_event, NULL);
   if (g->sock_watch == -1) {
     error (g, "add_handle failed in dispatch");
     goto cleanup1;
@@ -1243,6 +1294,139 @@ dispatch (guestfs_h *g, int proc_nr, xdrproc_t xdrp, char *args)
   return -1;
 }
 
+#if 0
+static int cancel = 0; /* XXX Implement file cancellation. */
+
+static int
+send_file (guestfs_h *g, const char *filename)
+{
+  char buf[GUESTFS_MAX_CHUNK_SIZE];
+  int fd, r;
+
+  fd = open (filename, O_RDONLY);
+  if (fd == -1) {
+    perrorf (g, "open: %s", filename);
+    send_file_cancellation (g);
+    /* Daemon sees cancellation and won't reply, so caller can
+     * just return here.
+     */
+    return -1;
+  }
+
+  /* Send file in chunked encoding. */
+  while (!cancel && (r = read (fd, buf, sizeof buf)) > 0) {
+    if (send_file_data (g, buf, r) == -1)
+      return -1;
+  }
+
+  if (cancel) {
+    send_file_cancellation (g);
+    return -1;
+  }
+
+  if (r == -1) {
+    perrorf (g, "read: %s", filename);
+    send_file_cancellation (g);
+    return -1;
+  }
+
+  /* End of file, but before we send that, we need to close
+   * the file and check for errors.
+   */
+  if (close (fd) == -1) {
+    perrorf (g, "close: %s", filename);
+    send_file_cancellation (g);
+    return -1;
+  }
+
+  return send_file_complete (g);
+}
+
+/* Send a chunk, cancellation or end of file, wait for it to go. */
+static int
+send_file_chunk (guestfs_h *g, int cancel, const char *buf, size_t len)
+{
+  void *data;
+  guestfs_chunk chunk;
+  XDR xdr;
+
+  if (g->state != BUSY) {
+    error (g, "send_file_chunk: state %d != READY", g->state);
+    return -1;
+  }
+
+  /* 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);
+    return -1;
+  }
+
+  chunkdatalen = xdr_getpos (&xdr);
+  xdr_destroy (&xdr);
+
+  len = xdr_getpos (&xdr);
+  xdr_destroy (&xdr);
+
+  data = safe_realloc (g, data, len);
+  g->msg_out = data;
+  g->msg_out_size = len;
+  g->msg_out_pos = 0;
+
+  /* Change the handle to sock_write_event. */
+  if (g->main_loop->remove_handle (g->main_loop, g, g->sock_watch) == -1) {
+    error (g, "remove_handle failed in dispatch");
+    goto cleanup1;
+  }
+  g->sock_watch =
+    g->main_loop->add_handle (g->main_loop, g, g->sock,
+                             GUESTFS_HANDLE_WRITABLE,
+                             sock_write_event, NULL);
+  if (g->sock_watch == -1) {
+    error (g, "add_handle failed in dispatch");
+    goto cleanup1;
+  }
+
+  return 0;
+
+ cleanup1:
+  free (g->msg_out);
+  g->msg_out = NULL;
+  g->msg_out_size = 0;
+  g->state = READY;
+  return -1;
+}
+
+/* Send a chunk of file data. */
+static int
+send_file_data (guestfs_h *g, const char *buf, size_t len)
+{
+  return send_file_chunk (g, 0, buf, len);
+}
+
+/* Send a cancellation message. */
+static int
+send_file_cancellation (guestfs_h *g)
+{
+  char buf[1];
+  return send_file_chunk (g, 1, buf, 0);
+}
+
+/* Send a file complete chunk. */
+static int
+send_file_complete (guestfs_h *g)
+{
+  char buf[0];
+  return send_file_chunk (g, 0, buf, 0);
+}
+#endif
+
 /* Check the return message from a call for validity. */
 static int
 check_reply_header (guestfs_h *g,
@@ -1313,36 +1497,11 @@ guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *x)
 
 /* This is the default main loop implementation, using select(2). */
 
-struct handle_cb_data {
-  guestfs_handle_event_cb cb;
-  void *data;
-};
-
-static fd_set rset;
-static fd_set wset;
-static fd_set xset;
-static int select_init_done = 0;
-static int max_fd = -1;
-static int nr_fds = 0;
-static struct handle_cb_data *handle_cb_data = NULL;
-
-static void
-select_init (void)
-{
-  if (!select_init_done) {
-    FD_ZERO (&rset);
-    FD_ZERO (&wset);
-    FD_ZERO (&xset);
-
-    select_init_done = 1;
-  }
-}
-
 static int
-select_add_handle (guestfs_h *g, int fd, int events,
+select_add_handle (guestfs_main_loop *mlv, guestfs_h *g, int fd, int events,
                   guestfs_handle_event_cb cb, void *data)
 {
-  select_init ();
+  struct select_main_loop *ml = (struct select_main_loop *) mlv;
 
   if (fd < 0 || fd >= FD_SETSIZE) {
     error (g, "fd %d is out of range", fd);
@@ -1362,7 +1521,9 @@ select_add_handle (guestfs_h *g, int fd, int events,
     return -1;
   }
 
-  if (FD_ISSET (fd, &rset) || FD_ISSET (fd, &wset) || FD_ISSET (fd, &xset)) {
+  if (FD_ISSET (fd, &ml->rset) ||
+      FD_ISSET (fd, &ml->wset) ||
+      FD_ISSET (fd, &ml->xset)) {
     error (g, "fd %d is already registered", fd);
     return -1;
   }
@@ -1373,102 +1534,111 @@ select_add_handle (guestfs_h *g, int fd, int events,
   }
 
   if ((events & GUESTFS_HANDLE_READABLE))
-    FD_SET (fd, &rset);
+    FD_SET (fd, &ml->rset);
   if ((events & GUESTFS_HANDLE_WRITABLE))
-    FD_SET (fd, &wset);
+    FD_SET (fd, &ml->wset);
   if ((events & GUESTFS_HANDLE_HANGUP) || (events & GUESTFS_HANDLE_ERROR))
-    FD_SET (fd, &xset);
+    FD_SET (fd, &ml->xset);
 
-  if (fd > max_fd) {
-    max_fd = fd;
-    handle_cb_data = safe_realloc (g, handle_cb_data,
-                                  sizeof (struct handle_cb_data) * (max_fd+1));
+  if (fd > ml->max_fd) {
+    ml->max_fd = fd;
+    ml->handle_cb_data =
+      safe_realloc (g, ml->handle_cb_data,
+                   sizeof (struct select_handle_cb_data) * (ml->max_fd+1));
   }
-  handle_cb_data[fd].cb = cb;
-  handle_cb_data[fd].data = data;
+  ml->handle_cb_data[fd].cb = cb;
+  ml->handle_cb_data[fd].g = g;
+  ml->handle_cb_data[fd].data = data;
 
-  nr_fds++;
+  ml->nr_fds++;
 
   /* Any integer >= 0 can be the handle, and this is as good as any ... */
   return fd;
 }
 
 static int
-select_remove_handle (guestfs_h *g, int fd)
+select_remove_handle (guestfs_main_loop *mlv, guestfs_h *g, int fd)
 {
-  select_init ();
+  struct select_main_loop *ml = (struct select_main_loop *) mlv;
 
   if (fd < 0 || fd >= FD_SETSIZE) {
     error (g, "fd %d is out of range", fd);
     return -1;
   }
 
-  if (!FD_ISSET (fd, &rset) && !FD_ISSET (fd, &wset) && !FD_ISSET (fd, &xset)) {
+  if (!FD_ISSET (fd, &ml->rset) &&
+      !FD_ISSET (fd, &ml->wset) &&
+      !FD_ISSET (fd, &ml->xset)) {
     error (g, "fd %d was not registered", fd);
     return -1;
   }
 
-  FD_CLR (fd, &rset);
-  FD_CLR (fd, &wset);
-  FD_CLR (fd, &xset);
+  FD_CLR (fd, &ml->rset);
+  FD_CLR (fd, &ml->wset);
+  FD_CLR (fd, &ml->xset);
 
-  if (fd == max_fd) {
-    max_fd--;
-    handle_cb_data = safe_realloc (g, handle_cb_data,
-                                  sizeof (struct handle_cb_data) * (max_fd+1));
+  if (fd == ml->max_fd) {
+    ml->max_fd--;
+    ml->handle_cb_data =
+      safe_realloc (g, ml->handle_cb_data,
+                   sizeof (struct select_handle_cb_data) * (ml->max_fd+1));
   }
 
-  nr_fds--;
+  ml->nr_fds--;
 
   return 0;
 }
 
 static int
-select_add_timeout (guestfs_h *g, int interval,
+select_add_timeout (guestfs_main_loop *mlv, guestfs_h *g, int interval,
                    guestfs_handle_timeout_cb cb, void *data)
 {
-  select_init ();
+  //struct select_main_loop *ml = (struct select_main_loop *) mlv;
 
   abort ();                    /* XXX not implemented yet */
 }
 
 static int
-select_remove_timeout (guestfs_h *g, int timer)
+select_remove_timeout (guestfs_main_loop *mlv, guestfs_h *g, int timer)
 {
-  select_init ();
+  //struct select_main_loop *ml = (struct select_main_loop *) mlv;
 
   abort ();                    /* XXX not implemented yet */
 }
 
-/* Note that main loops can be nested. */
-static int level = 0;
-
-static void
-select_main_loop_run (guestfs_h *g)
+/* The 'g' parameter is just used for error reporting.  Events
+ * for multiple handles can be dispatched by running the main
+ * loop.
+ */
+static int
+select_main_loop_run (guestfs_main_loop *mlv, guestfs_h *g)
 {
-  int old_level, fd, r, events;
+  struct select_main_loop *ml = (struct select_main_loop *) mlv;
+  int fd, r, events;
   fd_set rset2, wset2, xset2;
 
-  select_init ();
+  if (ml->is_running) {
+    error (g, "select_main_loop_run: this cannot be called recursively");
+    return -1;
+  }
+
+  ml->is_running = 1;
 
-  old_level = level++;
-  while (level > old_level) {
-    if (nr_fds == 0) {
-      level = old_level;
+  while (ml->is_running) {
+    if (ml->nr_fds == 0)
       break;
-    }
 
-    rset2 = rset;
-    wset2 = wset;
-    xset2 = xset;
-    r = select (max_fd+1, &rset2, &wset2, &xset2, NULL);
+    rset2 = ml->rset;
+    wset2 = ml->wset;
+    xset2 = ml->xset;
+    r = select (ml->max_fd+1, &rset2, &wset2, &xset2, NULL);
     if (r == -1) {
       perrorf (g, "select");
-      level = old_level;
-      break;
+      ml->is_running = 0;
+      return -1;
     }
 
-    for (fd = 0; r > 0 && fd <= max_fd; ++fd) {
+    for (fd = 0; r > 0 && fd <= ml->max_fd; ++fd) {
       events = 0;
       if (FD_ISSET (fd, &rset2))
        events |= GUESTFS_HANDLE_READABLE;
@@ -1478,22 +1648,28 @@ select_main_loop_run (guestfs_h *g)
        events |= GUESTFS_HANDLE_ERROR | GUESTFS_HANDLE_HANGUP;
       if (events) {
        r--;
-       handle_cb_data[fd].cb (handle_cb_data[fd].data,
-                              fd, fd, events);
+       ml->handle_cb_data[fd].cb ((guestfs_main_loop *) ml,
+                                  ml->handle_cb_data[fd].g,
+                                  ml->handle_cb_data[fd].data,
+                                  fd, fd, events);
       }
     }
   }
+
+  ml->is_running = 0;
+  return 0;
 }
 
-static void
-select_main_loop_quit (guestfs_h *g)
+static int
+select_main_loop_quit (guestfs_main_loop *mlv, guestfs_h *g)
 {
-  select_init ();
+  struct select_main_loop *ml = (struct select_main_loop *) mlv;
 
-  if (level == 0) {
-    error (g, "cannot quit, we are not in a main loop");
-    return;
+  if (!ml->is_running) {
+    error (g, "cannot quit, we are not running in a main loop");
+    return -1;
   }
 
-  level--;
+  ml->is_running = 0;
+  return 0;
 }
index 3905554..bfa6b9c 100644 (file)
@@ -53,11 +53,13 @@ extern void guestfs_free_lvm_vg_list (struct guestfs_lvm_vg_list *);
 extern void guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *);
 
 /* Low-level event API. */
+typedef void (*guestfs_send_cb) (guestfs_h *g, void *data);
 typedef void (*guestfs_reply_cb) (guestfs_h *g, void *data, XDR *xdr);
 typedef void (*guestfs_log_message_cb) (guestfs_h *g, void *data, char *buf, int len);
 typedef void (*guestfs_subprocess_quit_cb) (guestfs_h *g, void *data);
 typedef void (*guestfs_launch_done_cb) (guestfs_h *g, void *data);
 
+extern void guestfs_set_send_callback (guestfs_h *g, guestfs_send_cb cb, void *opaque);
 extern void guestfs_set_reply_callback (guestfs_h *g, guestfs_reply_cb cb, void *opaque);
 extern void guestfs_set_log_message_callback (guestfs_h *g, guestfs_log_message_cb cb, void *opaque);
 extern void guestfs_set_subprocess_quit_callback (guestfs_h *g, guestfs_subprocess_quit_cb cb, void *opaque);
@@ -69,15 +71,20 @@ extern void guestfs_set_launch_done_callback (guestfs_h *g, guestfs_launch_done_
 #define GUESTFS_HANDLE_HANGUP   0x4
 #define GUESTFS_HANDLE_ERROR    0x8
 
-typedef void (*guestfs_handle_event_cb) (void *data, int watch, int fd, int events);
-typedef int (*guestfs_add_handle_cb) (guestfs_h *g, int fd, int events, guestfs_handle_event_cb cb, void *data);
-typedef int (*guestfs_remove_handle_cb) (guestfs_h *g, int watch);
-typedef void (*guestfs_handle_timeout_cb) (void *data, int timer);
-typedef int (*guestfs_add_timeout_cb) (guestfs_h *g, int interval, guestfs_handle_timeout_cb cb, void *data);
-typedef int (*guestfs_remove_timeout_cb) (guestfs_h *g, int timer);
-typedef void (*guestfs_main_loop_run_cb) (guestfs_h *g);
-typedef void (*guestfs_main_loop_quit_cb) (guestfs_h *g);
+struct guestfs_main_loop;
 
+typedef void (*guestfs_handle_event_cb) (struct guestfs_main_loop *ml, guestfs_h *g, void *data, int watch, int fd, int events);
+typedef int (*guestfs_add_handle_cb) (struct guestfs_main_loop *ml, guestfs_h *g, int fd, int events, guestfs_handle_event_cb cb, void *data);
+typedef int (*guestfs_remove_handle_cb) (struct guestfs_main_loop *ml, guestfs_h *g, int watch);
+typedef void (*guestfs_handle_timeout_cb) (struct guestfs_main_loop *ml, guestfs_h *g, void *data, int timer);
+typedef int (*guestfs_add_timeout_cb) (struct guestfs_main_loop *ml, guestfs_h *g, int interval, guestfs_handle_timeout_cb cb, void *data);
+typedef int (*guestfs_remove_timeout_cb) (struct guestfs_main_loop *ml, guestfs_h *g, int timer);
+typedef int (*guestfs_main_loop_run_cb) (struct guestfs_main_loop *ml, guestfs_h *g);
+typedef int (*guestfs_main_loop_quit_cb) (struct guestfs_main_loop *ml, guestfs_h *g);
+
+/* This is the head of the main loop structure.  Concrete implementations
+ * use additional private data after this struct.
+ */
 struct guestfs_main_loop {
   guestfs_add_handle_cb add_handle;
   guestfs_remove_handle_cb remove_handle;
@@ -88,8 +95,11 @@ struct guestfs_main_loop {
 };
 typedef struct guestfs_main_loop guestfs_main_loop;
 
-extern void guestfs_set_main_loop (guestfs_main_loop *);
-extern void guestfs_main_loop_run (void);
-extern void guestfs_main_loop_quit (void);
+extern void guestfs_set_main_loop (guestfs_h *handle, guestfs_main_loop *main_loop);
+extern guestfs_main_loop *guestfs_get_main_loop (guestfs_h *handle);
+extern guestfs_main_loop *guestfs_get_default_main_loop (void);
+
+extern guestfs_main_loop *guestfs_create_main_loop (void);
+extern void guestfs_free_main_loop (guestfs_main_loop *);
 
 #endif /* GUESTFS_H_ */
index eb90d75..86a338f 100644 (file)
@@ -1245,3 +1245,15 @@ xdr_guestfs_message_header (XDR *xdrs, guestfs_message_header *objp)
                 return FALSE;
        return TRUE;
 }
+
+bool_t
+xdr_guestfs_chunk (XDR *xdrs, guestfs_chunk *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_int (xdrs, &objp->cancel))
+                return FALSE;
+        if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, GUESTFS_MAX_CHUNK_SIZE))
+                return FALSE;
+       return TRUE;
+}
index 822d960..c1837f8 100644 (file)
@@ -682,7 +682,7 @@ enum guestfs_procedure {
        GUESTFS_PROC_BLOCKDEV_GETSIZE64 = 63,
        GUESTFS_PROC_BLOCKDEV_FLUSHBUFS = 64,
        GUESTFS_PROC_BLOCKDEV_REREADPT = 65,
-       GUESTFS_PROC_dummy = 65 + 1,
+       GUESTFS_PROC_NR_PROCS = 65 + 1,
 };
 typedef enum guestfs_procedure guestfs_procedure;
 #define GUESTFS_MESSAGE_MAX 4194304
@@ -716,6 +716,16 @@ struct guestfs_message_header {
        guestfs_message_status status;
 };
 typedef struct guestfs_message_header guestfs_message_header;
+#define GUESTFS_MAX_CHUNK_SIZE 8192
+
+struct guestfs_chunk {
+       int cancel;
+       struct {
+               u_int data_len;
+               char *data_val;
+       } data;
+};
+typedef struct guestfs_chunk guestfs_chunk;
 
 /* the xdr functions */
 
@@ -818,6 +828,7 @@ extern  bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*)
 extern  bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
 extern  bool_t xdr_guestfs_message_error (XDR *, guestfs_message_error*);
 extern  bool_t xdr_guestfs_message_header (XDR *, guestfs_message_header*);
+extern  bool_t xdr_guestfs_chunk (XDR *, guestfs_chunk*);
 
 #else /* K&R C */
 extern bool_t xdr_str ();
@@ -918,6 +929,7 @@ extern bool_t xdr_guestfs_message_direction ();
 extern bool_t xdr_guestfs_message_status ();
 extern bool_t xdr_guestfs_message_error ();
 extern bool_t xdr_guestfs_message_header ();
+extern bool_t xdr_guestfs_chunk ();
 
 #endif /* K&R C */
 
index ba5d70c..d77bb5f 100644 (file)
@@ -541,7 +541,7 @@ enum guestfs_procedure {
   GUESTFS_PROC_BLOCKDEV_GETSIZE64 = 63,
   GUESTFS_PROC_BLOCKDEV_FLUSHBUFS = 64,
   GUESTFS_PROC_BLOCKDEV_REREADPT = 65,
-  GUESTFS_PROC_dummy
+  GUESTFS_PROC_NR_PROCS
 };
 
 const GUESTFS_MESSAGE_MAX = 4194304;
@@ -565,6 +565,19 @@ struct guestfs_message_error {
   string error<GUESTFS_ERROR_LEN>;   /* error message */
 };
 
+/* 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 */
@@ -573,3 +586,28 @@ struct guestfs_message_header {
   unsigned serial;                   /* message serial number */
   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 {
+  int cancel;                       /* if non-zero, transfer is cancelled */
+  /* data size is 0 bytes if the transfer has finished successfully */
+  opaque data<GUESTFS_MAX_CHUNK_SIZE>;
+};