[fedora-virt] [PATCH] Remove receive callbacks (libguestfs)
Richard W.M. Jones
rjones at redhat.com
Thu Jul 2 10:07:47 UTC 2009
On Wed, Jul 01, 2009 at 06:19:13PM +0100, Matthew Booth wrote:
> From commit message:
> ========
> This patch fixes a class of race conditions characterised by the
> following sequence of events:
>
> LIBRARY DAEMON
> send download request
> receive download request
> respond with download response
> start sending file chunks
> set reply callback to 'download'
> run main loop
>
> At this stage the download reply callback receives both the download
> reply and some file chunks. The current architecture doesn't provide a
> clean way
> to prevent this from happening.
>
> This patch fixes the above problem by changing the socket receive
> handler to do nothing but buffering, and provides 2 new apis:
>
> guestfs_get_reply
> guestfs_free_reply
>
> These will always de-queue exactly 1 message, which is always what is
> wanted.
> =======
>
> This is a fairly invasive patch. Note that it still uses the main loop
> for reading and writing data to the socket.
>
> The patch also looks a lot bigger than it really is, because it changes
> the auto-generated code. I'm separately planning to remove
> auto-generated code from git.
>
> Matt
> --
> Matthew Booth, RHCA, RHCSS
> Red Hat Engineering, Virtualisation Team
>
> M: +44 (0)7977 267231
> GPG ID: D33C3490
> GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
> >From 2e155ead570e8aba98d8763cebaa50cfa8a73da6 Mon Sep 17 00:00:00 2001
> From: Matthew Booth <mbooth at redhat.com>
> Date: Sat, 27 Jun 2009 22:05:48 +0100
> Subject: [PATCH] Remove receive callbacks
>
> This patch fixes a class of race conditions characterised by the
> following sequence of events:
>
> LIBRARY DAEMON
> send download request
> receive download request
> respond with download response
> start sending file chunks
> set reply callback to 'download'
> run main loop
>
> At this stage the download reply callback receives both the download
> reply and some file chunks. The current architecture doesn't provide a clean way
> to prevent this from happening.
>
> This patch fixes the above problem by changing the socket receive
> handler to do nothing but buffering, and provides 2 new apis:
>
> guestfs_get_reply
> guestfs_free_reply
>
> These will always de-queue exactly 1 message, which is always what is
> wanted.
> ---
> src/generator.ml | 207 +-
> src/guestfs-actions.c |15436 +++++++++++++++++++++++--------------------------
> src/guestfs.c | 668 +--
> src/guestfs.h | 13 +-
> 4 files changed, 7510 insertions(+), 8814 deletions(-)
>
> diff --git a/src/generator.ml b/src/generator.ml
> index 69fd706..c6e25ec 100755
> --- a/src/generator.ml
> +++ b/src/generator.ml
> @@ -3616,81 +3616,6 @@ check_state (guestfs_h *g, const char *caller)
> List.iter (
> fun (shortname, style, _, _, _, _, _) ->
> let name = "guestfs_" ^ shortname in
> -
> - (* Generate the context struct which stores the high-level
> - * state between callback functions.
> - *)
> - pr "struct %s_ctx {\n" shortname;
> - pr " /* This flag is set by the callbacks, so we know we've done\n";
> - pr " * the callbacks as expected, and in the right sequence.\n";
> - pr " * 0 = not called, 1 = reply_cb called.\n";
> - pr " */\n";
> - pr " int cb_sequence;\n";
> - pr " struct guestfs_message_header hdr;\n";
> - pr " struct guestfs_message_error err;\n";
> - (match fst style with
> - | RErr -> ()
> - | RConstString _ ->
> - failwithf "RConstString cannot be returned from a daemon function"
> - | RInt _ | RInt64 _
> - | RBool _ | RString _ | RStringList _
> - | RIntBool _
> - | RPVList _ | RVGList _ | RLVList _
> - | RStat _ | RStatVFS _
> - | RHashtable _ ->
You'll get some conflicts when you rebase, because I
added another case (RDirentList).
> - pr " struct %s_ret ret;\n" name
> - );
> - pr "};\n";
> - pr "\n";
> -
> - (* Generate the reply callback function. *)
> - pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
> - pr "{\n";
> - pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
> - pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
> - pr "\n";
> - pr " /* This should definitely not happen. */\n";
> - pr " if (ctx->cb_sequence != 0) {\n";
> - pr " ctx->cb_sequence = 9999;\n";
> - pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
> - pr " return;\n";
> - pr " }\n";
> - pr "\n";
> - pr " ml->main_loop_quit (ml, g);\n";
> - pr "\n";
> - pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
> - pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
> - pr " return;\n";
> - pr " }\n";
> - pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
> - pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
> - pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
> - name;
> - pr " return;\n";
> - pr " }\n";
> - pr " goto done;\n";
> - pr " }\n";
> -
> - (match fst style with
> - | RErr -> ()
> - | RConstString _ ->
> - failwithf "RConstString cannot be returned from a daemon function"
> - | RInt _ | RInt64 _
> - | RBool _ | RString _ | RStringList _
> - | RIntBool _
> - | RPVList _ | RVGList _ | RLVList _
> - | RStat _ | RStatVFS _
> - | RHashtable _ ->
> - pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
> - pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
> - pr " return;\n";
> - pr " }\n";
> - );
> -
> - pr " done:\n";
> - pr " ctx->cb_sequence = 1;\n";
> - pr "}\n\n";
> -
> (* Generate the action stub. *)
> generate_prototype ~extern:false ~semicolon:false ~newline:true
> ~handle:"g" name style;
> @@ -3713,15 +3638,26 @@ check_state (guestfs_h *g, const char *caller)
> | _ -> pr " struct %s_args args;\n" name
> );
>
> - pr " struct %s_ctx ctx;\n" shortname;
> - pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
> + pr " struct guestfs_message_header hdr = {};\n";
> + pr " struct guestfs_message_error err = {};\n";
> + (match fst style with
> + | RErr -> ()
> + | RConstString _ ->
> + failwithf "RConstString cannot be returned from a daemon function"
> + | RInt _ | RInt64 _
> + | RBool _ | RString _ | RStringList _
> + | RIntBool _
> + | RPVList _ | RVGList _ | RLVList _
> + | RStat _ | RStatVFS _
> + | RHashtable _ ->
> + pr " struct %s_ret ret = {};\n" name
> + );
> +
> pr " int serial;\n";
> pr "\n";
> pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
> pr " guestfs_set_busy (g);\n";
> pr "\n";
> - pr " memset (&ctx, 0, sizeof ctx);\n";
> - pr "\n";
>
> (* Send the main header and arguments. *)
> (match snd style with
> @@ -3756,7 +3692,6 @@ check_state (guestfs_h *g, const char *caller)
> pr "\n";
>
> (* Send any additional files (FileIn) requested. *)
> - let need_read_reply_label = ref false in
> List.iter (
> function
> | FileIn n ->
> @@ -3768,82 +3703,128 @@ check_state (guestfs_h *g, const char *caller)
> pr " guestfs_end_busy (g);\n";
> pr " return %s;\n" error_code;
> pr " }\n";
> - pr " if (r == -2) /* daemon cancelled */\n";
> - pr " goto read_reply;\n";
> - need_read_reply_label := true;
> pr " }\n";
> pr "\n";
> | _ -> ()
> ) (snd style);
>
> (* Wait for the reply from the remote end. *)
> - if !need_read_reply_label then pr " read_reply:\n";
> - pr " guestfs__switch_to_receiving (g);\n";
> - pr " ctx.cb_sequence = 0;\n";
> - pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
> - pr " (void) ml->main_loop_run (ml, g);\n";
> - pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
> - pr " if (ctx.cb_sequence != 1) {\n";
> - pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
> - pr " guestfs_end_busy (g);\n";
> - pr " return %s;\n" error_code;
> + pr " guestfs_reply_t reply;\n";
> + pr "\n";
> + pr " for (;;) {\n";
> + pr " guestfs_get_reply (g, &reply, 1);\n";
> + pr "\n";
> + pr " if (GUESTFS_CANCEL_FLAG == reply.len) {\n";
> + pr " /* This message was delayed from a previous file transaction. */\n";
> + pr " continue;\n";
> + pr " }\n";
> + pr "\n";
> + pr " if (GUESTFS_LAUNCH_FLAG == reply.len) {\n";
> + pr " error (g, \"%%s reply failed, received unexpected launch message\",\n";
> + pr " \"%s\");\n" name;
> + pr " guestfs_end_busy (g);\n";
> + pr " return %s;\n" error_code;
> + pr " }\n";
> + pr "\n";
> + pr " if (0 == reply.len) {\n";
> + pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
> + pr " guestfs_end_busy (g);\n";
> + pr " return %s;\n" error_code;
> + pr " }\n";
> + pr "\n";
> + pr " break;\n";
> pr " }\n";
> pr "\n";
>
> - pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
> + pr " if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {\n";
> + pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
> + pr " goto recv_error;\n";
> + pr " }\n";
> + pr "\n";
> + pr " if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
> + pr " if (!xdr_guestfs_message_error (&reply.xdr, &err)) {\n";
> + pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
> + name;
> + pr " goto recv_error;\n";
> + pr " }\n";
> + pr " }\n";
> +
> + (match fst style with
> + | RErr -> ()
> + | RConstString _ ->
> + failwithf "RConstString cannot be returned from a daemon function"
> + | RInt _ | RInt64 _
> + | RBool _ | RString _ | RStringList _
> + | RIntBool _
> + | RPVList _ | RVGList _ | RLVList _
> + | RStat _ | RStatVFS _
> + | RHashtable _ ->
> + pr " else if (!xdr_%s_ret (&reply.xdr, &ret)) {\n" name;
> + pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
> + pr " goto recv_error;\n";
> + pr " }\n";
> + );
> +
> + pr " if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
> (String.uppercase shortname);
> - pr " guestfs_end_busy (g);\n";
> - pr " return %s;\n" error_code;
> + pr " goto recv_error;\n";
> pr " }\n";
> pr "\n";
>
> - pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
> - pr " error (g, \"%%s\", ctx.err.error_message);\n";
> - pr " free (ctx.err.error_message);\n";
> - pr " guestfs_end_busy (g);\n";
> - pr " return %s;\n" error_code;
> + pr " if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
> + pr " error (g, \"%%s\", err.error_message);\n";
> + pr " free (err.error_message);\n";
> + pr " goto recv_error;\n";
> pr " }\n";
> pr "\n";
>
> + pr " guestfs_free_reply (g, &reply);\n\n";
> +
> (* Expecting to receive further files (FileOut)? *)
> List.iter (
> function
> | FileOut n ->
> pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
> - pr " guestfs_end_busy (g);\n";
> - pr " return %s;\n" error_code;
> + pr " guestfs_end_busy (g);\n";
> + pr " return %s;\n" error_code;
> pr " }\n";
> pr "\n";
> | _ -> ()
> ) (snd style);
>
> - pr " guestfs_end_busy (g);\n";
> + pr " guestfs_end_busy (g);\n\n";
>
> (match fst style with
> | RErr -> pr " return 0;\n"
> | RInt n | RInt64 n | RBool n ->
> - pr " return ctx.ret.%s;\n" n
> + pr " return ret.%s;\n" n
> | RConstString _ ->
> failwithf "RConstString cannot be returned from a daemon function"
> | RString n ->
> - pr " return ctx.ret.%s; /* caller will free */\n" n
> + pr " return 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 " ctx.ret.%s.%s_val =\n" n n;
> - pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
> - pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
> + pr " ret.%s.%s_val =\n" n n;
> + pr " safe_realloc (g, ret.%s.%s_val,\n" n n;
> + pr " sizeof (char *) * (ret.%s.%s_len + 1));\n"
> n n;
> - pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
> - pr " return ctx.ret.%s.%s_val;\n" n n
> + pr " ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
> + pr " return ret.%s.%s_val;\n" n n
> | RIntBool _ ->
> pr " /* caller with free this */\n";
> - pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
> + pr " return safe_memdup (g, &ret, sizeof (ret));\n"
> | RPVList n | RVGList n | RLVList n
> | RStat n | RStatVFS n ->
> pr " /* caller will free this */\n";
> - pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
> + pr " return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
> );
>
> + pr "\n";
> + pr " recv_error:\n";
> + pr " guestfs_free_reply (g, &reply);\n";
> + pr " guestfs_end_busy (g);\n";
> + pr " return %s;\n" error_code;
> +
> pr "}\n\n"
> ) daemon_functions
>
> diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c
> index a46b339..8df6170 100644
> --- a/src/guestfs-actions.c
> +++ b/src/guestfs-actions.c
> @@ -83,59 +83,18 @@ check_state (guestfs_h *g, const char *caller)
> return 0;
> }
>
> -struct mount_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> -
> -static void mount_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mount_ctx *ctx = (struct mount_ctx *) data;
> -
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mount");
> - return;
> - }
> -
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mount");
> - return;
> - }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mount");
> - return;
> - }
> - goto done;
> - }
> - done:
> - ctx->cb_sequence = 1;
> -}
> -
> int guestfs_mount (guestfs_h *g,
> const char *device,
> const char *mountpoint)
> {
> struct guestfs_mount_args args;
> - struct mount_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mount") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> args.mountpoint = (char *) mountpoint;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MOUNT,
> @@ -145,168 +104,150 @@ int guestfs_mount (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mount_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mount");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNT, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sync_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mount");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void sync_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sync_ctx *ctx = (struct sync_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mount");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sync");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sync");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mount");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sync");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mount");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MOUNT, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_sync (guestfs_h *g)
> {
> - struct sync_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_sync") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_SYNC, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sync_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sync");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SYNC, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct touch_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sync");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void touch_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct touch_ctx *ctx = (struct touch_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sync");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_touch");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_touch");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sync");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_touch");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sync");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SYNC, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_touch (guestfs_h *g,
> const char *path)
> {
> struct guestfs_touch_args args;
> - struct touch_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_touch") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_TOUCH,
> (xdrproc_t) xdr_guestfs_touch_args, (char *) &args);
> @@ -315,90 +256,77 @@ int guestfs_touch (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, touch_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_touch");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TOUCH, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct cat_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_cat_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_touch");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void cat_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct cat_ctx *ctx = (struct cat_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_touch");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_cat");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_cat");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_touch");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_cat");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_touch");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_cat_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_cat");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_TOUCH, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_cat (guestfs_h *g,
> const char *path)
> {
> struct guestfs_cat_args args;
> - struct cat_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_cat_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_cat") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_CAT,
> (xdrproc_t) xdr_guestfs_cat_args, (char *) &args);
> @@ -407,90 +335,81 @@ char *guestfs_cat (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, cat_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_cat");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CAT, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.content; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct ll_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_ll_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_cat");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void ll_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct ll_ctx *ctx = (struct ll_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_cat");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_ll");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_ll");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_cat");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_ll");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_cat");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_ll_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_ll");
> - return;
> + else if (!xdr_guestfs_cat_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_cat");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_CAT, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.content; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char *guestfs_ll (guestfs_h *g,
> const char *directory)
> {
> struct guestfs_ll_args args;
> - struct ll_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_ll_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_ll") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.directory = (char *) directory;
> serial = guestfs__send_sync (g, GUESTFS_PROC_LL,
> (xdrproc_t) xdr_guestfs_ll_args, (char *) &args);
> @@ -499,90 +418,81 @@ char *guestfs_ll (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, ll_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_ll");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LL, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - guestfs_end_busy (g);
> - return ctx.ret.listing; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct ls_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_ls_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_ll");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void ls_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct ls_ctx *ctx = (struct ls_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_ll");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_ls");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_ls");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_ll");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_ls");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_ll");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_ls_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_ls");
> - return;
> + else if (!xdr_guestfs_ll_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_ll");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LL, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.listing; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_ls (guestfs_h *g,
> const char *directory)
> {
> struct guestfs_ls_args args;
> - struct ls_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_ls_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_ls") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.directory = (char *) directory;
> serial = guestfs__send_sync (g, GUESTFS_PROC_LS,
> (xdrproc_t) xdr_guestfs_ls_args, (char *) &args);
> @@ -591,827 +501,746 @@ char **guestfs_ls (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, ls_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_ls");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.listing.listing_val =
> - safe_realloc (g, ctx.ret.listing.listing_val,
> - sizeof (char *) * (ctx.ret.listing.listing_len + 1));
> - ctx.ret.listing.listing_val[ctx.ret.listing.listing_len] = NULL;
> - return ctx.ret.listing.listing_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct list_devices_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_list_devices_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_ls");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void list_devices_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct list_devices_ctx *ctx = (struct list_devices_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_ls");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_list_devices");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_list_devices");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_ls");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_list_devices");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_ls");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_list_devices_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_list_devices");
> - return;
> + else if (!xdr_guestfs_ls_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_ls");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.listing.listing_val =
> + safe_realloc (g, ret.listing.listing_val,
> + sizeof (char *) * (ret.listing.listing_len + 1));
> + ret.listing.listing_val[ret.listing.listing_len] = NULL;
> + return ret.listing.listing_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_list_devices (guestfs_h *g)
> {
> - struct list_devices_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_list_devices_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_list_devices") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_LIST_DEVICES, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, list_devices_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_list_devices");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LIST_DEVICES, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.devices.devices_val =
> - safe_realloc (g, ctx.ret.devices.devices_val,
> - sizeof (char *) * (ctx.ret.devices.devices_len + 1));
> - ctx.ret.devices.devices_val[ctx.ret.devices.devices_len] = NULL;
> - return ctx.ret.devices.devices_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct list_partitions_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_list_partitions_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_list_devices");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void list_partitions_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct list_partitions_ctx *ctx = (struct list_partitions_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_list_devices");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_list_partitions");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_list_partitions");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_list_devices");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_list_partitions");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_list_devices");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_list_partitions_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_list_partitions");
> - return;
> + else if (!xdr_guestfs_list_devices_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_list_devices");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LIST_DEVICES, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.devices.devices_val =
> + safe_realloc (g, ret.devices.devices_val,
> + sizeof (char *) * (ret.devices.devices_len + 1));
> + ret.devices.devices_val[ret.devices.devices_len] = NULL;
> + return ret.devices.devices_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_list_partitions (guestfs_h *g)
> {
> - struct list_partitions_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_list_partitions_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_list_partitions") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_LIST_PARTITIONS, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, list_partitions_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_list_partitions");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LIST_PARTITIONS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.partitions.partitions_val =
> - safe_realloc (g, ctx.ret.partitions.partitions_val,
> - sizeof (char *) * (ctx.ret.partitions.partitions_len + 1));
> - ctx.ret.partitions.partitions_val[ctx.ret.partitions.partitions_len] = NULL;
> - return ctx.ret.partitions.partitions_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct pvs_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_pvs_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_list_partitions");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void pvs_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct pvs_ctx *ctx = (struct pvs_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_list_partitions");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_pvs");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_pvs");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_list_partitions");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_pvs");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_list_partitions");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_pvs_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_pvs");
> - return;
> + else if (!xdr_guestfs_list_partitions_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_list_partitions");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LIST_PARTITIONS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.partitions.partitions_val =
> + safe_realloc (g, ret.partitions.partitions_val,
> + sizeof (char *) * (ret.partitions.partitions_len + 1));
> + ret.partitions.partitions_val[ret.partitions.partitions_len] = NULL;
> + return ret.partitions.partitions_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_pvs (guestfs_h *g)
> {
> - struct pvs_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_pvs_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_pvs") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_PVS, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, pvs_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_pvs");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.physvols.physvols_val =
> - safe_realloc (g, ctx.ret.physvols.physvols_val,
> - sizeof (char *) * (ctx.ret.physvols.physvols_len + 1));
> - ctx.ret.physvols.physvols_val[ctx.ret.physvols.physvols_len] = NULL;
> - return ctx.ret.physvols.physvols_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct vgs_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_vgs_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_pvs");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void vgs_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct vgs_ctx *ctx = (struct vgs_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_pvs");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_vgs");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_vgs");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_pvs");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_vgs");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_pvs");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_vgs_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_vgs");
> - return;
> + else if (!xdr_guestfs_pvs_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_pvs");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_PVS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.physvols.physvols_val =
> + safe_realloc (g, ret.physvols.physvols_val,
> + sizeof (char *) * (ret.physvols.physvols_len + 1));
> + ret.physvols.physvols_val[ret.physvols.physvols_len] = NULL;
> + return ret.physvols.physvols_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_vgs (guestfs_h *g)
> {
> - struct vgs_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_vgs_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_vgs") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_VGS, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, vgs_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_vgs");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.volgroups.volgroups_val =
> - safe_realloc (g, ctx.ret.volgroups.volgroups_val,
> - sizeof (char *) * (ctx.ret.volgroups.volgroups_len + 1));
> - ctx.ret.volgroups.volgroups_val[ctx.ret.volgroups.volgroups_len] = NULL;
> - return ctx.ret.volgroups.volgroups_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct lvs_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_lvs_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_vgs");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void lvs_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct lvs_ctx *ctx = (struct lvs_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_vgs");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_lvs");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_lvs");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_vgs");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_lvs");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_vgs");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_lvs_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_lvs");
> - return;
> + else if (!xdr_guestfs_vgs_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_vgs");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_VGS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.volgroups.volgroups_val =
> + safe_realloc (g, ret.volgroups.volgroups_val,
> + sizeof (char *) * (ret.volgroups.volgroups_len + 1));
> + ret.volgroups.volgroups_val[ret.volgroups.volgroups_len] = NULL;
> + return ret.volgroups.volgroups_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_lvs (guestfs_h *g)
> {
> - struct lvs_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_lvs_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_lvs") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_LVS, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, lvs_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_lvs");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.logvols.logvols_val =
> - safe_realloc (g, ctx.ret.logvols.logvols_val,
> - sizeof (char *) * (ctx.ret.logvols.logvols_len + 1));
> - ctx.ret.logvols.logvols_val[ctx.ret.logvols.logvols_len] = NULL;
> - return ctx.ret.logvols.logvols_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct pvs_full_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_pvs_full_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_lvs");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void pvs_full_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct pvs_full_ctx *ctx = (struct pvs_full_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_lvs");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_pvs_full");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_pvs_full");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_lvs");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_pvs_full");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_lvs");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_pvs_full_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_pvs_full");
> - return;
> + else if (!xdr_guestfs_lvs_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_lvs");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LVS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.logvols.logvols_val =
> + safe_realloc (g, ret.logvols.logvols_val,
> + sizeof (char *) * (ret.logvols.logvols_len + 1));
> + ret.logvols.logvols_val[ret.logvols.logvols_len] = NULL;
> + return ret.logvols.logvols_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> struct guestfs_lvm_pv_list *guestfs_pvs_full (guestfs_h *g)
> {
> - struct pvs_full_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_pvs_full_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_pvs_full") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_PVS_FULL, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, pvs_full_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_pvs_full");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVS_FULL, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this */
> - return safe_memdup (g, &ctx.ret.physvols, sizeof (ctx.ret.physvols));
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct vgs_full_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_vgs_full_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_pvs_full");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void vgs_full_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct vgs_full_ctx *ctx = (struct vgs_full_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_pvs_full");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_vgs_full");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_vgs_full");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_pvs_full");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_vgs_full");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_pvs_full");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_vgs_full_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_vgs_full");
> - return;
> + else if (!xdr_guestfs_pvs_full_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_pvs_full");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_PVS_FULL, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this */
> + return safe_memdup (g, &ret.physvols, sizeof (ret.physvols));
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> struct guestfs_lvm_vg_list *guestfs_vgs_full (guestfs_h *g)
> {
> - struct vgs_full_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_vgs_full_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_vgs_full") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_VGS_FULL, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, vgs_full_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_vgs_full");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGS_FULL, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this */
> - return safe_memdup (g, &ctx.ret.volgroups, sizeof (ctx.ret.volgroups));
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct lvs_full_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_lvs_full_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_vgs_full");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void lvs_full_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct lvs_full_ctx *ctx = (struct lvs_full_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_vgs_full");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_lvs_full");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_lvs_full");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_vgs_full");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_lvs_full");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_vgs_full");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_lvs_full_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_lvs_full");
> - return;
> + else if (!xdr_guestfs_vgs_full_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_vgs_full");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_VGS_FULL, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this */
> + return safe_memdup (g, &ret.volgroups, sizeof (ret.volgroups));
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> struct guestfs_lvm_lv_list *guestfs_lvs_full (guestfs_h *g)
> {
> - struct lvs_full_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_lvs_full_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_lvs_full") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_LVS_FULL, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, lvs_full_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_lvs_full");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVS_FULL, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this */
> - return safe_memdup (g, &ctx.ret.logvols, sizeof (ctx.ret.logvols));
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct read_lines_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_read_lines_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_lvs_full");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void read_lines_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct read_lines_ctx *ctx = (struct read_lines_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_lvs_full");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_read_lines");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_read_lines");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_lvs_full");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_read_lines");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_lvs_full");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_read_lines_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_read_lines");
> - return;
> + else if (!xdr_guestfs_lvs_full_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_lvs_full");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LVS_FULL, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this */
> + return safe_memdup (g, &ret.logvols, sizeof (ret.logvols));
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_read_lines (guestfs_h *g,
> const char *path)
> {
> struct guestfs_read_lines_args args;
> - struct read_lines_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_read_lines_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_read_lines") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_READ_LINES,
> (xdrproc_t) xdr_guestfs_read_lines_args, (char *) &args);
> @@ -1420,75 +1249,72 @@ char **guestfs_read_lines (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, read_lines_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_read_lines");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_READ_LINES, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.lines.lines_val =
> - safe_realloc (g, ctx.ret.lines.lines_val,
> - sizeof (char *) * (ctx.ret.lines.lines_len + 1));
> - ctx.ret.lines.lines_val[ctx.ret.lines.lines_len] = NULL;
> - return ctx.ret.lines.lines_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_init_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_read_lines");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void aug_init_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_init_ctx *ctx = (struct aug_init_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_read_lines");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_init");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_init");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_read_lines");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_init");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_read_lines");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_read_lines_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_read_lines");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_READ_LINES, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.lines.lines_val =
> + safe_realloc (g, ret.lines.lines_val,
> + sizeof (char *) * (ret.lines.lines_len + 1));
> + ret.lines.lines_val[ret.lines.lines_len] = NULL;
> + return ret.lines.lines_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_aug_init (guestfs_h *g,
> @@ -1496,15 +1322,13 @@ int guestfs_aug_init (guestfs_h *g,
> int flags)
> {
> struct guestfs_aug_init_args args;
> - struct aug_init_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_init") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.root = (char *) root;
> args.flags = flags;
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_INIT,
> @@ -1514,158 +1338,137 @@ int guestfs_aug_init (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_init_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_init");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_INIT, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_close_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_init");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_close_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_close_ctx *ctx = (struct aug_close_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_init");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_close");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_close");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_init");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_close");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_init");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_INIT, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_aug_close (guestfs_h *g)
> {
> - struct aug_close_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_close") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_CLOSE, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_close_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_close");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_CLOSE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_defvar_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_aug_defvar_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_close");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_defvar_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_defvar_ctx *ctx = (struct aug_defvar_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_close");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_defvar");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_defvar");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_close");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_defvar");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_close");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_aug_defvar_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_aug_defvar");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_CLOSE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_aug_defvar (guestfs_h *g,
> @@ -1673,15 +1476,14 @@ int guestfs_aug_defvar (guestfs_h *g,
> const char *expr)
> {
> struct guestfs_aug_defvar_args args;
> - struct aug_defvar_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_aug_defvar_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_defvar") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.name = (char *) name;
> args.expr = expr ? (char **) &expr : NULL;
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_DEFVAR,
> @@ -1691,75 +1493,67 @@ int guestfs_aug_defvar (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_defvar_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_defvar");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_DEFVAR, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.nrnodes;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_defnode_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_aug_defnode_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_defvar");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_defnode_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_defnode_ctx *ctx = (struct aug_defnode_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_defvar");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_defnode");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_defnode");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_defvar");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_defnode");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_defvar");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_aug_defnode_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_aug_defnode");
> - return;
> + else if (!xdr_guestfs_aug_defvar_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_aug_defvar");
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_DEFVAR, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.nrnodes;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
> @@ -1768,15 +1562,14 @@ struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
> const char *val)
> {
> struct guestfs_aug_defnode_args args;
> - struct aug_defnode_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_aug_defnode_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_defnode") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.name = (char *) name;
> args.expr = (char *) expr;
> args.val = (char *) val;
> @@ -1787,91 +1580,82 @@ struct guestfs_int_bool *guestfs_aug_defnode (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_defnode_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_defnode");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_DEFNODE, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller with free this */
> - return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_get_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_aug_get_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_defnode");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void aug_get_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_get_ctx *ctx = (struct aug_get_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_defnode");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_get");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_get");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_defnode");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_get");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_defnode");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_aug_get_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_aug_get");
> - return;
> + else if (!xdr_guestfs_aug_defnode_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_aug_defnode");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_DEFNODE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller with free this */
> + return safe_memdup (g, &ret, sizeof (ret));
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char *guestfs_aug_get (guestfs_h *g,
> const char *path)
> {
> struct guestfs_aug_get_args args;
> - struct aug_get_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_aug_get_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_get") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_GET,
> (xdrproc_t) xdr_guestfs_aug_get_args, (char *) &args);
> @@ -1880,70 +1664,67 @@ char *guestfs_aug_get (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_get_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_get");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_GET, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - guestfs_end_busy (g);
> - return ctx.ret.val; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_set_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_get");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void aug_set_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_set_ctx *ctx = (struct aug_set_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_get");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_set");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_set");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_get");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_set");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_get");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_aug_get_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_aug_get");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_GET, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.val; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_aug_set (guestfs_h *g,
> @@ -1951,15 +1732,13 @@ int guestfs_aug_set (guestfs_h *g,
> const char *val)
> {
> struct guestfs_aug_set_args args;
> - struct aug_set_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_set") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> args.val = (char *) val;
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_SET,
> @@ -1969,70 +1748,63 @@ int guestfs_aug_set (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_set_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_set");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_SET, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_insert_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_set");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_insert_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_insert_ctx *ctx = (struct aug_insert_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_set");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_insert");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_insert");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_set");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_insert");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_set");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_SET, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_aug_insert (guestfs_h *g,
> @@ -2041,15 +1813,13 @@ int guestfs_aug_insert (guestfs_h *g,
> int before)
> {
> struct guestfs_aug_insert_args args;
> - struct aug_insert_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_insert") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> args.label = (char *) label;
> args.before = before;
> @@ -2060,90 +1830,77 @@ int guestfs_aug_insert (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_insert_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_insert");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_INSERT, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_rm_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_aug_rm_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_insert");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_rm_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_rm_ctx *ctx = (struct aug_rm_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_insert");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_rm");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_rm");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_insert");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_rm");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_insert");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_aug_rm_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_aug_rm");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_INSERT, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_aug_rm (guestfs_h *g,
> const char *path)
> {
> struct guestfs_aug_rm_args args;
> - struct aug_rm_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_aug_rm_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_rm") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_RM,
> (xdrproc_t) xdr_guestfs_aug_rm_args, (char *) &args);
> @@ -2152,70 +1909,67 @@ int guestfs_aug_rm (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_rm_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_rm");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_RM, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return ctx.ret.nrnodes;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_mv_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_rm");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_mv_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_mv_ctx *ctx = (struct aug_mv_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_rm");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_mv");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_mv");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_rm");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_mv");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_rm");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_aug_rm_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_aug_rm");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_RM, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.nrnodes;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_aug_mv (guestfs_h *g,
> @@ -2223,15 +1977,13 @@ int guestfs_aug_mv (guestfs_h *g,
> const char *dest)
> {
> struct guestfs_aug_mv_args args;
> - struct aug_mv_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_mv") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.src = (char *) src;
> args.dest = (char *) dest;
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_MV,
> @@ -2241,90 +1993,77 @@ int guestfs_aug_mv (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_mv_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_mv");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_MV, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_match_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_aug_match_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_mv");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_match_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_match_ctx *ctx = (struct aug_match_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_mv");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_match");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_match");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_mv");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_match");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_mv");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_aug_match_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_aug_match");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_MV, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char **guestfs_aug_match (guestfs_h *g,
> const char *path)
> {
> struct guestfs_aug_match_args args;
> - struct aug_match_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_aug_match_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_match") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_MATCH,
> (xdrproc_t) xdr_guestfs_aug_match_args, (char *) &args);
> @@ -2333,261 +2072,234 @@ char **guestfs_aug_match (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_match_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_match");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_MATCH, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.matches.matches_val =
> - safe_realloc (g, ctx.ret.matches.matches_val,
> - sizeof (char *) * (ctx.ret.matches.matches_len + 1));
> - ctx.ret.matches.matches_val[ctx.ret.matches.matches_len] = NULL;
> - return ctx.ret.matches.matches_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_save_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_match");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void aug_save_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_save_ctx *ctx = (struct aug_save_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_match");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_save");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_save");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_match");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_save");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_match");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_aug_match_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_aug_match");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_MATCH, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.matches.matches_val =
> + safe_realloc (g, ret.matches.matches_val,
> + sizeof (char *) * (ret.matches.matches_len + 1));
> + ret.matches.matches_val[ret.matches.matches_len] = NULL;
> + return ret.matches.matches_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_aug_save (guestfs_h *g)
> {
> - struct aug_save_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_save") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_SAVE, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_save_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_save");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_SAVE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_load_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_save");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_load_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_load_ctx *ctx = (struct aug_load_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_save");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_load");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_load");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_save");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_load");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_save");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_SAVE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_aug_load (guestfs_h *g)
> {
> - struct aug_load_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_load") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_LOAD, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_load_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_load");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_LOAD, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct aug_ls_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_aug_ls_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_load");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void aug_ls_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct aug_ls_ctx *ctx = (struct aug_ls_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_load");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_aug_ls");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_aug_ls");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_load");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_aug_ls");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_load");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_aug_ls_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_aug_ls");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_LOAD, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char **guestfs_aug_ls (guestfs_h *g,
> const char *path)
> {
> struct guestfs_aug_ls_args args;
> - struct aug_ls_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_aug_ls_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_aug_ls") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_AUG_LS,
> (xdrproc_t) xdr_guestfs_aug_ls_args, (char *) &args);
> @@ -2596,90 +2308,85 @@ char **guestfs_aug_ls (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, aug_ls_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_aug_ls");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_AUG_LS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.matches.matches_val =
> - safe_realloc (g, ctx.ret.matches.matches_val,
> - sizeof (char *) * (ctx.ret.matches.matches_len + 1));
> - ctx.ret.matches.matches_val[ctx.ret.matches.matches_len] = NULL;
> - return ctx.ret.matches.matches_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct rm_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_aug_ls");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void rm_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct rm_ctx *ctx = (struct rm_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_aug_ls");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_rm");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_rm");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_aug_ls");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_rm");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_aug_ls");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_aug_ls_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_aug_ls");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_AUG_LS, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.matches.matches_val =
> + safe_realloc (g, ret.matches.matches_val,
> + sizeof (char *) * (ret.matches.matches_len + 1));
> + ret.matches.matches_val[ret.matches.matches_len] = NULL;
> + return ret.matches.matches_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_rm (guestfs_h *g,
> const char *path)
> {
> struct guestfs_rm_args args;
> - struct rm_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_rm") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_RM,
> (xdrproc_t) xdr_guestfs_rm_args, (char *) &args);
> @@ -2688,85 +2395,76 @@ int guestfs_rm (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, rm_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_rm");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RM, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct rmdir_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_rm");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void rmdir_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct rmdir_ctx *ctx = (struct rmdir_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_rm");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_rmdir");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_rmdir");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_rm");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_rmdir");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_rm");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_RM, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_rmdir (guestfs_h *g,
> const char *path)
> {
> struct guestfs_rmdir_args args;
> - struct rmdir_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_rmdir") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_RMDIR,
> (xdrproc_t) xdr_guestfs_rmdir_args, (char *) &args);
> @@ -2775,85 +2473,76 @@ int guestfs_rmdir (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, rmdir_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_rmdir");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RMDIR, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct rm_rf_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_rmdir");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void rm_rf_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct rm_rf_ctx *ctx = (struct rm_rf_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_rmdir");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_rm_rf");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_rm_rf");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_rmdir");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_rm_rf");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_rmdir");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_RMDIR, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_rm_rf (guestfs_h *g,
> const char *path)
> {
> struct guestfs_rm_rf_args args;
> - struct rm_rf_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_rm_rf") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_RM_RF,
> (xdrproc_t) xdr_guestfs_rm_rf_args, (char *) &args);
> @@ -2862,85 +2551,76 @@ int guestfs_rm_rf (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, rm_rf_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_rm_rf");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RM_RF, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mkdir_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_rm_rf");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mkdir_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mkdir_ctx *ctx = (struct mkdir_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_rm_rf");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mkdir");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mkdir");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_rm_rf");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mkdir");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_rm_rf");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_RM_RF, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mkdir (guestfs_h *g,
> const char *path)
> {
> struct guestfs_mkdir_args args;
> - struct mkdir_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mkdir") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MKDIR,
> (xdrproc_t) xdr_guestfs_mkdir_args, (char *) &args);
> @@ -2949,85 +2629,76 @@ int guestfs_mkdir (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mkdir_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mkdir");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKDIR, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mkdir_p_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mkdir");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mkdir_p_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mkdir_p_ctx *ctx = (struct mkdir_p_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mkdir");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mkdir_p");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mkdir_p");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mkdir");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mkdir_p");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mkdir");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKDIR, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mkdir_p (guestfs_h *g,
> const char *path)
> {
> struct guestfs_mkdir_p_args args;
> - struct mkdir_p_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mkdir_p") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MKDIR_P,
> (xdrproc_t) xdr_guestfs_mkdir_p_args, (char *) &args);
> @@ -3036,70 +2707,63 @@ int guestfs_mkdir_p (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mkdir_p_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mkdir_p");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKDIR_P, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct chmod_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mkdir_p");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void chmod_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct chmod_ctx *ctx = (struct chmod_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mkdir_p");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_chmod");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_chmod");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mkdir_p");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_chmod");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mkdir_p");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKDIR_P, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_chmod (guestfs_h *g,
> @@ -3107,15 +2771,13 @@ int guestfs_chmod (guestfs_h *g,
> const char *path)
> {
> struct guestfs_chmod_args args;
> - struct chmod_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_chmod") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.mode = mode;
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_CHMOD,
> @@ -3125,70 +2787,63 @@ int guestfs_chmod (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, chmod_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_chmod");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CHMOD, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct chown_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_chmod");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void chown_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct chown_ctx *ctx = (struct chown_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_chmod");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_chown");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_chown");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_chmod");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_chown");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_chmod");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_CHMOD, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_chown (guestfs_h *g,
> @@ -3197,15 +2852,13 @@ int guestfs_chown (guestfs_h *g,
> const char *path)
> {
> struct guestfs_chown_args args;
> - struct chown_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_chown") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.owner = owner;
> args.group = group;
> args.path = (char *) path;
> @@ -3216,90 +2869,77 @@ int guestfs_chown (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, chown_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_chown");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CHOWN, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct exists_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_exists_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_chown");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void exists_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct exists_ctx *ctx = (struct exists_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_chown");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_exists");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_exists");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_chown");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_exists");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_chown");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_exists_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_exists");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_CHOWN, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_exists (guestfs_h *g,
> const char *path)
> {
> struct guestfs_exists_args args;
> - struct exists_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_exists_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_exists") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_EXISTS,
> (xdrproc_t) xdr_guestfs_exists_args, (char *) &args);
> @@ -3308,90 +2948,81 @@ int guestfs_exists (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, exists_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_exists");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_EXISTS, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.existsflag;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct is_file_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_is_file_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_exists");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void is_file_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct is_file_ctx *ctx = (struct is_file_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_exists");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_is_file");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_is_file");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_exists");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_is_file");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_exists");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_is_file_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_is_file");
> - return;
> + else if (!xdr_guestfs_exists_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_exists");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_EXISTS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.existsflag;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_is_file (guestfs_h *g,
> const char *path)
> {
> struct guestfs_is_file_args args;
> - struct is_file_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_is_file_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_is_file") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_IS_FILE,
> (xdrproc_t) xdr_guestfs_is_file_args, (char *) &args);
> @@ -3400,90 +3031,81 @@ int guestfs_is_file (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, is_file_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_is_file");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_IS_FILE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.fileflag;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct is_dir_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_is_dir_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_is_file");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void is_dir_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct is_dir_ctx *ctx = (struct is_dir_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_is_file");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_is_dir");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_is_dir");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_is_file");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_is_dir");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_is_file");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_is_dir_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_is_dir");
> - return;
> + else if (!xdr_guestfs_is_file_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_is_file");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_IS_FILE, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.fileflag;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_is_dir (guestfs_h *g,
> const char *path)
> {
> struct guestfs_is_dir_args args;
> - struct is_dir_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_is_dir_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_is_dir") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_IS_DIR,
> (xdrproc_t) xdr_guestfs_is_dir_args, (char *) &args);
> @@ -3492,85 +3114,80 @@ int guestfs_is_dir (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, is_dir_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_is_dir");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_IS_DIR, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.dirflag;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct pvcreate_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_is_dir");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void pvcreate_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct pvcreate_ctx *ctx = (struct pvcreate_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_is_dir");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_pvcreate");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_pvcreate");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_is_dir");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_pvcreate");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_is_dir");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_is_dir_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_is_dir");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_IS_DIR, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.dirflag;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_pvcreate (guestfs_h *g,
> const char *device)
> {
> struct guestfs_pvcreate_args args;
> - struct pvcreate_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_pvcreate") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_PVCREATE,
> (xdrproc_t) xdr_guestfs_pvcreate_args, (char *) &args);
> @@ -3579,70 +3196,63 @@ int guestfs_pvcreate (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, pvcreate_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_pvcreate");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVCREATE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct vgcreate_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_pvcreate");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void vgcreate_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct vgcreate_ctx *ctx = (struct vgcreate_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_pvcreate");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_vgcreate");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_vgcreate");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_pvcreate");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_vgcreate");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_pvcreate");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_PVCREATE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_vgcreate (guestfs_h *g,
> @@ -3650,15 +3260,13 @@ int guestfs_vgcreate (guestfs_h *g,
> char * const* const physvols)
> {
> struct guestfs_vgcreate_args args;
> - struct vgcreate_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_vgcreate") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.volgroup = (char *) volgroup;
> args.physvols.physvols_val = (char **) physvols;
> for (args.physvols.physvols_len = 0; physvols[args.physvols.physvols_len]; args.physvols.physvols_len++) ;
> @@ -3669,70 +3277,63 @@ int guestfs_vgcreate (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, vgcreate_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_vgcreate");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGCREATE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct lvcreate_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_vgcreate");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void lvcreate_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct lvcreate_ctx *ctx = (struct lvcreate_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_vgcreate");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_lvcreate");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_lvcreate");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_vgcreate");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_lvcreate");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_vgcreate");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_VGCREATE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_lvcreate (guestfs_h *g,
> @@ -3741,15 +3342,13 @@ int guestfs_lvcreate (guestfs_h *g,
> int mbytes)
> {
> struct guestfs_lvcreate_args args;
> - struct lvcreate_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_lvcreate") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.logvol = (char *) logvol;
> args.volgroup = (char *) volgroup;
> args.mbytes = mbytes;
> @@ -3760,70 +3359,63 @@ int guestfs_lvcreate (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, lvcreate_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_lvcreate");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVCREATE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mkfs_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_lvcreate");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mkfs_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mkfs_ctx *ctx = (struct mkfs_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_lvcreate");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mkfs");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mkfs");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_lvcreate");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mkfs");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_lvcreate");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LVCREATE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mkfs (guestfs_h *g,
> @@ -3831,15 +3423,13 @@ int guestfs_mkfs (guestfs_h *g,
> const char *device)
> {
> struct guestfs_mkfs_args args;
> - struct mkfs_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mkfs") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.fstype = (char *) fstype;
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MKFS,
> @@ -3849,70 +3439,63 @@ int guestfs_mkfs (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mkfs_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mkfs");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKFS, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sfdisk_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mkfs");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void sfdisk_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sfdisk_ctx *ctx = (struct sfdisk_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mkfs");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sfdisk");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sfdisk");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mkfs");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sfdisk");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mkfs");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKFS, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_sfdisk (guestfs_h *g,
> @@ -3923,15 +3506,13 @@ int guestfs_sfdisk (guestfs_h *g,
> char * const* const lines)
> {
> struct guestfs_sfdisk_args args;
> - struct sfdisk_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_sfdisk") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> args.cyls = cyls;
> args.heads = heads;
> @@ -3945,70 +3526,63 @@ int guestfs_sfdisk (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sfdisk_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct write_file_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sfdisk");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void write_file_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct write_file_ctx *ctx = (struct write_file_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_write_file");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_write_file");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sfdisk");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_write_file");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sfdisk");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SFDISK, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_write_file (guestfs_h *g,
> @@ -4017,15 +3591,13 @@ int guestfs_write_file (guestfs_h *g,
> int size)
> {
> struct guestfs_write_file_args args;
> - struct write_file_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_write_file") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> args.content = (char *) content;
> args.size = size;
> @@ -4036,85 +3608,76 @@ int guestfs_write_file (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, write_file_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_write_file");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_WRITE_FILE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct umount_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_write_file");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void umount_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct umount_ctx *ctx = (struct umount_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_write_file");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_umount");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_umount");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_write_file");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_umount");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_write_file");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_WRITE_FILE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_umount (guestfs_h *g,
> const char *pathordevice)
> {
> struct guestfs_umount_args args;
> - struct umount_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_umount") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.pathordevice = (char *) pathordevice;
> serial = guestfs__send_sync (g, GUESTFS_PROC_UMOUNT,
> (xdrproc_t) xdr_guestfs_umount_args, (char *) &args);
> @@ -4123,349 +3686,309 @@ int guestfs_umount (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, umount_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_umount");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UMOUNT, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mounts_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_mounts_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_umount");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mounts_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mounts_ctx *ctx = (struct mounts_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_umount");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mounts");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mounts");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_umount");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mounts");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_umount");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_mounts_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_mounts");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_UMOUNT, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char **guestfs_mounts (guestfs_h *g)
> {
> - struct mounts_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_mounts_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_mounts") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_MOUNTS, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mounts_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mounts");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNTS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.devices.devices_val =
> - safe_realloc (g, ctx.ret.devices.devices_val,
> - sizeof (char *) * (ctx.ret.devices.devices_len + 1));
> - ctx.ret.devices.devices_val[ctx.ret.devices.devices_len] = NULL;
> - return ctx.ret.devices.devices_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct umount_all_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mounts");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void umount_all_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct umount_all_ctx *ctx = (struct umount_all_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mounts");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_umount_all");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_umount_all");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mounts");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_umount_all");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mounts");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_mounts_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_mounts");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MOUNTS, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.devices.devices_val =
> + safe_realloc (g, ret.devices.devices_val,
> + sizeof (char *) * (ret.devices.devices_len + 1));
> + ret.devices.devices_val[ret.devices.devices_len] = NULL;
> + return ret.devices.devices_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_umount_all (guestfs_h *g)
> {
> - struct umount_all_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_umount_all") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_UMOUNT_ALL, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, umount_all_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_umount_all");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UMOUNT_ALL, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct lvm_remove_all_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_umount_all");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void lvm_remove_all_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct lvm_remove_all_ctx *ctx = (struct lvm_remove_all_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_umount_all");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_lvm_remove_all");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_lvm_remove_all");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_umount_all");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_lvm_remove_all");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_umount_all");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_UMOUNT_ALL, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_lvm_remove_all (guestfs_h *g)
> {
> - struct lvm_remove_all_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_lvm_remove_all") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_LVM_REMOVE_ALL, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, lvm_remove_all_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_lvm_remove_all");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVM_REMOVE_ALL, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct file_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_file_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_lvm_remove_all");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void file_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct file_ctx *ctx = (struct file_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_lvm_remove_all");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_file");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_file");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_lvm_remove_all");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_file");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_lvm_remove_all");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_file_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_file");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LVM_REMOVE_ALL, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_file (guestfs_h *g,
> const char *path)
> {
> struct guestfs_file_args args;
> - struct file_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_file_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_file") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_FILE,
> (xdrproc_t) xdr_guestfs_file_args, (char *) &args);
> @@ -4474,90 +3997,81 @@ char *guestfs_file (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, file_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_file");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_FILE, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.description; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct command_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_command_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_file");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void command_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct command_ctx *ctx = (struct command_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_file");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_command");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_command");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_file");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_command");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_file");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_command_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_command");
> - return;
> + else if (!xdr_guestfs_file_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_file");
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_FILE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.description; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char *guestfs_command (guestfs_h *g,
> char * const* const arguments)
> {
> struct guestfs_command_args args;
> - struct command_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_command_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_command") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.arguments.arguments_val = (char **) arguments;
> for (args.arguments.arguments_len = 0; arguments[args.arguments.arguments_len]; args.arguments.arguments_len++) ;
> serial = guestfs__send_sync (g, GUESTFS_PROC_COMMAND,
> @@ -4567,90 +4081,81 @@ char *guestfs_command (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, command_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_command");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_COMMAND, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - guestfs_end_busy (g);
> - return ctx.ret.output; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct command_lines_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_command_lines_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_command");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void command_lines_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct command_lines_ctx *ctx = (struct command_lines_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_command");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_command_lines");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_command_lines");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_command");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_command_lines");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_command");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_command_lines_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_command_lines");
> - return;
> + else if (!xdr_guestfs_command_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_command");
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_COMMAND, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.output; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_command_lines (guestfs_h *g,
> char * const* const arguments)
> {
> struct guestfs_command_lines_args args;
> - struct command_lines_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_command_lines_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_command_lines") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.arguments.arguments_val = (char **) arguments;
> for (args.arguments.arguments_len = 0; arguments[args.arguments.arguments_len]; args.arguments.arguments_len++) ;
> serial = guestfs__send_sync (g, GUESTFS_PROC_COMMAND_LINES,
> @@ -4660,95 +4165,86 @@ char **guestfs_command_lines (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, command_lines_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_command_lines");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_COMMAND_LINES, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.lines.lines_val =
> - safe_realloc (g, ctx.ret.lines.lines_val,
> - sizeof (char *) * (ctx.ret.lines.lines_len + 1));
> - ctx.ret.lines.lines_val[ctx.ret.lines.lines_len] = NULL;
> - return ctx.ret.lines.lines_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct stat_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_stat_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_command_lines");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void stat_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct stat_ctx *ctx = (struct stat_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_command_lines");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_stat");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_stat");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_command_lines");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_stat");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_command_lines");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_stat_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_stat");
> - return;
> + else if (!xdr_guestfs_command_lines_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_command_lines");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_COMMAND_LINES, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.lines.lines_val =
> + safe_realloc (g, ret.lines.lines_val,
> + sizeof (char *) * (ret.lines.lines_len + 1));
> + ret.lines.lines_val[ret.lines.lines_len] = NULL;
> + return ret.lines.lines_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> struct guestfs_stat *guestfs_stat (guestfs_h *g,
> const char *path)
> {
> struct guestfs_stat_args args;
> - struct stat_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_stat_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_stat") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_STAT,
> (xdrproc_t) xdr_guestfs_stat_args, (char *) &args);
> @@ -4757,91 +4253,82 @@ struct guestfs_stat *guestfs_stat (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, stat_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_stat");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_STAT, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this */
> - return safe_memdup (g, &ctx.ret.statbuf, sizeof (ctx.ret.statbuf));
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct lstat_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_lstat_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_stat");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void lstat_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct lstat_ctx *ctx = (struct lstat_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_stat");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_lstat");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_lstat");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_stat");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_lstat");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_stat");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_lstat_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_lstat");
> - return;
> + else if (!xdr_guestfs_stat_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_stat");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_STAT, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this */
> + return safe_memdup (g, &ret.statbuf, sizeof (ret.statbuf));
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> struct guestfs_stat *guestfs_lstat (guestfs_h *g,
> const char *path)
> {
> struct guestfs_lstat_args args;
> - struct lstat_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_lstat_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_lstat") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_LSTAT,
> (xdrproc_t) xdr_guestfs_lstat_args, (char *) &args);
> @@ -4850,91 +4337,82 @@ struct guestfs_stat *guestfs_lstat (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, lstat_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_lstat");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LSTAT, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this */
> - return safe_memdup (g, &ctx.ret.statbuf, sizeof (ctx.ret.statbuf));
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct statvfs_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_statvfs_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_lstat");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void statvfs_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct statvfs_ctx *ctx = (struct statvfs_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_lstat");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_statvfs");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_statvfs");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_lstat");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_statvfs");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_lstat");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_statvfs_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_statvfs");
> - return;
> + else if (!xdr_guestfs_lstat_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_lstat");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LSTAT, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this */
> + return safe_memdup (g, &ret.statbuf, sizeof (ret.statbuf));
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> struct guestfs_statvfs *guestfs_statvfs (guestfs_h *g,
> const char *path)
> {
> struct guestfs_statvfs_args args;
> - struct statvfs_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_statvfs_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_statvfs") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_STATVFS,
> (xdrproc_t) xdr_guestfs_statvfs_args, (char *) &args);
> @@ -4943,91 +4421,82 @@ struct guestfs_statvfs *guestfs_statvfs (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, statvfs_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_statvfs");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_STATVFS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this */
> - return safe_memdup (g, &ctx.ret.statbuf, sizeof (ctx.ret.statbuf));
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct tune2fs_l_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_tune2fs_l_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_statvfs");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void tune2fs_l_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct tune2fs_l_ctx *ctx = (struct tune2fs_l_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_statvfs");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_tune2fs_l");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_tune2fs_l");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_statvfs");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_tune2fs_l");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_statvfs");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_tune2fs_l_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_tune2fs_l");
> - return;
> + else if (!xdr_guestfs_statvfs_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_statvfs");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_STATVFS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this */
> + return safe_memdup (g, &ret.statbuf, sizeof (ret.statbuf));
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_tune2fs_l (guestfs_h *g,
> const char *device)
> {
> struct guestfs_tune2fs_l_args args;
> - struct tune2fs_l_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_tune2fs_l_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_tune2fs_l") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_TUNE2FS_L,
> (xdrproc_t) xdr_guestfs_tune2fs_l_args, (char *) &args);
> @@ -5036,90 +4505,85 @@ char **guestfs_tune2fs_l (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, tune2fs_l_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_tune2fs_l");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TUNE2FS_L, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.superblock.superblock_val =
> - safe_realloc (g, ctx.ret.superblock.superblock_val,
> - sizeof (char *) * (ctx.ret.superblock.superblock_len + 1));
> - ctx.ret.superblock.superblock_val[ctx.ret.superblock.superblock_len] = NULL;
> - return ctx.ret.superblock.superblock_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_setro_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_tune2fs_l");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void blockdev_setro_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_setro_ctx *ctx = (struct blockdev_setro_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_tune2fs_l");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_setro");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_setro");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_tune2fs_l");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_setro");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_tune2fs_l");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_tune2fs_l_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_tune2fs_l");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_TUNE2FS_L, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.superblock.superblock_val =
> + safe_realloc (g, ret.superblock.superblock_val,
> + sizeof (char *) * (ret.superblock.superblock_len + 1));
> + ret.superblock.superblock_val[ret.superblock.superblock_len] = NULL;
> + return ret.superblock.superblock_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_blockdev_setro (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_setro_args args;
> - struct blockdev_setro_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_setro") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_SETRO,
> (xdrproc_t) xdr_guestfs_blockdev_setro_args, (char *) &args);
> @@ -5128,85 +4592,76 @@ int guestfs_blockdev_setro (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_setro_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setro");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETRO, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_setrw_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_setro");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_setrw_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_setrw_ctx *ctx = (struct blockdev_setrw_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setro");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_setrw");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_setrw");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_setro");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_setrw");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_setro");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_SETRO, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_blockdev_setrw (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_setrw_args args;
> - struct blockdev_setrw_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_setrw") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_SETRW,
> (xdrproc_t) xdr_guestfs_blockdev_setrw_args, (char *) &args);
> @@ -5215,90 +4670,77 @@ int guestfs_blockdev_setrw (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_setrw_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setrw");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETRW, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_getro_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_blockdev_getro_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_setrw");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_getro_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_getro_ctx *ctx = (struct blockdev_getro_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setrw");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_getro");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_getro");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_setrw");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_getro");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_setrw");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_blockdev_getro_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_blockdev_getro");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_SETRW, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_blockdev_getro (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_getro_args args;
> - struct blockdev_getro_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_blockdev_getro_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_getro") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETRO,
> (xdrproc_t) xdr_guestfs_blockdev_getro_args, (char *) &args);
> @@ -5307,90 +4749,81 @@ int guestfs_blockdev_getro (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_getro_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getro");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETRO, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.ro;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_getss_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_blockdev_getss_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_getro");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_getss_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_getss_ctx *ctx = (struct blockdev_getss_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getro");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_getss");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_getss");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_getro");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_getss");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_getro");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_blockdev_getss_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_blockdev_getss");
> - return;
> + else if (!xdr_guestfs_blockdev_getro_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_blockdev_getro");
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_GETRO, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.ro;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_blockdev_getss (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_getss_args args;
> - struct blockdev_getss_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_blockdev_getss_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_getss") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETSS,
> (xdrproc_t) xdr_guestfs_blockdev_getss_args, (char *) &args);
> @@ -5399,90 +4832,81 @@ int guestfs_blockdev_getss (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_getss_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getss");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSS, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.sectorsize;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_getbsz_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_blockdev_getbsz_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_getss");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_getbsz_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_getbsz_ctx *ctx = (struct blockdev_getbsz_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getss");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_getbsz");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_getbsz");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_getss");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_getbsz");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_getss");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_blockdev_getbsz_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_blockdev_getbsz");
> - return;
> + else if (!xdr_guestfs_blockdev_getss_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_blockdev_getss");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_GETSS, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.sectorsize;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_blockdev_getbsz (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_getbsz_args args;
> - struct blockdev_getbsz_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_blockdev_getbsz_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_getbsz") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETBSZ,
> (xdrproc_t) xdr_guestfs_blockdev_getbsz_args, (char *) &args);
> @@ -5491,70 +4915,67 @@ int guestfs_blockdev_getbsz (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_getbsz_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getbsz");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETBSZ, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.blocksize;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_setbsz_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_getbsz");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_setbsz_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_setbsz_ctx *ctx = (struct blockdev_setbsz_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getbsz");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_setbsz");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_setbsz");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_getbsz");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_setbsz");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_getbsz");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_blockdev_getbsz_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_blockdev_getbsz");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_GETBSZ, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.blocksize;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_blockdev_setbsz (guestfs_h *g,
> @@ -5562,15 +4983,13 @@ int guestfs_blockdev_setbsz (guestfs_h *g,
> int blocksize)
> {
> struct guestfs_blockdev_setbsz_args args;
> - struct blockdev_setbsz_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_setbsz") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> args.blocksize = blocksize;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_SETBSZ,
> @@ -5580,90 +4999,77 @@ int guestfs_blockdev_setbsz (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_setbsz_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setbsz");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_SETBSZ, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_getsz_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_blockdev_getsz_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_setbsz");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_getsz_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_getsz_ctx *ctx = (struct blockdev_getsz_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_setbsz");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_getsz");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_getsz");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_setbsz");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_getsz");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_setbsz");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_blockdev_getsz_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_blockdev_getsz");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_SETBSZ, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int64_t guestfs_blockdev_getsz (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_getsz_args args;
> - struct blockdev_getsz_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_blockdev_getsz_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_getsz") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETSZ,
> (xdrproc_t) xdr_guestfs_blockdev_getsz_args, (char *) &args);
> @@ -5672,90 +5078,81 @@ int64_t guestfs_blockdev_getsz (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_getsz_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getsz");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSZ, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.sizeinsectors;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_getsize64_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_blockdev_getsize64_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_getsz");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_getsize64_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_getsize64_ctx *ctx = (struct blockdev_getsize64_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getsz");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_getsize64");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_getsize64");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_getsz");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_getsize64");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_getsz");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_blockdev_getsize64_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_blockdev_getsize64");
> - return;
> + else if (!xdr_guestfs_blockdev_getsz_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_blockdev_getsz");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_GETSZ, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.sizeinsectors;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int64_t guestfs_blockdev_getsize64 (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_getsize64_args args;
> - struct blockdev_getsize64_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_blockdev_getsize64_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_getsize64") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_GETSIZE64,
> (xdrproc_t) xdr_guestfs_blockdev_getsize64_args, (char *) &args);
> @@ -5764,85 +5161,80 @@ int64_t guestfs_blockdev_getsize64 (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_getsize64_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getsize64");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_GETSIZE64, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.sizeinbytes;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_flushbufs_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_getsize64");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_flushbufs_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_flushbufs_ctx *ctx = (struct blockdev_flushbufs_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_getsize64");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_flushbufs");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_flushbufs");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_getsize64");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_flushbufs");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_getsize64");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_blockdev_getsize64_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_blockdev_getsize64");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_GETSIZE64, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.sizeinbytes;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_blockdev_flushbufs (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_flushbufs_args args;
> - struct blockdev_flushbufs_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_flushbufs") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS,
> (xdrproc_t) xdr_guestfs_blockdev_flushbufs_args, (char *) &args);
> @@ -5851,85 +5243,76 @@ int guestfs_blockdev_flushbufs (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_flushbufs_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_flushbufs");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct blockdev_rereadpt_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_flushbufs");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void blockdev_rereadpt_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct blockdev_rereadpt_ctx *ctx = (struct blockdev_rereadpt_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_flushbufs");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_blockdev_rereadpt");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_blockdev_rereadpt");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_flushbufs");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_blockdev_rereadpt");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_flushbufs");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_FLUSHBUFS, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_blockdev_rereadpt (guestfs_h *g,
> const char *device)
> {
> struct guestfs_blockdev_rereadpt_args args;
> - struct blockdev_rereadpt_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_blockdev_rereadpt") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_BLOCKDEV_REREADPT,
> (xdrproc_t) xdr_guestfs_blockdev_rereadpt_args, (char *) &args);
> @@ -5938,70 +5321,63 @@ int guestfs_blockdev_rereadpt (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, blockdev_rereadpt_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_rereadpt");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_BLOCKDEV_REREADPT, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct upload_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_blockdev_rereadpt");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void upload_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct upload_ctx *ctx = (struct upload_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_blockdev_rereadpt");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_upload");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_upload");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_blockdev_rereadpt");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_upload");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_blockdev_rereadpt");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_BLOCKDEV_REREADPT, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_upload (guestfs_h *g,
> @@ -6009,15 +5385,13 @@ int guestfs_upload (guestfs_h *g,
> const char *remotefilename)
> {
> struct guestfs_upload_args args;
> - struct upload_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_upload") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.remotefilename = (char *) remotefilename;
> serial = guestfs__send_sync (g, GUESTFS_PROC_UPLOAD,
> (xdrproc_t) xdr_guestfs_upload_args, (char *) &args);
> @@ -6034,75 +5408,65 @@ int guestfs_upload (guestfs_h *g,
> guestfs_end_busy (g);
> return -1;
> }
> - if (r == -2) /* daemon cancelled */
> - goto read_reply;
> - }
> -
> - read_reply:
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, upload_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_upload");
> - guestfs_end_busy (g);
> - return -1;
> }
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UPLOAD, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct download_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_upload");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void download_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct download_ctx *ctx = (struct download_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_upload");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_download");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_download");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_upload");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_download");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_upload");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_UPLOAD, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_download (guestfs_h *g,
> @@ -6110,15 +5474,13 @@ int guestfs_download (guestfs_h *g,
> const char *filename)
> {
> struct guestfs_download_args args;
> - struct download_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_download") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.remotefilename = (char *) remotefilename;
> serial = guestfs__send_sync (g, GUESTFS_PROC_DOWNLOAD,
> (xdrproc_t) xdr_guestfs_download_args, (char *) &args);
> @@ -6127,80 +5489,68 @@ int guestfs_download (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, download_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_download");
> - guestfs_end_busy (g);
> - return -1;
> + guestfs_reply_t reply;
> +
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
> +
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
> +
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_download");
> + guestfs_end_busy (g);
> + return -1;
> + }
> +
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_download");
> + guestfs_end_busy (g);
> + return -1;
> + }
> +
> + break;
> }
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DOWNLOAD, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_download");
> + goto recv_error;
> }
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_download");
> + goto recv_error;
> + }
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_DOWNLOAD, serial) == -1) {
> + goto recv_error;
> }
>
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> if (guestfs__receive_file_sync (g, filename) == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> guestfs_end_busy (g);
> - return 0;
> -}
> -
> -struct checksum_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_checksum_ret ret;
> -};
> -
> -static void checksum_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct checksum_ctx *ctx = (struct checksum_ctx *) data;
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_checksum");
> - return;
> - }
> -
> - ml->main_loop_quit (ml, g);
> + return 0;
>
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_checksum");
> - return;
> - }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_checksum");
> - return;
> - }
> - goto done;
> - }
> - if (!xdr_guestfs_checksum_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_checksum");
> - return;
> - }
> - done:
> - ctx->cb_sequence = 1;
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_checksum (guestfs_h *g,
> @@ -6208,15 +5558,14 @@ char *guestfs_checksum (guestfs_h *g,
> const char *path)
> {
> struct guestfs_checksum_args args;
> - struct checksum_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_checksum_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_checksum") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.csumtype = (char *) csumtype;
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_CHECKSUM,
> @@ -6226,70 +5575,67 @@ char *guestfs_checksum (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, checksum_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_checksum");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CHECKSUM, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.checksum; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct tar_in_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_checksum");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void tar_in_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct tar_in_ctx *ctx = (struct tar_in_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_checksum");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_tar_in");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_tar_in");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_checksum");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_tar_in");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_checksum");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_checksum_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_checksum");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_CHECKSUM, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.checksum; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_tar_in (guestfs_h *g,
> @@ -6297,15 +5643,13 @@ int guestfs_tar_in (guestfs_h *g,
> const char *directory)
> {
> struct guestfs_tar_in_args args;
> - struct tar_in_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_tar_in") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.directory = (char *) directory;
> serial = guestfs__send_sync (g, GUESTFS_PROC_TAR_IN,
> (xdrproc_t) xdr_guestfs_tar_in_args, (char *) &args);
> @@ -6322,75 +5666,65 @@ int guestfs_tar_in (guestfs_h *g,
> guestfs_end_busy (g);
> return -1;
> }
> - if (r == -2) /* daemon cancelled */
> - goto read_reply;
> - }
> -
> - read_reply:
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, tar_in_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_tar_in");
> - guestfs_end_busy (g);
> - return -1;
> }
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TAR_IN, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct tar_out_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_tar_in");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void tar_out_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct tar_out_ctx *ctx = (struct tar_out_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_tar_in");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_tar_out");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_tar_out");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_tar_in");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_tar_out");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_tar_in");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_TAR_IN, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_tar_out (guestfs_h *g,
> @@ -6398,15 +5732,13 @@ int guestfs_tar_out (guestfs_h *g,
> const char *tarfile)
> {
> struct guestfs_tar_out_args args;
> - struct tar_out_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_tar_out") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.directory = (char *) directory;
> serial = guestfs__send_sync (g, GUESTFS_PROC_TAR_OUT,
> (xdrproc_t) xdr_guestfs_tar_out_args, (char *) &args);
> @@ -6415,75 +5747,68 @@ int guestfs_tar_out (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, tar_out_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_tar_out");
> - guestfs_end_busy (g);
> - return -1;
> + guestfs_reply_t reply;
> +
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
> +
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
> +
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_tar_out");
> + guestfs_end_busy (g);
> + return -1;
> + }
> +
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_tar_out");
> + guestfs_end_busy (g);
> + return -1;
> + }
> +
> + break;
> }
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TAR_OUT, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_tar_out");
> + goto recv_error;
> }
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_tar_out");
> + goto recv_error;
> + }
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_TAR_OUT, serial) == -1) {
> + goto recv_error;
> }
>
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> if (guestfs__receive_file_sync (g, tarfile) == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> guestfs_end_busy (g);
> - return 0;
> -}
> -
> -struct tgz_in_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> -
> -static void tgz_in_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct tgz_in_ctx *ctx = (struct tgz_in_ctx *) data;
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_tgz_in");
> - return;
> - }
> -
> - ml->main_loop_quit (ml, g);
> + return 0;
>
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_tgz_in");
> - return;
> - }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_tgz_in");
> - return;
> - }
> - goto done;
> - }
> - done:
> - ctx->cb_sequence = 1;
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_tgz_in (guestfs_h *g,
> @@ -6491,15 +5816,13 @@ int guestfs_tgz_in (guestfs_h *g,
> const char *directory)
> {
> struct guestfs_tgz_in_args args;
> - struct tgz_in_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_tgz_in") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.directory = (char *) directory;
> serial = guestfs__send_sync (g, GUESTFS_PROC_TGZ_IN,
> (xdrproc_t) xdr_guestfs_tgz_in_args, (char *) &args);
> @@ -6516,75 +5839,65 @@ int guestfs_tgz_in (guestfs_h *g,
> guestfs_end_busy (g);
> return -1;
> }
> - if (r == -2) /* daemon cancelled */
> - goto read_reply;
> }
>
> - read_reply:
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, tgz_in_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_tgz_in");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TGZ_IN, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct tgz_out_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_tgz_in");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void tgz_out_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct tgz_out_ctx *ctx = (struct tgz_out_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_tgz_in");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_tgz_out");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_tgz_out");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_tgz_in");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_tgz_out");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_tgz_in");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_TGZ_IN, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_tgz_out (guestfs_h *g,
> @@ -6592,15 +5905,13 @@ int guestfs_tgz_out (guestfs_h *g,
> const char *tarball)
> {
> struct guestfs_tgz_out_args args;
> - struct tgz_out_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_tgz_out") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.directory = (char *) directory;
> serial = guestfs__send_sync (g, GUESTFS_PROC_TGZ_OUT,
> (xdrproc_t) xdr_guestfs_tgz_out_args, (char *) &args);
> @@ -6609,75 +5920,68 @@ int guestfs_tgz_out (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, tgz_out_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_tgz_out");
> - guestfs_end_busy (g);
> - return -1;
> + guestfs_reply_t reply;
> +
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
> +
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
> +
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_tgz_out");
> + guestfs_end_busy (g);
> + return -1;
> + }
> +
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_tgz_out");
> + guestfs_end_busy (g);
> + return -1;
> + }
> +
> + break;
> }
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TGZ_OUT, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_tgz_out");
> + goto recv_error;
> }
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_tgz_out");
> + goto recv_error;
> + }
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_TGZ_OUT, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
>
> + guestfs_free_reply (g, &reply);
> +
> if (guestfs__receive_file_sync (g, tarball) == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> guestfs_end_busy (g);
> - return 0;
> -}
> -
> -struct mount_ro_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
>
> -static void mount_ro_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mount_ro_ctx *ctx = (struct mount_ro_ctx *) data;
> -
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mount_ro");
> - return;
> - }
> -
> - ml->main_loop_quit (ml, g);
> + return 0;
>
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mount_ro");
> - return;
> - }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mount_ro");
> - return;
> - }
> - goto done;
> - }
> - done:
> - ctx->cb_sequence = 1;
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mount_ro (guestfs_h *g,
> @@ -6685,15 +5989,13 @@ int guestfs_mount_ro (guestfs_h *g,
> const char *mountpoint)
> {
> struct guestfs_mount_ro_args args;
> - struct mount_ro_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mount_ro") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> args.mountpoint = (char *) mountpoint;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MOUNT_RO,
> @@ -6703,70 +6005,63 @@ int guestfs_mount_ro (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mount_ro_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mount_ro");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNT_RO, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mount_options_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mount_ro");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mount_options_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mount_options_ctx *ctx = (struct mount_options_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mount_ro");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mount_options");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mount_options");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mount_ro");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mount_options");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mount_ro");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MOUNT_RO, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mount_options (guestfs_h *g,
> @@ -6775,15 +6070,13 @@ int guestfs_mount_options (guestfs_h *g,
> const char *mountpoint)
> {
> struct guestfs_mount_options_args args;
> - struct mount_options_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mount_options") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.options = (char *) options;
> args.device = (char *) device;
> args.mountpoint = (char *) mountpoint;
> @@ -6794,70 +6087,63 @@ int guestfs_mount_options (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mount_options_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mount_options");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNT_OPTIONS, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mount_vfs_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mount_options");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mount_vfs_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mount_vfs_ctx *ctx = (struct mount_vfs_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mount_options");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mount_vfs");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mount_vfs");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mount_options");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mount_vfs");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mount_options");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MOUNT_OPTIONS, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mount_vfs (guestfs_h *g,
> @@ -6867,15 +6153,13 @@ int guestfs_mount_vfs (guestfs_h *g,
> const char *mountpoint)
> {
> struct guestfs_mount_vfs_args args;
> - struct mount_vfs_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mount_vfs") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.options = (char *) options;
> args.vfstype = (char *) vfstype;
> args.device = (char *) device;
> @@ -6887,75 +6171,63 @@ int guestfs_mount_vfs (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mount_vfs_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mount_vfs");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNT_VFS, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct debug_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_debug_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mount_vfs");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void debug_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct debug_ctx *ctx = (struct debug_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mount_vfs");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_debug");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_debug");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mount_vfs");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_debug");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mount_vfs");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_debug_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_debug");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MOUNT_VFS, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_debug (guestfs_h *g,
> @@ -6963,15 +6235,14 @@ char *guestfs_debug (guestfs_h *g,
> char * const* const extraargs)
> {
> struct guestfs_debug_args args;
> - struct debug_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_debug_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_debug") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.subcmd = (char *) subcmd;
> args.extraargs.extraargs_val = (char **) extraargs;
> for (args.extraargs.extraargs_len = 0; extraargs[args.extraargs.extraargs_len]; args.extraargs.extraargs_len++) ;
> @@ -6982,85 +6253,80 @@ char *guestfs_debug (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, debug_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_debug");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DEBUG, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.result; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct lvremove_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_debug");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void lvremove_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct lvremove_ctx *ctx = (struct lvremove_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_debug");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_lvremove");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_lvremove");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_debug");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_lvremove");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_debug");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_debug_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_debug");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_DEBUG, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.result; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_lvremove (guestfs_h *g,
> const char *device)
> {
> struct guestfs_lvremove_args args;
> - struct lvremove_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_lvremove") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_LVREMOVE,
> (xdrproc_t) xdr_guestfs_lvremove_args, (char *) &args);
> @@ -7069,85 +6335,76 @@ int guestfs_lvremove (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, lvremove_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_lvremove");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVREMOVE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct vgremove_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_lvremove");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void vgremove_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct vgremove_ctx *ctx = (struct vgremove_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_lvremove");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_vgremove");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_vgremove");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_lvremove");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_vgremove");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_lvremove");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LVREMOVE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_vgremove (guestfs_h *g,
> const char *vgname)
> {
> struct guestfs_vgremove_args args;
> - struct vgremove_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_vgremove") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.vgname = (char *) vgname;
> serial = guestfs__send_sync (g, GUESTFS_PROC_VGREMOVE,
> (xdrproc_t) xdr_guestfs_vgremove_args, (char *) &args);
> @@ -7156,85 +6413,76 @@ int guestfs_vgremove (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, vgremove_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_vgremove");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VGREMOVE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct pvremove_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_vgremove");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void pvremove_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct pvremove_ctx *ctx = (struct pvremove_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_vgremove");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_pvremove");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_pvremove");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_vgremove");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_pvremove");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_vgremove");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_VGREMOVE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_pvremove (guestfs_h *g,
> const char *device)
> {
> struct guestfs_pvremove_args args;
> - struct pvremove_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_pvremove") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_PVREMOVE,
> (xdrproc_t) xdr_guestfs_pvremove_args, (char *) &args);
> @@ -7243,70 +6491,63 @@ int guestfs_pvremove (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, pvremove_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_pvremove");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVREMOVE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct set_e2label_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_pvremove");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void set_e2label_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct set_e2label_ctx *ctx = (struct set_e2label_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_pvremove");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_set_e2label");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_set_e2label");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_pvremove");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_set_e2label");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_pvremove");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_PVREMOVE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_set_e2label (guestfs_h *g,
> @@ -7314,15 +6555,13 @@ int guestfs_set_e2label (guestfs_h *g,
> const char *label)
> {
> struct guestfs_set_e2label_args args;
> - struct set_e2label_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_set_e2label") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> args.label = (char *) label;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SET_E2LABEL,
> @@ -7332,90 +6571,77 @@ int guestfs_set_e2label (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, set_e2label_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_set_e2label");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SET_E2LABEL, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct get_e2label_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_get_e2label_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_set_e2label");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void get_e2label_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct get_e2label_ctx *ctx = (struct get_e2label_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_set_e2label");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_get_e2label");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_get_e2label");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_set_e2label");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_get_e2label");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_set_e2label");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_get_e2label_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_get_e2label");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SET_E2LABEL, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_get_e2label (guestfs_h *g,
> const char *device)
> {
> struct guestfs_get_e2label_args args;
> - struct get_e2label_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_get_e2label_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_get_e2label") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_GET_E2LABEL,
> (xdrproc_t) xdr_guestfs_get_e2label_args, (char *) &args);
> @@ -7424,70 +6650,67 @@ char *guestfs_get_e2label (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, get_e2label_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_get_e2label");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_GET_E2LABEL, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.label; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct set_e2uuid_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_get_e2label");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void set_e2uuid_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct set_e2uuid_ctx *ctx = (struct set_e2uuid_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_get_e2label");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_set_e2uuid");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_set_e2uuid");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_get_e2label");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_set_e2uuid");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_get_e2label");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_get_e2label_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_get_e2label");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_GET_E2LABEL, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.label; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_set_e2uuid (guestfs_h *g,
> @@ -7495,15 +6718,13 @@ int guestfs_set_e2uuid (guestfs_h *g,
> const char *uuid)
> {
> struct guestfs_set_e2uuid_args args;
> - struct set_e2uuid_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_set_e2uuid") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> args.uuid = (char *) uuid;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SET_E2UUID,
> @@ -7513,90 +6734,77 @@ int guestfs_set_e2uuid (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, set_e2uuid_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_set_e2uuid");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SET_E2UUID, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct get_e2uuid_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_get_e2uuid_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_set_e2uuid");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void get_e2uuid_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct get_e2uuid_ctx *ctx = (struct get_e2uuid_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_set_e2uuid");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_get_e2uuid");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_get_e2uuid");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_set_e2uuid");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_get_e2uuid");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_set_e2uuid");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_get_e2uuid_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_get_e2uuid");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SET_E2UUID, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_get_e2uuid (guestfs_h *g,
> const char *device)
> {
> struct guestfs_get_e2uuid_args args;
> - struct get_e2uuid_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_get_e2uuid_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_get_e2uuid") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_GET_E2UUID,
> (xdrproc_t) xdr_guestfs_get_e2uuid_args, (char *) &args);
> @@ -7605,75 +6813,67 @@ char *guestfs_get_e2uuid (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, get_e2uuid_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_get_e2uuid");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_GET_E2UUID, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.uuid; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct fsck_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_fsck_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_get_e2uuid");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void fsck_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct fsck_ctx *ctx = (struct fsck_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_get_e2uuid");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_fsck");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_fsck");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_get_e2uuid");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_fsck");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_get_e2uuid");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_fsck_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_fsck");
> - return;
> + else if (!xdr_guestfs_get_e2uuid_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_get_e2uuid");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_GET_E2UUID, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.uuid; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_fsck (guestfs_h *g,
> @@ -7681,15 +6881,14 @@ int guestfs_fsck (guestfs_h *g,
> const char *device)
> {
> struct guestfs_fsck_args args;
> - struct fsck_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_fsck_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_fsck") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.fstype = (char *) fstype;
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_FSCK,
> @@ -7699,85 +6898,80 @@ int guestfs_fsck (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, fsck_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_fsck");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_FSCK, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.status;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct zero_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_fsck");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void zero_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct zero_ctx *ctx = (struct zero_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_fsck");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_zero");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_zero");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_fsck");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_zero");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_fsck");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_fsck_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_fsck");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_FSCK, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.status;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_zero (guestfs_h *g,
> const char *device)
> {
> struct guestfs_zero_args args;
> - struct zero_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_zero") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_ZERO,
> (xdrproc_t) xdr_guestfs_zero_args, (char *) &args);
> @@ -7786,70 +6980,63 @@ int guestfs_zero (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, zero_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_zero");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_ZERO, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct grub_install_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_zero");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void grub_install_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct grub_install_ctx *ctx = (struct grub_install_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_zero");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_grub_install");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_grub_install");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_zero");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_grub_install");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_zero");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_ZERO, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_grub_install (guestfs_h *g,
> @@ -7857,15 +7044,13 @@ int guestfs_grub_install (guestfs_h *g,
> const char *device)
> {
> struct guestfs_grub_install_args args;
> - struct grub_install_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_grub_install") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.root = (char *) root;
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_GRUB_INSTALL,
> @@ -7875,70 +7060,63 @@ int guestfs_grub_install (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, grub_install_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_grub_install");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_GRUB_INSTALL, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct cp_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_grub_install");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void cp_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct cp_ctx *ctx = (struct cp_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_grub_install");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_cp");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_cp");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_grub_install");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_cp");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_grub_install");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_GRUB_INSTALL, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_cp (guestfs_h *g,
> @@ -7946,15 +7124,13 @@ int guestfs_cp (guestfs_h *g,
> const char *dest)
> {
> struct guestfs_cp_args args;
> - struct cp_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_cp") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.src = (char *) src;
> args.dest = (char *) dest;
> serial = guestfs__send_sync (g, GUESTFS_PROC_CP,
> @@ -7964,70 +7140,63 @@ int guestfs_cp (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, cp_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_cp");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CP, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct cp_a_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_cp");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void cp_a_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct cp_a_ctx *ctx = (struct cp_a_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_cp");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_cp_a");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_cp_a");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_cp");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_cp_a");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_cp");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_CP, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_cp_a (guestfs_h *g,
> @@ -8035,15 +7204,13 @@ int guestfs_cp_a (guestfs_h *g,
> const char *dest)
> {
> struct guestfs_cp_a_args args;
> - struct cp_a_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_cp_a") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.src = (char *) src;
> args.dest = (char *) dest;
> serial = guestfs__send_sync (g, GUESTFS_PROC_CP_A,
> @@ -8053,70 +7220,63 @@ int guestfs_cp_a (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, cp_a_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_cp_a");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_CP_A, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mv_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_cp_a");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mv_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mv_ctx *ctx = (struct mv_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_cp_a");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mv");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mv");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_cp_a");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mv");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_cp_a");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_CP_A, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mv (guestfs_h *g,
> @@ -8124,15 +7284,13 @@ int guestfs_mv (guestfs_h *g,
> const char *dest)
> {
> struct guestfs_mv_args args;
> - struct mv_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mv") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.src = (char *) src;
> args.dest = (char *) dest;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MV,
> @@ -8142,85 +7300,76 @@ int guestfs_mv (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mv_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mv");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MV, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct drop_caches_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mv");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void drop_caches_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct drop_caches_ctx *ctx = (struct drop_caches_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mv");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_drop_caches");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_drop_caches");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mv");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_drop_caches");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mv");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MV, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_drop_caches (guestfs_h *g,
> int whattodrop)
> {
> struct guestfs_drop_caches_args args;
> - struct drop_caches_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_drop_caches") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.whattodrop = whattodrop;
> serial = guestfs__send_sync (g, GUESTFS_PROC_DROP_CACHES,
> (xdrproc_t) xdr_guestfs_drop_caches_args, (char *) &args);
> @@ -8229,246 +7378,216 @@ int guestfs_drop_caches (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, drop_caches_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_drop_caches");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DROP_CACHES, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct dmesg_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_dmesg_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_drop_caches");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void dmesg_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct dmesg_ctx *ctx = (struct dmesg_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_drop_caches");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_dmesg");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_dmesg");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_drop_caches");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_dmesg");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_drop_caches");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_dmesg_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_dmesg");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_DROP_CACHES, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_dmesg (guestfs_h *g)
> {
> - struct dmesg_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_dmesg_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_dmesg") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_DMESG, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, dmesg_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_dmesg");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DMESG, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.kmsgs; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct ping_daemon_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_dmesg");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void ping_daemon_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct ping_daemon_ctx *ctx = (struct ping_daemon_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_dmesg");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_ping_daemon");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_ping_daemon");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_dmesg");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_ping_daemon");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_dmesg");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_dmesg_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_dmesg");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_DMESG, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.kmsgs; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_ping_daemon (guestfs_h *g)
> {
> - struct ping_daemon_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_ping_daemon") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_PING_DAEMON, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, ping_daemon_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_ping_daemon");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PING_DAEMON, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct equal_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_equal_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_ping_daemon");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void equal_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct equal_ctx *ctx = (struct equal_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_ping_daemon");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_equal");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_equal");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_ping_daemon");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_equal");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_ping_daemon");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_equal_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_equal");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_PING_DAEMON, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_equal (guestfs_h *g,
> @@ -8476,15 +7595,14 @@ int guestfs_equal (guestfs_h *g,
> const char *file2)
> {
> struct guestfs_equal_args args;
> - struct equal_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_equal_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_equal") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.file1 = (char *) file1;
> args.file2 = (char *) file2;
> serial = guestfs__send_sync (g, GUESTFS_PROC_EQUAL,
> @@ -8494,90 +7612,81 @@ int guestfs_equal (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, equal_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_equal");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_EQUAL, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return ctx.ret.equality;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct strings_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_strings_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_equal");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void strings_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct strings_ctx *ctx = (struct strings_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_equal");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_strings");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_strings");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_equal");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_strings");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_equal");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_strings_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_strings");
> - return;
> + else if (!xdr_guestfs_equal_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_equal");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_EQUAL, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.equality;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char **guestfs_strings (guestfs_h *g,
> const char *path)
> {
> struct guestfs_strings_args args;
> - struct strings_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_strings_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_strings") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_STRINGS,
> (xdrproc_t) xdr_guestfs_strings_args, (char *) &args);
> @@ -8586,80 +7695,72 @@ char **guestfs_strings (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, strings_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_strings");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_STRINGS, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.stringsout.stringsout_val =
> - safe_realloc (g, ctx.ret.stringsout.stringsout_val,
> - sizeof (char *) * (ctx.ret.stringsout.stringsout_len + 1));
> - ctx.ret.stringsout.stringsout_val[ctx.ret.stringsout.stringsout_len] = NULL;
> - return ctx.ret.stringsout.stringsout_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct strings_e_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_strings_e_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_strings");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void strings_e_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct strings_e_ctx *ctx = (struct strings_e_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_strings");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_strings_e");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_strings_e");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_strings");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_strings_e");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_strings");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_strings_e_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_strings_e");
> - return;
> + else if (!xdr_guestfs_strings_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_strings");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_STRINGS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.stringsout.stringsout_val =
> + safe_realloc (g, ret.stringsout.stringsout_val,
> + sizeof (char *) * (ret.stringsout.stringsout_len + 1));
> + ret.stringsout.stringsout_val[ret.stringsout.stringsout_len] = NULL;
> + return ret.stringsout.stringsout_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_strings_e (guestfs_h *g,
> @@ -8667,15 +7768,14 @@ char **guestfs_strings_e (guestfs_h *g,
> const char *path)
> {
> struct guestfs_strings_e_args args;
> - struct strings_e_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_strings_e_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_strings_e") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.encoding = (char *) encoding;
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_STRINGS_E,
> @@ -8685,95 +7785,86 @@ char **guestfs_strings_e (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, strings_e_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_strings_e");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_STRINGS_E, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.stringsout.stringsout_val =
> - safe_realloc (g, ctx.ret.stringsout.stringsout_val,
> - sizeof (char *) * (ctx.ret.stringsout.stringsout_len + 1));
> - ctx.ret.stringsout.stringsout_val[ctx.ret.stringsout.stringsout_len] = NULL;
> - return ctx.ret.stringsout.stringsout_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct hexdump_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_hexdump_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_strings_e");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void hexdump_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct hexdump_ctx *ctx = (struct hexdump_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_strings_e");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_hexdump");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_hexdump");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_strings_e");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_hexdump");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_strings_e");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_hexdump_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_hexdump");
> - return;
> + else if (!xdr_guestfs_strings_e_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_strings_e");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_STRINGS_E, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.stringsout.stringsout_val =
> + safe_realloc (g, ret.stringsout.stringsout_val,
> + sizeof (char *) * (ret.stringsout.stringsout_len + 1));
> + ret.stringsout.stringsout_val[ret.stringsout.stringsout_len] = NULL;
> + return ret.stringsout.stringsout_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char *guestfs_hexdump (guestfs_h *g,
> const char *path)
> {
> struct guestfs_hexdump_args args;
> - struct hexdump_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_hexdump_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_hexdump") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_HEXDUMP,
> (xdrproc_t) xdr_guestfs_hexdump_args, (char *) &args);
> @@ -8782,85 +7873,80 @@ char *guestfs_hexdump (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, hexdump_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_hexdump");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_HEXDUMP, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.dump; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct zerofree_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_hexdump");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void zerofree_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct zerofree_ctx *ctx = (struct zerofree_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_hexdump");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_zerofree");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_zerofree");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_hexdump");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_zerofree");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_hexdump");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_hexdump_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_hexdump");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_HEXDUMP, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.dump; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_zerofree (guestfs_h *g,
> const char *device)
> {
> struct guestfs_zerofree_args args;
> - struct zerofree_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_zerofree") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_ZEROFREE,
> (xdrproc_t) xdr_guestfs_zerofree_args, (char *) &args);
> @@ -8869,85 +7955,76 @@ int guestfs_zerofree (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, zerofree_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_zerofree");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_ZEROFREE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct pvresize_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_zerofree");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void pvresize_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct pvresize_ctx *ctx = (struct pvresize_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_zerofree");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_pvresize");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_pvresize");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_zerofree");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_pvresize");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_zerofree");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_ZEROFREE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_pvresize (guestfs_h *g,
> const char *device)
> {
> struct guestfs_pvresize_args args;
> - struct pvresize_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_pvresize") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_PVRESIZE,
> (xdrproc_t) xdr_guestfs_pvresize_args, (char *) &args);
> @@ -8956,70 +8033,63 @@ int guestfs_pvresize (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, pvresize_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_pvresize");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVRESIZE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sfdisk_N_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_pvresize");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void sfdisk_N_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sfdisk_N_ctx *ctx = (struct sfdisk_N_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_pvresize");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sfdisk_N");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sfdisk_N");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_pvresize");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sfdisk_N");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_pvresize");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_PVRESIZE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_sfdisk_N (guestfs_h *g,
> @@ -9031,15 +8101,13 @@ int guestfs_sfdisk_N (guestfs_h *g,
> const char *line)
> {
> struct guestfs_sfdisk_N_args args;
> - struct sfdisk_N_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_sfdisk_N") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> args.partnum = partnum;
> args.cyls = cyls;
> @@ -9053,90 +8121,77 @@ int guestfs_sfdisk_N (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sfdisk_N_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk_N");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK_N, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sfdisk_l_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_sfdisk_l_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sfdisk_N");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void sfdisk_l_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sfdisk_l_ctx *ctx = (struct sfdisk_l_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk_N");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sfdisk_l");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sfdisk_l");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sfdisk_N");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sfdisk_l");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sfdisk_N");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_sfdisk_l_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_sfdisk_l");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SFDISK_N, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_sfdisk_l (guestfs_h *g,
> const char *device)
> {
> struct guestfs_sfdisk_l_args args;
> - struct sfdisk_l_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_sfdisk_l_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_sfdisk_l") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SFDISK_L,
> (xdrproc_t) xdr_guestfs_sfdisk_l_args, (char *) &args);
> @@ -9145,90 +8200,81 @@ char *guestfs_sfdisk_l (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sfdisk_l_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk_l");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK_L, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.partitions; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sfdisk_kernel_geometry_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_sfdisk_kernel_geometry_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sfdisk_l");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void sfdisk_kernel_geometry_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sfdisk_kernel_geometry_ctx *ctx = (struct sfdisk_kernel_geometry_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk_l");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sfdisk_kernel_geometry");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sfdisk_kernel_geometry");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sfdisk_l");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sfdisk_kernel_geometry");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sfdisk_l");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_sfdisk_kernel_geometry_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_sfdisk_kernel_geometry");
> - return;
> + else if (!xdr_guestfs_sfdisk_l_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_sfdisk_l");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SFDISK_L, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.partitions; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char *guestfs_sfdisk_kernel_geometry (guestfs_h *g,
> const char *device)
> {
> struct guestfs_sfdisk_kernel_geometry_args args;
> - struct sfdisk_kernel_geometry_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_sfdisk_kernel_geometry_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_sfdisk_kernel_geometry") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY,
> (xdrproc_t) xdr_guestfs_sfdisk_kernel_geometry_args, (char *) &args);
> @@ -9237,90 +8283,81 @@ char *guestfs_sfdisk_kernel_geometry (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sfdisk_kernel_geometry_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk_kernel_geometry");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.partitions; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sfdisk_disk_geometry_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_sfdisk_disk_geometry_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sfdisk_kernel_geometry");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void sfdisk_disk_geometry_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sfdisk_disk_geometry_ctx *ctx = (struct sfdisk_disk_geometry_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk_kernel_geometry");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sfdisk_disk_geometry");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sfdisk_disk_geometry");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sfdisk_kernel_geometry");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sfdisk_disk_geometry");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sfdisk_kernel_geometry");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_sfdisk_disk_geometry_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_sfdisk_disk_geometry");
> - return;
> + else if (!xdr_guestfs_sfdisk_kernel_geometry_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_sfdisk_kernel_geometry");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.partitions; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char *guestfs_sfdisk_disk_geometry (guestfs_h *g,
> const char *device)
> {
> struct guestfs_sfdisk_disk_geometry_args args;
> - struct sfdisk_disk_geometry_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_sfdisk_disk_geometry_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_sfdisk_disk_geometry") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SFDISK_DISK_GEOMETRY,
> (xdrproc_t) xdr_guestfs_sfdisk_disk_geometry_args, (char *) &args);
> @@ -9329,85 +8366,80 @@ char *guestfs_sfdisk_disk_geometry (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sfdisk_disk_geometry_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk_disk_geometry");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK_DISK_GEOMETRY, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.partitions; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct vg_activate_all_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sfdisk_disk_geometry");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void vg_activate_all_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct vg_activate_all_ctx *ctx = (struct vg_activate_all_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sfdisk_disk_geometry");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_vg_activate_all");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_vg_activate_all");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sfdisk_disk_geometry");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_vg_activate_all");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sfdisk_disk_geometry");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_sfdisk_disk_geometry_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_sfdisk_disk_geometry");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SFDISK_DISK_GEOMETRY, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.partitions; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_vg_activate_all (guestfs_h *g,
> int activate)
> {
> struct guestfs_vg_activate_all_args args;
> - struct vg_activate_all_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_vg_activate_all") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.activate = activate;
> serial = guestfs__send_sync (g, GUESTFS_PROC_VG_ACTIVATE_ALL,
> (xdrproc_t) xdr_guestfs_vg_activate_all_args, (char *) &args);
> @@ -9416,70 +8448,63 @@ int guestfs_vg_activate_all (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, vg_activate_all_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_vg_activate_all");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VG_ACTIVATE_ALL, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct vg_activate_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_vg_activate_all");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void vg_activate_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct vg_activate_ctx *ctx = (struct vg_activate_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_vg_activate_all");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_vg_activate");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_vg_activate");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_vg_activate_all");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_vg_activate");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_vg_activate_all");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_VG_ACTIVATE_ALL, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_vg_activate (guestfs_h *g,
> @@ -9487,15 +8512,13 @@ int guestfs_vg_activate (guestfs_h *g,
> char * const* const volgroups)
> {
> struct guestfs_vg_activate_args args;
> - struct vg_activate_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_vg_activate") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.activate = activate;
> args.volgroups.volgroups_val = (char **) volgroups;
> for (args.volgroups.volgroups_len = 0; volgroups[args.volgroups.volgroups_len]; args.volgroups.volgroups_len++) ;
> @@ -9506,70 +8529,63 @@ int guestfs_vg_activate (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, vg_activate_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_vg_activate");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VG_ACTIVATE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct lvresize_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_vg_activate");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void lvresize_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct lvresize_ctx *ctx = (struct lvresize_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_vg_activate");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_lvresize");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_lvresize");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_vg_activate");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_lvresize");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_vg_activate");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_VG_ACTIVATE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_lvresize (guestfs_h *g,
> @@ -9577,15 +8593,13 @@ int guestfs_lvresize (guestfs_h *g,
> int mbytes)
> {
> struct guestfs_lvresize_args args;
> - struct lvresize_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_lvresize") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> args.mbytes = mbytes;
> serial = guestfs__send_sync (g, GUESTFS_PROC_LVRESIZE,
> @@ -9595,85 +8609,76 @@ int guestfs_lvresize (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, lvresize_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_lvresize");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_LVRESIZE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct resize2fs_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_lvresize");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void resize2fs_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct resize2fs_ctx *ctx = (struct resize2fs_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_lvresize");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_resize2fs");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_resize2fs");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_lvresize");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_resize2fs");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_lvresize");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_LVRESIZE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_resize2fs (guestfs_h *g,
> const char *device)
> {
> struct guestfs_resize2fs_args args;
> - struct resize2fs_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_resize2fs") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_RESIZE2FS,
> (xdrproc_t) xdr_guestfs_resize2fs_args, (char *) &args);
> @@ -9682,90 +8687,77 @@ int guestfs_resize2fs (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, resize2fs_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_resize2fs");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_RESIZE2FS, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct find_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_find_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_resize2fs");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void find_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct find_ctx *ctx = (struct find_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_resize2fs");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_find");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_find");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_resize2fs");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_find");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_resize2fs");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_find_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_find");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_RESIZE2FS, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char **guestfs_find (guestfs_h *g,
> const char *directory)
> {
> struct guestfs_find_args args;
> - struct find_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_find_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_find") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.directory = (char *) directory;
> serial = guestfs__send_sync (g, GUESTFS_PROC_FIND,
> (xdrproc_t) xdr_guestfs_find_args, (char *) &args);
> @@ -9774,90 +8766,85 @@ char **guestfs_find (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, find_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_find");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_FIND, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.names.names_val =
> - safe_realloc (g, ctx.ret.names.names_val,
> - sizeof (char *) * (ctx.ret.names.names_len + 1));
> - ctx.ret.names.names_val[ctx.ret.names.names_len] = NULL;
> - return ctx.ret.names.names_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct e2fsck_f_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_find");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void e2fsck_f_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct e2fsck_f_ctx *ctx = (struct e2fsck_f_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_find");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_e2fsck_f");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_e2fsck_f");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_find");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_e2fsck_f");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_find");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_find_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_find");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_FIND, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.names.names_val =
> + safe_realloc (g, ret.names.names_val,
> + sizeof (char *) * (ret.names.names_len + 1));
> + ret.names.names_val[ret.names.names_len] = NULL;
> + return ret.names.names_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_e2fsck_f (guestfs_h *g,
> const char *device)
> {
> struct guestfs_e2fsck_f_args args;
> - struct e2fsck_f_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_e2fsck_f") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_E2FSCK_F,
> (xdrproc_t) xdr_guestfs_e2fsck_f_args, (char *) &args);
> @@ -9866,85 +8853,76 @@ int guestfs_e2fsck_f (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, e2fsck_f_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_e2fsck_f");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_E2FSCK_F, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sleep_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_e2fsck_f");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void sleep_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sleep_ctx *ctx = (struct sleep_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_e2fsck_f");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sleep");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sleep");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_e2fsck_f");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sleep");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_e2fsck_f");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_E2FSCK_F, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_sleep (guestfs_h *g,
> int secs)
> {
> struct guestfs_sleep_args args;
> - struct sleep_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_sleep") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.secs = secs;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SLEEP,
> (xdrproc_t) xdr_guestfs_sleep_args, (char *) &args);
> @@ -9953,75 +8931,63 @@ int guestfs_sleep (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sleep_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sleep");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SLEEP, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct ntfs_3g_probe_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_ntfs_3g_probe_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sleep");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void ntfs_3g_probe_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct ntfs_3g_probe_ctx *ctx = (struct ntfs_3g_probe_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sleep");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_ntfs_3g_probe");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_ntfs_3g_probe");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sleep");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_ntfs_3g_probe");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sleep");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_ntfs_3g_probe_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_ntfs_3g_probe");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SLEEP, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_ntfs_3g_probe (guestfs_h *g,
> @@ -10029,15 +8995,14 @@ int guestfs_ntfs_3g_probe (guestfs_h *g,
> const char *device)
> {
> struct guestfs_ntfs_3g_probe_args args;
> - struct ntfs_3g_probe_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_ntfs_3g_probe_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_ntfs_3g_probe") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.rw = rw;
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_NTFS_3G_PROBE,
> @@ -10047,90 +9012,81 @@ int guestfs_ntfs_3g_probe (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, ntfs_3g_probe_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_ntfs_3g_probe");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_NTFS_3G_PROBE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return ctx.ret.status;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sh_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_sh_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_ntfs_3g_probe");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void sh_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sh_ctx *ctx = (struct sh_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_ntfs_3g_probe");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sh");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sh");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_ntfs_3g_probe");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sh");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_ntfs_3g_probe");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_sh_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_sh");
> - return;
> + else if (!xdr_guestfs_ntfs_3g_probe_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_ntfs_3g_probe");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_NTFS_3G_PROBE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.status;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_sh (guestfs_h *g,
> const char *command)
> {
> struct guestfs_sh_args args;
> - struct sh_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_sh_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_sh") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.command = (char *) command;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SH,
> (xdrproc_t) xdr_guestfs_sh_args, (char *) &args);
> @@ -10139,90 +9095,81 @@ char *guestfs_sh (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sh_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sh");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SH, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.output; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct sh_lines_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_sh_lines_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sh");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void sh_lines_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct sh_lines_ctx *ctx = (struct sh_lines_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sh");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_sh_lines");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_sh_lines");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sh");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_sh_lines");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sh");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_sh_lines_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_sh_lines");
> - return;
> + else if (!xdr_guestfs_sh_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_sh");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SH, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.output; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_sh_lines (guestfs_h *g,
> const char *command)
> {
> struct guestfs_sh_lines_args args;
> - struct sh_lines_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_sh_lines_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_sh_lines") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.command = (char *) command;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SH_LINES,
> (xdrproc_t) xdr_guestfs_sh_lines_args, (char *) &args);
> @@ -10231,95 +9178,86 @@ char **guestfs_sh_lines (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, sh_lines_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_sh_lines");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SH_LINES, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.lines.lines_val =
> - safe_realloc (g, ctx.ret.lines.lines_val,
> - sizeof (char *) * (ctx.ret.lines.lines_len + 1));
> - ctx.ret.lines.lines_val[ctx.ret.lines.lines_len] = NULL;
> - return ctx.ret.lines.lines_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct glob_expand_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_glob_expand_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_sh_lines");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void glob_expand_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct glob_expand_ctx *ctx = (struct glob_expand_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_sh_lines");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_glob_expand");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_glob_expand");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_sh_lines");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_glob_expand");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_sh_lines");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_glob_expand_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_glob_expand");
> - return;
> + else if (!xdr_guestfs_sh_lines_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_sh_lines");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SH_LINES, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.lines.lines_val =
> + safe_realloc (g, ret.lines.lines_val,
> + sizeof (char *) * (ret.lines.lines_len + 1));
> + ret.lines.lines_val[ret.lines.lines_len] = NULL;
> + return ret.lines.lines_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_glob_expand (guestfs_h *g,
> const char *pattern)
> {
> struct guestfs_glob_expand_args args;
> - struct glob_expand_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_glob_expand_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_glob_expand") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.pattern = (char *) pattern;
> serial = guestfs__send_sync (g, GUESTFS_PROC_GLOB_EXPAND,
> (xdrproc_t) xdr_guestfs_glob_expand_args, (char *) &args);
> @@ -10328,90 +9266,85 @@ char **guestfs_glob_expand (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, glob_expand_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_glob_expand");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_GLOB_EXPAND, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.paths.paths_val =
> - safe_realloc (g, ctx.ret.paths.paths_val,
> - sizeof (char *) * (ctx.ret.paths.paths_len + 1));
> - ctx.ret.paths.paths_val[ctx.ret.paths.paths_len] = NULL;
> - return ctx.ret.paths.paths_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct scrub_device_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_glob_expand");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void scrub_device_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct scrub_device_ctx *ctx = (struct scrub_device_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_glob_expand");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_scrub_device");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_scrub_device");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_glob_expand");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_scrub_device");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_glob_expand");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_glob_expand_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_glob_expand");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_GLOB_EXPAND, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.paths.paths_val =
> + safe_realloc (g, ret.paths.paths_val,
> + sizeof (char *) * (ret.paths.paths_len + 1));
> + ret.paths.paths_val[ret.paths.paths_len] = NULL;
> + return ret.paths.paths_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_scrub_device (guestfs_h *g,
> const char *device)
> {
> struct guestfs_scrub_device_args args;
> - struct scrub_device_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_scrub_device") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SCRUB_DEVICE,
> (xdrproc_t) xdr_guestfs_scrub_device_args, (char *) &args);
> @@ -10420,85 +9353,76 @@ int guestfs_scrub_device (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, scrub_device_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_scrub_device");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SCRUB_DEVICE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct scrub_file_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_scrub_device");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void scrub_file_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct scrub_file_ctx *ctx = (struct scrub_file_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_scrub_device");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_scrub_file");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_scrub_file");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_scrub_device");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_scrub_file");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_scrub_device");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SCRUB_DEVICE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_scrub_file (guestfs_h *g,
> const char *file)
> {
> struct guestfs_scrub_file_args args;
> - struct scrub_file_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_scrub_file") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.file = (char *) file;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SCRUB_FILE,
> (xdrproc_t) xdr_guestfs_scrub_file_args, (char *) &args);
> @@ -10507,85 +9431,76 @@ int guestfs_scrub_file (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, scrub_file_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_scrub_file");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SCRUB_FILE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct scrub_freespace_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_scrub_file");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void scrub_freespace_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct scrub_freespace_ctx *ctx = (struct scrub_freespace_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_scrub_file");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_scrub_freespace");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_scrub_freespace");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_scrub_file");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_scrub_freespace");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_scrub_file");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SCRUB_FILE, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_scrub_freespace (guestfs_h *g,
> const char *dir)
> {
> struct guestfs_scrub_freespace_args args;
> - struct scrub_freespace_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_scrub_freespace") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.dir = (char *) dir;
> serial = guestfs__send_sync (g, GUESTFS_PROC_SCRUB_FREESPACE,
> (xdrproc_t) xdr_guestfs_scrub_freespace_args, (char *) &args);
> @@ -10594,90 +9509,77 @@ int guestfs_scrub_freespace (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, scrub_freespace_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_scrub_freespace");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SCRUB_FREESPACE, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mkdtemp_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_mkdtemp_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_scrub_freespace");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mkdtemp_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mkdtemp_ctx *ctx = (struct mkdtemp_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_scrub_freespace");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mkdtemp");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mkdtemp");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_scrub_freespace");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mkdtemp");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_scrub_freespace");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_mkdtemp_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_mkdtemp");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_SCRUB_FREESPACE, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char *guestfs_mkdtemp (guestfs_h *g,
> const char *template)
> {
> struct guestfs_mkdtemp_args args;
> - struct mkdtemp_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_mkdtemp_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_mkdtemp") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.template = (char *) template;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MKDTEMP,
> (xdrproc_t) xdr_guestfs_mkdtemp_args, (char *) &args);
> @@ -10686,90 +9588,81 @@ char *guestfs_mkdtemp (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mkdtemp_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mkdtemp");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKDTEMP, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.dir; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct wc_l_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_wc_l_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mkdtemp");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void wc_l_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct wc_l_ctx *ctx = (struct wc_l_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mkdtemp");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_wc_l");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_wc_l");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mkdtemp");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_wc_l");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mkdtemp");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_wc_l_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_wc_l");
> - return;
> + else if (!xdr_guestfs_mkdtemp_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_mkdtemp");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKDTEMP, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.dir; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_wc_l (guestfs_h *g,
> const char *path)
> {
> struct guestfs_wc_l_args args;
> - struct wc_l_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_wc_l_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_wc_l") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_WC_L,
> (xdrproc_t) xdr_guestfs_wc_l_args, (char *) &args);
> @@ -10778,90 +9671,81 @@ int guestfs_wc_l (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, wc_l_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_wc_l");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_WC_L, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.lines;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct wc_w_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_wc_w_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_wc_l");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void wc_w_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct wc_w_ctx *ctx = (struct wc_w_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_wc_l");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_wc_w");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_wc_w");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_wc_l");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_wc_w");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_wc_l");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_wc_w_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_wc_w");
> - return;
> + else if (!xdr_guestfs_wc_l_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_wc_l");
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_WC_L, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.lines;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_wc_w (guestfs_h *g,
> const char *path)
> {
> struct guestfs_wc_w_args args;
> - struct wc_w_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_wc_w_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_wc_w") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_WC_W,
> (xdrproc_t) xdr_guestfs_wc_w_args, (char *) &args);
> @@ -10870,90 +9754,81 @@ int guestfs_wc_w (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, wc_w_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_wc_w");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_WC_W, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.words;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct wc_c_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_wc_c_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_wc_w");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void wc_c_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct wc_c_ctx *ctx = (struct wc_c_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_wc_w");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_wc_c");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_wc_c");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_wc_w");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_wc_c");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_wc_w");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_wc_c_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_wc_c");
> - return;
> + else if (!xdr_guestfs_wc_w_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_wc_w");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_WC_W, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.words;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_wc_c (guestfs_h *g,
> const char *path)
> {
> struct guestfs_wc_c_args args;
> - struct wc_c_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_wc_c_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_wc_c") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_WC_C,
> (xdrproc_t) xdr_guestfs_wc_c_args, (char *) &args);
> @@ -10962,90 +9837,81 @@ int guestfs_wc_c (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, wc_c_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_wc_c");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_WC_C, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.chars;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct head_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_head_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_wc_c");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void head_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct head_ctx *ctx = (struct head_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_wc_c");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_head");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_head");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_wc_c");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_head");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_wc_c");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_head_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_head");
> - return;
> + else if (!xdr_guestfs_wc_c_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_wc_c");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_WC_C, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.chars;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char **guestfs_head (guestfs_h *g,
> const char *path)
> {
> struct guestfs_head_args args;
> - struct head_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_head_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_head") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_HEAD,
> (xdrproc_t) xdr_guestfs_head_args, (char *) &args);
> @@ -11054,80 +9920,72 @@ char **guestfs_head (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, head_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_head");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_HEAD, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.lines.lines_val =
> - safe_realloc (g, ctx.ret.lines.lines_val,
> - sizeof (char *) * (ctx.ret.lines.lines_len + 1));
> - ctx.ret.lines.lines_val[ctx.ret.lines.lines_len] = NULL;
> - return ctx.ret.lines.lines_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct head_n_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_head_n_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_head");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void head_n_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct head_n_ctx *ctx = (struct head_n_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_head");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_head_n");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_head_n");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_head");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_head_n");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_head");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_head_n_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_head_n");
> - return;
> + else if (!xdr_guestfs_head_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_head");
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_HEAD, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.lines.lines_val =
> + safe_realloc (g, ret.lines.lines_val,
> + sizeof (char *) * (ret.lines.lines_len + 1));
> + ret.lines.lines_val[ret.lines.lines_len] = NULL;
> + return ret.lines.lines_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_head_n (guestfs_h *g,
> @@ -11135,15 +9993,14 @@ char **guestfs_head_n (guestfs_h *g,
> const char *path)
> {
> struct guestfs_head_n_args args;
> - struct head_n_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_head_n_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_head_n") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.nrlines = nrlines;
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_HEAD_N,
> @@ -11153,95 +10010,86 @@ char **guestfs_head_n (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, head_n_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_head_n");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_HEAD_N, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.lines.lines_val =
> - safe_realloc (g, ctx.ret.lines.lines_val,
> - sizeof (char *) * (ctx.ret.lines.lines_len + 1));
> - ctx.ret.lines.lines_val[ctx.ret.lines.lines_len] = NULL;
> - return ctx.ret.lines.lines_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct tail_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_tail_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_head_n");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void tail_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct tail_ctx *ctx = (struct tail_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_head_n");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_tail");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_tail");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_head_n");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_tail");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_head_n");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_tail_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_tail");
> - return;
> + else if (!xdr_guestfs_head_n_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_head_n");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_HEAD_N, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.lines.lines_val =
> + safe_realloc (g, ret.lines.lines_val,
> + sizeof (char *) * (ret.lines.lines_len + 1));
> + ret.lines.lines_val[ret.lines.lines_len] = NULL;
> + return ret.lines.lines_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_tail (guestfs_h *g,
> const char *path)
> {
> struct guestfs_tail_args args;
> - struct tail_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_tail_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_tail") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_TAIL,
> (xdrproc_t) xdr_guestfs_tail_args, (char *) &args);
> @@ -11250,80 +10098,72 @@ char **guestfs_tail (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, tail_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_tail");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TAIL, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.lines.lines_val =
> - safe_realloc (g, ctx.ret.lines.lines_val,
> - sizeof (char *) * (ctx.ret.lines.lines_len + 1));
> - ctx.ret.lines.lines_val[ctx.ret.lines.lines_len] = NULL;
> - return ctx.ret.lines.lines_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct tail_n_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_tail_n_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_tail");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void tail_n_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct tail_n_ctx *ctx = (struct tail_n_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_tail");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_tail_n");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_tail_n");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_tail");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_tail_n");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_tail");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_tail_n_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_tail_n");
> - return;
> + else if (!xdr_guestfs_tail_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_tail");
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_TAIL, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.lines.lines_val =
> + safe_realloc (g, ret.lines.lines_val,
> + sizeof (char *) * (ret.lines.lines_len + 1));
> + ret.lines.lines_val[ret.lines.lines_len] = NULL;
> + return ret.lines.lines_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char **guestfs_tail_n (guestfs_h *g,
> @@ -11331,15 +10171,14 @@ char **guestfs_tail_n (guestfs_h *g,
> const char *path)
> {
> struct guestfs_tail_n_args args;
> - struct tail_n_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_tail_n_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_tail_n") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.nrlines = nrlines;
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_TAIL_N,
> @@ -11349,271 +10188,244 @@ char **guestfs_tail_n (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, tail_n_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_tail_n");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_TAIL_N, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.lines.lines_val =
> - safe_realloc (g, ctx.ret.lines.lines_val,
> - sizeof (char *) * (ctx.ret.lines.lines_len + 1));
> - ctx.ret.lines.lines_val[ctx.ret.lines.lines_len] = NULL;
> - return ctx.ret.lines.lines_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct df_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_df_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_tail_n");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void df_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct df_ctx *ctx = (struct df_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_tail_n");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_df");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_df");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_tail_n");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_df");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_tail_n");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_df_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_df");
> - return;
> + else if (!xdr_guestfs_tail_n_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_tail_n");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_TAIL_N, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.lines.lines_val =
> + safe_realloc (g, ret.lines.lines_val,
> + sizeof (char *) * (ret.lines.lines_len + 1));
> + ret.lines.lines_val[ret.lines.lines_len] = NULL;
> + return ret.lines.lines_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char *guestfs_df (guestfs_h *g)
> {
> - struct df_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_df_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_df") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_DF, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, df_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_df");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DF, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - guestfs_end_busy (g);
> - return ctx.ret.output; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct df_h_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_df_h_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_df");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void df_h_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct df_h_ctx *ctx = (struct df_h_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_df");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_df_h");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_df_h");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_df");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_df_h");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_df");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_df_h_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_df_h");
> - return;
> + else if (!xdr_guestfs_df_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_df");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_DF, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.output; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> char *guestfs_df_h (guestfs_h *g)
> {
> - struct df_h_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_df_h_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_df_h") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> serial = guestfs__send_sync (g, GUESTFS_PROC_DF_H, NULL, NULL);
> if (serial == -1) {
> guestfs_end_busy (g);
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, df_h_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_df_h");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DF_H, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.output; /* caller will free */
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct du_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_du_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_df_h");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void du_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct du_ctx *ctx = (struct du_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_df_h");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_du");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_du");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_df_h");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_du");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_df_h");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_du_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_du");
> - return;
> + else if (!xdr_guestfs_df_h_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_df_h");
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_DF_H, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.output; /* caller will free */
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int64_t guestfs_du (guestfs_h *g,
> const char *path)
> {
> struct guestfs_du_args args;
> - struct du_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_du_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_du") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_DU,
> (xdrproc_t) xdr_guestfs_du_args, (char *) &args);
> @@ -11622,90 +10434,81 @@ int64_t guestfs_du (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, du_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_du");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DU, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return ctx.ret.sizekb;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct initrd_list_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_initrd_list_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_du");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void initrd_list_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct initrd_list_ctx *ctx = (struct initrd_list_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_du");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_initrd_list");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_initrd_list");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_du");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_initrd_list");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_du");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_initrd_list_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_initrd_list");
> - return;
> + else if (!xdr_guestfs_du_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_du");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_DU, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.sizekb;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> char **guestfs_initrd_list (guestfs_h *g,
> const char *path)
> {
> struct guestfs_initrd_list_args args;
> - struct initrd_list_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_initrd_list_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_initrd_list") == -1) return NULL;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_INITRD_LIST,
> (xdrproc_t) xdr_guestfs_initrd_list_args, (char *) &args);
> @@ -11714,75 +10517,72 @@ char **guestfs_initrd_list (guestfs_h *g,
> return NULL;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, initrd_list_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_initrd_list");
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_INITRD_LIST, serial) == -1) {
> - guestfs_end_busy (g);
> - return NULL;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return NULL;
> - }
> -
> - guestfs_end_busy (g);
> - /* caller will free this, but we need to add a NULL entry */
> - ctx.ret.filenames.filenames_val =
> - safe_realloc (g, ctx.ret.filenames.filenames_val,
> - sizeof (char *) * (ctx.ret.filenames.filenames_len + 1));
> - ctx.ret.filenames.filenames_val[ctx.ret.filenames.filenames_len] = NULL;
> - return ctx.ret.filenames.filenames_val;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mount_loop_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_initrd_list");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> -static void mount_loop_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mount_loop_ctx *ctx = (struct mount_loop_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_initrd_list");
> + guestfs_end_busy (g);
> + return NULL;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mount_loop");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mount_loop");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_initrd_list");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mount_loop");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_initrd_list");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + else if (!xdr_guestfs_initrd_list_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_initrd_list");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_INITRD_LIST, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + /* caller will free this, but we need to add a NULL entry */
> + ret.filenames.filenames_val =
> + safe_realloc (g, ret.filenames.filenames_val,
> + sizeof (char *) * (ret.filenames.filenames_len + 1));
> + ret.filenames.filenames_val[ret.filenames.filenames_len] = NULL;
> + return ret.filenames.filenames_val;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return NULL;
> }
>
> int guestfs_mount_loop (guestfs_h *g,
> @@ -11790,15 +10590,13 @@ int guestfs_mount_loop (guestfs_h *g,
> const char *mountpoint)
> {
> struct guestfs_mount_loop_args args;
> - struct mount_loop_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mount_loop") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.file = (char *) file;
> args.mountpoint = (char *) mountpoint;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MOUNT_LOOP,
> @@ -11808,85 +10606,76 @@ int guestfs_mount_loop (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mount_loop_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mount_loop");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MOUNT_LOOP, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mkswap_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mount_loop");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mkswap_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mkswap_ctx *ctx = (struct mkswap_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mount_loop");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mkswap");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mkswap");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mount_loop");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mkswap");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mount_loop");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MOUNT_LOOP, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mkswap (guestfs_h *g,
> const char *device)
> {
> struct guestfs_mkswap_args args;
> - struct mkswap_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mkswap") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MKSWAP,
> (xdrproc_t) xdr_guestfs_mkswap_args, (char *) &args);
> @@ -11895,70 +10684,63 @@ int guestfs_mkswap (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mkswap_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mkswap");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKSWAP, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mkswap_L_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mkswap");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mkswap_L_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mkswap_L_ctx *ctx = (struct mkswap_L_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mkswap");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mkswap_L");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mkswap_L");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mkswap");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mkswap_L");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mkswap");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKSWAP, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mkswap_L (guestfs_h *g,
> @@ -11966,15 +10748,13 @@ int guestfs_mkswap_L (guestfs_h *g,
> const char *device)
> {
> struct guestfs_mkswap_L_args args;
> - struct mkswap_L_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mkswap_L") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.label = (char *) label;
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MKSWAP_L,
> @@ -11984,70 +10764,63 @@ int guestfs_mkswap_L (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mkswap_L_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mkswap_L");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKSWAP_L, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mkswap_U_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mkswap_L");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mkswap_U_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mkswap_U_ctx *ctx = (struct mkswap_U_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mkswap_L");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mkswap_U");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mkswap_U");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mkswap_L");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mkswap_U");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mkswap_L");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKSWAP_L, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mkswap_U (guestfs_h *g,
> @@ -12055,15 +10828,13 @@ int guestfs_mkswap_U (guestfs_h *g,
> const char *device)
> {
> struct guestfs_mkswap_U_args args;
> - struct mkswap_U_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mkswap_U") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.uuid = (char *) uuid;
> args.device = (char *) device;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MKSWAP_U,
> @@ -12073,70 +10844,63 @@ int guestfs_mkswap_U (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mkswap_U_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mkswap_U");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKSWAP_U, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mknod_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mkswap_U");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mknod_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mknod_ctx *ctx = (struct mknod_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mkswap_U");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mknod");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mknod");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mkswap_U");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mknod");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mkswap_U");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKSWAP_U, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mknod (guestfs_h *g,
> @@ -12146,15 +10910,13 @@ int guestfs_mknod (guestfs_h *g,
> const char *path)
> {
> struct guestfs_mknod_args args;
> - struct mknod_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mknod") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.mode = mode;
> args.devmajor = devmajor;
> args.devminor = devminor;
> @@ -12166,70 +10928,63 @@ int guestfs_mknod (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mknod_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mknod");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKNOD, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mkfifo_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mknod");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mkfifo_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mkfifo_ctx *ctx = (struct mkfifo_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mknod");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mkfifo");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mkfifo");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mknod");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mkfifo");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mknod");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKNOD, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mkfifo (guestfs_h *g,
> @@ -12237,15 +10992,13 @@ int guestfs_mkfifo (guestfs_h *g,
> const char *path)
> {
> struct guestfs_mkfifo_args args;
> - struct mkfifo_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mkfifo") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.mode = mode;
> args.path = (char *) path;
> serial = guestfs__send_sync (g, GUESTFS_PROC_MKFIFO,
> @@ -12255,70 +11008,63 @@ int guestfs_mkfifo (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mkfifo_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mkfifo");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKFIFO, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mknod_b_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mkfifo");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mknod_b_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mknod_b_ctx *ctx = (struct mknod_b_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mkfifo");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mknod_b");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mknod_b");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mkfifo");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mknod_b");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mkfifo");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKFIFO, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mknod_b (guestfs_h *g,
> @@ -12328,15 +11074,13 @@ int guestfs_mknod_b (guestfs_h *g,
> const char *path)
> {
> struct guestfs_mknod_b_args args;
> - struct mknod_b_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mknod_b") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.mode = mode;
> args.devmajor = devmajor;
> args.devminor = devminor;
> @@ -12348,70 +11092,63 @@ int guestfs_mknod_b (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mknod_b_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mknod_b");
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKNOD_B, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct mknod_c_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mknod_b");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void mknod_c_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct mknod_c_ctx *ctx = (struct mknod_c_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mknod_b");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_mknod_c");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_mknod_c");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mknod_b");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_mknod_c");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mknod_b");
> + goto recv_error;
> }
> - goto done;
> }
> - done:
> - ctx->cb_sequence = 1;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKNOD_B, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_mknod_c (guestfs_h *g,
> @@ -12421,15 +11158,13 @@ int guestfs_mknod_c (guestfs_h *g,
> const char *path)
> {
> struct guestfs_mknod_c_args args;
> - struct mknod_c_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> int serial;
>
> if (check_state (g, "guestfs_mknod_c") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.mode = mode;
> args.devmajor = devmajor;
> args.devminor = devminor;
> @@ -12441,90 +11176,77 @@ int guestfs_mknod_c (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, mknod_c_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_mknod_c");
> - guestfs_end_busy (g);
> - return -1;
> - }
> + guestfs_reply_t reply;
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKNOD_C, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> - }
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> - }
> -
> - guestfs_end_busy (g);
> - return 0;
> -}
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
>
> -struct umask_ctx {
> - /* This flag is set by the callbacks, so we know we've done
> - * the callbacks as expected, and in the right sequence.
> - * 0 = not called, 1 = reply_cb called.
> - */
> - int cb_sequence;
> - struct guestfs_message_header hdr;
> - struct guestfs_message_error err;
> - struct guestfs_umask_ret ret;
> -};
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_mknod_c");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> -static void umask_reply_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct umask_ctx *ctx = (struct umask_ctx *) data;
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_mknod_c");
> + guestfs_end_busy (g);
> + return -1;
> + }
>
> - /* This should definitely not happen. */
> - if (ctx->cb_sequence != 0) {
> - ctx->cb_sequence = 9999;
> - error (g, "%s: internal error: reply callback called twice", "guestfs_umask");
> - return;
> + break;
> }
>
> - ml->main_loop_quit (ml, g);
> -
> - if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
> - error (g, "%s: failed to parse reply header", "guestfs_umask");
> - return;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_mknod_c");
> + goto recv_error;
> }
> - if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
> - if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
> - error (g, "%s: failed to parse reply error", "guestfs_umask");
> - return;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_mknod_c");
> + goto recv_error;
> }
> - goto done;
> }
> - if (!xdr_guestfs_umask_ret (xdr, &ctx->ret)) {
> - error (g, "%s: failed to parse reply", "guestfs_umask");
> - return;
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_MKNOD_C, serial) == -1) {
> + goto recv_error;
> }
> - done:
> - ctx->cb_sequence = 1;
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return 0;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> + guestfs_end_busy (g);
> + return -1;
> }
>
> int guestfs_umask (guestfs_h *g,
> int mask)
> {
> struct guestfs_umask_args args;
> - struct umask_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> + struct guestfs_message_header hdr = {};
> + struct guestfs_message_error err = {};
> + struct guestfs_umask_ret ret = {};
> int serial;
>
> if (check_state (g, "guestfs_umask") == -1) return -1;
> guestfs_set_busy (g);
>
> - memset (&ctx, 0, sizeof ctx);
> -
> args.mask = mask;
> serial = guestfs__send_sync (g, GUESTFS_PROC_UMASK,
> (xdrproc_t) xdr_guestfs_umask_args, (char *) &args);
> @@ -12533,30 +11255,66 @@ int guestfs_umask (guestfs_h *g,
> return -1;
> }
>
> - guestfs__switch_to_receiving (g);
> - ctx.cb_sequence = 0;
> - guestfs_set_reply_callback (g, umask_reply_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> - if (ctx.cb_sequence != 1) {
> - error (g, "%s reply failed, see earlier error messages", "guestfs_umask");
> - guestfs_end_busy (g);
> - return -1;
> + guestfs_reply_t reply;
> +
> + for (;;) {
> + guestfs_get_reply (g, &reply, 1);
> +
> + if (GUESTFS_CANCEL_FLAG == reply.len) {
> + /* This message was delayed from a previous file transaction. */
> + continue;
> + }
> +
> + if (GUESTFS_LAUNCH_FLAG == reply.len) {
> + error (g, "%s reply failed, received unexpected launch message",
> + "guestfs_umask");
> + guestfs_end_busy (g);
> + return -1;
> + }
> +
> + if (0 == reply.len) {
> + error (g, "%s reply failed, see earlier error messages", "guestfs_umask");
> + guestfs_end_busy (g);
> + return -1;
> + }
> +
> + break;
> }
>
> - if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UMASK, serial) == -1) {
> - guestfs_end_busy (g);
> - return -1;
> + if (!xdr_guestfs_message_header (&reply.xdr, &hdr)) {
> + error (g, "%s: failed to parse reply header", "guestfs_umask");
> + goto recv_error;
> }
>
> - if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
> - error (g, "%s", ctx.err.error_message);
> - free (ctx.err.error_message);
> - guestfs_end_busy (g);
> - return -1;
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + if (!xdr_guestfs_message_error (&reply.xdr, &err)) {
> + error (g, "%s: failed to parse reply error", "guestfs_umask");
> + goto recv_error;
> + }
> + }
> + else if (!xdr_guestfs_umask_ret (&reply.xdr, &ret)) {
> + error (g, "%s: failed to parse reply", "guestfs_umask");
> + goto recv_error;
> + }
> + if (check_reply_header (g, &hdr, GUESTFS_PROC_UMASK, serial) == -1) {
> + goto recv_error;
> + }
> +
> + if (hdr.status == GUESTFS_STATUS_ERROR) {
> + error (g, "%s", err.error_message);
> + free (err.error_message);
> + goto recv_error;
> }
>
> + guestfs_free_reply (g, &reply);
> +
> + guestfs_end_busy (g);
> +
> + return ret.oldmask;
> +
> + recv_error:
> + guestfs_free_reply (g, &reply);
> guestfs_end_busy (g);
> - return ctx.ret.oldmask;
> + return -1;
> }
>
> diff --git a/src/guestfs.c b/src/guestfs.c
> index 2d4db66..6f4c83e 100644
> --- a/src/guestfs.c
> +++ b/src/guestfs.c
> @@ -21,6 +21,7 @@
> #define _BSD_SOURCE /* for mkdtemp, usleep */
> #define _GNU_SOURCE /* for vasprintf, GNU strerror_r, strchrnul */
>
> +#include <assert.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <stdarg.h>
> @@ -77,8 +78,10 @@
>
> static void default_error_cb (guestfs_h *g, void *data, const char *msg);>
> 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 sock_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, int watch, int fd, int events);
> +static void sock_read (guestfs_h *g);
> +static void sock_write (guestfs_h *g);
> +static int sock_update_events (guestfs_h *g);
>
> static void close_handles (void);
>
> @@ -160,6 +163,9 @@ struct guestfs_h
> int stdout_watch; /* Watches qemu stdout for log messages. */
> int sock_watch; /* Watches daemon comm socket. */
>
> + int sock_events; /* events we're listening for on the comm
> + socket */
> +
> char *tmpdir; /* Temporary directory containing socket. */
>
> char *qemu_help, *qemu_version; /* Output of qemu -help, qemu -version. */
> @@ -184,21 +190,18 @@ struct guestfs_h
> 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;
> void * log_message_cb_data;
> guestfs_subprocess_quit_cb subprocess_quit_cb;
> void * subprocess_quit_cb_data;
> - guestfs_launch_done_cb launch_done_cb;
> - void * launch_done_cb_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;
> + size_t msg_in_size, msg_in_pos, msg_in_consumed, msg_in_len;
> +
> char *msg_out;
> int msg_out_size, msg_out_pos;
>
> @@ -227,6 +230,8 @@ guestfs_create (void)
> g->stdout_watch = -1;
> g->sock_watch = -1;
>
> + g->sock_events = 0;
> +
> g->abort_cb = abort;
> g->error_cb = default_error_cb;
> g->error_cb_data = NULL;
> @@ -264,6 +269,11 @@ guestfs_create (void)
> } else
> g->memsize = 500;
>
> + /* Initialise the message receive buffer */
> + g->msg_in_size = GUESTFS_MESSAGE_MAX + sizeof (g->msg_in_len);
The size of the length word is always 4 bytes - it's defined
that way in the XDR standard.
> + g->msg_in = safe_malloc (g, g->msg_in_size);
> + g->msg_in_pos = g->msg_in_consumed = 0;
> +
> g->main_loop = guestfs_get_default_main_loop ();
>
> /* Start with large serial numbers so they are easy to spot
> @@ -289,9 +299,10 @@ guestfs_create (void)
> return g;
>
> error:
> - free (g->path);
> - free (g->qemu);
> - free (g->append);
> + if (g->msg_in) free (g->msg_in);
> + if (g->path) free (g->path);
> + if (g->qemu) free (g->qemu);
> + if (g->append) free (g->append);
This is wrong. free (NULL) is always correct, so we just need to
do:
free (g->msg_in);
etc. (without the 'if').
> free (g);
> return NULL;
> }
> @@ -1122,10 +1133,6 @@ guestfs_launch (guestfs_h *g)
>
> connected:
> /* Watch the file descriptors. */
> - free (g->msg_in);
> - g->msg_in = NULL;
> - g->msg_in_size = g->msg_in_allocated = 0;
> -
> free (g->msg_out);
> g->msg_out = NULL;
> g->msg_out_size = 0;
> @@ -1140,7 +1147,9 @@ guestfs_launch (guestfs_h *g)
> goto cleanup3;
> }
>
> - if (guestfs__switch_to_receiving (g) == -1)
> + g->sock_events = GUESTFS_HANDLE_READABLE |
> + GUESTFS_HANDLE_ERROR | GUESTFS_HANDLE_HANGUP;
> + if (sock_update_events (g) == -1)
> goto cleanup3;
>
> g->state = LAUNCHING;
> @@ -1298,20 +1307,10 @@ qemu_supports (guestfs_h *g, const char *option)
> return g->qemu_help && strstr (g->qemu_help, option) != NULL;
> }
>
> -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;
> - g->main_loop->main_loop_quit (g->main_loop, g);
> -}
> -
> int
> guestfs_wait_ready (guestfs_h *g)
> {
> - int finished = 0, r;
> + guestfs_reply_t reply = {};
>
> if (g->state == READY) return 0;
>
> @@ -1325,29 +1324,29 @@ guestfs_wait_ready (guestfs_h *g)
> return -1;
> }
>
> - g->launch_done_cb = finish_wait_ready;
> - g->launch_done_cb_data = &finished;
> - r = g->main_loop->main_loop_run (g->main_loop, g);
> - g->launch_done_cb = NULL;
> - g->launch_done_cb_data = NULL;
> -
> - if (r == -1) return -1;
> -
> - if (finished != 1) {
> - error (g, _("guestfs_wait_ready failed, see earlier error messages"));
> + guestfs_get_reply (g, &reply, 1);
> + if (0 == reply.len) {
> + error (g, _("guestfs_wait_ready: error receiving reply"));
> + return -1;
> + }
This convention for indicating errors is a little odd. Why doesn't
guestfs_get_reply return 0 / -1 ?
> + if (GUESTFS_LAUNCH_FLAG != reply.len) {
> + error (g, _("guestfs_wait_ready: received non-launch reply"));
> return -1;
> }
> + guestfs_free_reply (g, &reply);
Does this leak the reply message on the error path?
> /* This is possible in some really strange situations, such as
> * guestfsd starts up OK but then qemu immediately exits. Check for
> * it because the caller is probably expecting to be able to send
> * commands after this function returns.
> */
> - if (g->state != READY) {
> - error (g, _("qemu launched and contacted daemon, but state != READY"));
> + if (g->state != LAUNCHING) {
> + error (g, _("qemu launched and contacted daemon, but state != LAUNCHING"));
> return -1;
> }
>
> + g->state = READY;
> +
> return 0;
> }
>
> @@ -1473,7 +1472,7 @@ guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *x)
> free (x);
> }
>
> -/* We don't know if stdout_event or sock_read_event will be the
> +/* We don't know if stdout_event or sock_read will be the
> * first to receive EOF if the qemu process dies. This function
> * has the common cleanup code for both.
> */
> @@ -1551,175 +1550,218 @@ stdout_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
> g->log_message_cb (g, g->log_message_cb_data, buf, n);
> }
>
> -/* The function is called whenever we can read something on the
> - * guestfsd (daemon inside the guest) communication socket.
> - */
> -static void
> -sock_read_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
> - int watch, int fd, int events)
> +void
> +guestfs_get_reply (guestfs_h *g, guestfs_reply_t *msg,
> + unsigned char blocking)
> {
> - XDR xdr;
> - u_int32_t len;
> - int n;
> + msg->len = 0;
>
> - if (g->verbose)
> - fprintf (stderr,
> - "sock_read_event: %p g->state = %d, fd = %d, events = 0x%x\n",
> - g, g->state, fd, events);
> -
> - if (g->sock != fd) {
> - error (g, _("sock_read_event: internal error: %d != %d"), g->sock, fd);
> + /* Not in the expected state. */
> + if (g->state != BUSY && g->state != LAUNCHING) {
> + error (g, _("state %d != BUSY && g->state != LAUNCHING"), g->state);
> return;
> }
>
> - if (g->msg_in_size <= g->msg_in_allocated) {
> - g->msg_in_allocated += 4096;
> - g->msg_in = safe_realloc (g, g->msg_in, g->msg_in_allocated);
> + /* Execute the main loop until we've received at least 1 complete message */
> + for (;;) {
> + struct guestfs_main_loop *ml = guestfs_get_main_loop(g);
> +
> + size_t available = g->msg_in_pos - g->msg_in_consumed;
> +
> + if (available >= sizeof (g->msg_in_len)) {
As above, I think you mean '>= 4' here. And also some places below too.
> + xdrmem_create (&msg->xdr, g->msg_in + g->msg_in_consumed,
> + g->msg_in_pos - g->msg_in_consumed, XDR_DECODE);
> +
> + /* Read the message length */
> + if (!xdr_uint32_t (&msg->xdr, &g->msg_in_len)) {
> + error (g, _("can't decode length"));
> + xdr_destroy(&msg->xdr);
> + return;
> + }
> +
> + if (g->verbose) {
> + fprintf(stderr, "message length is %u\n", g->msg_in_len);
> + }
> +
> + /* Special cases for messages which are represented by magic message
> + * lengths */
> + if (GUESTFS_LAUNCH_FLAG == g->msg_in_len ||
> + GUESTFS_CANCEL_FLAG == g->msg_in_len) {
> + msg->len = g->msg_in_len;
> + g->msg_in_len = sizeof(g->msg_in_len);
> + break;
> + }
> +
> + else if (g->msg_in_len > GUESTFS_MESSAGE_MAX) {
> + error (g, _("message length (%u) > maximum possible size (%d)"),
> + g->msg_in_len, GUESTFS_MESSAGE_MAX);
> + /* We're doomed at this point. */
> + abort();
> + }
> +
> + /* Quit the loop if we've got a complete message */
> + else if (available >= g->msg_in_len + sizeof (g->msg_in_len)) {
> + /* Total message length includes the length header itself */
> + g->msg_in_len += sizeof (g->msg_in_len);
> + msg->len = g->msg_in_len;
> + break;
> + }
> +
> + xdr_destroy (&msg->xdr);
> + }
> +
> + if(!blocking) return;
> +
> + ml->main_loop_run (ml, g);
> }
> - n = read (g->sock, g->msg_in + g->msg_in_size,
> - g->msg_in_allocated - g->msg_in_size);
> - if (n == 0) {
> - /* Disconnected. */
> - child_cleanup (g);
> - return;
> +}
> +
> +void
> +guestfs_free_reply (guestfs_h *g, guestfs_reply_t *msg)
> +{
> + /* Check that the whole message has been consumed */
> + if (g->msg_in_len != xdr_getpos(&msg->xdr)) {
> + error (g, _("guestfs_free_reply: consumed %u bytes of %u length message"),
> + xdr_getpos(&msg->xdr), g->msg_in_len);
> }
>
> - if (n == -1) {
> - if (errno != EINTR && errno != EAGAIN)
> - perrorf (g, "read");
> - return;
> + xdr_destroy (&msg->xdr);
> +
> + g->msg_in_consumed += g->msg_in_len;
> +
> + if (g->verbose) {
> + fprintf (stderr, "guestfs_free_reply: consumed %u bytes\n",
> + g->msg_in_consumed);
> }
>
> - g->msg_in_size += n;
> + /* If there's nothing left in the buffer, reset to the beginning */
> + if (g->msg_in_consumed == g->msg_in_pos) {
> + g->msg_in_consumed = 0;
> + g->msg_in_pos = 0;
> + }
>
> - /* Have we got enough of a message to be able to process it yet? */
> - again:
> - if (g->msg_in_size < 4) return;
> + /* If we got to the end of the buffer, move to the beginning */
> + else if (g->msg_in_size == g->msg_in_pos) {
> + memmove (g->msg_in, g->msg_in + g->msg_in_consumed,
> + g->msg_in_size - g->msg_in_consumed);
> + g->msg_in_pos = g->msg_in_size - g->msg_in_consumed;
> + g->msg_in_consumed = 0;
> + }
> +
> + g->msg_in_len = 0;
>
> - xdrmem_create (&xdr, g->msg_in, g->msg_in_size, XDR_DECODE);
> - if (!xdr_uint32_t (&xdr, &len)) {
> - error (g, _("can't decode length word"));
> - goto cleanup;
> + /* If we were ignoring incoming messages, switch them back on */
> + if (!(g->sock_events & GUESTFS_HANDLE_READABLE)) {
> + g->sock_events |= GUESTFS_HANDLE_READABLE;
> + sock_update_events (g);
> }
> +}
>
> - /* Length is normally the length of the message, but when guestfsd
> - * starts up it sends a "magic" value (longer than any possible
> - * message). Check for this.
> - */
> - if (len == GUESTFS_LAUNCH_FLAG) {
> - if (g->state != LAUNCHING)
> - error (g, _("received magic signature from guestfsd, but in state %d"),
> - g->state);
> - else if (g->msg_in_size != 4)
> - error (g, _("received magic signature from guestfsd, but msg size is %d"),
> - g->msg_in_size);
> - else {
> - g->state = READY;
> - if (g->launch_done_cb)
> - g->launch_done_cb (g, g->launch_done_cb_data);
> - }
> +/* This function is called whenever an event happens on the communications
> + * socket */
> +static void
> +sock_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
> + int watch, int fd, int events)
> +{
> + if (g->verbose)
> + fprintf (stderr,
> + "sock_event: %p g->state = %d, fd = %d, events = 0x%x\n",
> + g, g->state, fd, events);
>
> - goto cleanup;
> + if (fd != g->sock) {
> + error (g, _("sock_event: received event for non-sock fd %d"), fd);
> + return;
> }
>
> - /* This can happen if a cancellation happens right at the end
> - * of us sending a FileIn parameter to the daemon. Discard. The
> - * daemon should send us an error message next.
> - */
> - if (len == GUESTFS_CANCEL_FLAG) {
> - g->msg_in_size -= 4;
> - memmove (g->msg_in, g->msg_in+4, g->msg_in_size);
> - goto again;
> + if (events & GUESTFS_HANDLE_READABLE) {
> + sock_read (g);
> }
>
> - /* If this happens, it's pretty bad and we've probably lost
> - * synchronization.
> - */
> - if (len > GUESTFS_MESSAGE_MAX) {
> - error (g, _("message length (%u) > maximum possible size (%d)"),
> - len, GUESTFS_MESSAGE_MAX);
> - goto cleanup;
> + if (events & GUESTFS_HANDLE_WRITABLE) {
> + sock_write (g);
> }
>
> - if (g->msg_in_size-4 < len) return; /* Need more of this message. */
> + if (events & (GUESTFS_HANDLE_ERROR | GUESTFS_HANDLE_HANGUP)) {
> + error (g, _("sock_event: received error on communications socket: %m"));
> + child_cleanup (g);
> + }
> +}
>
> - /* Got the full message, begin processing it. */
> -#if 0
> - if (g->verbose) {
> - int i, j;
> -
> - for (i = 0; i < g->msg_in_size; i += 16) {
> - printf ("%04x: ", i);
> - for (j = i; j < MIN (i+16, g->msg_in_size); ++j)
> - printf ("%02x ", (unsigned char) g->msg_in[j]);
> - for (; j < i+16; ++j)
> - printf (" ");
> - printf ("|");
> - for (j = i; j < MIN (i+16, g->msg_in_size); ++j)
> - if (isprint (g->msg_in[j]))
> - printf ("%c", g->msg_in[j]);
> - else
> - printf (".");
> - for (; j < i+16; ++j)
> - printf (" ");
> - printf ("|\n");
> +/* This function reads as much data as is available from the guestfsd
> + * communication socket.
> + */
> +static void
> +sock_read (guestfs_h *g)
> +{
> + guestfs_main_loop *ml = guestfs_get_main_loop (g);
> +
> + size_t available = g->msg_in_size - g->msg_in_pos;
> +
> + if (g->verbose)
> + fprintf (stderr, "sock_read: before g->msg_in_pos = %d "
> + "available = %d\n", g->msg_in_pos, available);
> +
> + while (available > 0) {
> + ssize_t in;
> + while((in = read(g->sock, g->msg_in + g->msg_in_pos, available)) < 0) {
> + /* Retry if interrupted */
> + if(EINTR == errno) continue;
> +
> + if(EWOULDBLOCK != errno) {
> + error (g, _("sock_read_data: error reading from socket: %s"),
> + strerror(errno));
> + }
> +
> + break;
> + }
> +
> + /* Cleanup if we got an EOF */
> + if (0 == in) {
> + child_cleanup(g);
> + return;
> + }
> +
> + /* We got data */
> + else if (in > 0) {
> + available -= in;
> + g->msg_in_pos += in;
> + }
> +
> + /* There was some error */
> + else {
> + break;
> }
> }
> -#endif
>
> - /* Not in the expected state. */
> - if (g->state != BUSY)
> - error (g, _("state %d != BUSY"), g->state);
> -
> - /* Push the message up to the higher layer. */
> - if (g->reply_cb)
> - g->reply_cb (g, g->reply_cb_data, &xdr);
> - else
> - /* This message (probably) should never be printed. */
> - fprintf (stderr, "libguesfs: sock_read_event: !!! dropped message !!!\n");
> -
> - g->msg_in_size -= len + 4;
> - memmove (g->msg_in, g->msg_in+len+4, g->msg_in_size);
> - if (g->msg_in_size > 0) goto again;
> -
> - cleanup:
> - /* Free the message buffer if it's grown excessively large. */
> - if (g->msg_in_allocated > 65536) {
> - free (g->msg_in);
> - g->msg_in = NULL;
> - g->msg_in_size = g->msg_in_allocated = 0;
> - } else
> - g->msg_in_size = 0;
> + if (g->verbose)
> + fprintf (stderr, "sock_read: after g->msg_in_pos = %d "
> + "available = %d\n", g->msg_in_pos, available);
>
> - xdr_destroy (&xdr);
> + /* Ignore further read events if we've filled the buffer */
> + if (0 == available) {
> + g->sock_events &= ~GUESTFS_HANDLE_READABLE;
> + sock_update_events (g);
> + }
> +
> + /* Exit the main loop to give the caller a chance to pick up the message */
> + ml->main_loop_quit (ml, g);
> }
>
> /* The function is called whenever we can write something on the
> * guestfsd (daemon inside the guest) communication socket.
> */
> static void
> -sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
> - int watch, int fd, int events)
> +sock_write (guestfs_h *g)
> {
> int n, err;
>
> - if (g->verbose)
> - fprintf (stderr,
> - "sock_write_event: %p g->state = %d, fd = %d, events = 0x%x\n",
> - g, g->state, fd, events);
> -
> - if (g->sock != fd) {
> - error (g, _("sock_write_event: internal error: %d != %d"), g->sock, fd);
> - return;
> - }
> -
> if (g->state != BUSY) {
> - error (g, _("sock_write_event: state %d != BUSY"), g->state);
> + error (g, _("sock_write: state %d != BUSY"), g->state);
> return;
> }
>
> if (g->verbose)
> - fprintf (stderr, "sock_write_event: writing %d bytes ...\n",
> + fprintf (stderr, "sock_write: writing %d bytes ...\n",
> g->msg_out_size - g->msg_out_pos);
>
> n = write (g->sock, g->msg_out + g->msg_out_pos,
> @@ -1734,7 +1776,7 @@ sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
> }
>
> if (g->verbose)
> - fprintf (stderr, "sock_write_event: wrote %d bytes\n", n);
> + fprintf (stderr, "sock_write: wrote %d bytes\n", n);
>
> g->msg_out_pos += n;
>
> @@ -1743,7 +1785,7 @@ sock_write_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data,
> return;
>
> if (g->verbose)
> - fprintf (stderr, "sock_write_event: done writing, calling send_cb\n");
> + fprintf (stderr, "sock_write: done writing, calling send_cb\n");
>
> free (g->msg_out);
> g->msg_out = NULL;
> @@ -1763,14 +1805,6 @@ guestfs_set_send_callback (guestfs_h *g,
> }
>
> void
> -guestfs_set_reply_callback (guestfs_h *g,
> - guestfs_reply_cb cb, void *opaque)
> -{
> - g->reply_cb = cb;
> - g->reply_cb_data = opaque;
> -}
> -
> -void
> guestfs_set_log_message_callback (guestfs_h *g,
> guestfs_log_message_cb cb, void *opaque)
> {
> @@ -1786,14 +1820,6 @@ guestfs_set_subprocess_quit_callback (guestfs_h *g,
> g->subprocess_quit_cb_data = opaque;
> }
>
> -void
> -guestfs_set_launch_done_callback (guestfs_h *g,
> - guestfs_launch_done_cb cb, void *opaque)
> -{
> - g->launch_done_cb = cb;
> - g->launch_done_cb_data = opaque;
> -}
> -
> /* Access to the handle's main loop and the default main loop. */
> void
> guestfs_set_main_loop (guestfs_h *g, guestfs_main_loop *main_loop)
> @@ -1813,35 +1839,15 @@ guestfs_get_default_main_loop (void)
> return (guestfs_main_loop *) &default_main_loop;
> }
>
> -/* Change the daemon socket handler so that we are now writing.
> - * This sets the handle to sock_write_event.
> +/* Update the events which will cause the daemon socket callback to be called.
> */
> -int
> -guestfs__switch_to_sending (guestfs_h *g)
> +static int
> +sock_update_events (guestfs_h *g)
> {
> - if (g->sock_watch >= 0) {
> - if (g->main_loop->remove_handle (g->main_loop, g, g->sock_watch) == -1) {
> - error (g, _("remove_handle failed"));
> - g->sock_watch = -1;
> - return -1;
> - }
> - }
> -
> - g->sock_watch =
> - g->main_loop->add_handle (g->main_loop, g, g->sock,
> - GUESTFS_HANDLE_WRITABLE,
> - sock_write_event, NULL);
> - if (g->sock_watch == -1) {
> - error (g, _("add_handle failed"));
> - return -1;
> + if(g->verbose) {
> + fprintf(stderr, "updating socket events to %d\n", g->sock_events);
> }
>
> - return 0;
> -}
> -
> -int
> -guestfs__switch_to_receiving (guestfs_h *g)
> -{
> if (g->sock_watch >= 0) {
> if (g->main_loop->remove_handle (g->main_loop, g, g->sock_watch) == -1) {
> error (g, _("remove_handle failed"));
> @@ -1852,8 +1858,8 @@ guestfs__switch_to_receiving (guestfs_h *g)
>
> g->sock_watch =
> g->main_loop->add_handle (g->main_loop, g, g->sock,
> - GUESTFS_HANDLE_READABLE,
> - sock_read_event, NULL);
> + g->sock_events,
> + sock_event, NULL);
> if (g->sock_watch == -1) {
> error (g, _("add_handle failed"));
> return -1;
> @@ -1945,7 +1951,9 @@ guestfs__send_sync (guestfs_h *g, int proc_nr,
> xdrmem_create (&xdr, g->msg_out, 4, XDR_ENCODE);
> xdr_uint32_t (&xdr, &len);
>
> - if (guestfs__switch_to_sending (g) == -1)
> + /* Respond to writable events */
> + g->sock_events |= GUESTFS_HANDLE_WRITABLE;
> + if (sock_update_events (g) == -1)
> goto cleanup1;
>
> sent = 0;
> @@ -1957,6 +1965,13 @@ guestfs__send_sync (guestfs_h *g, int proc_nr,
> goto cleanup1;
> }
>
> + /* No longer interested in writable events */
> + g->sock_events &= ~(GUESTFS_HANDLE_WRITABLE);
> + if (sock_update_events (g) == -1) {
> + error (g, _("guestfs__send_sync: "
> + "failed to remove socket writable callback\n"));
> + }
> +
> return serial;
>
> cleanup1:
> @@ -2056,8 +2071,6 @@ send_file_complete_sync (guestfs_h *g)
> /* Send a chunk, cancellation or end of file, synchronously (ie. wait
> * for it to go).
> */
> -static int check_for_daemon_cancellation (guestfs_h *g);
> -
> static int
> send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen)
> {
> @@ -2067,6 +2080,8 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen)
> XDR xdr;
> guestfs_main_loop *ml = guestfs_get_main_loop (g);
>
> + guestfs_reply_t cancellation = {};
> +
> if (g->state != BUSY) {
> error (g, _("send_file_chunk_sync: state %d != READY"), g->state);
> return -1;
> @@ -2081,11 +2096,15 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen)
> }
>
> /* Did the daemon send a cancellation message? */
> - if (check_for_daemon_cancellation (g)) {
> + guestfs_get_reply (g, &cancellation, 0);
> + if (GUESTFS_CANCEL_FLAG == cancellation.len) {
> if (g->verbose)
> fprintf (stderr, "got daemon cancellation\n");
> return -2;
> }
> + if (0 != cancellation.len) {
> + guestfs_free_reply (g, &cancellation);
> + }
>
> /* Allocate the chunk buffer. Don't use the stack to avoid
> * excessive stack usage and unnecessary copies.
> @@ -2116,7 +2135,9 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen)
> xdrmem_create (&xdr, g->msg_out, 4, XDR_ENCODE);
> xdr_uint32_t (&xdr, &len);
>
> - if (guestfs__switch_to_sending (g) == -1)
> + /* Respond to socket writable events */
> + g->sock_events |= GUESTFS_HANDLE_WRITABLE;
> + if (sock_update_events (g) == -1)
> goto cleanup1;
>
> sent = 0;
> @@ -2128,6 +2149,12 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen)
> goto cleanup1;
> }
>
> + g->sock_events &= ~(GUESTFS_HANDLE_WRITABLE);
> + if (sock_update_events (g) == -1) {
> + error (g, _("send_file_chunk_sync: "
> + "failed to remove socket writable callback\n"));
> + }
> +
> return 0;
>
> cleanup1:
> @@ -2137,52 +2164,6 @@ send_file_chunk_sync (guestfs_h *g, int cancel, const char *buf, size_t buflen)
> return -1;
> }
>
> -/* At this point we are sending FileIn file(s) to the guest, and not
> - * expecting to read anything, so if we do read anything, it must be
> - * a cancellation message. This checks for this case without blocking.
> - */
> -static int
> -check_for_daemon_cancellation (guestfs_h *g)
> -{
> - fd_set rset;
> - struct timeval tv;
> - int r;
> - char buf[4];
> - uint32_t flag;
> - XDR xdr;
> -
> - FD_ZERO (&rset);
> - FD_SET (g->sock, &rset);
> - tv.tv_sec = 0;
> - tv.tv_usec = 0;
> - r = select (g->sock+1, &rset, NULL, NULL, &tv);
> - if (r == -1) {
> - perrorf (g, "select");
> - return 0;
> - }
> - if (r == 0)
> - return 0;
> -
> - /* Read the message from the daemon. */
> - r = xread (g->sock, buf, sizeof buf);
> - if (r == -1) {
> - perrorf (g, "read");
> - return 0;
> - }
> -
> - xdrmem_create (&xdr, buf, sizeof buf, XDR_DECODE);
> - xdr_uint32_t (&xdr, &flag);
> - xdr_destroy (&xdr);
> -
> - if (flag != GUESTFS_CANCEL_FLAG) {
> - error (g, _("check_for_daemon_cancellation: read 0x%x from daemon, expected 0x%x\n"),
> - flag, GUESTFS_CANCEL_FLAG);
> - return 0;
> - }
> -
> - return 1;
> -}
> -
> /* Synchronously receive a file. */
>
> /* Returns -1 = error, 0 = EOF, 1 = more data */
> @@ -2194,6 +2175,7 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename)
> void *buf;
> int fd, r;
> size_t len;
> + size_t total_bytes = 0, total_receives = 0;
>
> fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
> if (fd == -1) {
> @@ -2203,6 +2185,11 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename)
>
> /* Receive the file in chunked encoding. */
> while ((r = receive_file_data_sync (g, &buf, &len)) >= 0) {
> + if (g->verbose) {
> + fprintf(stderr, "guestfs__receive_file_sync: "
> + "writing %zi bytes to %s\n", len, filename);
> + }
> +
> if (xwrite (fd, buf, len) == -1) {
> perrorf (g, "%s: write", filename);
> free (buf);
> @@ -2210,6 +2197,9 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename)
> }
> free (buf);
> if (r == 0) break; /* End of file. */
> +
> + total_bytes += len;
> + total_receives++;
> }
>
> if (r == -1) {
> @@ -2222,6 +2212,12 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename)
> return -1;
> }
>
> + if (g->verbose) {
> + fprintf(stderr, "guestfs__receive_file_sync: "
> + "wrote %zi bytes in %zi calls to %s\n",
> + total_bytes, total_receives, filename);
> + }
> +
> return 0;
>
> cancel: ;
> @@ -2247,117 +2243,75 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename)
> return -1;
> }
>
> -/* Note that the reply callback can be called multiple times before
> - * the main loop quits and we get back to the synchronous code. So
> - * we have to be prepared to save multiple chunks on a list here.
> - */
> -struct receive_file_ctx {
> - int count; /* 0 if receive_file_cb not called, or
> - * else count number of chunks.
> - */
> - guestfs_chunk *chunks; /* Array of chunks. */
> -};
> -
> -static void
> -free_chunks (struct receive_file_ctx *ctx)
> -{
> - int i;
> -
> - for (i = 0; i < ctx->count; ++i)
> - free (ctx->chunks[i].data.data_val);
> -
> - free (ctx->chunks);
> -}
> -
> -static void
> -receive_file_cb (guestfs_h *g, void *data, XDR *xdr)
> -{
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - struct receive_file_ctx *ctx = (struct receive_file_ctx *) data;
> - guestfs_chunk chunk;
> -
> - if (ctx->count == -1) /* Parse error occurred previously. */
> - return;
> -
> - ml->main_loop_quit (ml, g);
> -
> - memset (&chunk, 0, sizeof chunk);
> -
> - if (!xdr_guestfs_chunk (xdr, &chunk)) {
> - error (g, _("failed to parse file chunk"));
> - free_chunks (ctx);
> - ctx->chunks = NULL;
> - ctx->count = -1;
> - return;
> - }
> -
> - /* Copy the chunk to the list. */
> - ctx->chunks = safe_realloc (g, ctx->chunks,
> - sizeof (guestfs_chunk) * (ctx->count+1));
> - ctx->chunks[ctx->count] = chunk;
> - ctx->count++;
> -}
> -
> /* Receive a chunk of file data. */
> /* Returns -1 = error, 0 = EOF, 1 = more data */
> static int
> -receive_file_data_sync (guestfs_h *g, void **buf, size_t *len_r)
> +receive_file_data_sync (guestfs_h *g, void **buf, size_t *len)
> {
> - struct receive_file_ctx ctx;
> - guestfs_main_loop *ml = guestfs_get_main_loop (g);
> - int i;
> - size_t len;
> + unsigned char block = 1;
>
> - ctx.count = 0;
> - ctx.chunks = NULL;
> + /* Accumulate data in this buffer. */
> + if (buf) *buf = NULL;
> + if (len) *len = 0;
>
> - guestfs_set_reply_callback (g, receive_file_cb, &ctx);
> - (void) ml->main_loop_run (ml, g);
> - guestfs_set_reply_callback (g, NULL, NULL);
> + /* Buffer chunks until one of:
> + * There are no more immediately available
> + * The buffer got too big
> + * We got the last chunk
> + */
> + for(;;) {
> + guestfs_reply_t reply;
> + guestfs_chunk chunk;
> +
> + /* Get a reply message if there's one available */
> + guestfs_get_reply (g, &reply, block);
> +
> + /* No more replies available right now */
> + if (0 == reply.len) {
> + /* We should have waited until we got at least 1 */
> + if (NULL == *buf) {
> + error (g, _("receive_file_data: error receiving chunk"));
> + guestfs_free_reply (g, &reply);
> + return -1;
> + }
>
> - if (ctx.count == 0) {
> - error (g, _("receive_file_data_sync: reply callback not called\n"));
> - return -1;
> - }
> + break;
> + }
>
> - if (ctx.count == -1) {
> - error (g, _("receive_file_data_sync: parse error in reply callback\n"));
> - /* callback already freed the chunks */
> - return -1;
> - }
> + if (g->verbose)
> + fprintf (stderr, "receive_file_data_sync: got chunk\n");
> +
> + memset (&chunk, 0, sizeof (chunk));
>
> - if (g->verbose)
> - fprintf (stderr, "receive_file_data_sync: got %d chunks\n", ctx.count);
> -
> - /* Process each chunk in the list. */
> - if (buf) *buf = NULL; /* Accumulate data in this buffer. */
> - len = 0;
> -
> - for (i = 0; i < ctx.count; ++i) {
> - if (ctx.chunks[i].cancel) {
> - error (g, _("file receive cancelled by daemon"));
> - free_chunks (&ctx);
> - if (buf) free (*buf);
> - if (len_r) *len_r = 0;
> + if (!xdr_guestfs_chunk (&reply.xdr, &chunk)) {
> + error (g, _("receive_file_data_sync: failed to parse file chunk"));
> + guestfs_free_reply (g, &reply);
> return -1;
> }
>
> - if (ctx.chunks[i].data.data_len == 0) { /* end of transfer */
> - free_chunks (&ctx);
> - if (len_r) *len_r = len;
> + /* Copy the chunk into the output buffer */
> + if (len && buf) {
> + *buf = safe_realloc (g, *buf, *len + chunk.data.data_len);
> + memcpy (*buf + *len, chunk.data.data_val, chunk.data.data_len);
> + *len += chunk.data.data_len;
> + }
> +
> + guestfs_free_reply (g, &reply);
> +
> + /* Received the last chunk */
> + if (0 == chunk.data.data_len) {
> return 0;
> }
>
> - if (buf) {
> - *buf = safe_realloc (g, *buf, len + ctx.chunks[i].data.data_len);
> - memcpy (*buf+len, ctx.chunks[i].data.data_val,
> - ctx.chunks[i].data.data_len);
> + /* Return early if the the output buffer length is bigger than some
> + * arbitrary size. Note that the output buffer may exceed this size. */
> + if (len && *len > 1024 * 1024) {
> + break;
> }
> - len += ctx.chunks[i].data.data_len;
> +
> + block = 0;
> }
>
> - if (len_r) *len_r = len;
> - free_chunks (&ctx);
> return 1;
> }
The way git has formatted this patch makes it really hard to
follow what has changed ...
> diff --git a/src/guestfs.h b/src/guestfs.h
> index b5ed0f7..018183d 100644
> --- a/src/guestfs.h
> +++ b/src/guestfs.h
> @@ -63,13 +63,10 @@ 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);
> -extern void guestfs_set_launch_done_callback (guestfs_h *g, guestfs_launch_done_cb cb, void *opaque);
>
> extern void guestfs_error (guestfs_h *g, const char *fs, ...)
> __attribute__((format (printf,2,3)));
> @@ -80,8 +77,14 @@ extern void *guestfs_safe_realloc (guestfs_h *g, void *ptr, int nbytes);
> extern char *guestfs_safe_strdup (guestfs_h *g, const char *str);
> extern void *guestfs_safe_memdup (guestfs_h *g, void *ptr, size_t size);
>
> -extern int guestfs__switch_to_sending (guestfs_h *g);
> -extern int guestfs__switch_to_receiving (guestfs_h *g);
> +typedef struct {
> + u_int32_t len;
> + XDR xdr;
> +} guestfs_reply_t;
> +
> +extern void guestfs_get_reply (guestfs_h *g, guestfs_reply_t *msg,
> + unsigned char blocking);
> +extern void guestfs_free_reply (guestfs_h *g, guestfs_reply_t *msg);
>
> /* These *_sync calls wait until the action is performed, using the
> * main loop. We should implement asynchronous versions too.
Rich.
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
More information about the Fedora-virt
mailing list