X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fguestfs-actions.c;h=94a08629698734b9a2d2b7dbb32d22f0186c854f;hp=f36fcf06d9a0ad31bdf790f4d44a138c50c857f0;hb=128f822e16bb96677c75b88125e18f48d7ccedaf;hpb=4211c7a258debd236017a19c70965bc1b3658edb diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index f36fcf0..94a0862 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -9024,7 +9024,7 @@ static void sfdisk_N_reply_cb (guestfs_h *g, void *data, XDR *xdr) int guestfs_sfdisk_N (guestfs_h *g, const char *device, - int n, + int partnum, int cyls, int heads, int sectors, @@ -9041,7 +9041,7 @@ int guestfs_sfdisk_N (guestfs_h *g, memset (&ctx, 0, sizeof ctx); args.device = (char *) device; - args.n = n; + args.partnum = partnum; args.cyls = cyls; args.heads = heads; args.sectors = sectors; @@ -10263,3 +10263,1575 @@ char **guestfs_sh_lines (guestfs_h *g, return ctx.ret.lines.lines_val; } +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_glob_expand_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_glob_expand"); + return; + } + done: + ctx->cb_sequence = 1; +} + +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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + done: + ctx->cb_sequence = 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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + done: + ctx->cb_sequence = 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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_mkdtemp_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_mkdtemp"); + return; + } + done: + ctx->cb_sequence = 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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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.dir; /* caller will free */ +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_wc_l_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_wc_l"); + return; + } + done: + ctx->cb_sequence = 1; +} + +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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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.lines; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_wc_w_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_wc_w"); + return; + } + done: + ctx->cb_sequence = 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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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.words; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_wc_c_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_wc_c"); + return; + } + done: + ctx->cb_sequence = 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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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.chars; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_head_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_head"); + return; + } + done: + ctx->cb_sequence = 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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_HEAD, 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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_head_n_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_head_n"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char **guestfs_head_n (guestfs_h *g, + int nrlines, + const char *path) +{ + struct guestfs_head_n_args args; + struct head_n_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + 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, + (xdrproc_t) xdr_guestfs_head_n_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_tail_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_tail"); + return; + } + done: + ctx->cb_sequence = 1; +} + +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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_tail_n_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_tail_n"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char **guestfs_tail_n (guestfs_h *g, + int nrlines, + const char *path) +{ + struct guestfs_tail_n_args args; + struct tail_n_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + 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, + (xdrproc_t) xdr_guestfs_tail_n_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_df_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_df"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_df (guestfs_h *g) +{ + struct df_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + 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; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DF, 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; + } + + guestfs_end_busy (g); + return ctx.ret.output; /* caller will free */ +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_df_h_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_df_h"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_df_h (guestfs_h *g) +{ + struct df_h_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + 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; + } + + 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 */ +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_du_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_du"); + return; + } + done: + ctx->cb_sequence = 1; +} + +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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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.sizekb; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + if (!xdr_guestfs_initrd_list_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_initrd_list"); + return; + } + done: + ctx->cb_sequence = 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); + 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); + if (serial == -1) { + guestfs_end_busy (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; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_INITRD_LIST, 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; + } + + 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; +} + +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; +}; + +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; + + /* 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; + } + + 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 (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; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_mount_loop (guestfs_h *g, + const char *file, + const char *mountpoint) +{ + struct guestfs_mount_loop_args args; + struct mount_loop_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + 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, + (xdrproc_t) xdr_guestfs_mount_loop_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (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; + } + + 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; +} +