Richard W.M. Jones
2012-Jul-14 13:28 UTC
[Libguestfs] [PATCH 0/6] Allow non-optargs functions to gain optional arguments.
This rather complex set of patches allow non-optargs functions to gain optional arguments, while preserving source and binary backwards compatibility. The problem is that we cannot add an optional argument to an existing function. For example, we might want to add flags to the 'lvresize' API which currently has no optional arguments. http://libguestfs.org/guestfs.3.html#guestfs_lvresize The reason this wouldn't be possible is because in C the call is specified as: int guestfs_lvresize (guestfs_h *g, const char *device, int mbytes); which leaves no scope for extra parameters to be added. However in other languages, it wouldn't be a problem, eg. in Perl you can overload functions with additional arguments perfectly happily: $g->lvresize (device, mbytes); $g->lvresize (device, mbytes, free_percent => 50); and this is true in most non-C languages. The way to make this work is to generate C bindings differently. We would still generate the (backwards-compatible) guestfs_lvresize function as before, but we would generate an additional function 'guestfs_lvresize_opts' which could take optional arguments. Additionally, there are three "*-opts" APIs already (add-drive-opts, mkfs-opts, ntfsresize-opts). By luck, all of these have "non-opts" variants which take all the same required arguments. Therefore we can rename these as non-opts functions (add-drive, mkfs, ntfsresize) and use the same machinery above to generate the "*-opts" variants automatically. Existing callers will not be affected. The patches in this series do just this: 1/6, 2/6: Adds a 'once_had_no_optargs' flag to the generator, allowing functions to be transitioned from non-opts -> opts. This flag must be set to true when this is done so the corresponding backwards- compatibility functions can be generated. 3/6: Adds *-opts aliases in non-C languages. This ensures that non-C bindings won't be broken by this transition. *NB* PHP, Haskell and GObject bindings *are* broken at the moment; see the notes in the commit message. 4/6, 5/6, 6/6: Rename add-drive-opts -> add_drive, mkfs-opts -> mkfs, ntfsresize-opts -> ntfsresize. By setting the once_had_no_optargs flag we avoid breaking code for callers. ---- At the moment, the GObject bindings don't run at all on Rawhide. I suspect this is a general bug in Rawhide, since it doesn't happen on F17. The error is: JS ERROR: !!! Exception was: Error: Unsupported type void, deriving from fundamental void JS ERROR: !!! message = '"Unsupported type void, deriving from fundamental void"' JS ERROR: !!! fileName = '"./bindtests.js"' JS ERROR: !!! lineNumber = '27' JS ERROR: !!! stack = '"@./bindtests.js:27 Rich.
Richard W.M. Jones
2012-Jul-14 13:28 UTC
[Libguestfs] [PATCH 1/6] generator: Rearrange some C generator code into sub-functions.
From: "Richard W.M. Jones" <rjones at redhat.com> This is just code motion. I verified this by comparing the generator output before and after this commit. --- generator/generator_c.ml | 1156 +++++++++++++++++++++++----------------------- 1 file changed, 585 insertions(+), 571 deletions(-) diff --git a/generator/generator_c.ml b/generator/generator_c.ml index 219aec8..6f24bee 100644 --- a/generator/generator_c.ml +++ b/generator/generator_c.ml @@ -177,113 +177,115 @@ and generate_actions_pod () List.iter ( function | { in_docs = false } -> () - | ({ name = shortname; style = (ret, args, optargs as style); - in_docs = true } as f) -> - let name = "guestfs_" ^ shortname in - pr "=head2 %s\n\n" name; - generate_prototype ~extern:false ~indent:" " ~handle:"g" name style; - pr "\n\n"; - - (match deprecation_notice ~prefix:"guestfs_" f with - | None -> () - | Some txt -> pr "%s\n\n" txt - ); + | ({ in_docs = true } as f) -> generate_actions_pod_entry f + ) all_functions_sorted - let uc_shortname = String.uppercase shortname in - if optargs <> [] then ( - pr "You may supply a list of optional arguments to this call.\n"; - pr "Use zero or more of the following pairs of parameters,\n"; - pr "and terminate the list with C<-1> on its own.\n"; - pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n"; - List.iter ( - fun argt -> - let n = name_of_optargt argt in - let uc_n = String.uppercase n in - pr " GUESTFS_%s_%s, " uc_shortname uc_n; - match argt with - | OBool n -> pr "int %s,\n" n - | OInt n -> pr "int %s,\n" n - | OInt64 n -> pr "int64_t %s,\n" n - | OString n -> pr "const char *%s,\n" n - ) optargs; - pr "\n"; - ); +and generate_actions_pod_entry ({ name = shortname; + style = ret, args, optargs as style } as f) + let name = "guestfs_" ^ shortname in + pr "=head2 %s\n\n" name; + generate_prototype ~extern:false ~indent:" " ~handle:"g" name style; + pr "\n\n"; + + (match deprecation_notice ~prefix:"guestfs_" f with + | None -> () + | Some txt -> pr "%s\n\n" txt + ); + + let uc_shortname = String.uppercase shortname in + if optargs <> [] then ( + pr "You may supply a list of optional arguments to this call.\n"; + pr "Use zero or more of the following pairs of parameters,\n"; + pr "and terminate the list with C<-1> on its own.\n"; + pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n"; + List.iter ( + fun argt -> + let n = name_of_optargt argt in + let uc_n = String.uppercase n in + pr " GUESTFS_%s_%s, " uc_shortname uc_n; + match argt with + | OBool n -> pr "int %s,\n" n + | OInt n -> pr "int %s,\n" n + | OInt64 n -> pr "int64_t %s,\n" n + | OString n -> pr "const char *%s,\n" n + ) optargs; + pr "\n"; + ); - pr "%s\n\n" f.longdesc; - let ret, args, optargs = style in - (match ret with - | RErr -> - pr "This function returns 0 on success or -1 on error.\n\n" - | RInt _ -> - pr "On error this function returns -1.\n\n" - | RInt64 _ -> - pr "On error this function returns -1.\n\n" - | RBool _ -> - pr "This function returns a C truth value on success or -1 on error.\n\n" - | RConstString _ -> - pr "This function returns a string, or NULL on error. + pr "%s\n\n" f.longdesc; + let ret, args, optargs = style in + (match ret with + | RErr -> + pr "This function returns 0 on success or -1 on error.\n\n" + | RInt _ -> + pr "On error this function returns -1.\n\n" + | RInt64 _ -> + pr "On error this function returns -1.\n\n" + | RBool _ -> + pr "This function returns a C truth value on success or -1 on error.\n\n" + | RConstString _ -> + pr "This function returns a string, or NULL on error. The string is owned by the guest handle and must I<not> be freed.\n\n" - | RConstOptString _ -> - pr "This function returns a string which may be NULL. + | RConstOptString _ -> + pr "This function returns a string which may be NULL. There is no way to return an error from this function. The string is owned by the guest handle and must I<not> be freed.\n\n" - | RString _ -> - pr "This function returns a string, or NULL on error. + | RString _ -> + pr "This function returns a string, or NULL on error. I<The caller must free the returned string after use>.\n\n" - | RStringList _ -> - pr "This function returns a NULL-terminated array of strings + | RStringList _ -> + pr "This function returns a NULL-terminated array of strings (like L<environ(3)>), or NULL if there was an error. I<The caller must free the strings and the array after use>.\n\n" - | RStruct (_, typ) -> - pr "This function returns a C<struct guestfs_%s *>, + | RStruct (_, typ) -> + pr "This function returns a C<struct guestfs_%s *>, or NULL if there was an error. I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ - | RStructList (_, typ) -> - pr "This function returns a C<struct guestfs_%s_list *>, + | RStructList (_, typ) -> + pr "This function returns a C<struct guestfs_%s_list *>, or NULL if there was an error. I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ - | RHashtable _ -> - pr "This function returns a NULL-terminated array of + | RHashtable _ -> + pr "This function returns a NULL-terminated array of strings, or NULL if there was an error. The array of strings will always have length C<2n+1>, where C<n> keys and values alternate, followed by the trailing NULL entry. I<The caller must free the strings and the array after use>.\n\n" - | RBufferOut _ -> - pr "This function returns a buffer, or NULL on error. + | RBufferOut _ -> + pr "This function returns a buffer, or NULL on error. The size of the returned buffer is written to C<*size_r>. I<The caller must free the returned buffer after use>.\n\n" - ); - if f.progress then - pr "%s\n\n" progress_message; - if f.protocol_limit_warning then - pr "%s\n\n" protocol_limit_warning; - if List.exists (function Key _ -> true | _ -> false) args then - pr "This function takes a key or passphrase parameter which + ); + if f.progress then + pr "%s\n\n" progress_message; + if f.protocol_limit_warning then + pr "%s\n\n" protocol_limit_warning; + if List.exists (function Key _ -> true | _ -> false) args then + pr "This function takes a key or passphrase parameter which could contain sensitive material. Read the section L</KEYS AND PASSPHRASES> for more information.\n\n"; - (match lookup_api_version name with - | Some version -> pr "(Added in %s)\n\n" version - | None -> () - ); + (match lookup_api_version name with + | Some version -> pr "(Added in %s)\n\n" version + | None -> () + ); - (* Handling of optional argument variants. *) - if optargs <> [] then ( - pr "=head2 %s_va\n\n" name; - generate_prototype ~extern:false ~indent:" " ~handle:"g" - ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA - shortname style; - pr "\n\n"; - pr "This is the \"va_list variant\" of L</%s>.\n\n" name; - pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n"; - pr "=head2 %s_argv\n\n" name; - generate_prototype ~extern:false ~indent:" " ~handle:"g" - ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv - shortname style; - pr "\n\n"; - pr "This is the \"argv variant\" of L</%s>.\n\n" name; - pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n"; - ); - ) all_functions_sorted + (* Handling of optional argument variants. *) + if optargs <> [] then ( + pr "=head2 %s_va\n\n" name; + generate_prototype ~extern:false ~indent:" " ~handle:"g" + ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA + shortname style; + pr "\n\n"; + pr "This is the \"va_list variant\" of L</%s>.\n\n" name; + pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n"; + pr "=head2 %s_argv\n\n" name; + generate_prototype ~extern:false ~indent:" " ~handle:"g" + ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv + shortname style; + pr "\n\n"; + pr "This is the \"argv variant\" of L</%s>.\n\n" name; + pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n"; + ) and generate_structs_pod () (* Structs documentation. *) @@ -548,72 +550,76 @@ extern GUESTFS_DLL_PUBLIC void *guestfs_next_private (guestfs_h *g, const char * /* Actions. */ "; - List.iter ( - fun { name = shortname; style = (ret, args, optargs as style); - deprecated_by = deprecated_by } -> - let test - String.length shortname >= 13 && - String.sub shortname 0 13 = "internal_test" in - let debug - String.length shortname >= 5 && String.sub shortname 0 5 = "debug" in - if deprecated_by = None && not test && not debug then - pr "#define LIBGUESTFS_HAVE_%s 1\n" (String.uppercase shortname); - - if optargs <> [] then ( - iteri ( - fun i argt -> - let uc_shortname = String.uppercase shortname in - let n = name_of_optargt argt in - let uc_n = String.uppercase n in - pr "#define GUESTFS_%s_%s %d\n" uc_shortname uc_n i; - ) optargs; - ); - - generate_prototype ~single_line:true ~semicolon:false ~dll_public:true - ~handle:"g" ~prefix:"guestfs_" shortname style; - (match deprecated_by with - | Some fn -> pr "\n GUESTFS_DEPRECATED_BY (%S);\n" fn - | None -> pr ";\n" - ); + let generate_action_header { name = shortname; + style = ret, args, optargs as style; + deprecated_by = deprecated_by } + let test + String.length shortname >= 13 && + String.sub shortname 0 13 = "internal_test" in + let debug + String.length shortname >= 5 && String.sub shortname 0 5 = "debug" in + if deprecated_by = None && not test && not debug then + pr "#define LIBGUESTFS_HAVE_%s 1\n" (String.uppercase shortname); - if optargs <> [] then ( - generate_prototype ~single_line:true ~newline:true ~handle:"g" - ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA - ~dll_public:true - shortname style; + if optargs <> [] then ( + iteri ( + fun i argt -> + let uc_shortname = String.uppercase shortname in + let n = name_of_optargt argt in + let uc_n = String.uppercase n in + pr "#define GUESTFS_%s_%s %d\n" uc_shortname uc_n i; + ) optargs; + ); - pr "\n"; - pr "struct guestfs_%s_argv {\n" shortname; - pr " uint64_t bitmask;\n"; - iteri ( - fun i argt -> - let c_type - match argt with - | OBool n -> "int " - | OInt n -> "int " - | OInt64 n -> "int64_t " - | OString n -> "const char *" in - let uc_shortname = String.uppercase shortname in - let n = name_of_optargt argt in - let uc_n = String.uppercase n in - pr "\n"; - pr "# define GUESTFS_%s_%s_BITMASK (UINT64_C(1)<<%d)\n" uc_shortname uc_n i; - pr " /* The field below is only valid in this struct if the\n"; - pr " * GUESTFS_%s_%s_BITMASK bit is set\n" uc_shortname uc_n; - pr " * in the bitmask above. If not, the field is ignored.\n"; - pr " */\n"; - pr " %s%s;\n" c_type n - ) optargs; - pr "};\n"; - pr "\n"; + generate_prototype ~single_line:true ~semicolon:false ~dll_public:true + ~handle:"g" ~prefix:"guestfs_" shortname style; + (match deprecated_by with + | Some fn -> pr "\n GUESTFS_DEPRECATED_BY (%S);\n" fn + | None -> pr ";\n" + ); - generate_prototype ~single_line:true ~newline:true ~handle:"g" - ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv - ~dll_public:true - shortname style; - ); + if optargs <> [] then ( + generate_prototype ~single_line:true ~newline:true ~handle:"g" + ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA + ~dll_public:true + shortname style; pr "\n"; + pr "struct guestfs_%s_argv {\n" shortname; + pr " uint64_t bitmask;\n"; + iteri ( + fun i argt -> + let c_type + match argt with + | OBool n -> "int " + | OInt n -> "int " + | OInt64 n -> "int64_t " + | OString n -> "const char *" in + let uc_shortname = String.uppercase shortname in + let n = name_of_optargt argt in + let uc_n = String.uppercase n in + pr "\n"; + pr "# define GUESTFS_%s_%s_BITMASK (UINT64_C(1)<<%d)\n" uc_shortname uc_n i; + pr " /* The field below is only valid in this struct if the\n"; + pr " * GUESTFS_%s_%s_BITMASK bit is set\n" uc_shortname uc_n; + pr " * in the bitmask above. If not, the field is ignored.\n"; + pr " */\n"; + pr " %s%s;\n" c_type n + ) optargs; + pr "};\n"; + pr "\n"; + + generate_prototype ~single_line:true ~newline:true ~handle:"g" + ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv + ~dll_public:true + shortname style; + ); + + pr "\n" + in + + List.iter ( + fun f -> generate_action_header f ) all_functions_sorted; pr "\ @@ -1008,355 +1014,356 @@ trace_send_line (guestfs_h *g) in (* For non-daemon functions, generate a wrapper around each function. *) - List.iter ( - fun { name = shortname; style = (ret, _, optargs as style); - config_only = config_only } -> - if optargs = [] then - generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" - shortname style - else - generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv - shortname style; - pr "{\n"; + let generate_non_daemon_wrapper { name = shortname; + style = ret, _, optargs as style; + config_only = config_only } + if optargs = [] then + generate_prototype ~extern:false ~semicolon:false ~newline:true + ~handle:"g" ~prefix:"guestfs_" + shortname style + else + generate_prototype ~extern:false ~semicolon:false ~newline:true + ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv + shortname style; + pr "{\n"; - handle_null_optargs optargs shortname; - - pr " int trace_flag = g->trace;\n"; - pr " FILE *trace_fp;\n"; - (match ret with - | RErr | RInt _ | RBool _ -> - pr " int r;\n" - | RInt64 _ -> - pr " int64_t r;\n" - | RConstString _ -> - pr " const char *r;\n" - | RConstOptString _ -> - pr " const char *r;\n" - | RString _ | RBufferOut _ -> - pr " char *r;\n" - | RStringList _ | RHashtable _ -> - pr " char **r;\n" - | RStruct (_, typ) -> - pr " struct guestfs_%s *r;\n" typ - | RStructList (_, typ) -> - pr " struct guestfs_%s_list *r;\n" typ - ); - pr "\n"; - if config_only then ( - pr " if (g->state != CONFIG) {\n"; - pr " error (g, \"%%s: this function can only be called in the config state\",\n"; - pr " \"%s\");\n" shortname; - pr " return -1;\n"; - pr " }\n"; - ); - enter_event shortname; - check_null_strings shortname style; - reject_unknown_optargs shortname style; - trace_call shortname style; - pr " r = guestfs__%s " shortname; - generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; - pr ";\n"; - pr "\n"; - (match errcode_of_ret ret with - | (`ErrorIsMinusOne | `ErrorIsNULL) as errcode -> - pr " if (r != %s) {\n" (string_of_errcode errcode); - trace_return ~indent:4 shortname style "r"; - pr " } else {\n"; - trace_return_error ~indent:4 shortname style errcode; - pr " }\n"; - | `CannotReturnError -> - trace_return shortname style "r"; - ); - pr "\n"; - pr " return r;\n"; - pr "}\n"; - pr "\n" + handle_null_optargs optargs shortname; + + pr " int trace_flag = g->trace;\n"; + pr " FILE *trace_fp;\n"; + (match ret with + | RErr | RInt _ | RBool _ -> + pr " int r;\n" + | RInt64 _ -> + pr " int64_t r;\n" + | RConstString _ -> + pr " const char *r;\n" + | RConstOptString _ -> + pr " const char *r;\n" + | RString _ | RBufferOut _ -> + pr " char *r;\n" + | RStringList _ | RHashtable _ -> + pr " char **r;\n" + | RStruct (_, typ) -> + pr " struct guestfs_%s *r;\n" typ + | RStructList (_, typ) -> + pr " struct guestfs_%s_list *r;\n" typ + ); + pr "\n"; + if config_only then ( + pr " if (g->state != CONFIG) {\n"; + pr " error (g, \"%%s: this function can only be called in the config state\",\n"; + pr " \"%s\");\n" shortname; + pr " return -1;\n"; + pr " }\n"; + ); + enter_event shortname; + check_null_strings shortname style; + reject_unknown_optargs shortname style; + trace_call shortname style; + pr " r = guestfs__%s " shortname; + generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; + pr ";\n"; + pr "\n"; + (match errcode_of_ret ret with + | (`ErrorIsMinusOne | `ErrorIsNULL) as errcode -> + pr " if (r != %s) {\n" (string_of_errcode errcode); + trace_return ~indent:4 shortname style "r"; + pr " } else {\n"; + trace_return_error ~indent:4 shortname style errcode; + pr " }\n"; + | `CannotReturnError -> + trace_return shortname style "r"; + ); + pr "\n"; + pr " return r;\n"; + pr "}\n"; + pr "\n" + in + + List.iter ( + fun f -> generate_non_daemon_wrapper f ) non_daemon_functions; (* Client-side stubs for each function. *) - List.iter ( - fun { name = shortname; style = (ret, args, optargs as style) } -> - let name = "guestfs_" ^ shortname in - let errcode - match errcode_of_ret ret with - | `CannotReturnError -> assert false - | (`ErrorIsMinusOne | `ErrorIsNULL) as e -> e in - - (* Generate the action stub. *) - if optargs = [] then - generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" shortname style - else - generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" - ~optarg_proto:Argv shortname style; + let generate_daemon_stub { name = shortname; + style = ret, args, optargs as style } + let name = "guestfs_" ^ shortname in + let errcode + match errcode_of_ret ret with + | `CannotReturnError -> assert false + | (`ErrorIsMinusOne | `ErrorIsNULL) as e -> e in + + (* Generate the action stub. *) + if optargs = [] then + generate_prototype ~extern:false ~semicolon:false ~newline:true + ~handle:"g" ~prefix:"guestfs_" shortname style + else + generate_prototype ~extern:false ~semicolon:false ~newline:true + ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" + ~optarg_proto:Argv shortname style; + + pr "{\n"; + + handle_null_optargs optargs shortname; + + (match args with + | [] -> () + | _ -> pr " struct %s_args args;\n" name + ); - pr "{\n"; + pr " guestfs_message_header hdr;\n"; + pr " guestfs_message_error err;\n"; + let has_ret + match ret with + | RErr -> false + | RConstString _ | RConstOptString _ -> + failwithf "RConstString|RConstOptString cannot be used by daemon functions" + | RInt _ | RInt64 _ + | RBool _ | RString _ | RStringList _ + | RStruct _ | RStructList _ + | RHashtable _ | RBufferOut _ -> + pr " struct %s_ret ret;\n" name; + true in + + pr " int serial;\n"; + pr " int r;\n"; + pr " int trace_flag = g->trace;\n"; + pr " FILE *trace_fp;\n"; + (match ret with + | RErr | RInt _ | RBool _ -> pr " int ret_v;\n" + | RInt64 _ -> pr " int64_t ret_v;\n" + | RConstString _ | RConstOptString _ -> pr " const char *ret_v;\n" + | RString _ | RBufferOut _ -> pr " char *ret_v;\n" + | RStringList _ | RHashtable _ -> pr " char **ret_v;\n" + | RStruct (_, typ) -> pr " struct guestfs_%s *ret_v;\n" typ + | RStructList (_, typ) -> pr " struct guestfs_%s_list *ret_v;\n" typ + ); - handle_null_optargs optargs shortname; + let has_filein + List.exists (function FileIn _ -> true | _ -> false) args in + if has_filein then ( + pr " uint64_t progress_hint = 0;\n"; + pr " struct stat progress_stat;\n"; + ) else + pr " const uint64_t progress_hint = 0;\n"; - (match args with - | [] -> () - | _ -> pr " struct %s_args args;\n" name - ); + pr "\n"; + enter_event shortname; + check_null_strings shortname style; + reject_unknown_optargs shortname style; + trace_call shortname style; - pr " guestfs_message_header hdr;\n"; - pr " guestfs_message_error err;\n"; - let has_ret - match ret with - | RErr -> false - | RConstString _ | RConstOptString _ -> - failwithf "RConstString|RConstOptString cannot be used by daemon functions" - | RInt _ | RInt64 _ - | RBool _ | RString _ | RStringList _ - | RStruct _ | RStructList _ - | RHashtable _ | RBufferOut _ -> - pr " struct %s_ret ret;\n" name; - true in - - pr " int serial;\n"; - pr " int r;\n"; - pr " int trace_flag = g->trace;\n"; - pr " FILE *trace_fp;\n"; - (match ret with - | RErr | RInt _ | RBool _ -> - pr " int ret_v;\n" - | RInt64 _ -> - pr " int64_t ret_v;\n" - | RConstString _ | RConstOptString _ -> - pr " const char *ret_v;\n" - | RString _ | RBufferOut _ -> - pr " char *ret_v;\n" - | RStringList _ | RHashtable _ -> - pr " char **ret_v;\n" - | RStruct (_, typ) -> - pr " struct guestfs_%s *ret_v;\n" typ - | RStructList (_, typ) -> - pr " struct guestfs_%s_list *ret_v;\n" typ - ); + (* Calculate the total size of all FileIn arguments to pass + * as a progress bar hint. + *) + List.iter ( + function + | FileIn n -> + pr " if (stat (%s, &progress_stat) == 0 &&\n" n; + pr " S_ISREG (progress_stat.st_mode))\n"; + pr " progress_hint += progress_stat.st_size;\n"; + pr "\n"; + | _ -> () + ) args; - let has_filein - List.exists (function FileIn _ -> true | _ -> false) args in - if has_filein then ( - pr " uint64_t progress_hint = 0;\n"; - pr " struct stat progress_stat;\n"; - ) else - pr " const uint64_t progress_hint = 0;\n"; + (* This is a daemon_function so check the appliance is up. *) + pr " if (check_appliance_up (g, \"%s\") == -1) {\n" shortname; + trace_return_error ~indent:4 shortname style errcode; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr "\n"; - pr "\n"; - enter_event shortname; - check_null_strings shortname style; - reject_unknown_optargs shortname style; - trace_call shortname style; - - (* Calculate the total size of all FileIn arguments to pass - * as a progress bar hint. - *) + (* Send the main header and arguments. *) + if args = [] && optargs = [] then ( + pr " serial = guestfs___send (g, GUESTFS_PROC_%s, progress_hint, 0,\n" + (String.uppercase shortname); + pr " NULL, NULL);\n" + ) else ( List.iter ( function - | FileIn n -> - pr " if (stat (%s, &progress_stat) == 0 &&\n" n; - pr " S_ISREG (progress_stat.st_mode))\n"; - pr " progress_hint += progress_stat.st_size;\n"; - pr "\n"; - | _ -> () + | Pathname n | Device n | Dev_or_Path n | String n | Key n -> + pr " args.%s = (char *) %s;\n" n n + | OptString n -> + pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n + | StringList n | DeviceList n -> + pr " args.%s.%s_val = (char **) %s;\n" n n n; + pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n; + | Bool n -> + pr " args.%s = %s;\n" n n + | Int n -> + pr " args.%s = %s;\n" n n + | Int64 n -> + pr " args.%s = %s;\n" n n + | FileIn _ | FileOut _ -> () + | BufferIn n -> + pr " /* Just catch grossly large sizes. XDR encoding will make this precise. */\n"; + pr " if (%s_size >= GUESTFS_MESSAGE_MAX) {\n" n; + trace_return_error ~indent:4 shortname style errcode; + pr " error (g, \"%%s: size of input buffer too large\", \"%s\");\n" + shortname; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr " args.%s.%s_val = (char *) %s;\n" n n n; + pr " args.%s.%s_len = %s_size;\n" n n n + | Pointer _ -> assert false ) args; - (* This is a daemon_function so check the appliance is up. *) - pr " if (check_appliance_up (g, \"%s\") == -1) {\n" shortname; - trace_return_error ~indent:4 shortname style errcode; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr "\n"; + List.iter ( + fun argt -> + let n = name_of_optargt argt in + let uc_shortname = String.uppercase shortname in + let uc_n = String.uppercase n in + pr " if (optargs->bitmask & GUESTFS_%s_%s_BITMASK)\n" + uc_shortname uc_n; + (match argt with + | OBool n + | OInt n + | OInt64 n -> + pr " args.%s = optargs->%s;\n" n n; + pr " else\n"; + pr " args.%s = 0;\n" n + | OString n -> + pr " args.%s = (char *) optargs->%s;\n" n n; + pr " else\n"; + pr " args.%s = (char *) \"\";\n" n + ) + ) optargs; + + pr " serial = guestfs___send (g, GUESTFS_PROC_%s,\n" + (String.uppercase shortname); + pr " progress_hint, %s,\n" + (if optargs <> [] then "optargs->bitmask" else "0"); + pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n" + name; + ); + pr " if (serial == -1) {\n"; + trace_return_error ~indent:4 shortname style errcode; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr "\n"; - (* Send the main header and arguments. *) - if args = [] && optargs = [] then ( - pr " serial = guestfs___send (g, GUESTFS_PROC_%s, progress_hint, 0,\n" - (String.uppercase shortname); - pr " NULL, NULL);\n" - ) else ( - List.iter ( - function - | Pathname n | Device n | Dev_or_Path n | String n | Key n -> - pr " args.%s = (char *) %s;\n" n n - | OptString n -> - pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n - | StringList n | DeviceList n -> - pr " args.%s.%s_val = (char **) %s;\n" n n n; - pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n; - | Bool n -> - pr " args.%s = %s;\n" n n - | Int n -> - pr " args.%s = %s;\n" n n - | Int64 n -> - pr " args.%s = %s;\n" n n - | FileIn _ | FileOut _ -> () - | BufferIn n -> - pr " /* Just catch grossly large sizes. XDR encoding will make this precise. */\n"; - pr " if (%s_size >= GUESTFS_MESSAGE_MAX) {\n" n; - trace_return_error ~indent:4 shortname style errcode; - pr " error (g, \"%%s: size of input buffer too large\", \"%s\");\n" - shortname; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr " args.%s.%s_val = (char *) %s;\n" n n n; - pr " args.%s.%s_len = %s_size;\n" n n n - | Pointer _ -> assert false - ) args; - - List.iter ( - fun argt -> - let n = name_of_optargt argt in - let uc_shortname = String.uppercase shortname in - let uc_n = String.uppercase n in - pr " if (optargs->bitmask & GUESTFS_%s_%s_BITMASK)\n" - uc_shortname uc_n; - (match argt with - | OBool n - | OInt n - | OInt64 n -> - pr " args.%s = optargs->%s;\n" n n; - pr " else\n"; - pr " args.%s = 0;\n" n - | OString n -> - pr " args.%s = (char *) optargs->%s;\n" n n; - pr " else\n"; - pr " args.%s = (char *) \"\";\n" n - ) - ) optargs; - - pr " serial = guestfs___send (g, GUESTFS_PROC_%s,\n" - (String.uppercase shortname); - pr " progress_hint, %s,\n" - (if optargs <> [] then "optargs->bitmask" else "0"); - pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n" - name; - ); - pr " if (serial == -1) {\n"; - trace_return_error ~indent:4 shortname style errcode; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr "\n"; + (* Send any additional files (FileIn) requested. *) + let need_read_reply_label = ref false in + List.iter ( + function + | FileIn n -> + pr " r = guestfs___send_file (g, %s);\n" n; + pr " if (r == -1) {\n"; + trace_return_error ~indent:4 shortname style errcode; + pr " /* daemon will send an error reply which we discard */\n"; + pr " guestfs___recv_discard (g, \"%s\");\n" shortname; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr " if (r == -2) /* daemon cancelled */\n"; + pr " goto read_reply;\n"; + need_read_reply_label := true; + pr "\n"; + | _ -> () + ) args; - (* Send any additional files (FileIn) requested. *) - let need_read_reply_label = ref false in - List.iter ( - function - | FileIn n -> - pr " r = guestfs___send_file (g, %s);\n" n; - pr " if (r == -1) {\n"; - trace_return_error ~indent:4 shortname style errcode; - pr " /* daemon will send an error reply which we discard */\n"; - pr " guestfs___recv_discard (g, \"%s\");\n" shortname; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr " if (r == -2) /* daemon cancelled */\n"; - pr " goto read_reply;\n"; - need_read_reply_label := true; - pr "\n"; - | _ -> () - ) args; + (* Wait for the reply from the remote end. *) + if !need_read_reply_label then pr " read_reply:\n"; + pr " memset (&hdr, 0, sizeof hdr);\n"; + pr " memset (&err, 0, sizeof err);\n"; + if has_ret then pr " memset (&ret, 0, sizeof ret);\n"; + pr "\n"; + pr " r = guestfs___recv (g, \"%s\", &hdr, &err,\n " shortname; + if not has_ret then + pr "NULL, NULL" + else + pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname; + pr ");\n"; + + pr " if (r == -1) {\n"; + trace_return_error ~indent:4 shortname style errcode; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr "\n"; - (* Wait for the reply from the remote end. *) - if !need_read_reply_label then pr " read_reply:\n"; - pr " memset (&hdr, 0, sizeof hdr);\n"; - pr " memset (&err, 0, sizeof err);\n"; - if has_ret then pr " memset (&ret, 0, sizeof ret);\n"; - pr "\n"; - pr " r = guestfs___recv (g, \"%s\", &hdr, &err,\n " shortname; - if not has_ret then - pr "NULL, NULL" - else - pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname; - pr ");\n"; - - pr " if (r == -1) {\n"; - trace_return_error ~indent:4 shortname style errcode; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr "\n"; + pr " if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n" + (String.uppercase shortname); + trace_return_error ~indent:4 shortname style errcode; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr "\n"; - pr " if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n" - (String.uppercase shortname); - trace_return_error ~indent:4 shortname style errcode; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr "\n"; + pr " if (hdr.status == GUESTFS_STATUS_ERROR) {\n"; + trace_return_error ~indent:4 shortname style errcode; + pr " int errnum = 0;\n"; + pr " if (err.errno_string[0] != '\\0')\n"; + pr " errnum = guestfs___string_to_errno (err.errno_string);\n"; + pr " if (errnum <= 0)\n"; + pr " error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" + shortname; + pr " else\n"; + pr " guestfs_error_errno (g, errnum, \"%%s: %%s\", \"%s\",\n" + shortname; + pr " err.error_message);\n"; + pr " free (err.error_message);\n"; + pr " free (err.errno_string);\n"; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr "\n"; - pr " if (hdr.status == GUESTFS_STATUS_ERROR) {\n"; - trace_return_error ~indent:4 shortname style errcode; - pr " int errnum = 0;\n"; - pr " if (err.errno_string[0] != '\\0')\n"; - pr " errnum = guestfs___string_to_errno (err.errno_string);\n"; - pr " if (errnum <= 0)\n"; - pr " error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" - shortname; - pr " else\n"; - pr " guestfs_error_errno (g, errnum, \"%%s: %%s\", \"%s\",\n" - shortname; - pr " err.error_message);\n"; - pr " free (err.error_message);\n"; - pr " free (err.errno_string);\n"; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr "\n"; + (* Expecting to receive further files (FileOut)? *) + List.iter ( + function + | FileOut n -> + pr " if (guestfs___recv_file (g, %s) == -1) {\n" n; + trace_return_error ~indent:4 shortname style errcode; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr "\n"; + | _ -> () + ) args; - (* Expecting to receive further files (FileOut)? *) - List.iter ( - function - | FileOut n -> - pr " if (guestfs___recv_file (g, %s) == -1) {\n" n; - trace_return_error ~indent:4 shortname style errcode; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr "\n"; - | _ -> () - ) args; + (match ret with + | RErr -> + pr " ret_v = 0;\n" + | RInt n | RInt64 n | RBool n -> + pr " ret_v = ret.%s;\n" n + | RConstString _ | RConstOptString _ -> + failwithf "RConstString|RConstOptString cannot be used by daemon functions" + | RString n -> + pr " ret_v = 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 " 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 " ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n; + pr " ret_v = ret.%s.%s_val;\n" n n + | RStruct (n, _) -> + pr " /* caller will free this */\n"; + pr " ret_v = safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n + | RStructList (n, _) -> + pr " /* caller will free this */\n"; + pr " ret_v = safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n + | RBufferOut n -> + pr " /* RBufferOut is tricky: If the buffer is zero-length, then\n"; + pr " * _val might be NULL here. To make the API saner for\n"; + pr " * callers, we turn this case into a unique pointer (using\n"; + pr " * malloc(1)).\n"; + pr " */\n"; + pr " if (ret.%s.%s_len > 0) {\n" n n; + pr " *size_r = ret.%s.%s_len;\n" n n; + pr " ret_v = ret.%s.%s_val; /* caller will free */\n" n n; + pr " } else {\n"; + pr " free (ret.%s.%s_val);\n" n n; + pr " char *p = safe_malloc (g, 1);\n"; + pr " *size_r = ret.%s.%s_len;\n" n n; + pr " ret_v = p;\n"; + pr " }\n"; + ); + trace_return shortname style "ret_v"; + pr " return ret_v;\n"; + pr "}\n\n" + in - (match ret with - | RErr -> - pr " ret_v = 0;\n" - | RInt n | RInt64 n | RBool n -> - pr " ret_v = ret.%s;\n" n - | RConstString _ | RConstOptString _ -> - failwithf "RConstString|RConstOptString cannot be used by daemon functions" - | RString n -> - pr " ret_v = 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 " 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 " ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n; - pr " ret_v = ret.%s.%s_val;\n" n n - | RStruct (n, _) -> - pr " /* caller will free this */\n"; - pr " ret_v = safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n - | RStructList (n, _) -> - pr " /* caller will free this */\n"; - pr " ret_v = safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n - | RBufferOut n -> - pr " /* RBufferOut is tricky: If the buffer is zero-length, then\n"; - pr " * _val might be NULL here. To make the API saner for\n"; - pr " * callers, we turn this case into a unique pointer (using\n"; - pr " * malloc(1)).\n"; - pr " */\n"; - pr " if (ret.%s.%s_len > 0) {\n" n n; - pr " *size_r = ret.%s.%s_len;\n" n n; - pr " ret_v = ret.%s.%s_val; /* caller will free */\n" n n; - pr " } else {\n"; - pr " free (ret.%s.%s_val);\n" n n; - pr " char *p = safe_malloc (g, 1);\n"; - pr " *size_r = ret.%s.%s_len;\n" n n; - pr " ret_v = p;\n"; - pr " }\n"; - ); - trace_return shortname style "ret_v"; - pr " return ret_v;\n"; - pr "}\n\n" + List.iter ( + fun f -> generate_daemon_stub f ) daemon_functions; (* Functions to free structures. *) @@ -1387,105 +1394,112 @@ trace_send_line (guestfs_h *g) ) structs; (* Functions which have optional arguments have two generated variants. *) - List.iter ( - function - | { style = _, _, [] } -> () - | { name = shortname; style = (ret, args, (_::_ as optargs) as style) } -> - let uc_shortname = String.uppercase shortname in + let generate_va_variants { name = shortname; + style = ret, args, optargs as style } + assert (optargs <> []); (* checked by caller *) - (* Get the name of the last regular argument. *) - let last_arg - match ret with - | RBufferOut _ -> "size_r" - | _ -> - match args with - | [] -> "g" - | args -> - let last = List.hd (List.rev args) in - let name = name_of_argt last in - match last with - | BufferIn n -> name ^ "_size" - | _ -> name - in - - let rtype - match ret with - | RErr | RInt _ | RBool _ -> "int " - | RInt64 _ -> "int64_t " - | RConstString _ | RConstOptString _ -> "const char *" - | RString _ | RBufferOut _ -> "char *" - | RStringList _ | RHashtable _ -> "char **" - | RStruct (_, typ) -> sprintf "struct guestfs_%s *" typ - | RStructList (_, typ) -> - sprintf "struct guestfs_%s_list *" typ in - - (* The regular variable args function, just calls the _va variant. *) - generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" shortname style; - pr "{\n"; - pr " va_list optargs;\n"; - pr "\n"; - pr " va_start (optargs, %s);\n" last_arg; - pr " %sr = guestfs_%s_va " rtype shortname; - generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; - pr ";\n"; - pr " va_end (optargs);\n"; - pr "\n"; - pr " return r;\n"; - pr "}\n\n"; - - generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA - shortname style; - pr "{\n"; - pr " struct guestfs_%s_argv optargs_s;\n" shortname; - pr " struct guestfs_%s_argv *optargs = &optargs_s;\n" shortname; - pr " int i;\n"; - pr "\n"; - pr " optargs_s.bitmask = 0;\n"; - pr "\n"; - pr " while ((i = va_arg (args, int)) >= 0) {\n"; - pr " switch (i) {\n"; - - List.iter ( - fun argt -> - let n = name_of_optargt argt in - let uc_n = String.uppercase n in - pr " case GUESTFS_%s_%s:\n" uc_shortname uc_n; - pr " optargs_s.%s = va_arg (args, " n; - (match argt with - | OBool _ | OInt _ -> pr "int" - | OInt64 _ -> pr "int64_t" - | OString _ -> pr "const char *" - ); - pr ");\n"; - pr " break;\n"; - ) optargs; + let uc_shortname = String.uppercase shortname in - let errcode - match errcode_of_ret ret with - | `CannotReturnError -> assert false - | (`ErrorIsMinusOne | `ErrorIsNULL) as e -> e in + (* Get the name of the last regular argument. *) + let last_arg + match ret with + | RBufferOut _ -> "size_r" + | _ -> + match args with + | [] -> "g" + | args -> + let last = List.hd (List.rev args) in + let name = name_of_argt last in + match last with + | BufferIn n -> name ^ "_size" + | _ -> name + in - pr " default:\n"; - pr " error (g, \"%%s: unknown option %%d (this can happen if a program is compiled against a newer version of libguestfs, then dynamically linked to an older version)\",\n"; - pr " \"%s\", i);\n" shortname; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr "\n"; - pr " uint64_t i_mask = UINT64_C(1) << i;\n"; - pr " if (optargs_s.bitmask & i_mask) {\n"; - pr " error (g, \"%%s: same optional argument specified more than once\",\n"; - pr " \"%s\");\n" shortname; - pr " return %s;\n" (string_of_errcode errcode); - pr " }\n"; - pr " optargs_s.bitmask |= i_mask;\n"; - pr " }\n"; - pr "\n"; - pr " return guestfs_%s_argv " shortname; - generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; - pr ";\n"; - pr "}\n\n" + let rtype + match ret with + | RErr | RInt _ | RBool _ -> "int " + | RInt64 _ -> "int64_t " + | RConstString _ | RConstOptString _ -> "const char *" + | RString _ | RBufferOut _ -> "char *" + | RStringList _ | RHashtable _ -> "char **" + | RStruct (_, typ) -> sprintf "struct guestfs_%s *" typ + | RStructList (_, typ) -> + sprintf "struct guestfs_%s_list *" typ in + + (* The regular variable args function, just calls the _va variant. *) + generate_prototype ~extern:false ~semicolon:false ~newline:true + ~handle:"g" ~prefix:"guestfs_" shortname style; + pr "{\n"; + pr " va_list optargs;\n"; + pr "\n"; + pr " va_start (optargs, %s);\n" last_arg; + pr " %sr = guestfs_%s_va " rtype shortname; + generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; + pr ";\n"; + pr " va_end (optargs);\n"; + pr "\n"; + pr " return r;\n"; + pr "}\n\n"; + + generate_prototype ~extern:false ~semicolon:false ~newline:true + ~handle:"g" ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA + shortname style; + pr "{\n"; + pr " struct guestfs_%s_argv optargs_s;\n" shortname; + pr " struct guestfs_%s_argv *optargs = &optargs_s;\n" shortname; + pr " int i;\n"; + pr "\n"; + pr " optargs_s.bitmask = 0;\n"; + pr "\n"; + pr " while ((i = va_arg (args, int)) >= 0) {\n"; + pr " switch (i) {\n"; + + List.iter ( + fun argt -> + let n = name_of_optargt argt in + let uc_n = String.uppercase n in + pr " case GUESTFS_%s_%s:\n" uc_shortname uc_n; + pr " optargs_s.%s = va_arg (args, " n; + (match argt with + | OBool _ | OInt _ -> pr "int" + | OInt64 _ -> pr "int64_t" + | OString _ -> pr "const char *" + ); + pr ");\n"; + pr " break;\n"; + ) optargs; + + let errcode + match errcode_of_ret ret with + | `CannotReturnError -> assert false + | (`ErrorIsMinusOne | `ErrorIsNULL) as e -> e in + + pr " default:\n"; + pr " error (g, \"%%s: unknown option %%d (this can happen if a program is compiled against a newer version of libguestfs, then dynamically linked to an older version)\",\n"; + pr " \"%s\", i);\n" shortname; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr "\n"; + pr " uint64_t i_mask = UINT64_C(1) << i;\n"; + pr " if (optargs_s.bitmask & i_mask) {\n"; + pr " error (g, \"%%s: same optional argument specified more than once\",\n"; + pr " \"%s\");\n" shortname; + pr " return %s;\n" (string_of_errcode errcode); + pr " }\n"; + pr " optargs_s.bitmask |= i_mask;\n"; + pr " }\n"; + pr "\n"; + pr " return guestfs_%s_argv " shortname; + generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; + pr ";\n"; + pr "}\n\n" + in + + List.iter ( + function + | { style = _, _, [] } -> () + | ({ style = _, _, (_::_) } as f) -> + generate_va_variants f ) all_functions_sorted (* Generate the linker script which controls the visibility of -- 1.7.10.4
Richard W.M. Jones
2012-Jul-14 13:28 UTC
[Libguestfs] [PATCH 2/6] generator: Allow non-optargs functions to gain optargs.
From: "Richard W.M. Jones" <rjones at redhat.com> This commit adds a flag (once_had_no_optargs) which can be used to add optargs to functions that currently don't have any. The idea is that if 'func' currently has no optargs, we can safely add optargs provided we are backwards compatible for existing callers. In C that means we leave 'guestfs_func' alone and provide an extra function 'guestfs_func_opts' that takes the optargs ('guestfs_func' becomes a wrapper that calls 'guestfs_func_opts'). In the C generator this means there are two names for each function (although the two names are normally identical). 'c_name' is the name that we export publicly (eg. [guestfs_] 'func_opts'). 'name' is the internal name of the function (eg. 'func') which is used for everything apart from the public interface, and also to generate the no-optargs compat function. In other languages that can add optional arguments safely, we simply add the arguments to the existing 'func', so for example in Perl: $g->func (required_args) $g->func (required_args, optional_args) can be used. Note that this commit does not cause any change to the output of the generator. I verified this by diffing the output before and after. --- generator/README | 4 + generator/generator_actions.ml | 20 +++- generator/generator_c.ml | 256 ++++++++++++++++++++++++---------------- generator/generator_checks.ml | 21 +++- generator/generator_types.ml | 7 +- 5 files changed, 196 insertions(+), 112 deletions(-) diff --git a/generator/README b/generator/README index f7dde11..afc58eb 100644 --- a/generator/README +++ b/generator/README @@ -48,3 +48,7 @@ backwards compatibility. You may add another optional argument, *if* the function has >= 1 optional arguments already. Add it at the end of the list. + +You may add optional arguments to a function that doesn't have any. +However you *must* set the once_had_no_optargs flag to true, so that +the relevant backwards compatibility bindings can be added. diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index c83bf70..97b0290 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -31,7 +31,8 @@ let defaults = { name = ""; style = RErr, [], []; proc_nr = None; deprecated_by = None; optional = None; progress = false; camel_name = ""; cancellable = false; config_only = false; - c_function = ""; c_optarg_prefix = "" } + once_had_no_optargs = false; + c_name = ""; c_function = ""; c_optarg_prefix = "" } (* These test functions are used in the language binding tests. *) @@ -9296,22 +9297,29 @@ Remove C<VAR> from the environment." }; (* Some post-processing of the basic lists of actions. *) -(* Add the name of the C function that non-C language bindings should - * call. Currently this is simply guestfs_<name> or - * guestfs_<name>_argv depending on whether the function has no - * optional args or some optional args. +(* Add the name of the C function: + * c_name = short name, used by C bindings so we know what to export + * c_function = full name that non-C bindings should call + * c_optarg_prefix = prefix for optarg / bitmask names *) let non_daemon_functions, daemon_functions let make_c_function f match f with | { style = _, _, [] } -> { f with + c_name = f.name; c_function = "guestfs_" ^ f.name; c_optarg_prefix = "GUESTFS_" ^ String.uppercase f.name } - | { style = _, _, (_::_) } -> + | { style = _, _, (_::_); once_had_no_optargs = false } -> { f with + c_name = f.name; c_function = "guestfs_" ^ f.name ^ "_argv"; c_optarg_prefix = "GUESTFS_" ^ String.uppercase f.name } + | { style = _, _, (_::_); once_had_no_optargs = true } -> + { f with + c_name = f.name ^ "_opts"; + c_function = "guestfs_" ^ f.name ^ "_opts_argv"; + c_optarg_prefix = "GUESTFS_" ^ String.uppercase f.name ^ "_OPTS" } in let non_daemon_functions = List.map make_c_function non_daemon_functions in let daemon_functions = List.map make_c_function daemon_functions in diff --git a/generator/generator_c.ml b/generator/generator_c.ml index 6f24bee..ebd252f 100644 --- a/generator/generator_c.ml +++ b/generator/generator_c.ml @@ -177,14 +177,18 @@ and generate_actions_pod () List.iter ( function | { in_docs = false } -> () - | ({ in_docs = true } as f) -> generate_actions_pod_entry f + | ({ in_docs = true; once_had_no_optargs = false } as f) -> + generate_actions_pod_entry f + | ({ in_docs = true; once_had_no_optargs = true } as f) -> + generate_actions_pod_back_compat_entry f; + generate_actions_pod_entry f ) all_functions_sorted -and generate_actions_pod_entry ({ name = shortname; +and generate_actions_pod_entry ({ c_name = c_name; style = ret, args, optargs as style } as f) - let name = "guestfs_" ^ shortname in - pr "=head2 %s\n\n" name; - generate_prototype ~extern:false ~indent:" " ~handle:"g" name style; + pr "=head2 guestfs_%s\n\n" c_name; + generate_prototype ~extern:false ~indent:" " ~handle:"g" + ~prefix:"guestfs_" c_name style; pr "\n\n"; (match deprecation_notice ~prefix:"guestfs_" f with @@ -192,7 +196,6 @@ and generate_actions_pod_entry ({ name = shortname; | Some txt -> pr "%s\n\n" txt ); - let uc_shortname = String.uppercase shortname in if optargs <> [] then ( pr "You may supply a list of optional arguments to this call.\n"; pr "Use zero or more of the following pairs of parameters,\n"; @@ -201,8 +204,7 @@ and generate_actions_pod_entry ({ name = shortname; List.iter ( fun argt -> let n = name_of_optargt argt in - let uc_n = String.uppercase n in - pr " GUESTFS_%s_%s, " uc_shortname uc_n; + pr " GUESTFS_%s_%s, " (String.uppercase c_name) (String.uppercase n); match argt with | OBool n -> pr "int %s,\n" n | OInt n -> pr "int %s,\n" n @@ -264,29 +266,47 @@ I<The caller must free the returned buffer after use>.\n\n" pr "This function takes a key or passphrase parameter which could contain sensitive material. Read the section L</KEYS AND PASSPHRASES> for more information.\n\n"; - (match lookup_api_version name with + (match lookup_api_version ("guestfs_" ^ c_name) with | Some version -> pr "(Added in %s)\n\n" version | None -> () ); (* Handling of optional argument variants. *) if optargs <> [] then ( - pr "=head2 %s_va\n\n" name; + pr "=head2 guestfs_%s_va\n\n" c_name; generate_prototype ~extern:false ~indent:" " ~handle:"g" ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA - shortname style; + c_name style; pr "\n\n"; - pr "This is the \"va_list variant\" of L</%s>.\n\n" name; + pr "This is the \"va_list variant\" of L</guestfs_%s>.\n\n" c_name; pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n"; - pr "=head2 %s_argv\n\n" name; + pr "=head2 guestfs_%s_argv\n\n" c_name; generate_prototype ~extern:false ~indent:" " ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv - shortname style; + c_name style; pr "\n\n"; - pr "This is the \"argv variant\" of L</%s>.\n\n" name; + pr "This is the \"argv variant\" of L</guestfs_%s>.\n\n" c_name; pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n"; ) +and generate_actions_pod_back_compat_entry { name = name; + style = ret, args, _ } + pr "= head2 guestfs_%s\n\n" name; + generate_prototype ~extern:false ~indent:" " ~handle:"g" + ~prefix:"guestfs_" name (ret, args, []); + pr "\n\n"; + + pr "This function is provided for backwards compatibility\n"; + pr "with earlier versions of libguestfs. It simply calls\n"; + pr "L</guestfs_%s_opts> with no optional arguments.\n" name; + pr "\n"; + + (match lookup_api_version ("guestfs_" ^ name) with + | Some version -> pr "(Added in %s)\n\n" version + | None -> () + ); + pr "\n" + and generate_structs_pod () (* Structs documentation. *) List.iter ( @@ -619,7 +639,17 @@ extern GUESTFS_DLL_PUBLIC void *guestfs_next_private (guestfs_h *g, const char * in List.iter ( - fun f -> generate_action_header f + fun ({ name = name; style = ret, args, _ } as f) -> + (* If once_had_no_optargs is set, then we need to generate a + * <name>_opts variant, plus a backwards-compatible wrapper + * called just <name> with no optargs. + *) + if f.once_had_no_optargs then ( + generate_action_header { f with style = ret, args, [] }; + generate_action_header { f with name = f.name ^ "_opts" }; + ) + else + generate_action_header f ) all_functions_sorted; pr "\ @@ -651,10 +681,10 @@ extern GUESTFS_DLL_PUBLIC int guestfs___for_each_disk (guestfs_h *g, virDomainPt and generate_internal_actions_h () generate_header CStyle LGPLv2plus; List.iter ( - fun { name = shortname; style = style } -> + fun { c_name = c_name; style = style } -> generate_prototype ~single_line:true ~newline:true ~handle:"g" ~prefix:"guestfs__" ~optarg_proto:Argv - shortname style + c_name style ) non_daemon_functions (* Generate the client-side dispatch stubs. *) @@ -772,7 +802,7 @@ trace_send_line (guestfs_h *g) (* Generate code to check String-like parameters are not passed in * as NULL (returning an error if they are). *) - let check_null_strings shortname (ret, args, optargs) + let check_null_strings c_name (ret, args, optargs) let pr_newline = ref false in List.iter ( function @@ -790,17 +820,17 @@ trace_send_line (guestfs_h *g) | Pointer (_, n) -> pr " if (%s == NULL) {\n" n; pr " error (g, \"%%s: %%s: parameter cannot be NULL\",\n"; - pr " \"%s\", \"%s\");\n" shortname n; + pr " \"%s\", \"%s\");\n" c_name n; let errcode match errcode_of_ret ret with | `CannotReturnError -> (* XXX hack *) - if shortname = "internal_test_rconstoptstring" then + if c_name = "internal_test_rconstoptstring" then `ErrorIsNULL else failwithf "%s: RConstOptString function has invalid parameter '%s'" - shortname n + c_name n | (`ErrorIsMinusOne |`ErrorIsNULL) as e -> e in pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; @@ -820,10 +850,10 @@ trace_send_line (guestfs_h *g) function | OString n -> pr " if ((optargs->bitmask & GUESTFS_%s_%s_BITMASK) &&\n" - (String.uppercase shortname) (String.uppercase n); + (String.uppercase c_name) (String.uppercase n); pr " optargs->%s == NULL) {\n" n; pr " error (g, \"%%s: %%s: optional parameter cannot be NULL\",\n"; - pr " \"%s\", \"%s\");\n" shortname n; + pr " \"%s\", \"%s\");\n" c_name n; let errcode match errcode_of_ret ret with | `CannotReturnError -> assert false @@ -840,14 +870,14 @@ trace_send_line (guestfs_h *g) in (* Generate code to reject optargs we don't know about. *) - let reject_unknown_optargs shortname = function + let reject_unknown_optargs c_name = function | _, _, [] -> () | ret, _, optargs -> let len = List.length optargs in let mask = Int64.lognot (Int64.pred (Int64.shift_left 1L len)) in pr " if (optargs->bitmask & UINT64_C(0x%Lx)) {\n" mask; pr " error (g, \"%%s: unknown option in guestfs_%%s_argv->bitmask (this can happen if a program is compiled against a newer version of libguestfs, then dynamically linked to an older version)\",\n"; - pr " \"%s\", \"%s\");\n" shortname shortname; + pr " \"%s\", \"%s\");\n" c_name c_name; let errcode match errcode_of_ret ret with | `CannotReturnError -> assert false @@ -858,7 +888,7 @@ trace_send_line (guestfs_h *g) in (* Generate code to generate guestfish call traces. *) - let trace_call shortname (ret, args, optargs) + let trace_call name c_name (ret, args, optargs) pr " if (trace_flag) {\n"; let needs_i @@ -872,7 +902,7 @@ trace_send_line (guestfs_h *g) pr " trace_fp = trace_open (g);\n"; - pr " fprintf (trace_fp, \"%%s\", \"%s\");\n" shortname; + pr " fprintf (trace_fp, \"%%s\", \"%s\");\n" name; (* Required arguments. *) List.iter ( @@ -917,10 +947,8 @@ trace_send_line (guestfs_h *g) List.iter ( fun argt -> let n = name_of_optargt argt in - let uc_shortname = String.uppercase shortname in - let uc_n = String.uppercase n in pr " if (optargs->bitmask & GUESTFS_%s_%s_BITMASK)\n" - uc_shortname uc_n; + (String.uppercase c_name) (String.uppercase n); (match argt with | OString n -> pr " fprintf (trace_fp, \" \\\"%%s:%%s\\\"\", \"%s\", optargs->%s);\n" n n @@ -938,7 +966,7 @@ trace_send_line (guestfs_h *g) pr "\n"; in - let trace_return ?(indent = 2) shortname (ret, _, _) rv + let trace_return ?(indent = 2) name (ret, _, _) rv let indent = spaces indent in pr "%sif (trace_flag) {\n" indent; @@ -954,7 +982,7 @@ trace_send_line (guestfs_h *g) pr "%s trace_fp = trace_open (g);\n" indent; - pr "%s fprintf (trace_fp, \"%%s = \", \"%s\");\n" indent shortname; + pr "%s fprintf (trace_fp, \"%%s = \", \"%s\");\n" indent name; (match ret with | RErr | RInt _ | RBool _ -> @@ -993,19 +1021,19 @@ trace_send_line (guestfs_h *g) pr "\n"; in - let trace_return_error ?(indent = 2) shortname (ret, _, _) errcode + let trace_return_error ?(indent = 2) name (ret, _, _) errcode let indent = spaces indent in pr "%sif (trace_flag)\n" indent; pr "%s guestfs___trace (g, \"%%s = %%s (error)\",\n" indent; pr "%s \"%s\", \"%s\");\n" - indent shortname (string_of_errcode errcode) + indent name (string_of_errcode errcode) in - let handle_null_optargs optargs shortname + let handle_null_optargs optargs c_name if optargs <> [] then ( - pr " struct guestfs_%s_argv optargs_null;\n" shortname; + pr " struct guestfs_%s_argv optargs_null;\n" c_name; pr " if (!optargs) {\n"; pr " optargs_null.bitmask = 0;\n"; pr " optargs = &optargs_null;\n"; @@ -1014,20 +1042,20 @@ trace_send_line (guestfs_h *g) in (* For non-daemon functions, generate a wrapper around each function. *) - let generate_non_daemon_wrapper { name = shortname; + let generate_non_daemon_wrapper { name = name; c_name = c_name; style = ret, _, optargs as style; config_only = config_only } if optargs = [] then generate_prototype ~extern:false ~semicolon:false ~newline:true ~handle:"g" ~prefix:"guestfs_" - shortname style + c_name style else generate_prototype ~extern:false ~semicolon:false ~newline:true ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv - shortname style; + c_name style; pr "{\n"; - handle_null_optargs optargs shortname; + handle_null_optargs optargs c_name; pr " int trace_flag = g->trace;\n"; pr " FILE *trace_fp;\n"; @@ -1053,27 +1081,27 @@ trace_send_line (guestfs_h *g) if config_only then ( pr " if (g->state != CONFIG) {\n"; pr " error (g, \"%%s: this function can only be called in the config state\",\n"; - pr " \"%s\");\n" shortname; + pr " \"%s\");\n" c_name; pr " return -1;\n"; pr " }\n"; ); - enter_event shortname; - check_null_strings shortname style; - reject_unknown_optargs shortname style; - trace_call shortname style; - pr " r = guestfs__%s " shortname; + enter_event name; + check_null_strings c_name style; + reject_unknown_optargs c_name style; + trace_call name c_name style; + pr " r = guestfs__%s " c_name; generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; pr ";\n"; pr "\n"; (match errcode_of_ret ret with | (`ErrorIsMinusOne | `ErrorIsNULL) as errcode -> pr " if (r != %s) {\n" (string_of_errcode errcode); - trace_return ~indent:4 shortname style "r"; + trace_return ~indent:4 name style "r"; pr " } else {\n"; - trace_return_error ~indent:4 shortname style errcode; + trace_return_error ~indent:4 name style errcode; pr " }\n"; | `CannotReturnError -> - trace_return shortname style "r"; + trace_return name style "r"; ); pr "\n"; pr " return r;\n"; @@ -1086,9 +1114,8 @@ trace_send_line (guestfs_h *g) ) non_daemon_functions; (* Client-side stubs for each function. *) - let generate_daemon_stub { name = shortname; + let generate_daemon_stub { name = name; c_name = c_name; style = ret, args, optargs as style } - let name = "guestfs_" ^ shortname in let errcode match errcode_of_ret ret with | `CannotReturnError -> assert false @@ -1097,19 +1124,19 @@ trace_send_line (guestfs_h *g) (* Generate the action stub. *) if optargs = [] then generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" shortname style + ~handle:"g" ~prefix:"guestfs_" c_name style else generate_prototype ~extern:false ~semicolon:false ~newline:true ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" - ~optarg_proto:Argv shortname style; + ~optarg_proto:Argv c_name style; pr "{\n"; - handle_null_optargs optargs shortname; + handle_null_optargs optargs c_name; (match args with | [] -> () - | _ -> pr " struct %s_args args;\n" name + | _ -> pr " struct guestfs_%s_args args;\n" name ); pr " guestfs_message_header hdr;\n"; @@ -1123,7 +1150,7 @@ trace_send_line (guestfs_h *g) | RBool _ | RString _ | RStringList _ | RStruct _ | RStructList _ | RHashtable _ | RBufferOut _ -> - pr " struct %s_ret ret;\n" name; + pr " struct guestfs_%s_ret ret;\n" name; true in pr " int serial;\n"; @@ -1149,10 +1176,10 @@ trace_send_line (guestfs_h *g) pr " const uint64_t progress_hint = 0;\n"; pr "\n"; - enter_event shortname; - check_null_strings shortname style; - reject_unknown_optargs shortname style; - trace_call shortname style; + enter_event name; + check_null_strings c_name style; + reject_unknown_optargs c_name style; + trace_call name c_name style; (* Calculate the total size of all FileIn arguments to pass * as a progress bar hint. @@ -1168,8 +1195,8 @@ trace_send_line (guestfs_h *g) ) args; (* This is a daemon_function so check the appliance is up. *) - pr " if (check_appliance_up (g, \"%s\") == -1) {\n" shortname; - trace_return_error ~indent:4 shortname style errcode; + pr " if (check_appliance_up (g, \"%s\") == -1) {\n" name; + trace_return_error ~indent:4 name style errcode; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr "\n"; @@ -1177,7 +1204,7 @@ trace_send_line (guestfs_h *g) (* Send the main header and arguments. *) if args = [] && optargs = [] then ( pr " serial = guestfs___send (g, GUESTFS_PROC_%s, progress_hint, 0,\n" - (String.uppercase shortname); + (String.uppercase name); pr " NULL, NULL);\n" ) else ( List.iter ( @@ -1199,9 +1226,9 @@ trace_send_line (guestfs_h *g) | BufferIn n -> pr " /* Just catch grossly large sizes. XDR encoding will make this precise. */\n"; pr " if (%s_size >= GUESTFS_MESSAGE_MAX) {\n" n; - trace_return_error ~indent:4 shortname style errcode; + trace_return_error ~indent:4 name style errcode; pr " error (g, \"%%s: size of input buffer too large\", \"%s\");\n" - shortname; + name; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr " args.%s.%s_val = (char *) %s;\n" n n n; @@ -1212,10 +1239,8 @@ trace_send_line (guestfs_h *g) List.iter ( fun argt -> let n = name_of_optargt argt in - let uc_shortname = String.uppercase shortname in - let uc_n = String.uppercase n in pr " if (optargs->bitmask & GUESTFS_%s_%s_BITMASK)\n" - uc_shortname uc_n; + (String.uppercase c_name) (String.uppercase n); (match argt with | OBool n | OInt n @@ -1231,14 +1256,14 @@ trace_send_line (guestfs_h *g) ) optargs; pr " serial = guestfs___send (g, GUESTFS_PROC_%s,\n" - (String.uppercase shortname); + (String.uppercase name); pr " progress_hint, %s,\n" (if optargs <> [] then "optargs->bitmask" else "0"); - pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n" + pr " (xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n" name; ); pr " if (serial == -1) {\n"; - trace_return_error ~indent:4 shortname style errcode; + trace_return_error ~indent:4 name style errcode; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr "\n"; @@ -1250,9 +1275,9 @@ trace_send_line (guestfs_h *g) | FileIn n -> pr " r = guestfs___send_file (g, %s);\n" n; pr " if (r == -1) {\n"; - trace_return_error ~indent:4 shortname style errcode; + trace_return_error ~indent:4 name style errcode; pr " /* daemon will send an error reply which we discard */\n"; - pr " guestfs___recv_discard (g, \"%s\");\n" shortname; + pr " guestfs___recv_discard (g, \"%s\");\n" name; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr " if (r == -2) /* daemon cancelled */\n"; @@ -1268,37 +1293,37 @@ trace_send_line (guestfs_h *g) pr " memset (&err, 0, sizeof err);\n"; if has_ret then pr " memset (&ret, 0, sizeof ret);\n"; pr "\n"; - pr " r = guestfs___recv (g, \"%s\", &hdr, &err,\n " shortname; + pr " r = guestfs___recv (g, \"%s\", &hdr, &err,\n " name; if not has_ret then pr "NULL, NULL" else - pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname; + pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" name; pr ");\n"; pr " if (r == -1) {\n"; - trace_return_error ~indent:4 shortname style errcode; + trace_return_error ~indent:4 name style errcode; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr "\n"; pr " if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n" - (String.uppercase shortname); - trace_return_error ~indent:4 shortname style errcode; + (String.uppercase name); + trace_return_error ~indent:4 name style errcode; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr "\n"; pr " if (hdr.status == GUESTFS_STATUS_ERROR) {\n"; - trace_return_error ~indent:4 shortname style errcode; + trace_return_error ~indent:4 name style errcode; pr " int errnum = 0;\n"; pr " if (err.errno_string[0] != '\\0')\n"; pr " errnum = guestfs___string_to_errno (err.errno_string);\n"; pr " if (errnum <= 0)\n"; pr " error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" - shortname; + name; pr " else\n"; pr " guestfs_error_errno (g, errnum, \"%%s: %%s\", \"%s\",\n" - shortname; + name; pr " err.error_message);\n"; pr " free (err.error_message);\n"; pr " free (err.errno_string);\n"; @@ -1311,7 +1336,7 @@ trace_send_line (guestfs_h *g) function | FileOut n -> pr " if (guestfs___recv_file (g, %s) == -1) {\n" n; - trace_return_error ~indent:4 shortname style errcode; + trace_return_error ~indent:4 name style errcode; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr "\n"; @@ -1357,7 +1382,7 @@ trace_send_line (guestfs_h *g) pr " ret_v = p;\n"; pr " }\n"; ); - trace_return shortname style "ret_v"; + trace_return name style "ret_v"; pr " return ret_v;\n"; pr "}\n\n" in @@ -1393,13 +1418,13 @@ trace_send_line (guestfs_h *g) ) structs; - (* Functions which have optional arguments have two generated variants. *) - let generate_va_variants { name = shortname; + (* Functions which have optional arguments have two or three + * generated variants. + *) + let generate_va_variants { name = name; c_name = c_name; style = ret, args, optargs as style } assert (optargs <> []); (* checked by caller *) - let uc_shortname = String.uppercase shortname in - (* Get the name of the last regular argument. *) let last_arg match ret with @@ -1428,12 +1453,12 @@ trace_send_line (guestfs_h *g) (* The regular variable args function, just calls the _va variant. *) generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" shortname style; + ~handle:"g" ~prefix:"guestfs_" c_name style; pr "{\n"; pr " va_list optargs;\n"; pr "\n"; pr " va_start (optargs, %s);\n" last_arg; - pr " %sr = guestfs_%s_va " rtype shortname; + pr " %sr = guestfs_%s_va " rtype c_name; generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; pr ";\n"; pr " va_end (optargs);\n"; @@ -1443,10 +1468,10 @@ trace_send_line (guestfs_h *g) generate_prototype ~extern:false ~semicolon:false ~newline:true ~handle:"g" ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA - shortname style; + c_name style; pr "{\n"; - pr " struct guestfs_%s_argv optargs_s;\n" shortname; - pr " struct guestfs_%s_argv *optargs = &optargs_s;\n" shortname; + pr " struct guestfs_%s_argv optargs_s;\n" c_name; + pr " struct guestfs_%s_argv *optargs = &optargs_s;\n" c_name; pr " int i;\n"; pr "\n"; pr " optargs_s.bitmask = 0;\n"; @@ -1457,8 +1482,8 @@ trace_send_line (guestfs_h *g) List.iter ( fun argt -> let n = name_of_optargt argt in - let uc_n = String.uppercase n in - pr " case GUESTFS_%s_%s:\n" uc_shortname uc_n; + pr " case GUESTFS_%s_%s:\n" + (String.uppercase c_name) (String.uppercase n); pr " optargs_s.%s = va_arg (args, " n; (match argt with | OBool _ | OInt _ -> pr "int" @@ -1476,30 +1501,48 @@ trace_send_line (guestfs_h *g) pr " default:\n"; pr " error (g, \"%%s: unknown option %%d (this can happen if a program is compiled against a newer version of libguestfs, then dynamically linked to an older version)\",\n"; - pr " \"%s\", i);\n" shortname; + pr " \"%s\", i);\n" name; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr "\n"; pr " uint64_t i_mask = UINT64_C(1) << i;\n"; pr " if (optargs_s.bitmask & i_mask) {\n"; pr " error (g, \"%%s: same optional argument specified more than once\",\n"; - pr " \"%s\");\n" shortname; + pr " \"%s\");\n" name; pr " return %s;\n" (string_of_errcode errcode); pr " }\n"; pr " optargs_s.bitmask |= i_mask;\n"; pr " }\n"; pr "\n"; - pr " return guestfs_%s_argv " shortname; + pr " return guestfs_%s_argv " c_name; generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; pr ";\n"; pr "}\n\n" + + and generate_back_compat_wrapper { name = name; + style = ret, args, _ as style } + generate_prototype ~extern:false ~semicolon:false ~newline:true + ~handle:"g" ~prefix:"guestfs_" + name (ret, args, []); + pr "{\n"; + pr " struct guestfs_%s_opts_argv optargs_s = { .bitmask = 0 };\n" name; + pr " struct guestfs_%s_opts_argv *optargs = &optargs_s;\n" name; + pr "\n"; + pr " return guestfs_%s_opts_argv " name; + generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style; + pr ";\n"; + pr "}\n"; + pr "\n" in List.iter ( function | { style = _, _, [] } -> () - | ({ style = _, _, (_::_) } as f) -> + | ({ style = _, _, (_::_); once_had_no_optargs = false } as f) -> generate_va_variants f + | ({ style = _, _, (_::_); once_had_no_optargs = true } as f) -> + generate_va_variants f; + generate_back_compat_wrapper f ) all_functions_sorted (* Generate the linker script which controls the visibility of @@ -1545,11 +1588,18 @@ and generate_linker_script () List.flatten ( List.map ( function - | { name = name; style = _, _, [] } -> ["guestfs_" ^ name] - | { name = name } -> + | { c_name = c_name; style = _, _, [] } -> ["guestfs_" ^ c_name] + | { c_name = c_name; style = _, _, (_::_); + once_had_no_optargs = false } -> + ["guestfs_" ^ c_name; + "guestfs_" ^ c_name ^ "_va"; + "guestfs_" ^ c_name ^ "_argv"] + | { name = name; c_name = c_name; style = _, _, (_::_); + once_had_no_optargs = true } -> ["guestfs_" ^ name; - "guestfs_" ^ name ^ "_va"; - "guestfs_" ^ name ^ "_argv"] + "guestfs_" ^ c_name; + "guestfs_" ^ c_name ^ "_va"; + "guestfs_" ^ c_name ^ "_argv"] ) all_functions ) in let structs diff --git a/generator/generator_checks.ml b/generator/generator_checks.ml index b48a598..b40aab4 100644 --- a/generator/generator_checks.ml +++ b/generator/generator_checks.ml @@ -40,7 +40,9 @@ let () (* Check function names. *) List.iter ( fun { name = name } -> - if String.length name >= 7 && String.sub name 0 7 = "guestfs" then + let len = String.length name in + + if len >= 7 && String.sub name 0 7 = "guestfs" then failwithf "function name %s does not need 'guestfs' prefix" name; if name = "" then failwithf "function name is empty"; @@ -48,7 +50,14 @@ let () failwithf "function name %s must start with lowercase a-z" name; if String.contains name '-' then failwithf "function name %s should not contain '-', use '_' instead." - name + name; +(* + (* Functions mustn't be named '_opts' since that is reserved for + * backwards compatibility functions. + *) + if len >= 5 && String.sub name (len-5) 5 = "_opts" then + failwithf "function name %s cannot end with _opts" name +*) ) (all_functions @ fish_commands); (* Check function parameter/return names. *) @@ -243,6 +252,14 @@ let () | { config_only = false } -> () ) (daemon_functions @ fish_commands); + (* once_had_no_optargs can only apply if the function now has optargs. *) + List.iter ( + function + | { name = name; once_had_no_optargs = true; style = _, _, [] } -> + failwithf "%s cannot have once_had_no_optargs flag and no optargs" name + | { once_had_no_optargs = false } | { style = _, _, (_::_) } -> () + ) all_functions; + (* Check tests. *) List.iter ( function diff --git a/generator/generator_types.ml b/generator/generator_types.ml index bd1d759..ce7aea3 100644 --- a/generator/generator_types.ml +++ b/generator/generator_types.ml @@ -408,11 +408,16 @@ type action = { function *) config_only : bool; (* non-daemon-function which can only be used while in CONFIG state *) + once_had_no_optargs : bool; (* mark functions that once had no optargs + but now do, so we can generate the + required back-compat machinery *) (* "Internal" data attached by the generator at various stages. This * doesn't need to (and shouldn't) be set when defining actions. *) - c_function : string; (* name of C API function *) + c_name : string; (* shortname exposed by C API *) + c_function : string; (* full name of C API function called by + non-C bindings *) c_optarg_prefix : string; (* prefix for optarg names/bitmask names *) } -- 1.7.10.4
Richard W.M. Jones
2012-Jul-14 13:28 UTC
[Libguestfs] [PATCH 3/6] generator: In non-C bindings, generate '*_opts' alias.
From: "Richard W.M. Jones" <rjones at redhat.com> In C, a function called 'func' which has once_had_no_optargs=true will (because of the previous commit) generate 'func_opts' and a backwards-compatibility function called 'func'. This commit changes some of the non-C bindings so that they also generate 'func_opts' which is merely a wrapper that calls 'func'. This avoids incompatibility when we rename 'mkfs_opts' etc back to plain 'mkfs', and it also makes it easier to translate between other language bindings and C code. NB: Some bindings do not include aliases: PHP: There's no way to easily alias methods in PHP < 5.3, and we can't assume everyone has this minimum version. GObject: Very complex to add aliases, but we should probably do this at some point. Haskell: No support for optargs in these bindings. Unfortunately this means that we can no longer bind 'Guestfs.add_drive' (since it will be changed to add optional arguments) making the Haskell bindings even less useful than they were already. --- generator/generator_actions.ml | 6 +++-- generator/generator_csharp.ml | 20 ++++++++++++--- generator/generator_erlang.ml | 54 +++++++++++++++++++++++++++++++++++----- generator/generator_fish.ml | 28 +++++++++++++++------ generator/generator_java.ml | 48 ++++++++++++++++++++++++++++++++++- generator/generator_ocaml.ml | 38 +++++++++++++++++++++------- generator/generator_perl.ml | 36 +++++++++++++++++++++++++-- generator/generator_python.ml | 8 +++++- generator/generator_ruby.ml | 12 +++++++-- generator/generator_types.ml | 2 ++ 10 files changed, 218 insertions(+), 34 deletions(-) diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 97b0290..0073c45 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -32,7 +32,8 @@ let defaults = { name = ""; style = RErr, [], []; proc_nr = None; progress = false; camel_name = ""; cancellable = false; config_only = false; once_had_no_optargs = false; - c_name = ""; c_function = ""; c_optarg_prefix = "" } + c_name = ""; c_function = ""; c_optarg_prefix = ""; + non_c_aliases = [] } (* These test functions are used in the language binding tests. *) @@ -9319,7 +9320,8 @@ let non_daemon_functions, daemon_functions { f with c_name = f.name ^ "_opts"; c_function = "guestfs_" ^ f.name ^ "_opts_argv"; - c_optarg_prefix = "GUESTFS_" ^ String.uppercase f.name ^ "_OPTS" } + c_optarg_prefix = "GUESTFS_" ^ String.uppercase f.name ^ "_OPTS"; + non_c_aliases = [ f.name ^ "_opts" ] } in let non_daemon_functions = List.map make_c_function non_daemon_functions in let daemon_functions = List.map make_c_function daemon_functions in diff --git a/generator/generator_csharp.ml b/generator/generator_csharp.ml index 70b9a8d..e1a31cf 100644 --- a/generator/generator_csharp.ml +++ b/generator/generator_csharp.ml @@ -136,7 +136,7 @@ namespace Guestfs (* Generate C# function bindings. *) List.iter ( fun { name = name; style = ret, args, optargs; c_function = c_function; - shortdesc = shortdesc } -> + shortdesc = shortdesc; non_c_aliases = non_c_aliases } -> let rec csharp_return_type () match ret with | RErr -> "void" @@ -204,7 +204,7 @@ namespace Guestfs if optargs <> [] then pr ", void *"; pr ");\n" - and generate_public_prototype () + and generate_public_prototype name pr " public %s %s (" (csharp_return_type ()) name; let comma = ref false in let next () @@ -237,15 +237,27 @@ namespace Guestfs *) if optargs <> [] then pr ", NULL"; pr ");\n"; + + and generate_alias alias + generate_public_prototype alias; + pr " {\n"; + (match ret with + | RErr -> pr " "; + | _ -> pr " return " + ); + pr "%s (%s);\n" name (String.concat ", " (List.map name_of_argt args)); + pr " }\n"; + pr "\n"; in pr " [DllImport (\"%s\")]\n" library; generate_extern_prototype (); pr "\n"; + pr " /// <summary>\n"; pr " /// %s\n" shortdesc; pr " /// </summary>\n"; - generate_public_prototype (); + generate_public_prototype name; pr " {\n"; pr " %s r;\n" (c_return_type ()); pr " r = "; @@ -268,6 +280,8 @@ namespace Guestfs ); pr " }\n"; pr "\n"; + + List.iter generate_alias non_c_aliases ) all_functions_sorted; pr " } diff --git a/generator/generator_erlang.ml b/generator/generator_erlang.ml index 083b573..3c2c04d 100644 --- a/generator/generator_erlang.ml +++ b/generator/generator_erlang.ml @@ -40,12 +40,16 @@ let rec generate_erlang_erl () (* Export the public actions. *) List.iter ( - fun { name = name; style = _, args, optargs } -> + fun { name = name; style = _, args, optargs; non_c_aliases = aliases } -> let nr_args = List.length args in - if optargs = [] then - pr "-export([%s/%d]).\n" name (nr_args+1) - else - pr "-export([%s/%d, %s/%d]).\n" name (nr_args+1) name (nr_args+2) + let export name + if optargs = [] then + pr "-export([%s/%d]).\n" name (nr_args+1) + else + pr "-export([%s/%d, %s/%d]).\n" name (nr_args+1) name (nr_args+2) + in + export name; + List.iter export aliases ) all_functions_sorted; pr "\n"; @@ -95,7 +99,7 @@ loop(Port) -> * process which dispatches them to the port. *) List.iter ( - fun { name = name; style = _, args, optargs } -> + fun { name = name; style = _, args, optargs; non_c_aliases = aliases } -> pr "%s(G" name; List.iter ( fun arg -> @@ -135,6 +139,44 @@ loop(Port) -> pr ").\n" ); + (* Aliases. *) + List.iter ( + fun alias -> + pr "%s(G" alias; + List.iter ( + fun arg -> + pr ", %s" (String.capitalize (name_of_argt arg)) + ) args; + if optargs <> [] then + pr ", Optargs"; + pr ") ->\n"; + + pr " %s(G" name; + List.iter ( + fun arg -> + pr ", %s" (String.capitalize (name_of_argt arg)) + ) args; + if optargs <> [] then + pr ", Optargs"; + pr ").\n"; + + if optargs <> [] then ( + pr "%s(G" alias; + List.iter ( + fun arg -> + pr ", %s" (String.capitalize (name_of_argt arg)) + ) args; + pr ") ->\n"; + + pr " %s(G" name; + List.iter ( + fun arg -> + pr ", %s" (String.capitalize (name_of_argt arg)) + ) args; + pr ").\n" + ) + ) aliases; + pr "\n" ) all_functions_sorted diff --git a/generator/generator_fish.ml b/generator/generator_fish.ml index 12e2acd..aba46e9 100644 --- a/generator/generator_fish.ml +++ b/generator/generator_fish.ml @@ -37,6 +37,11 @@ let doc_opttype_of = function | OInt64 n -> "N" | OString n -> ".." +let get_aliases { fish_alias = fish_alias; non_c_aliases = non_c_aliases } + let non_c_aliases + List.map (fun n -> replace_char n '_' '-') non_c_aliases in + fish_alias @ non_c_aliases + (* Generate a lot of different functions for guestfish. *) let generate_fish_cmds () generate_header CStyle GPLv2plus; @@ -84,8 +89,9 @@ let generate_fish_cmds () (* List of command_entry structs. *) List.iter ( - fun { name = name; fish_alias = aliases; shortdesc = shortdesc; - longdesc = longdesc } -> + fun ({ name = name; shortdesc = shortdesc; longdesc = longdesc } as f) -> + let aliases = get_aliases f in + let name2 = replace_char name '_' '-' in let describe_alias if aliases <> [] then @@ -109,8 +115,10 @@ let generate_fish_cmds () ) fish_commands; List.iter ( - fun ({ name = name; style = _, args, optargs; fish_alias = aliases; + fun ({ name = name; style = _, args, optargs; shortdesc = shortdesc; longdesc = longdesc } as f) -> + let aliases = get_aliases f in + let name2 = replace_char name '_' '-' in let longdesc = replace_str longdesc "C<guestfs_" "C<" in @@ -694,7 +702,8 @@ struct command_table; "; List.iter ( - fun { name = name; fish_alias = aliases } -> + fun ({ name = name } as f) -> + let aliases = get_aliases f in let name2 = replace_char name '_' '-' in (* The basic command. *) @@ -742,7 +751,8 @@ static const char *const commands[] = { *) let commands List.map ( - fun { name = name; fish_alias = aliases } -> + fun ({ name = name } as f) -> + let aliases = get_aliases f in let name2 = replace_char name '_' '-' in name2 :: aliases ) (all_functions @ fish_commands) in @@ -813,8 +823,9 @@ and generate_fish_actions_pod () let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in List.iter ( - fun ({ name = name; style = _, args, optargs; fish_alias = aliases; - longdesc = longdesc } as f) -> + fun ({ name = name; style = _, args, optargs; longdesc = longdesc } as f) -> + let aliases = get_aliases f in + let longdesc Str.global_substitute rex ( fun s -> @@ -876,7 +887,8 @@ Guestfish will prompt for these separately.\n\n"; (* Generate documentation for guestfish-only commands. *) and generate_fish_commands_pod () List.iter ( - fun { name = name; fish_alias = aliases; longdesc = longdesc } -> + fun ({ name = name; longdesc = longdesc } as f) -> + let aliases = get_aliases f in let name = replace_char name '_' '-' in List.iter ( diff --git a/generator/generator_java.ml b/generator/generator_java.ml index 62a1775..d239e1f 100644 --- a/generator/generator_java.ml +++ b/generator/generator_java.ml @@ -95,7 +95,7 @@ public class GuestFS { List.iter ( fun ({ name = name; style = (ret, args, optargs as style); in_docs = in_docs; shortdesc = shortdesc; - longdesc = longdesc } as f) -> + longdesc = longdesc; non_c_aliases = non_c_aliases } as f) -> if in_docs then ( let doc = replace_str longdesc "C<guestfs_" "C<g." in let doc @@ -200,6 +200,52 @@ public class GuestFS { pr "\n" ); + (* Aliases. *) + List.iter ( + fun alias -> + pr " "; + generate_java_prototype ~public:true ~semicolon:false alias style; + pr "\n"; + pr " {\n"; + (match ret with + | RErr -> pr " " + | _ -> pr " return " + ); + pr "%s (" name; + let needs_comma = ref false in + List.iter ( + fun arg -> + if !needs_comma then pr ", "; + needs_comma := true; + pr "%s" (name_of_argt arg) + ) args; + if optargs <> [] then ( + if !needs_comma then pr ", "; + needs_comma := true; + pr "optargs" + ); + pr ");\n"; + pr " }\n"; + pr "\n"; + + if optargs <> [] then ( + pr " "; + generate_java_prototype ~public:true ~semicolon:false + alias (ret, args, []); + pr "\n"; + pr " {\n"; + (match ret with + | RErr -> pr " " + | _ -> pr " return " + ); + pr "%s (" name; + List.iter (fun arg -> pr "%s, " (name_of_argt arg)) args; + pr "null);\n"; + pr " }\n"; + pr "\n" + ) + ) non_c_aliases; + (* Prototype for the native method. *) pr " "; generate_java_prototype ~privat:true ~native:true name style; diff --git a/generator/generator_ocaml.ml b/generator/generator_ocaml.ml index f54ed2c..392f9cb 100644 --- a/generator/generator_ocaml.ml +++ b/generator/generator_ocaml.ml @@ -125,6 +125,7 @@ val user_cancel : t -> unit (* The actions. *) List.iter ( fun { name = name; style = style; deprecated_by = deprecated_by; + non_c_aliases = non_c_aliases; in_docs = in_docs; shortdesc = shortdesc } -> generate_ocaml_prototype name style; @@ -137,7 +138,14 @@ val user_cancel : t -> unit ); pr " *)\n"; ); - pr "\n" + pr "\n"; + + (* Aliases. *) + List.iter ( + fun alias -> + generate_ocaml_prototype alias style; + pr "\n"; + ) non_c_aliases; ) all_functions_sorted; pr "\ @@ -173,15 +181,22 @@ class guestfs : unit -> object "; List.iter ( - function - | { name = name; style = ((_, [], _) as style) } -> + fun { name = name; style = style; non_c_aliases = non_c_aliases } -> + (match style with + | _, [], _ -> pr " method %s : " name; generate_ocaml_function_type ~extra_unit:true style; pr "\n" - | { name = name; style = style } -> + | _, (_::_), _ -> pr " method %s : " name; generate_ocaml_function_type style; pr "\n" + ); + List.iter (fun alias -> + pr " method %s : " alias; + generate_ocaml_function_type style; + pr "\n" + ) non_c_aliases ) all_functions_sorted; pr "end\n" @@ -243,15 +258,16 @@ let () (* The actions. *) List.iter ( - fun { name = name; style = style } -> + fun { name = name; style = style; non_c_aliases = non_c_aliases } -> generate_ocaml_prototype ~is_external:true name style; + List.iter (fun alias -> pr "let %s = %s\n" alias name) non_c_aliases ) all_functions_sorted; (* OO API. *) pr " class guestfs () let g = create () in - object + object (self) method close () = close g method set_event_callback = set_event_callback g method delete_event_callback = delete_event_callback g @@ -261,15 +277,19 @@ class guestfs () "; List.iter ( - function - | { name = name; style = _, [], optargs } -> + fun { name = name; style = style; non_c_aliases = non_c_aliases } -> + (match style with + | _, [], optargs -> (* No required params? Add explicit unit. *) let optargs String.concat "" (List.map (fun arg -> " ?" ^ name_of_optargt arg) optargs) in pr " method %s%s () = %s g%s\n" name optargs name optargs - | { name = name } -> + | _, (_::_), _ -> pr " method %s = %s g\n" name name + ); + List.iter + (fun alias -> pr " method %s = self#%s\n" alias name) non_c_aliases ) all_functions_sorted; pr " end\n" diff --git a/generator/generator_perl.ml b/generator/generator_perl.ml index d5cf814..b363bfc 100644 --- a/generator/generator_perl.ml +++ b/generator/generator_perl.ml @@ -797,7 +797,7 @@ handlers and threads. function | { in_docs = false } -> () | ({ name = name; style = style; in_docs = true; - longdesc = longdesc } as f) -> + longdesc = longdesc; non_c_aliases = non_c_aliases } as f) -> let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in pr "=item "; generate_perl_prototype name style; @@ -805,9 +805,28 @@ handlers and threads. pr "%s\n\n" longdesc; if f.protocol_limit_warning then pr "%s\n\n" protocol_limit_warning; - match deprecation_notice f with + (match deprecation_notice f with | None -> () | Some txt -> pr "%s\n\n" txt + ); + + (* Aliases. *) + List.iter ( + fun alias -> + pr "=item "; + generate_perl_prototype alias style; + pr "\n"; + pr "\n"; + pr "This is an alias of L</%s>.\n" name; + pr "\n"; + pr "=cut\n\n"; + pr "sub %s {\n" alias; + pr " &%s (@_)\n" name; + pr "}\n"; + pr "\n"; + pr "=pod\n"; + pr "\n"; + ) non_c_aliases ) all_functions_sorted; pr "=cut\n\n"; @@ -873,6 +892,19 @@ handlers and threads. ) all_functions_sorted; pr ");\n\n"; + pr "# Add aliases to the introspection hash.\n"; + let i = ref 0 in + List.iter ( + fun { name = name; non_c_aliases = non_c_aliases } -> + List.iter ( + fun alias -> + pr "my %%ielem%d = %%{$guestfs_introspection{%s}};\n" !i name; + pr "$guestfs_introspection{%s} = \\%%ielem%d;\n" alias !i; + incr i + ) non_c_aliases + ) all_functions_sorted; + pr "\n"; + (* End of file. *) pr "\ 1; diff --git a/generator/generator_python.ml b/generator/generator_python.ml index 548094c..dda0414 100644 --- a/generator/generator_python.ml +++ b/generator/generator_python.ml @@ -695,7 +695,7 @@ class GuestFS: List.iter ( fun ({ name = name; style = ret, args, optargs; in_docs = in_docs; - longdesc = longdesc } as f) -> + longdesc = longdesc; non_c_aliases = non_c_aliases } as f) -> pr " def %s (self" name; List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args; List.iter ( @@ -750,4 +750,10 @@ class GuestFS: List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (args @ args_of_optargs optargs); pr ")\n\n"; + + (* Aliases. *) + List.iter ( + fun alias -> + pr " %s = %s\n\n" alias name + ) non_c_aliases ) all_functions diff --git a/generator/generator_ruby.ml b/generator/generator_ruby.ml index f82d90c..7ab2177 100644 --- a/generator/generator_ruby.ml +++ b/generator/generator_ruby.ml @@ -633,10 +633,18 @@ void Init__guestfs () (* Methods. *) List.iter ( - fun { name = name; style = _, args, optargs } -> + fun { name = name; style = _, args, optargs; + non_c_aliases = non_c_aliases } -> let nr_args = List.length args + if optargs <> [] then 1 else 0 in pr " rb_define_method (c_guestfs, \"%s\",\n" name; - pr " ruby_guestfs_%s, %d);\n" name nr_args + pr " ruby_guestfs_%s, %d);\n" name nr_args; + + (* Aliases. *) + List.iter ( + fun alias -> + pr " rb_define_method (c_guestfs, \"%s\",\n" alias; + pr " ruby_guestfs_%s, %d);\n" name nr_args + ) non_c_aliases ) all_functions; pr "}\n" diff --git a/generator/generator_types.ml b/generator/generator_types.ml index ce7aea3..aeb751c 100644 --- a/generator/generator_types.ml +++ b/generator/generator_types.ml @@ -419,6 +419,8 @@ type action = { c_function : string; (* full name of C API function called by non-C bindings *) c_optarg_prefix : string; (* prefix for optarg names/bitmask names *) + non_c_aliases : string list; (* back-compat aliases that have to be + generated for this function *) } (* Field types for structures. *) -- 1.7.10.4
Richard W.M. Jones
2012-Jul-14 13:28 UTC
[Libguestfs] [PATCH 4/6] generator: Rename 'add_drive_opts' API to 'add_drive'.
From: "Richard W.M. Jones" <rjones at redhat.com> By using the once_had_no_optargs flag, this change is backwards compatible for callers (except Haskell, PHP and GObject as discussed in earlier commit). --- erlang/examples/create_disk.erl | 4 ++-- erlang/examples/guestfs-erlang.pod | 10 +++++----- erlang/examples/inspect_vm.erl | 2 +- fish/guestfish.pod | 8 ++++---- generator/generator_actions.ml | 26 +++++--------------------- gobject/Makefile.am | 6 +++++- gobject/Makefile.inc | 4 ++-- gobject/tests-misc.js | 2 +- haskell/Guestfs010Basic.hs | 2 +- java/examples/CreateDisk.java | 2 +- java/examples/InspectVM.java | 2 +- java/examples/guestfs-java.pod | 2 +- java/t/GuestFS080OptArgs.java | 8 ++++---- ocaml/examples/create_disk.ml | 2 +- ocaml/examples/guestfs-ocaml.pod | 4 ++-- ocaml/examples/inspect_vm.ml | 2 +- ocaml/t/guestfs_080_optargs.ml | 9 ++++----- ocaml/t/guestfs_500_parallel_mount_local.ml | 2 +- perl/examples/create_disk.pl | 2 +- perl/examples/guestfs-perl.pod | 2 +- perl/examples/inspect_vm.pl | 2 +- perl/lib/Sys/Guestfs/Lib.pm | 4 ++-- perl/t/070-optargs.t | 6 +++--- perl/t/810-mkdir-eexist.t | 2 +- perl/t/900-introspection.t | 1 + php/extension/guestfs_php_003.phpt | 16 ++++++++-------- po/POTFILES | 2 +- python/examples/create_disk.py | 2 +- python/examples/guestfs-python.pod | 2 +- python/examples/inspect_vm.py | 2 +- python/t/060-optargs.py | 6 +++--- python/t/rhbz811650.py | 2 +- resize/resize.ml | 8 ++++---- ruby/examples/create_disk.rb | 2 +- ruby/examples/guestfs-ruby.pod | 4 ++-- ruby/examples/inspect_vm.rb | 2 +- ruby/tests/tc_060_optargs.rb | 10 +++++----- sparsify/sparsify.ml | 4 ++-- src/launch.c | 10 ---------- sysprep/main.ml | 2 +- tests/btrfs/test-btrfs-subvolume-default.pl | 2 +- tests/disks/test-max-disks.pl | 2 +- tests/lvm/test-lvm-mapping.pl | 2 +- tests/md/test-inspect-fstab.sh | 4 ++-- tests/qemu/qemu-liveness.sh | 4 ++-- tests/selinux/run-test.pl | 2 +- tools/virt-make-fs | 2 +- 47 files changed, 93 insertions(+), 115 deletions(-) diff --git a/erlang/examples/create_disk.erl b/erlang/examples/create_disk.erl index d192435..0e1f031 100755 --- a/erlang/examples/create_disk.erl +++ b/erlang/examples/create_disk.erl @@ -17,8 +17,8 @@ main(_) -> ok = guestfs:set_trace(G, true), % Attach the disk image to libguestfs. - ok = guestfs:add_drive_opts(G, Output, - [{format, "raw"}, {readonly, false}]), + ok = guestfs:add_drive(G, Output, + [{format, "raw"}, {readonly, false}]), % Run the libguestfs back-end. ok = guestfs:launch(G), diff --git a/erlang/examples/guestfs-erlang.pod b/erlang/examples/guestfs-erlang.pod index 8721318..1016d98 100644 --- a/erlang/examples/guestfs-erlang.pod +++ b/erlang/examples/guestfs-erlang.pod @@ -7,8 +7,8 @@ guestfs-erlang - How to use libguestfs from Erlang =head1 SYNOPSIS {ok, G} = guestfs:create(), - ok = guestfs:add_drive_opts(G, Disk, - [{format, "raw"}, {readonly, true}]), + ok = guestfs:add_drive(G, Disk, + [{format, "raw"}, {readonly, true}]), ok = guestfs:launch(G), [Device] = guestfs:list_devices(G), ok = guestfs:close(G). @@ -43,12 +43,12 @@ For functions that take optional arguments, the first arguments are the non-optional ones. The last argument is a list of tuples supplying the remaining optional arguments. - ok = guestfs:add_drive_opts(G, Disk, - [{format, "raw"}, {readonly, true}]). + ok = guestfs:add_drive(G, Disk, + [{format, "raw"}, {readonly, true}]). If the last argument would be an empty list, you can also omit it: - ok = guestfs:add_drive_opts(G, Disk). + ok = guestfs:add_drive(G, Disk). =head2 RETURN VALUES AND ERRORS diff --git a/erlang/examples/inspect_vm.erl b/erlang/examples/inspect_vm.erl index 87d751c..2455889 100755 --- a/erlang/examples/inspect_vm.erl +++ b/erlang/examples/inspect_vm.erl @@ -6,7 +6,7 @@ main([Disk]) -> {ok, G} = guestfs:create(), % Attach the disk image read-only to libguestfs. - ok = guestfs:add_drive_opts(G, Disk, [{readonly, true}]), + ok = guestfs:add_drive(G, Disk, [{readonly, true}]), % Run the libguestfs back-end. ok = guestfs:launch(G), diff --git a/fish/guestfish.pod b/fish/guestfish.pod index 29aa2d6..07e268c 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -253,7 +253,7 @@ auto-detection for C<another.img>. If you have untrusted raw-format guest disk images, you should use this option to specify the disk format. This avoids a possible security problem with malicious guests (CVE-2010-3851). See also -L</add-drive-opts>. +L</add>. =item B<-i> @@ -594,11 +594,11 @@ Some commands take optional arguments. These arguments appear in this documentation as C<[argname:..]>. You can use them as in these examples: - add-drive-opts filename + add filename - add-drive-opts filename readonly:true + add filename readonly:true - add-drive-opts filename format:qcow2 readonly:false + add filename format:qcow2 readonly:false Each optional argument can appear at most once. All optional arguments must appear after the required ones. diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 0073c45..6f46f80 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -164,26 +164,9 @@ This kills the qemu subprocess. Do not call this. See: C<guestfs_shutdown> instead." }; { defaults with - name = "add_drive"; - style = RErr, [String "filename"], []; - config_only = true; - shortdesc = "add an image to examine or modify"; - longdesc = "\ -This function is the equivalent of calling C<guestfs_add_drive_opts> -with no optional parameters, so the disk is added writable, with -the format being detected automatically. - -Automatic detection of the format opens you up to a potential -security hole when dealing with untrusted raw-format images. -See CVE-2010-3851 and RHBZ#642934. Specifying the format closes -this security hole. Therefore you should think about replacing -calls to this function with calls to C<guestfs_add_drive_opts>, -and specifying the format." }; - - { defaults with name = "add_cdrom"; style = RErr, [String "filename"], []; - deprecated_by = Some "add_drive_opts"; config_only = true; + deprecated_by = Some "add_drive"; config_only = true; shortdesc = "add a CD-ROM disk image to examine"; longdesc = "\ This function adds a virtual CD-ROM disk image to the guest. @@ -648,7 +631,7 @@ Return the recovery process enabled flag." }; { defaults with name = "add_drive_with_if"; style = RErr, [String "filename"; String "iface"], []; - deprecated_by = Some "add_drive_opts"; config_only = true; + deprecated_by = Some "add_drive"; config_only = true; shortdesc = "add a drive specifying the QEMU block emulation to use"; longdesc = "\ This is the same as C<guestfs_add_drive> but it allows you @@ -657,7 +640,7 @@ to specify the QEMU interface emulation to use at run time." }; { defaults with name = "add_drive_ro_with_if"; style = RErr, [String "filename"; String "iface"], []; - deprecated_by = Some "add_drive_opts"; config_only = true; + deprecated_by = Some "add_drive"; config_only = true; shortdesc = "add a drive read-only specifying the QEMU block emulation to use"; longdesc = "\ This is the same as C<guestfs_add_drive_ro> but it allows you @@ -1150,8 +1133,9 @@ not all belong to a single logical operating system (use C<guestfs_inspect_os> to look for OSes)." }; { defaults with - name = "add_drive_opts"; + name = "add_drive"; style = RErr, [String "filename"], [OBool "readonly"; OString "format"; OString "iface"; OString "name"]; + once_had_no_optargs = true; fish_alias = ["add"]; config_only = true; shortdesc = "add an image to examine or modify"; longdesc = "\ diff --git a/gobject/Makefile.am b/gobject/Makefile.am index deaf543..cc360c8 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -42,7 +42,11 @@ CLEANFILES = \ guestfs-gobject*.c *.o *.lo # Remove old test0 API files. -CLEANFILES += src/optargs-test0.c include/guestfs-gobject/optargs-test0.h +CLEANFILES += \ + src/optargs-add_drive_opts.c \ + include/guestfs-gobject/optargs-add_drive_opts.h \ + src/optargs-test0.c \ + include/guestfs-gobject/optargs-test0.h libname = libguestfs-gobject-1.0.la diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index e84236d..d8c6eed 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -39,7 +39,7 @@ guestfs_gobject_headers= \ include/guestfs-gobject/struct-mdstat.h \ include/guestfs-gobject/struct-btrfssubvolume.h \ include/guestfs-gobject/optargs-internal_test.h \ - include/guestfs-gobject/optargs-add_drive_opts.h \ + include/guestfs-gobject/optargs-add_drive.h \ include/guestfs-gobject/optargs-add_domain.h \ include/guestfs-gobject/optargs-inspect_get_icon.h \ include/guestfs-gobject/optargs-mount_local.h \ @@ -83,7 +83,7 @@ guestfs_gobject_sources= \ src/struct-mdstat.c \ src/struct-btrfssubvolume.c \ src/optargs-internal_test.c \ - src/optargs-add_drive_opts.c \ + src/optargs-add_drive.c \ src/optargs-add_domain.c \ src/optargs-inspect_get_icon.c \ src/optargs-mount_local.c \ diff --git a/gobject/tests-misc.js b/gobject/tests-misc.js index 058a695..a97da24 100644 --- a/gobject/tests-misc.js +++ b/gobject/tests-misc.js @@ -39,7 +39,7 @@ g.connect('trace', function(session, params) { } }); -g.add_drive('../tests/guests/fedora.img'); +g.add_drive('../tests/guests/fedora.img', null); g.set_trace(true); g.launch(); // Fake progress messages for a 5 second event. We do this as launch() will not diff --git a/haskell/Guestfs010Basic.hs b/haskell/Guestfs010Basic.hs index 0f919e3..5cf8826 100644 --- a/haskell/Guestfs010Basic.hs +++ b/haskell/Guestfs010Basic.hs @@ -26,7 +26,7 @@ main = do fd <- openFile "test.img" WriteMode hSetFileSize fd (500 * 1024 * 1024) hClose fd - Guestfs.add_drive g "test.img" + Guestfs.add_drive_ro g "test.img" Guestfs.launch g Guestfs.pvcreate g "/dev/sda" diff --git a/java/examples/CreateDisk.java b/java/examples/CreateDisk.java index 381fae1..7eecf9e 100644 --- a/java/examples/CreateDisk.java +++ b/java/examples/CreateDisk.java @@ -29,7 +29,7 @@ public class CreateDisk put ("readonly", Boolean.FALSE); } }; - g.add_drive_opts (output, optargs); + g.add_drive (output, optargs); // Run the libguestfs back-end. g.launch (); diff --git a/java/examples/InspectVM.java b/java/examples/InspectVM.java index d92aa70..1feadbe 100644 --- a/java/examples/InspectVM.java +++ b/java/examples/InspectVM.java @@ -35,7 +35,7 @@ public class InspectVM } }; - g.add_drive_opts (disk, optargs); + g.add_drive (disk, optargs); // Run the libguestfs back-end. g.launch (); diff --git a/java/examples/guestfs-java.pod b/java/examples/guestfs-java.pod index 482539b..f7b1e7a 100644 --- a/java/examples/guestfs-java.pod +++ b/java/examples/guestfs-java.pod @@ -9,7 +9,7 @@ guestfs-java - How to use libguestfs from Java import com.redhat.et.libguestfs.*; GuestFS g = new GuestFS (); - g.add_drive_opts ("disk.img"); + g.add_drive ("disk.img"); g.launch (); =head1 DESCRIPTION diff --git a/java/t/GuestFS080OptArgs.java b/java/t/GuestFS080OptArgs.java index 6eee6c6..417d0ad 100644 --- a/java/t/GuestFS080OptArgs.java +++ b/java/t/GuestFS080OptArgs.java @@ -27,7 +27,7 @@ public class GuestFS080OptArgs try { GuestFS g = new GuestFS (); - g.add_drive_opts ("/dev/null"); + g.add_drive ("/dev/null"); HashMap<String,Object> optargs; @@ -36,7 +36,7 @@ public class GuestFS080OptArgs put ("readonly", Boolean.TRUE); } }; - g.add_drive_opts ("/dev/null", optargs); + g.add_drive ("/dev/null", optargs); optargs = new HashMap<String,Object>() { { @@ -44,7 +44,7 @@ public class GuestFS080OptArgs put ("format", "raw"); } }; - g.add_drive_opts ("/dev/null", optargs); + g.add_drive ("/dev/null", optargs); optargs = new HashMap<String,Object>() { { @@ -53,7 +53,7 @@ public class GuestFS080OptArgs put ("iface", "virtio"); } }; - g.add_drive_opts ("/dev/null", optargs); + g.add_drive ("/dev/null", optargs); } catch (Exception exn) { System.err.println (exn); diff --git a/ocaml/examples/create_disk.ml b/ocaml/examples/create_disk.ml index 4437b1c..fab5e70 100644 --- a/ocaml/examples/create_disk.ml +++ b/ocaml/examples/create_disk.ml @@ -17,7 +17,7 @@ let () g#set_trace true; (* Attach the disk image to libguestfs. *) - g#add_drive_opts ~format:"raw" ~readonly:false output; + g#add_drive ~format:"raw" ~readonly:false output; (* Run the libguestfs back-end. *) g#launch (); diff --git a/ocaml/examples/guestfs-ocaml.pod b/ocaml/examples/guestfs-ocaml.pod index 139997b..019e84a 100644 --- a/ocaml/examples/guestfs-ocaml.pod +++ b/ocaml/examples/guestfs-ocaml.pod @@ -9,13 +9,13 @@ guestfs-ocaml - How to use libguestfs from OCaml Module style: let g = Guestfs.create () in - Guestfs.add_drive_opts g ~format:"raw" ~readonly:true "disk.img"; + Guestfs.add_drive g ~format:"raw" ~readonly:true "disk.img"; Guestfs.launch g; Object-oriented style: let g = new Guestfs.guestfs () in - g#add_drive_opts ~format:"raw" ~readonly:true "disk.img"; + g#add_drive ~format:"raw" ~readonly:true "disk.img"; g#launch (); ocamlfind opt prog.ml -package guestfs -linkpkg -o prog diff --git a/ocaml/examples/inspect_vm.ml b/ocaml/examples/inspect_vm.ml index 44d348e..c19953b 100644 --- a/ocaml/examples/inspect_vm.ml +++ b/ocaml/examples/inspect_vm.ml @@ -12,7 +12,7 @@ let () let g = new Guestfs.guestfs () in (* Attach the disk image read-only to libguestfs. *) - g#add_drive_opts (*~format:"raw"*) ~readonly:true disk; + g#add_drive (*~format:"raw"*) ~readonly:true disk; (* Run the libguestfs back-end. *) g#launch (); diff --git a/ocaml/t/guestfs_080_optargs.ml b/ocaml/t/guestfs_080_optargs.ml index a43a83e..e2b2f6c 100644 --- a/ocaml/t/guestfs_080_optargs.ml +++ b/ocaml/t/guestfs_080_optargs.ml @@ -21,10 +21,9 @@ open Unix let () let g = Guestfs.create () in - Guestfs.add_drive_opts g "/dev/null"; - Guestfs.add_drive_opts g ~readonly:true "/dev/null"; - Guestfs.add_drive_opts g ~readonly:true ~format:"raw" "/dev/null"; - Guestfs.add_drive_opts g ~iface:"virtio" ~readonly:true ~format:"raw" - "/dev/null"; + Guestfs.add_drive g "/dev/null"; + Guestfs.add_drive g ~readonly:true "/dev/null"; + Guestfs.add_drive g ~readonly:true ~format:"raw" "/dev/null"; + Guestfs.add_drive g ~iface:"virtio" ~readonly:true ~format:"raw" "/dev/null"; Guestfs.close g diff --git a/ocaml/t/guestfs_500_parallel_mount_local.ml b/ocaml/t/guestfs_500_parallel_mount_local.ml index e1f5e26..926b9ee 100644 --- a/ocaml/t/guestfs_500_parallel_mount_local.ml +++ b/ocaml/t/guestfs_500_parallel_mount_local.ml @@ -100,7 +100,7 @@ and start_thread (filename, mp) ftruncate fd (500 * 1024 * 1024); close fd; - g#add_drive_opts filename; + g#add_drive filename; g#launch (); g#part_disk "/dev/sda" "mbr"; diff --git a/perl/examples/create_disk.pl b/perl/examples/create_disk.pl index 11b9146..76b51de 100755 --- a/perl/examples/create_disk.pl +++ b/perl/examples/create_disk.pl @@ -18,7 +18,7 @@ close FILE or die "$output: $!"; $g->set_trace (1); # Attach the disk image to libguestfs. -$g->add_drive_opts ($output, format => "raw", readonly => 0); +$g->add_drive ($output, format => "raw", readonly => 0); # Run the libguestfs back-end. $g->launch (); diff --git a/perl/examples/guestfs-perl.pod b/perl/examples/guestfs-perl.pod index f83d1fd..c38377c 100644 --- a/perl/examples/guestfs-perl.pod +++ b/perl/examples/guestfs-perl.pod @@ -9,7 +9,7 @@ guestfs-perl - How to use libguestfs from Perl use Sys::Guestfs; my $h = Sys::Guestfs->new (); - $h->add_drive_opts ('guest.img', format => 'raw'); + $h->add_drive ('guest.img', format => 'raw'); $h->launch (); $h->mount_options ('', '/dev/sda1', '/'); $h->touch ('/hello'); diff --git a/perl/examples/inspect_vm.pl b/perl/examples/inspect_vm.pl index 6d95b69..7800ce0 100755 --- a/perl/examples/inspect_vm.pl +++ b/perl/examples/inspect_vm.pl @@ -16,7 +16,7 @@ my $g = new Sys::Guestfs (); # Attach the disk image read-only to libguestfs. # You could also add an optional format => ... argument here. This is # advisable since automatic format detection is insecure. -$g->add_drive_opts ($disk, readonly => 1); +$g->add_drive ($disk, readonly => 1); # Run the libguestfs back-end. $g->launch (); diff --git a/perl/lib/Sys/Guestfs/Lib.pm b/perl/lib/Sys/Guestfs/Lib.pm index 2ccc09a..037a050 100644 --- a/perl/lib/Sys/Guestfs/Lib.pm +++ b/perl/lib/Sys/Guestfs/Lib.pm @@ -133,7 +133,7 @@ If the C<Sys::Virt> module is not available, then libvirt is bypassed, and this function can only open disk images. The optional C<interface> parameter can be used to open devices with a -specified qemu interface. See L<Sys::Guestfs/guestfs_add_drive_opts> +specified qemu interface. See L<Sys::Guestfs/guestfs_add_drive> for more details. =cut @@ -257,7 +257,7 @@ sub open_guest push @args, format => $_->[1] if defined $_->[1]; push @args, readonly => 1 unless $rw; push @args, iface => $interface if defined $interface; - $g->add_drive_opts (@args); + $g->add_drive (@args); } return wantarray ? ($g, $conn, $dom, @images) : $g diff --git a/perl/t/070-optargs.t b/perl/t/070-optargs.t index 978db92..885f0cc 100644 --- a/perl/t/070-optargs.t +++ b/perl/t/070-optargs.t @@ -24,11 +24,11 @@ use Sys::Guestfs; my $h = Sys::Guestfs->new (); ok ($h); -$h->add_drive_opts ("/dev/null"); +$h->add_drive ("/dev/null"); ok (1); -$h->add_drive_opts ("/dev/null", readonly => 1); +$h->add_drive ("/dev/null", readonly => 1); ok (1); -$h->add_drive_opts ("/dev/null", format => "raw", readonly => 0); +$h->add_drive ("/dev/null", format => "raw", readonly => 0); ok (1); diff --git a/perl/t/810-mkdir-eexist.t b/perl/t/810-mkdir-eexist.t index a059ee4..0b25776 100644 --- a/perl/t/810-mkdir-eexist.t +++ b/perl/t/810-mkdir-eexist.t @@ -33,7 +33,7 @@ truncate FILE, 500*1024*1024; close FILE; ok (1); -$g->add_drive_opts ("test.img", format => "raw"); +$g->add_drive ("test.img", format => "raw"); ok (1); $g->launch (); diff --git a/perl/t/900-introspection.t b/perl/t/900-introspection.t index c1fa6f8..0182250 100644 --- a/perl/t/900-introspection.t +++ b/perl/t/900-introspection.t @@ -33,6 +33,7 @@ is ($add_drive{args}[0][0], "filename"); is ($add_drive{args}[0][1], "string"); is ($add_drive{args}[0][2], 0); +# In libguestfs >= 1.19.19, this is an alias. my %add_drive_opts = %{$Sys::Guestfs::guestfs_introspection{add_drive_opts}}; ok(1); diff --git a/php/extension/guestfs_php_003.phpt b/php/extension/guestfs_php_003.phpt index 08e53a3..2624a29 100644 --- a/php/extension/guestfs_php_003.phpt +++ b/php/extension/guestfs_php_003.phpt @@ -11,20 +11,20 @@ if ($g == false) { echo ("Failed to create guestfs_php handle.\n"); exit; } -if (guestfs_add_drive_opts ($g, "/dev/null") == false) { - echo ("Failed add_drive_opts, no optional arguments.\n"); +if (guestfs_add_drive ($g, "/dev/null") == false) { + echo ("Failed add_drive, no optional arguments.\n"); exit; } -if (guestfs_add_drive_opts ($g, "/dev/null", 0) == false) { - echo ("Failed add_drive_opts, one optional argument.\n"); +if (guestfs_add_drive ($g, "/dev/null", 0) == false) { + echo ("Failed add_drive, one optional argument.\n"); exit; } -if (guestfs_add_drive_opts ($g, "/dev/null", 1) == false) { - echo ("Failed add_drive_opts, one optional argument.\n"); +if (guestfs_add_drive ($g, "/dev/null", 1) == false) { + echo ("Failed add_drive, one optional argument.\n"); exit; } -if (guestfs_add_drive_opts ($g, "/dev/null", 1, "qcow2") == false) { - echo ("Failed add_drive_opts, two optional arguments.\n"); +if (guestfs_add_drive ($g, "/dev/null", 1, "qcow2") == false) { + echo ("Failed add_drive, two optional arguments.\n"); exit; } echo ("Completed tests OK.\n"); diff --git a/po/POTFILES b/po/POTFILES index 6c819d3..f659a9d 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -133,7 +133,7 @@ fish/virt.c format/format.c fuse/guestmount.c gobject/src/optargs-add_domain.c -gobject/src/optargs-add_drive_opts.c +gobject/src/optargs-add_drive.c gobject/src/optargs-btrfs_filesystem_resize.c gobject/src/optargs-btrfs_fsck.c gobject/src/optargs-compress_device_out.c diff --git a/python/examples/create_disk.py b/python/examples/create_disk.py index 86f5042..a854c23 100644 --- a/python/examples/create_disk.py +++ b/python/examples/create_disk.py @@ -16,7 +16,7 @@ f.close () g.set_trace (1) # Attach the disk image to libguestfs. -g.add_drive_opts (output, format = "raw", readonly = 0) +g.add_drive (output, format = "raw", readonly = 0) # Run the libguestfs back-end. g.launch () diff --git a/python/examples/guestfs-python.pod b/python/examples/guestfs-python.pod index e4406f5..59f60e5 100644 --- a/python/examples/guestfs-python.pod +++ b/python/examples/guestfs-python.pod @@ -8,7 +8,7 @@ guestfs-python - How to use libguestfs from Python import guestfs g = guestfs.GuestFS () - g.add_drive_opts ("disk.img", format="raw", readonly=1) + g.add_drive ("disk.img", format="raw", readonly=1) g.launch () =head1 DESCRIPTION diff --git a/python/examples/inspect_vm.py b/python/examples/inspect_vm.py index c491a2c..816779c 100644 --- a/python/examples/inspect_vm.py +++ b/python/examples/inspect_vm.py @@ -9,7 +9,7 @@ disk = sys.argv[1] g = guestfs.GuestFS () # Attach the disk image read-only to libguestfs. -g.add_drive_opts (disk, readonly=1) +g.add_drive (disk, readonly=1) # Run the libguestfs back-end. g.launch () diff --git a/python/t/060-optargs.py b/python/t/060-optargs.py index be28a3c..ae2d934 100644 --- a/python/t/060-optargs.py +++ b/python/t/060-optargs.py @@ -19,7 +19,7 @@ import os import guestfs g = guestfs.GuestFS() -g.add_drive_opts ("/dev/null") -g.add_drive_opts ("/dev/null", readonly = 1) -g.add_drive_opts ("/dev/null", iface = "virtio", format = "raw") +g.add_drive ("/dev/null") +g.add_drive ("/dev/null", readonly = 1) +g.add_drive ("/dev/null", iface = "virtio", format = "raw") g.close () diff --git a/python/t/rhbz811650.py b/python/t/rhbz811650.py index cf01673..c84f094 100644 --- a/python/t/rhbz811650.py +++ b/python/t/rhbz811650.py @@ -25,7 +25,7 @@ f.close () g = guestfs.GuestFS () # Deliberate error: the disk format is supposed to be raw. -g.add_drive_opts ("test.img", format="qcow2"); +g.add_drive ("test.img", format="qcow2"); # Because error() wasn't being called, guestfs_last_error would return # NULL, causing a segfault in the Python bindings (RHBZ#811650). diff --git a/resize/resize.ml b/resize/resize.ml index cd4c9d6..9ef2bbd 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -173,7 +173,7 @@ read the man page virt-resize(1). printf "alignment\n"; printf "align-first\n"; let g = new G.guestfs () in - g#add_drive_opts "/dev/null"; + g#add_drive "/dev/null"; g#launch (); if feature_available g [| "ntfsprogs"; "ntfs3g" |] then printf "ntfs\n"; @@ -209,8 +209,8 @@ let btrfs_available = ref true let connect_both_disks () let g = new G.guestfs () in if debug then g#set_trace true; - g#add_drive_opts ?format ~readonly:true infile; - g#add_drive_opts ?format:output_format ~readonly:false outfile; + g#add_drive ?format ~readonly:true infile; + g#add_drive ?format:output_format ~readonly:false outfile; if not quiet then Progress.set_up_progress_bar ~machine_readable g; g#launch (); @@ -1125,7 +1125,7 @@ let g let g = new G.guestfs () in if debug then g#set_trace true; - g#add_drive_opts ?format:output_format ~readonly:false outfile; + g#add_drive ?format:output_format ~readonly:false outfile; if not quiet then Progress.set_up_progress_bar ~machine_readable g; g#launch (); diff --git a/ruby/examples/create_disk.rb b/ruby/examples/create_disk.rb index 32fb117..fd6ec01 100644 --- a/ruby/examples/create_disk.rb +++ b/ruby/examples/create_disk.rb @@ -15,7 +15,7 @@ File.open(output, "w") { g.set_trace(1) # Attach the disk image to libguestfs. -g.add_drive_opts(output, :format => "raw") +g.add_drive(output, :format => "raw") # Run the libguestfs back-end. g.launch(); diff --git a/ruby/examples/guestfs-ruby.pod b/ruby/examples/guestfs-ruby.pod index 1af133d..4b53d01 100644 --- a/ruby/examples/guestfs-ruby.pod +++ b/ruby/examples/guestfs-ruby.pod @@ -8,8 +8,8 @@ guestfs-ruby - How to use libguestfs from Ruby require 'guestfs' g = Guestfs::Guestfs.new() - g.add_drive_opts("disk.img", - :readonly => 1, :format => "raw") + g.add_drive("disk.img", + :readonly => 1, :format => "raw") g.launch() =head1 DESCRIPTION diff --git a/ruby/examples/inspect_vm.rb b/ruby/examples/inspect_vm.rb index abf2279..c29114e 100644 --- a/ruby/examples/inspect_vm.rb +++ b/ruby/examples/inspect_vm.rb @@ -11,7 +11,7 @@ disk = ARGV[0] g = Guestfs::Guestfs.new() # Attach the disk image read-only to libguestfs. -g.add_drive_opts(disk, :readonly => 1) +g.add_drive(disk, :readonly => 1) # Run the libguestfs back-end. g.launch() diff --git a/ruby/tests/tc_060_optargs.rb b/ruby/tests/tc_060_optargs.rb index de411d6..6556bc7 100644 --- a/ruby/tests/tc_060_optargs.rb +++ b/ruby/tests/tc_060_optargs.rb @@ -24,10 +24,10 @@ class TestLoad < Test::Unit::TestCase def test_optargs g = Guestfs::create() - g.add_drive_opts("/dev/null", {}) - g.add_drive_opts("/dev/null", :readonly => 1) - g.add_drive_opts("/dev/null", :readonly => 1, :iface => "virtio") - g.add_drive_opts("/dev/null", - :readonly => 1, :iface => "virtio", :format => "qcow2") + g.add_drive("/dev/null", {}) + g.add_drive("/dev/null", :readonly => 1) + g.add_drive("/dev/null", :readonly => 1, :iface => "virtio") + g.add_drive("/dev/null", + :readonly => 1, :iface => "virtio", :format => "qcow2") end end diff --git a/sparsify/sparsify.ml b/sparsify/sparsify.ml index 6f1635b..418eb67 100644 --- a/sparsify/sparsify.ml +++ b/sparsify/sparsify.ml @@ -107,7 +107,7 @@ read the man page virt-sparsify(1). printf "linux-swap\n"; printf "zero\n"; let g = new G.guestfs () in - g#add_drive_opts "/dev/null"; + g#add_drive "/dev/null"; g#launch (); if feature_available g [| "ntfsprogs"; "ntfs3g" |] then printf "ntfs\n"; @@ -195,7 +195,7 @@ let g if verbose then g#set_verbose true; (* Note that the temporary overlay disk is always qcow2 format. *) - g#add_drive_opts ~format:"qcow2" ~readonly:false overlaydisk; + g#add_drive ~format:"qcow2" ~readonly:false overlaydisk; if not quiet then Progress.set_up_progress_bar ~machine_readable g; g#launch (); diff --git a/src/launch.c b/src/launch.c index e786519..be834a8 100644 --- a/src/launch.c +++ b/src/launch.c @@ -441,16 +441,6 @@ err_out: } int -guestfs__add_drive (guestfs_h *g, const char *filename) -{ - struct guestfs_add_drive_opts_argv optargs = { - .bitmask = 0, - }; - - return guestfs__add_drive_opts (g, filename, &optargs); -} - -int guestfs__add_drive_ro (guestfs_h *g, const char *filename) { struct guestfs_add_drive_opts_argv optargs = { diff --git a/sysprep/main.ml b/sysprep/main.ml index 05dd57d..4c3f970 100644 --- a/sysprep/main.ml +++ b/sysprep/main.ml @@ -161,7 +161,7 @@ read the man page virt-sysprep(1). fun g readonly -> List.iter ( fun (file, format) -> - g#add_drive_opts ~readonly ?format file + g#add_drive ~readonly ?format file ) files in diff --git a/tests/btrfs/test-btrfs-subvolume-default.pl b/tests/btrfs/test-btrfs-subvolume-default.pl index 2c09ce2..4672bed 100755 --- a/tests/btrfs/test-btrfs-subvolume-default.pl +++ b/tests/btrfs/test-btrfs-subvolume-default.pl @@ -33,7 +33,7 @@ close FILE or die "$testimg: $!"; my $g = Sys::Guestfs->new (); -$g->add_drive_opts ($testimg, format => "raw"); +$g->add_drive ($testimg, format => "raw"); $g->launch (); # If btrfs is not available, bail. diff --git a/tests/disks/test-max-disks.pl b/tests/disks/test-max-disks.pl index a0bba7f..7062434 100755 --- a/tests/disks/test-max-disks.pl +++ b/tests/disks/test-max-disks.pl @@ -40,7 +40,7 @@ for ($i = 0; $i < $max_disks; ++$i) { truncate FILE, 1024*1024 or die "$name: truncate: $!"; close FILE or die "$name: $!"; - $g->add_drive_opts ($name, format => "raw"); + $g->add_drive ($name, format => "raw"); } $g->launch (); diff --git a/tests/lvm/test-lvm-mapping.pl b/tests/lvm/test-lvm-mapping.pl index b92a5c5..beb388a 100755 --- a/tests/lvm/test-lvm-mapping.pl +++ b/tests/lvm/test-lvm-mapping.pl @@ -34,7 +34,7 @@ my $g = Sys::Guestfs->new (); #$g->set_verbose (1); #$g->set_trace (1); -$g->add_drive_opts ($testimg, format => "raw"); +$g->add_drive ($testimg, format => "raw"); $g->launch (); # Create an arrangement of PVs, VGs and LVs. diff --git a/tests/md/test-inspect-fstab.sh b/tests/md/test-inspect-fstab.sh index 2822c4d..889ceee 100755 --- a/tests/md/test-inspect-fstab.sh +++ b/tests/md/test-inspect-fstab.sh @@ -88,7 +88,7 @@ $guestfish -a test1.qcow2 <<'EOF' EOF $guestfish <<'EOF' | $canonical > test.output - add-drive-opts test1.qcow2 readonly:true name:xvdg + add test1.qcow2 readonly:true name:xvdg run inspect-os inspect-get-mountpoints /dev/VG/Root @@ -119,7 +119,7 @@ $guestfish -a test1.qcow2 <<'EOF' EOF $guestfish <<'EOF' | $canonical > test.output - add-drive-opts test1.qcow2 readonly:true name:cciss/c1d3 + add test1.qcow2 readonly:true name:cciss/c1d3 run inspect-os inspect-get-mountpoints /dev/VG/Root diff --git a/tests/qemu/qemu-liveness.sh b/tests/qemu/qemu-liveness.sh index d95321c..eb8f608 100755 --- a/tests/qemu/qemu-liveness.sh +++ b/tests/qemu/qemu-liveness.sh @@ -28,7 +28,7 @@ rm -f test1.img test1_md5sum="$(md5sum test1.img | awk '{print $1}')" ../../fish/guestfish <<'EOF' -add-drive-opts test1.img format:raw +add test1.img format:raw run part-disk /dev/sda mbr @@ -49,4 +49,4 @@ if [ "$(md5sum test1.img | awk '{print $1}')" = "$test1_md5sum" ]; then exit 1 fi -rm test1.img \ No newline at end of file +rm test1.img diff --git a/tests/selinux/run-test.pl b/tests/selinux/run-test.pl index bbe3a2f..0d3300c 100755 --- a/tests/selinux/run-test.pl +++ b/tests/selinux/run-test.pl @@ -108,7 +108,7 @@ open FILE, ">$testimg" or die "$testimg: $!"; truncate FILE, 256*1024*1024 or die "$testimg: truncate: $!"; close FILE or die "$testimg: $!"; -$g->add_drive_opts ($testimg, format => "raw"); +$g->add_drive ($testimg, format => "raw"); $g->launch (); unless (feature_available ($g, "linuxxattrs")) { diff --git a/tools/virt-make-fs b/tools/virt-make-fs index b53e860..a4da3f2 100755 --- a/tools/virt-make-fs +++ b/tools/virt-make-fs @@ -421,7 +421,7 @@ eval { # Run libguestfs. my $g = Sys::Guestfs->new (); - $g->add_drive_opts ($output, format => $format); + $g->add_drive ($output, format => $format); $g->launch (); if ($type eq "ntfs" && !feature_available ($g, "ntfs3g", "ntfsprogs")) { -- 1.7.10.4
Richard W.M. Jones
2012-Jul-14 13:28 UTC
[Libguestfs] [PATCH 5/6] generator: Rename 'mkfs_opts' API to 'mkfs'.
From: "Richard W.M. Jones" <rjones at redhat.com> By using the once_had_no_optargs flag, this change is backwards compatible for callers. --- daemon/mkfs.c | 23 +++++-------- generator/generator_actions.ml | 51 ++++++++++------------------- generator/generator_perl.ml | 4 +-- generator/generator_tests_c_api.ml | 4 +-- gobject/Makefile.am | 2 ++ gobject/Makefile.inc | 4 +-- po/POTFILES | 2 +- tests/guests/guest-aux/make-debian-img.sh | 10 +++--- tests/guests/guest-aux/make-fedora-img.pl | 10 +++--- tests/guests/guest-aux/make-ubuntu-img.sh | 4 +-- 10 files changed, 46 insertions(+), 68 deletions(-) diff --git a/daemon/mkfs.c b/daemon/mkfs.c index 85442e0..c7ae50d 100644 --- a/daemon/mkfs.c +++ b/daemon/mkfs.c @@ -33,8 +33,8 @@ /* Takes optional arguments, consult optargs_bitmask. */ int -do_mkfs_opts (const char *fstype, const char *device, int blocksize, - const char *features, int inode, int sectorsize) +do_mkfs (const char *fstype, const char *device, int blocksize, + const char *features, int inode, int sectorsize) { const char *argv[MAX_ARGS]; size_t i = 0; @@ -100,7 +100,7 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize, } /* Process blocksize parameter if set. */ - if (optargs_bitmask & GUESTFS_MKFS_OPTS_BLOCKSIZE_BITMASK) { + if (optargs_bitmask & GUESTFS_MKFS_BLOCKSIZE_BITMASK) { if (blocksize <= 0 || !is_power_of_2 (blocksize)) { reply_with_error ("block size must be > 0 and a power of 2"); return -1; @@ -146,12 +146,12 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize, } } - if (optargs_bitmask & GUESTFS_MKFS_OPTS_FEATURES_BITMASK) { + if (optargs_bitmask & GUESTFS_MKFS_FEATURES_BITMASK) { ADD_ARG (argv, i, "-O"); ADD_ARG (argv, i, features); } - if (optargs_bitmask & GUESTFS_MKFS_OPTS_INODE_BITMASK) { + if (optargs_bitmask & GUESTFS_MKFS_INODE_BITMASK) { if (!extfs) { reply_with_error ("inode size (-I) can only be set on ext2/3/4 filesystems"); return -1; @@ -167,7 +167,7 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize, ADD_ARG (argv, i, inode_str); } - if (optargs_bitmask & GUESTFS_MKFS_OPTS_SECTORSIZE_BITMASK) { + if (optargs_bitmask & GUESTFS_MKFS_SECTORSIZE_BITMASK) { if (!STREQ (fstype, "ufs")) { reply_with_error ("sector size (-S) can only be set on ufs filesystems"); return -1; @@ -198,15 +198,8 @@ do_mkfs_opts (const char *fstype, const char *device, int blocksize, } int -do_mkfs (const char *fstype, const char *device) -{ - optargs_bitmask = 0; - return do_mkfs_opts (fstype, device, 0, 0, 0, 0); -} - -int do_mkfs_b (const char *fstype, int blocksize, const char *device) { - optargs_bitmask = GUESTFS_MKFS_OPTS_BLOCKSIZE_BITMASK; - return do_mkfs_opts (fstype, device, blocksize, 0, 0, 0); + optargs_bitmask = GUESTFS_MKFS_BLOCKSIZE_BITMASK; + return do_mkfs (fstype, device, blocksize, 0, 0, 0); } diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 6f46f80..b530f77 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -1950,7 +1950,7 @@ let daemon_functions = [ tests = [ InitEmpty, Always, TestOutput ( [["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs"; "ext2"; "/dev/sda1"]; + ["mkfs"; "ext2"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["mount"; "/dev/sda1"; "/"]; ["write"; "/new"; "new file contents"]; ["cat"; "/new"]], "new file contents") @@ -2713,24 +2713,6 @@ This creates an LVM logical volume called C<logvol> on the volume group C<volgroup>, with C<size> megabytes." }; { defaults with - name = "mkfs"; - style = RErr, [String "fstype"; Device "device"], []; - proc_nr = Some 42; - tests = [ - InitEmpty, Always, TestOutput ( - [["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs"; "ext2"; "/dev/sda1"]; - ["mount_options"; ""; "/dev/sda1"; "/"]; - ["write"; "/new"; "new file contents"]; - ["cat"; "/new"]], "new file contents") - ]; - shortdesc = "make a filesystem"; - longdesc = "\ -This creates a filesystem on C<device> (usually a partition -or LVM logical volume). The filesystem type is C<fstype>, for -example C<ext3>." }; - - { defaults with name = "sfdisk"; style = RErr, [Device "device"; Int "cyls"; Int "heads"; Int "sectors"; @@ -2793,12 +2775,12 @@ characters does I<not> work, even if the length is specified." }; tests = [ InitEmpty, Always, TestOutputListOfDevices ( [["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs"; "ext2"; "/dev/sda1"]; + ["mkfs"; "ext2"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["mount_options"; ""; "/dev/sda1"; "/"]; ["mounts"]], ["/dev/sda1"]); InitEmpty, Always, TestOutputList ( [["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs"; "ext2"; "/dev/sda1"]; + ["mkfs"; "ext2"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["mount_options"; ""; "/dev/sda1"; "/"]; ["umount"; "/"]; ["mounts"]], []) @@ -2841,9 +2823,9 @@ See also: C<guestfs_mountpoints>" }; ["part_add"; "/dev/sda"; "p"; "64"; "204799"]; ["part_add"; "/dev/sda"; "p"; "204800"; "409599"]; ["part_add"; "/dev/sda"; "p"; "409600"; "-64"]; - ["mkfs"; "ext2"; "/dev/sda1"]; - ["mkfs"; "ext2"; "/dev/sda2"]; - ["mkfs"; "ext2"; "/dev/sda3"]; + ["mkfs"; "ext2"; "/dev/sda1"; ""; "NOARG"; ""; ""]; + ["mkfs"; "ext2"; "/dev/sda2"; ""; "NOARG"; ""; ""]; + ["mkfs"; "ext2"; "/dev/sda3"; ""; "NOARG"; ""; ""]; ["mount_options"; ""; "/dev/sda1"; "/"]; ["mkdir"; "/mp1"]; ["mount_options"; ""; "/dev/sda2"; "/mp1"]; @@ -4093,7 +4075,7 @@ the human-readable, canonical hex dump of the file." }; tests = [ InitNone, Always, TestOutput ( [["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs"; "ext3"; "/dev/sda1"]; + ["mkfs"; "ext3"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["mount_options"; ""; "/dev/sda1"; "/"]; ["write"; "/new"; "test file"]; ["umount"; "/dev/sda1"]; @@ -4217,7 +4199,7 @@ are activated or deactivated." }; ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV"; "VG"; "10"]; - ["mkfs"; "ext2"; "/dev/VG/LV"]; + ["mkfs"; "ext2"; "/dev/VG/LV"; ""; "NOARG"; ""; ""]; ["mount_options"; ""; "/dev/VG/LV"; "/"]; ["write"; "/new"; "test content"]; ["umount"; "/"]; @@ -4331,11 +4313,11 @@ Sleep for C<secs> seconds." }; tests = [ InitNone, Always, TestOutputInt ( [["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs"; "ntfs"; "/dev/sda1"]; + ["mkfs"; "ntfs"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0); InitNone, Always, TestOutputInt ( [["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs"; "ext2"; "/dev/sda1"]; + ["mkfs"; "ext2"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12) ]; shortdesc = "probe NTFS volume"; @@ -5700,7 +5682,7 @@ and C<guestfs_setcon>" }; name = "mkfs_b"; style = RErr, [String "fstype"; Int "blocksize"; Device "device"], []; proc_nr = Some 187; - deprecated_by = Some "mkfs_opts"; + deprecated_by = Some "mkfs"; tests = [ InitEmpty, Always, TestOutput ( [["part_disk"; "/dev/sda"; "mbr"]; @@ -7565,13 +7547,14 @@ not refer to a logical volume. See also C<guestfs_is_lv>, C<guestfs_canonical_device_name>." }; { defaults with - name = "mkfs_opts"; + name = "mkfs"; style = RErr, [String "fstype"; Device "device"], [OInt "blocksize"; OString "features"; OInt "inode"; OInt "sectorsize"]; proc_nr = Some 278; + once_had_no_optargs = true; tests = [ InitEmpty, Always, TestOutput ( [["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs_opts"; "ext2"; "/dev/sda1"; ""; "NOARG"; ""; ""]; + ["mkfs"; "ext2"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["mount_options"; ""; "/dev/sda1"; "/"]; ["write"; "/new"; "new file contents"]; ["cat"; "/new"]], "new file contents") @@ -8293,7 +8276,7 @@ device." }; optional = Some "ntfs3g"; tests = [ InitPartition, IfAvailable "ntfs3g", TestRun ( - [["mkfs"; "ntfs"; "/dev/sda1"]; + [["mkfs"; "ntfs"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["ntfsfix"; "/dev/sda1"; "false"]]) ]; shortdesc = "fix common errors and force Windows to check NTFS"; @@ -8352,7 +8335,7 @@ any existing contents of this device." }; [["set_label"; "/dev/sda1"; "testlabel"]; ["vfs_label"; "/dev/sda1"]], "testlabel"); InitPartition, IfAvailable "ntfs3g", TestOutput ( - [["mkfs"; "ntfs"; "/dev/sda1"]; + [["mkfs"; "ntfs"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["set_label"; "/dev/sda1"; "testlabel2"]; ["vfs_label"; "/dev/sda1"]], "testlabel2"); InitPartition, Always, TestLastFail ( @@ -8539,7 +8522,7 @@ For more information on the optional arguments, see L<mkfs.btrfs(8)>. Since btrfs filesystems can span multiple devices, this takes a non-empty list of devices. -To create general filesystems, use C<guestfs_mkfs_opts>." }; +To create general filesystems, use C<guestfs_mkfs>." }; { defaults with name = "get_e2attrs"; diff --git a/generator/generator_perl.ml b/generator/generator_perl.ml index b363bfc..3fd5c2d 100644 --- a/generator/generator_perl.ml +++ b/generator/generator_perl.ml @@ -938,7 +938,7 @@ containing useful introspection information about the method (further fields may be added to this in future). use Sys::Guestfs; - $Sys::Guestfs::guestfs_introspection{mkfs_opts} + $Sys::Guestfs::guestfs_introspection{mkfs} => { ret => 'void', # return type args => [ # required arguments @@ -951,7 +951,7 @@ containing useful introspection information about the method inode => [ 'inode', 'int', 2 ], sectorsize => [ 'sectorsize', 'int', 3 ], }, - name => \"mkfs_opts\", + name => \"mkfs\", description => \"make a filesystem\", } diff --git a/generator/generator_tests_c_api.ml b/generator/generator_tests_c_api.ml index 6505e91..83087da 100644 --- a/generator/generator_tests_c_api.ml +++ b/generator/generator_tests_c_api.ml @@ -452,7 +452,7 @@ and generate_one_test_body name i test_name init test ["umount_all"]; ["lvm_remove_all"]; ["part_disk"; "/dev/sda"; "mbr"]; - ["mkfs"; "ext2"; "/dev/sda1"]; + ["mkfs"; "ext2"; "/dev/sda1"; ""; "NOARG"; ""; ""]; ["mount_options"; ""; "/dev/sda1"; "/"]] | InitBasicFSonLVM -> pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n" @@ -465,7 +465,7 @@ and generate_one_test_body name i test_name init test ["pvcreate"; "/dev/sda1"]; ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV"; "VG"; "8"]; - ["mkfs"; "ext2"; "/dev/VG/LV"]; + ["mkfs"; "ext2"; "/dev/VG/LV"; ""; "NOARG"; ""; ""]; ["mount_options"; ""; "/dev/VG/LV"; "/"]] | InitISOFS -> pr " /* InitISOFS for %s */\n" test_name; diff --git a/gobject/Makefile.am b/gobject/Makefile.am index cc360c8..60e4fb9 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -45,6 +45,8 @@ CLEANFILES = \ CLEANFILES += \ src/optargs-add_drive_opts.c \ include/guestfs-gobject/optargs-add_drive_opts.h \ + src/optargs-mkfs_opts.c \ + include/guestfs-gobject/optargs-mkfs_opts.h \ src/optargs-test0.c \ include/guestfs-gobject/optargs-test0.h diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index d8c6eed..543fd9b 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -44,7 +44,7 @@ guestfs_gobject_headers= \ include/guestfs-gobject/optargs-inspect_get_icon.h \ include/guestfs-gobject/optargs-mount_local.h \ include/guestfs-gobject/optargs-umount_local.h \ - include/guestfs-gobject/optargs-mkfs_opts.h \ + include/guestfs-gobject/optargs-mkfs.h \ include/guestfs-gobject/optargs-mount_9p.h \ include/guestfs-gobject/optargs-ntfsresize_opts.h \ include/guestfs-gobject/optargs-btrfs_filesystem_resize.h \ @@ -88,7 +88,7 @@ guestfs_gobject_sources= \ src/optargs-inspect_get_icon.c \ src/optargs-mount_local.c \ src/optargs-umount_local.c \ - src/optargs-mkfs_opts.c \ + src/optargs-mkfs.c \ src/optargs-mount_9p.c \ src/optargs-ntfsresize_opts.c \ src/optargs-btrfs_filesystem_resize.c \ diff --git a/po/POTFILES b/po/POTFILES index f659a9d..d09a23c 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -147,8 +147,8 @@ gobject/src/optargs-fstrim.c gobject/src/optargs-inspect_get_icon.c gobject/src/optargs-internal_test.c gobject/src/optargs-md_create.c +gobject/src/optargs-mkfs.c gobject/src/optargs-mkfs_btrfs.c -gobject/src/optargs-mkfs_opts.c gobject/src/optargs-mount_9p.c gobject/src/optargs-mount_local.c gobject/src/optargs-ntfsclone_out.c diff --git a/tests/guests/guest-aux/make-debian-img.sh b/tests/guests/guest-aux/make-debian-img.sh index 659e8ec..00a68d5 100755 --- a/tests/guests/guest-aux/make-debian-img.sh +++ b/tests/guests/guest-aux/make-debian-img.sh @@ -48,18 +48,18 @@ lvcreate var debian 32 lvcreate home debian 32 # Phony /boot filesystem. -mkfs-opts ext2 /dev/sda1 blocksize:4096 +mkfs ext2 /dev/sda1 blocksize:4096 set-label /dev/sda1 BOOT set-e2uuid /dev/sda1 01234567-0123-0123-0123-012345678901 # Phony root and other filesystems. -mkfs-opts ext2 /dev/debian/root blocksize:4096 +mkfs ext2 /dev/debian/root blocksize:4096 set-e2uuid /dev/debian/root 01234567-0123-0123-0123-012345678902 -mkfs-opts ext2 /dev/debian/usr blocksize:4096 +mkfs ext2 /dev/debian/usr blocksize:4096 set-e2uuid /dev/debian/usr 01234567-0123-0123-0123-012345678903 -mkfs-opts ext2 /dev/debian/var blocksize:4096 +mkfs ext2 /dev/debian/var blocksize:4096 set-e2uuid /dev/debian/var 01234567-0123-0123-0123-012345678904 -mkfs-opts ext2 /dev/debian/home blocksize:4096 +mkfs ext2 /dev/debian/home blocksize:4096 set-e2uuid /dev/debian/home 01234567-0123-0123-0123-012345678905 # Enough to fool inspection API. diff --git a/tests/guests/guest-aux/make-fedora-img.pl b/tests/guests/guest-aux/make-fedora-img.pl index 6a0a183..9991b73 100755 --- a/tests/guests/guest-aux/make-fedora-img.pl +++ b/tests/guests/guest-aux/make-fedora-img.pl @@ -125,12 +125,12 @@ $g->lvcreate ('LV2', 'VG', 32); $g->lvcreate ('LV3', 'VG', 64); # Phony /boot filesystem -$g->mkfs_opts ('ext2', $bootdev, blocksize => 4096); +$g->mkfs ('ext2', $bootdev, blocksize => 4096); $g->set_label ($bootdev, 'BOOT'); $g->set_e2uuid ($bootdev, '01234567-0123-0123-0123-012345678901'); # Phony root filesystem. -$g->mkfs_opts ('ext2', '/dev/VG/Root', blocksize => 4096); +$g->mkfs ('ext2', '/dev/VG/Root', blocksize => 4096); $g->set_label ('/dev/VG/Root', 'ROOT'); $g->set_e2uuid ('/dev/VG/Root', '01234567-0123-0123-0123-012345678902'); @@ -190,9 +190,9 @@ $g->mknod (0777, 10, 10, '/bin/test7'); # Other filesystems. # Note that these should be empty, for testing virt-df. -$g->mkfs_opts ('ext2', '/dev/VG/LV1', blocksize => 4096); -$g->mkfs_opts ('ext2', '/dev/VG/LV2', blocksize => 1024); -$g->mkfs_opts ('ext2', '/dev/VG/LV3', blocksize => 2048); +$g->mkfs ('ext2', '/dev/VG/LV1', blocksize => 4096); +$g->mkfs ('ext2', '/dev/VG/LV2', blocksize => 1024); +$g->mkfs ('ext2', '/dev/VG/LV3', blocksize => 2048); # Cleanup $g->shutdown (); diff --git a/tests/guests/guest-aux/make-ubuntu-img.sh b/tests/guests/guest-aux/make-ubuntu-img.sh index 8138860..7a58319 100755 --- a/tests/guests/guest-aux/make-ubuntu-img.sh +++ b/tests/guests/guest-aux/make-ubuntu-img.sh @@ -49,12 +49,12 @@ part-add /dev/sda p 64 524287 part-add /dev/sda p 524288 -64 # Phony /boot filesystem. -mkfs-opts ext2 /dev/sda1 blocksize:4096 +mkfs ext2 /dev/sda1 blocksize:4096 set-label /dev/sda1 BOOT set-e2uuid /dev/sda1 01234567-0123-0123-0123-012345678901 # Phony root filesystem (Ubuntu doesn't use LVM by default). -mkfs-opts ext2 /dev/sda2 blocksize:4096 +mkfs ext2 /dev/sda2 blocksize:4096 set-e2uuid /dev/sda2 01234567-0123-0123-0123-012345678902 # Enough to fool inspection API. -- 1.7.10.4
Richard W.M. Jones
2012-Jul-14 13:28 UTC
[Libguestfs] [PATCH 6/6] generator: Rename 'ntfsresize_opts' API to 'ntfsresize'.
From: "Richard W.M. Jones" <rjones at redhat.com> By using the once_had_no_optargs flag, this change is backwards compatible for callers. --- daemon/ntfs.c | 16 +++++----------- generator/generator_actions.ml | 27 ++++----------------------- gobject/Makefile.am | 2 ++ gobject/Makefile.inc | 4 ++-- po/POTFILES | 2 +- resize/resize.ml | 2 +- 6 files changed, 15 insertions(+), 38 deletions(-) diff --git a/daemon/ntfs.c b/daemon/ntfs.c index 235ecbc..2dedc26 100644 --- a/daemon/ntfs.c +++ b/daemon/ntfs.c @@ -64,7 +64,7 @@ do_ntfs_3g_probe (int rw, const char *device) /* Takes optional arguments, consult optargs_bitmask. */ int -do_ntfsresize_opts (const char *device, int64_t size, int force) +do_ntfsresize (const char *device, int64_t size, int force) { char *err; int r; @@ -75,7 +75,7 @@ do_ntfsresize_opts (const char *device, int64_t size, int force) ADD_ARG (argv, i, "ntfsresize"); ADD_ARG (argv, i, "-P"); - if (optargs_bitmask & GUESTFS_NTFSRESIZE_OPTS_SIZE_BITMASK) { + if (optargs_bitmask & GUESTFS_NTFSRESIZE_SIZE_BITMASK) { if (size <= 0) { reply_with_error ("size is zero or negative"); return -1; @@ -86,7 +86,7 @@ do_ntfsresize_opts (const char *device, int64_t size, int force) ADD_ARG (argv, i, size_str); } - if (optargs_bitmask & GUESTFS_NTFSRESIZE_OPTS_FORCE_BITMASK && force) + if (optargs_bitmask & GUESTFS_NTFSRESIZE_FORCE_BITMASK && force) ADD_ARG (argv, i, "--force"); ADD_ARG (argv, i, device); @@ -104,16 +104,10 @@ do_ntfsresize_opts (const char *device, int64_t size, int force) } int -do_ntfsresize (const char *device) -{ - return do_ntfsresize_opts (device, 0, 0); -} - -int do_ntfsresize_size (const char *device, int64_t size) { - optargs_bitmask = GUESTFS_NTFSRESIZE_OPTS_SIZE_BITMASK; - return do_ntfsresize_opts (device, size, 0); + optargs_bitmask = GUESTFS_NTFSRESIZE_SIZE_BITMASK; + return do_ntfsresize (device, size, 0); } /* Takes optional arguments, consult optargs_bitmask. */ diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index b530f77..9322126 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -6710,26 +6710,6 @@ This command packs the contents of C<directory> and downloads it to local file C<tarball> (as an xz compressed tar archive)." }; { defaults with - name = "ntfsresize"; - style = RErr, [Device "device"], []; - proc_nr = Some 231; - optional = Some "ntfsprogs"; deprecated_by = Some "ntfsresize_opts"; - shortdesc = "resize an NTFS filesystem"; - longdesc = "\ -This command resizes an NTFS filesystem, expanding or -shrinking it to the size of the underlying device. - -I<Note:> After the resize operation, the filesystem is marked -as requiring a consistency check (for safety). You have to boot -into Windows to perform this check and clear this condition. -Furthermore, ntfsresize refuses to resize filesystems -which have been marked in this way. So in effect it is -not possible to call ntfsresize multiple times on a single -filesystem without booting into Windows between each resize. - -See also L<ntfsresize(8)>." }; - - { defaults with name = "vgscan"; style = RErr, [], []; proc_nr = Some 232; @@ -7039,7 +7019,7 @@ allows you to specify the new size (in bytes) explicitly." }; name = "ntfsresize_size"; style = RErr, [Device "device"; Int64 "size"], []; proc_nr = Some 250; - optional = Some "ntfsprogs"; deprecated_by = Some "ntfsresize_opts"; + optional = Some "ntfsprogs"; deprecated_by = Some "ntfsresize"; shortdesc = "resize an NTFS filesystem (with size)"; longdesc = "\ This command is the same as C<guestfs_ntfsresize> except that it @@ -7750,8 +7730,9 @@ returned in this list. Call C<guestfs_lvs> if you want to list logical volumes." }; { defaults with - name = "ntfsresize_opts"; + name = "ntfsresize"; style = RErr, [Device "device"], [OInt64 "size"; OBool "force"]; + once_had_no_optargs = true; proc_nr = Some 288; optional = Some "ntfsprogs"; camel_name = "NTFSResizeOpts"; shortdesc = "resize an NTFS filesystem"; @@ -7777,7 +7758,7 @@ After the resize operation, the filesystem is always marked as requiring a consistency check (for safety). You have to boot into Windows to perform this check and clear this condition. If you I<don't> set the C<force> option then it is not -possible to call C<guestfs_ntfsresize_opts> multiple times on a +possible to call C<guestfs_ntfsresize> multiple times on a single filesystem without booting into Windows between each resize. =back diff --git a/gobject/Makefile.am b/gobject/Makefile.am index 60e4fb9..ce4a853 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -47,6 +47,8 @@ CLEANFILES += \ include/guestfs-gobject/optargs-add_drive_opts.h \ src/optargs-mkfs_opts.c \ include/guestfs-gobject/optargs-mkfs_opts.h \ + src/optargs-ntfsresize_opts.c \ + include/guestfs-gobject/optargs-ntfsresize_opts.h \ src/optargs-test0.c \ include/guestfs-gobject/optargs-test0.h diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index 543fd9b..4de56a9 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -46,7 +46,7 @@ guestfs_gobject_headers= \ include/guestfs-gobject/optargs-umount_local.h \ include/guestfs-gobject/optargs-mkfs.h \ include/guestfs-gobject/optargs-mount_9p.h \ - include/guestfs-gobject/optargs-ntfsresize_opts.h \ + include/guestfs-gobject/optargs-ntfsresize.h \ include/guestfs-gobject/optargs-btrfs_filesystem_resize.h \ include/guestfs-gobject/optargs-compress_out.h \ include/guestfs-gobject/optargs-compress_device_out.h \ @@ -90,7 +90,7 @@ guestfs_gobject_sources= \ src/optargs-umount_local.c \ src/optargs-mkfs.c \ src/optargs-mount_9p.c \ - src/optargs-ntfsresize_opts.c \ + src/optargs-ntfsresize.c \ src/optargs-btrfs_filesystem_resize.c \ src/optargs-compress_out.c \ src/optargs-compress_device_out.c \ diff --git a/po/POTFILES b/po/POTFILES index d09a23c..7f67911 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -153,7 +153,7 @@ gobject/src/optargs-mount_9p.c gobject/src/optargs-mount_local.c gobject/src/optargs-ntfsclone_out.c gobject/src/optargs-ntfsfix.c -gobject/src/optargs-ntfsresize_opts.c +gobject/src/optargs-ntfsresize.c gobject/src/optargs-set_e2attrs.c gobject/src/optargs-tune2fs.c gobject/src/optargs-umount_local.c diff --git a/resize/resize.ml b/resize/resize.ml index 9ef2bbd..90b4e99 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1139,7 +1139,7 @@ let () let do_expand_content target = function | PVResize -> g#pvresize target | Resize2fs -> g#resize2fs target - | NTFSResize -> g#ntfsresize_opts ~force:ntfsresize_force target + | NTFSResize -> g#ntfsresize ~force:ntfsresize_force target | BtrfsFilesystemResize -> (* Complicated ... Btrfs forces us to mount the filesystem * in order to resize it. -- 1.7.10.4
Reasonably Related Threads
- [PATCH 1/2] c: NFC Remove redundant parentheses
- [PATCH 1/2] gobject: Use generator_built macro to ensure generated files are rebuilt properly.
- [PATCH 0/9] build: Require OCaml >= 4.02.
- [PATCH 0/7] Add tar compress, numericowner, excludes flags.
- [PATCH v3 0/5] Add symbol versioning.