X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fgenerator.ml;h=cf5db8764c078aa4f93e0fbc8ffe90a58fa79933;hb=749708a7ec8930c34605ec58c18fefe0ed8e7981;hp=c0a47404b687217117f833a8083b7093075e4f6f;hpb=a5f68bd57d887c8c8818dbb92a9f8b7643f67827;p=libguestfs.git diff --git a/src/generator.ml b/src/generator.ml index c0a4740..cf5db87 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -98,6 +98,16 @@ and argt = | StringList of string(* list of strings (each string cannot be NULL) *) | Bool of string (* boolean *) | Int of string (* int (smallish ints, signed, <= 31 bits) *) + (* These are treated as filenames (simple string parameters) in + * the C API and bindings. But in the RPC protocol, we transfer + * the actual file content up to or down from the daemon. + * FileIn: local machine -> daemon (in request) + * FileOut: daemon -> local machine (in reply) + * In guestfish (only), the special name "-" means read from + * stdin or write to stdout. + *) + | FileIn of string + | FileOut of string type flags = | ProtocolLimitWarning (* display warning about protocol size limits *) @@ -324,7 +334,52 @@ C is defined and set to C<1>."); [], "get verbose mode", "\ -This returns the verbose messages flag.") +This returns the verbose messages flag."); + + ("is_ready", (RBool "ready", []), -1, [], + [], + "is ready to accept commands", + "\ +This returns true iff this handle is ready to accept commands +(in the C state). + +For more information on states, see L."); + + ("is_config", (RBool "config", []), -1, [], + [], + "is in configuration state", + "\ +This returns true iff this handle is being configured +(in the C state). + +For more information on states, see L."); + + ("is_launching", (RBool "launching", []), -1, [], + [], + "is launching subprocess", + "\ +This returns true iff this handle is launching the subprocess +(in the C state). + +For more information on states, see L."); + + ("is_busy", (RBool "busy", []), -1, [], + [], + "is busy processing a command", + "\ +This returns true iff this handle is busy processing a command +(in the C state). + +For more information on states, see L."); + + ("get_state", (RInt "state", []), -1, [], + [], + "get the current state", + "\ +This returns the current state as an opaque integer. This is +only useful for printing debug and internal error messages. + +For more information on states, see L."); ] let daemon_functions = [ @@ -384,7 +439,7 @@ Return the contents of the file named C. Note that this function cannot correctly handle binary files (specifically, files containing C<\\0> character which is treated -as end of string). For those you need to use the C +as end of string). For those you need to use the C function which has a more complex interface."); ("ll", (RString "listing", [String "directory"]), 5, [], @@ -1198,6 +1253,28 @@ Reread the partition table on C. This uses the L command."); + ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [], + [], + "upload a file from the local machine", + "\ +Upload local file C to C on the +filesystem. + +C can also be a named pipe. + +See also C."); + + ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [], + [], + "download a file to the local machine", + "\ +Download file C and save it as C +on the local machine. + +C can also be a named pipe. + +See also C, C."); + ] let all_functions = non_daemon_functions @ daemon_functions @@ -1410,7 +1487,8 @@ let mapi f xs = loop 0 xs let name_of_argt = function - | String n | OptString n | StringList n | Bool n | Int n -> n + | String n | OptString n | StringList n | Bool n | Int n + | FileIn n | FileOut n -> n let seq_of_test = function | TestRun s | TestOutput (s, _) | TestOutputList (s, _) @@ -1765,6 +1843,7 @@ and generate_xdr () = | StringList n -> pr " str %s<>;\n" n | Bool n -> pr " bool %s;\n" n | Int n -> pr " int %s;\n" n + | FileIn _ | FileOut _ -> () ) args; pr "};\n\n" ); @@ -1830,7 +1909,7 @@ and generate_xdr () = fun (shortname, _, proc_nr, _, _, _, _) -> pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr ) daemon_functions; - pr " GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *) + pr " GUESTFS_PROC_NR_PROCS\n"; pr "};\n"; pr "\n"; @@ -1861,9 +1940,22 @@ enum guestfs_message_status { const GUESTFS_ERROR_LEN = 256; struct guestfs_message_error { - string error; /* error message */ + string error_message; }; +/* For normal requests and replies (not involving any FileIn or + * FileOut parameters), the protocol is: + * + * For requests: + * total length (header + args, but not including length word itself) + * header + * guestfs_foo_args struct + * For replies: + * total length (as above) + * header + * guestfs_foo_ret struct + */ + struct guestfs_message_header { unsigned prog; /* GUESTFS_PROGRAM */ unsigned vers; /* GUESTFS_PROTOCOL_VERSION */ @@ -1872,6 +1964,31 @@ struct guestfs_message_header { unsigned serial; /* message serial number */ guestfs_message_status status; }; + +/* Chunked encoding used to transfer files, for FileIn and FileOut + * parameters. + * + * For requests which have >= 1 FileIn parameter: + * length of header + args (but not length word itself, and not chunks) + * header + * guestfs_foo_args struct + * sequence of chunks for FileIn param #0 + * sequence of chunks for FileIn param #1 etc + * + * For replies which have >= 1 FileOut parameter: + * length of header + ret (but not length word itself, and not chunks) + * header + * guestfs_foo_ret struct + * sequence of chunks for FileOut param #0 + * sequence of chunks for FileOut param #1 etc + */ +const GUESTFS_MAX_CHUNK_SIZE = 8192; + +struct guestfs_chunk { + int cancel; /* if non-zero, transfer is cancelled */ + /* data size is 0 bytes if the transfer has finished successfully */ + opaque data; +}; " (* Generate the guestfs-structs.h file. *) @@ -1948,14 +2065,88 @@ and generate_actions_h () = and generate_client_actions () = generate_header CStyle LGPLv2; + pr "\ +#include +#include + +#include \"guestfs.h\" +#include \"guestfs_protocol.h\" + +#define error guestfs_error +#define perrorf guestfs_perrorf +#define safe_malloc guestfs_safe_malloc +#define safe_realloc guestfs_safe_realloc +#define safe_strdup guestfs_safe_strdup +#define safe_memdup guestfs_safe_memdup + +/* Check the return message from a call for validity. */ +static int +check_reply_header (guestfs_h *g, + const struct guestfs_message_header *hdr, + int proc_nr, int serial) +{ + if (hdr->prog != GUESTFS_PROGRAM) { + error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM); + return -1; + } + if (hdr->vers != GUESTFS_PROTOCOL_VERSION) { + error (g, \"wrong protocol version (%%d/%%d)\", + hdr->vers, GUESTFS_PROTOCOL_VERSION); + return -1; + } + if (hdr->direction != GUESTFS_DIRECTION_REPLY) { + error (g, \"unexpected message direction (%%d/%%d)\", + hdr->direction, GUESTFS_DIRECTION_REPLY); + return -1; + } + if (hdr->proc != proc_nr) { + error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr); + return -1; + } + if (hdr->serial != serial) { + error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial); + return -1; + } + + return 0; +} + +/* Check we are in the right state to run a high-level action. */ +static int +check_state (guestfs_h *g, const char *caller) +{ + if (!guestfs_is_ready (g)) { + if (guestfs_is_config (g)) + error (g, \"%%s: call launch() before using this function\", + caller); + else if (guestfs_is_launching (g)) + error (g, \"%%s: call wait_ready() before using this function\", + caller); + else + error (g, \"%%s called from the wrong state, %%d != READY\", + caller, guestfs_get_state (g)); + return -1; + } + return 0; +} + +"; + (* Client-side stubs for each function. *) List.iter ( fun (shortname, style, _, _, _, _, _) -> let name = "guestfs_" ^ shortname in - (* Generate the return value struct. *) - pr "struct %s_rv {\n" shortname; - pr " int cb_done; /* flag to indicate callback was called */\n"; + (* Generate the 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 = send called,\n"; + pr " * 1001 = reply 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 @@ -1970,20 +2161,25 @@ and generate_client_actions () = | RHashtable _ -> pr " struct %s_ret ret;\n" name ); - pr "};\n\n"; + pr "};\n"; + pr "\n"; - (* Generate the callback function. *) - pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname; + (* Generate the reply callback function. *) + pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname; pr "{\n"; - pr " struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname; + pr " 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 " ml->main_loop_quit (ml, g);\n"; pr "\n"; - pr " if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n"; - pr " error (g, \"%s: failed to parse reply header\");\n" name; + 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 (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n"; - pr " if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n"; - pr " error (g, \"%s: failed to parse reply error\");\n" name; + 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"; @@ -1999,15 +2195,14 @@ and generate_client_actions () = | RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _ | RHashtable _ -> - pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name; - pr " error (g, \"%s: failed to parse reply\");\n" name; + 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 " rv->cb_done = 1;\n"; - pr " main_loop.main_loop_quit (g);\n"; + pr " ctx->cb_sequence = 1001;\n"; pr "}\n\n"; (* Generate the action stub. *) @@ -2032,22 +2227,19 @@ and generate_client_actions () = | _ -> pr " struct %s_args args;\n" name ); - pr " struct %s_rv rv;\n" shortname; + pr " struct %s_ctx ctx;\n" shortname; + pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n"; pr " int serial;\n"; pr "\n"; - pr " if (g->state != READY) {\n"; - pr " error (g, \"%s called from the wrong state, %%d != READY\",\n" - name; - pr " g->state);\n"; - pr " return %s;\n" error_code; - pr " }\n"; + pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code; pr "\n"; - pr " memset (&rv, 0, sizeof rv);\n"; + pr " memset (&ctx, 0, sizeof ctx);\n"; pr "\n"; + (* Send the main header and arguments. *) (match snd style with | [] -> - pr " serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n" + pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n" (String.uppercase shortname) | args -> List.iter ( @@ -2063,62 +2255,83 @@ and generate_client_actions () = pr " args.%s = %s;\n" n n | Int n -> pr " args.%s = %s;\n" n n + | FileIn _ | FileOut _ -> () ) args; - pr " serial = dispatch (g, GUESTFS_PROC_%s,\n" + pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n" (String.uppercase shortname); - pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n" + pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n" name; ); pr " if (serial == -1)\n"; pr " return %s;\n" error_code; pr "\n"; - pr " rv.cb_done = 0;\n"; - pr " g->reply_cb_internal = %s_cb;\n" shortname; - pr " g->reply_cb_internal_data = &rv;\n"; - pr " main_loop.main_loop_run (g);\n"; - pr " g->reply_cb_internal = NULL;\n"; - pr " g->reply_cb_internal_data = NULL;\n"; - pr " if (!rv.cb_done) {\n"; - pr " error (g, \"%s failed, see earlier error messages\");\n" name; + (* Send any additional files (FileIn) requested. *) + List.iter ( + function + | FileIn n -> + pr " if (guestfs__send_file_sync (g, %s) == -1)\n" n; + pr " return %s;\n" error_code; + pr "\n"; + | _ -> () + ) (snd style); + + (* Wait for the reply from the remote end. *) + 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 != 1001) {\n"; + pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name; pr " return %s;\n" error_code; pr " }\n"; pr "\n"; - pr " if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n" + pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1)\n" (String.uppercase shortname); pr " return %s;\n" error_code; pr "\n"; - pr " if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n"; - pr " error (g, \"%%s\", rv.err.error);\n"; + pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n"; + pr " error (g, \"%%s\", ctx.err.error_message);\n"; pr " return %s;\n" error_code; pr " }\n"; pr "\n"; + (* Expecting to receive further files (FileOut)? *) + List.iter ( + function + | FileOut n -> + pr " if (guestfs__receive_file_sync (g, %s) == -1)\n" n; + pr " return %s;\n" error_code; + pr "\n"; + | _ -> () + ) (snd style); + (match fst style with | RErr -> pr " return 0;\n" | RInt n | RInt64 n | RBool n -> - pr " return rv.ret.%s;\n" n + pr " return ctx.ret.%s;\n" n | RConstString _ -> failwithf "RConstString cannot be returned from a daemon function" | RString n -> - pr " return rv.ret.%s; /* caller will free */\n" n + pr " return ctx.ret.%s; /* caller will free */\n" n | RStringList n | RHashtable n -> pr " /* caller will free this, but we need to add a NULL entry */\n"; - pr " rv.ret.%s.%s_val =" n n; - pr " safe_realloc (g, rv.ret.%s.%s_val,\n" n n; - pr " sizeof (char *) * (rv.ret.%s.%s_len + 1));\n" + pr " 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" n n; - pr " rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n; - pr " return rv.ret.%s.%s_val;\n" n n + pr " 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 | RIntBool _ -> pr " /* caller with free this */\n"; - pr " return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n" + pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n" | RPVList n | RVGList n | RLVList n | RStat n | RStatVFS n -> pr " /* caller will free this */\n"; - pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n + pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n ); pr "}\n\n" @@ -2189,6 +2402,7 @@ and generate_daemon_actions () = | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n + | FileIn _ | FileOut _ -> () ) args ); pr "\n"; @@ -2212,12 +2426,19 @@ and generate_daemon_actions () = pr " %s = args.%s.%s_val;\n" n n n | Bool n -> pr " %s = args.%s;\n" n n | Int n -> pr " %s = args.%s;\n" n n + | FileIn _ | FileOut _ -> () ) args; pr "\n" ); + (* Don't want to call the impl with any FileIn or FileOut + * parameters, since these go "outside" the RPC protocol. + *) + let argsnofile = + List.filter (function FileIn _ | FileOut _ -> false | _ -> true) + (snd style) in pr " r = do_%s " name; - generate_call_args style; + generate_call_args argsnofile; pr ";\n"; pr " if (r == %s)\n" error_code; @@ -2225,34 +2446,48 @@ and generate_daemon_actions () = pr " goto done;\n"; pr "\n"; - (match fst style with - | RErr -> pr " reply (NULL, NULL);\n" - | RInt n | RInt64 n | RBool n -> - pr " struct guestfs_%s_ret ret;\n" name; - pr " ret.%s = r;\n" n; - pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name - | RConstString _ -> - failwithf "RConstString cannot be returned from a daemon function" - | RString n -> - pr " struct guestfs_%s_ret ret;\n" name; - pr " ret.%s = r;\n" n; - pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name; - pr " free (r);\n" - | RStringList n | RHashtable n -> - pr " struct guestfs_%s_ret ret;\n" name; - pr " ret.%s.%s_len = count_strings (r);\n" n n; - pr " ret.%s.%s_val = r;\n" n n; - pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name; - pr " free_strings (r);\n" - | RIntBool _ -> - pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name; - pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name - | RPVList n | RVGList n | RLVList n - | RStat n | RStatVFS n -> - pr " struct guestfs_%s_ret ret;\n" name; - pr " ret.%s = *r;\n" n; - pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name; - pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name + (* If there are any FileOut parameters, then the impl must + * send its own reply. + *) + let no_reply = + List.exists (function FileOut _ -> true | _ -> false) (snd style) in + if no_reply then + pr " /* do_%s has already sent a reply */\n" name + else ( + match fst style with + | RErr -> pr " reply (NULL, NULL);\n" + | RInt n | RInt64 n | RBool n -> + pr " struct guestfs_%s_ret ret;\n" name; + pr " ret.%s = r;\n" n; + pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" + name + | RConstString _ -> + failwithf "RConstString cannot be returned from a daemon function" + | RString n -> + pr " struct guestfs_%s_ret ret;\n" name; + pr " ret.%s = r;\n" n; + pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" + name; + pr " free (r);\n" + | RStringList n | RHashtable n -> + pr " struct guestfs_%s_ret ret;\n" name; + pr " ret.%s.%s_len = count_strings (r);\n" n n; + pr " ret.%s.%s_val = r;\n" n n; + pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" + name; + pr " free_strings (r);\n" + | RIntBool _ -> + pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" + name; + pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name + | RPVList n | RVGList n | RLVList n + | RStat n | RStatVFS n -> + pr " struct guestfs_%s_ret ret;\n" name; + pr " ret.%s = *r;\n" n; + pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" + name; + pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" + name ); (* Free the args. *) @@ -2890,6 +3125,7 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd = | OptString _, _ | Int _, _ | Bool _, _ -> () + | FileIn _, _ | FileOut _, _ -> () | StringList n, arg -> pr " char *%s[] = {\n" n; let strs = string_split " " arg in @@ -2929,7 +3165,9 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd = (* Generate the parameters. *) List.iter ( function - | String _, arg -> pr ", \"%s\"" (c_quote arg) + | String _, arg + | FileIn _, arg | FileOut _, arg -> + pr ", \"%s\"" (c_quote arg) | OptString _, arg -> if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg) | StringList n, _ -> @@ -3151,7 +3389,9 @@ and generate_fish_cmds () = List.iter ( function | String n - | OptString n -> pr " const char *%s;\n" n + | OptString n + | FileIn n + | FileOut n -> pr " const char *%s;\n" n | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n @@ -3172,6 +3412,12 @@ and generate_fish_cmds () = | OptString name -> pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n" name i i + | FileIn name -> + pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n" + name i i + | FileOut name -> + pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n" + name i i | StringList name -> pr " %s = parse_string_list (argv[%d]);\n" name i | Bool name -> @@ -3185,7 +3431,7 @@ and generate_fish_cmds () = try find_map (function FishAction n -> Some n | _ -> None) flags with Not_found -> sprintf "guestfs_%s" name in pr " r = %s " fn; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; (* Check return value for errors and display command results. *) @@ -3394,11 +3640,16 @@ and generate_fish_actions_pod () = | StringList n -> pr " %s,..." n | Bool _ -> pr " true|false" | Int n -> pr " %s" n + | FileIn n | FileOut n -> pr " (%s|-)" n ) (snd style); pr "\n"; pr "\n"; pr "%s\n\n" longdesc; + if List.exists (function FileIn _ | FileOut _ -> true + | _ -> false) (snd style) then + pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n"; + if List.mem ProtocolLimitWarning flags then pr "%s\n\n" protocol_limit_warning; @@ -3457,11 +3708,14 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true) in List.iter ( function - | String n -> next (); pr "const char *%s" n + | String n | OptString n -> next (); pr "const char *%s" n | StringList n -> next (); pr "char * const* const %s" n | Bool n -> next (); pr "int %s" n | Int n -> next (); pr "int %s" n + | FileIn n + | FileOut n -> + if not in_daemon then (next (); pr "const char *%s" n) ) (snd style); ); pr ")"; @@ -3469,7 +3723,7 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true) if newline then pr "\n" (* Generate C call arguments, eg "(handle, foo, bar)" *) -and generate_call_args ?handle style = +and generate_call_args ?handle args = pr "("; let comma = ref false in (match handle with @@ -3480,13 +3734,8 @@ and generate_call_args ?handle style = fun arg -> if !comma then pr ", "; comma := true; - match arg with - | String n - | OptString n - | StringList n - | Bool n - | Int n -> pr "%s" n - ) (snd style); + pr "%s" (name_of_argt arg) + ) args; pr ")" (* Generate the OCaml bindings interface. *) @@ -3715,7 +3964,9 @@ copy_table (char * const * argv) List.iter ( function - | String n -> + | String n + | FileIn n + | FileOut n -> pr " const char *%s = String_val (%sv);\n" n n | OptString n -> pr " const char *%s =\n" n; @@ -3760,7 +4011,7 @@ copy_table (char * const * argv) pr " caml_enter_blocking_section ();\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; pr " caml_leave_blocking_section ();\n"; @@ -3768,7 +4019,7 @@ copy_table (char * const * argv) function | StringList n -> pr " ocaml_guestfs_free_strings (%s);\n" n; - | String _ | OptString _ | Bool _ | Int _ -> () + | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> () ) (snd style); pr " if (r == %s)\n" error_code; @@ -3864,7 +4115,7 @@ and generate_ocaml_prototype ?(is_external = false) name style = pr "%s : t -> " name; List.iter ( function - | String _ -> pr "string -> " + | String _ | FileIn _ | FileOut _ -> pr "string -> " | OptString _ -> pr "string option -> " | StringList _ -> pr "string array -> " | Bool _ -> pr "bool -> " @@ -4003,12 +4254,12 @@ DESTROY (g) ); (* Call and arguments. *) pr "%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr "\n"; pr " guestfs_h *g;\n"; List.iter ( function - | String n -> pr " char *%s;\n" n + | String n | FileIn n | FileOut n -> pr " char *%s;\n" n | OptString n -> pr " char *%s;\n" n | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n @@ -4018,10 +4269,8 @@ DESTROY (g) let do_cleanups () = List.iter ( function - | String _ - | OptString _ - | Bool _ - | Int _ -> () + | String _ | OptString _ | Bool _ | Int _ + | FileIn _ | FileOut _ -> () | StringList n -> pr " free (%s);\n" n ) (snd style) in @@ -4033,7 +4282,7 @@ DESTROY (g) pr " int r;\n"; pr " PPCODE:\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (r == -1)\n"; @@ -4044,7 +4293,7 @@ DESTROY (g) pr " int %s;\n" n; pr " CODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == -1)\n" n; @@ -4057,7 +4306,7 @@ DESTROY (g) pr " int64_t %s;\n" n; pr " CODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == -1)\n" n; @@ -4070,7 +4319,7 @@ DESTROY (g) pr " const char *%s;\n" n; pr " CODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4083,7 +4332,7 @@ DESTROY (g) pr " char *%s;\n" n; pr " CODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4098,7 +4347,7 @@ DESTROY (g) pr " int i, n;\n"; pr " PPCODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4115,7 +4364,7 @@ DESTROY (g) pr " struct guestfs_int_bool *r;\n"; pr " PPCODE:\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (r == NULL)\n"; @@ -4147,7 +4396,7 @@ and generate_perl_lvm_code typ cols name style n do_cleanups = pr " HV *hv;\n"; pr " PPCODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4182,7 +4431,7 @@ and generate_perl_stat_code typ cols name style n do_cleanups = pr " struct guestfs_%s *%s;\n" typ n; pr " PPCODE:\n"; pr " %s = guestfs_%s " n name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; do_cleanups (); pr " if (%s == NULL)\n" n; @@ -4338,7 +4587,7 @@ and generate_perl_prototype name style = if !comma then pr ", "; comma := true; match arg with - | String n | OptString n | Bool n | Int n -> + | String n | OptString n | Bool n | Int n | FileIn n | FileOut n -> pr "$%s" n | StringList n -> pr "\\@%s" n @@ -4434,7 +4683,6 @@ put_table (char * const * const argv) list = PyList_New (argc >> 1); for (i = 0; i < argc; i += 2) { - PyObject *item; item = PyTuple_New (2); PyTuple_SetItem (item, 0, PyString_FromString (argv[i])); PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1])); @@ -4590,7 +4838,7 @@ py_guestfs_close (PyObject *self, PyObject *args) List.iter ( function - | String n -> pr " const char *%s;\n" n + | String n | FileIn n | FileOut n -> pr " const char *%s;\n" n | OptString n -> pr " const char *%s;\n" n | StringList n -> pr " PyObject *py_%s;\n" n; @@ -4605,7 +4853,7 @@ py_guestfs_close (PyObject *self, PyObject *args) pr " if (!PyArg_ParseTuple (args, (char *) \"O"; List.iter ( function - | String _ -> pr "s" + | String _ | FileIn _ | FileOut _ -> pr "s" | OptString _ -> pr "z" | StringList _ -> pr "O" | Bool _ -> pr "i" (* XXX Python has booleans? *) @@ -4615,7 +4863,7 @@ py_guestfs_close (PyObject *self, PyObject *args) pr " &py_g"; List.iter ( function - | String n -> pr ", &%s" n + | String n | FileIn n | FileOut n -> pr ", &%s" n | OptString n -> pr ", &%s" n | StringList n -> pr ", &py_%s" n | Bool n -> pr ", &%s" n @@ -4628,7 +4876,7 @@ py_guestfs_close (PyObject *self, PyObject *args) pr " g = get_handle (py_g);\n"; List.iter ( function - | String _ | OptString _ | Bool _ | Int _ -> () + | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> () | StringList n -> pr " %s = get_string_list (py_%s);\n" n n; pr " if (!%s) return NULL;\n" n @@ -4637,12 +4885,12 @@ py_guestfs_close (PyObject *self, PyObject *args) pr "\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; List.iter ( function - | String _ | OptString _ | Bool _ | Int _ -> () + | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> () | StringList n -> pr " free (%s);\n" n ) (snd style); @@ -4826,11 +5074,11 @@ class GuestFS: let doc = String.concat "\n " doc in pr " def %s " name; - generate_call_args ~handle:"self" style; + generate_call_args ~handle:"self" (snd style); pr ":\n"; pr " u\"\"\"%s\"\"\"\n" doc; pr " return libguestfsmod.%s " name; - generate_call_args ~handle:"self._o" style; + generate_call_args ~handle:"self._o" (snd style); pr "\n"; pr "\n"; ) all_functions @@ -4932,7 +5180,7 @@ static VALUE ruby_guestfs_close (VALUE gv) List.iter ( function - | String n -> + | String n | FileIn n | FileOut n -> pr " const char *%s = StringValueCStr (%sv);\n" n n; pr " if (!%s)\n" n; pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n"; @@ -4972,12 +5220,12 @@ static VALUE ruby_guestfs_close (VALUE gv) pr "\n"; pr " r = guestfs_%s " name; - generate_call_args ~handle:"g" style; + generate_call_args ~handle:"g" (snd style); pr ";\n"; List.iter ( function - | String _ | OptString _ | Bool _ | Int _ -> () + | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> () | StringList n -> pr " free (%s);\n" n ) (snd style);