X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=generator%2Fgenerator_daemon.ml;h=9f15abdf90438ae30af8a96360b95ef74fe5138c;hp=4ac2a6e924039ddda925da79c409008b05a0260e;hb=HEAD;hpb=04d8209077d2227eb1d42695ba71147f78987050 diff --git a/generator/generator_daemon.ml b/generator/generator_daemon.ml index 4ac2a6e..9f15abd 100644 --- a/generator/generator_daemon.ml +++ b/generator/generator_daemon.ml @@ -33,11 +33,26 @@ open Generator_c let generate_daemon_actions_h () = generate_header CStyle GPLv2plus; - pr "#include \"../src/guestfs_protocol.h\"\n"; + pr "#include \"guestfs_protocol.h\"\n"; pr "\n"; List.iter ( - fun (name, style, _, _, _, _, _) -> + function + | shortname, (_, _, (_::_ as optargs)), _, _, _, _, _ -> + iteri ( + fun i arg -> + let uc_shortname = String.uppercase shortname in + let n = name_of_optargt arg in + let uc_n = String.uppercase n in + pr "#define GUESTFS_%s_%s_BITMASK (UINT64_C(1)<<%d)\n" + uc_shortname uc_n i + ) optargs + | _ -> () + ) daemon_functions; + + List.iter ( + fun (name, (ret, args, optargs), _, _, _, _, _) -> + let style = ret, args @ args_of_optargs optargs, [] in generate_prototype ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_" name style; @@ -58,147 +73,176 @@ and generate_daemon_actions () = pr "\n"; pr "#include \"daemon.h\"\n"; pr "#include \"c-ctype.h\"\n"; - pr "#include \"../src/guestfs_protocol.h\"\n"; + pr "#include \"guestfs_protocol.h\"\n"; pr "#include \"actions.h\"\n"; pr "\n"; List.iter ( - fun (name, style, _, _, _, _, _) -> + fun (name, (ret, args, optargs), _, _, _, _, _) -> (* Generate server-side stubs. *) pr "static void %s_stub (XDR *xdr_in)\n" name; pr "{\n"; - let error_code = - match fst style with - | RErr | RInt _ -> pr " int r;\n"; "-1" - | RInt64 _ -> pr " int64_t r;\n"; "-1" - | RBool _ -> pr " int r;\n"; "-1" - | RConstString _ | RConstOptString _ -> - failwithf "RConstString|RConstOptString cannot be used by daemon functions" - | RString _ -> pr " char *r;\n"; "NULL" - | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL" - | RStruct (_, typ) -> pr " guestfs_int_%s *r;\n" typ; "NULL" - | RStructList (_, typ) -> pr " guestfs_int_%s_list *r;\n" typ; "NULL" - | RBufferOut _ -> - pr " size_t size = 1;\n"; - pr " char *r;\n"; - "NULL" in - - (match snd style with - | [] -> () - | args -> - pr " struct guestfs_%s_args args;\n" name; - List.iter ( - function - | Device n | Dev_or_Path n - | Pathname n - | String n - | Key n -> () - | OptString n -> pr " char *%s;\n" n - | StringList n | DeviceList n -> pr " char **%s;\n" n - | Bool n -> pr " int %s;\n" n - | Int n -> pr " int %s;\n" n - | Int64 n -> pr " int64_t %s;\n" n - | FileIn _ | FileOut _ -> () - | BufferIn n -> - pr " const char *%s;\n" n; - pr " size_t %s_size;\n" n - ) args + (match ret with + | RErr | RInt _ -> pr " int r;\n" + | RInt64 _ -> pr " int64_t r;\n" + | RBool _ -> pr " int r;\n" + | RConstString _ | RConstOptString _ -> + failwithf "RConstString|RConstOptString cannot be used by daemon functions" + | RString _ -> pr " char *r;\n" + | RStringList _ | RHashtable _ -> pr " char **r;\n" + | RStruct (_, typ) -> pr " guestfs_int_%s *r;\n" typ + | RStructList (_, typ) -> pr " guestfs_int_%s_list *r;\n" typ + | RBufferOut _ -> + pr " size_t size = 1;\n"; + pr " char *r;\n" + ); + + if args <> [] || optargs <> [] then ( + pr " struct guestfs_%s_args args;\n" name; + List.iter ( + function + | Device n | Dev_or_Path n + | Pathname n + | String n + | Key n -> () + | OptString n -> pr " char *%s;\n" n + | StringList n | DeviceList n -> pr " char **%s;\n" n + | Bool n -> pr " int %s;\n" n + | Int n -> pr " int %s;\n" n + | Int64 n -> pr " int64_t %s;\n" n + | FileIn _ | FileOut _ -> () + | BufferIn n -> + pr " const char *%s;\n" n; + pr " size_t %s_size;\n" n + | Pointer _ -> assert false + ) (args @ args_of_optargs optargs) ); pr "\n"; let is_filein = - List.exists (function FileIn _ -> true | _ -> false) (snd style) in + List.exists (function FileIn _ -> true | _ -> false) args in - (match snd style with - | [] -> () - | args -> - pr " memset (&args, 0, sizeof args);\n"; - pr "\n"; - pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name; - if is_filein then - pr " if (cancel_receive () != -2)\n"; - pr " reply_with_error (\"daemon failed to decode procedure arguments\");\n"; - pr " goto done;\n"; - pr " }\n"; - let pr_args n = - pr " char *%s = args.%s;\n" n n - in - let pr_list_handling_code n = - pr " %s = realloc (args.%s.%s_val,\n" n n n; - pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n; - pr " if (%s == NULL) {\n" n; - if is_filein then - pr " if (cancel_receive () != -2)\n"; - pr " reply_with_perror (\"realloc\");\n"; - pr " goto done;\n"; - pr " }\n"; - pr " %s[args.%s.%s_len] = NULL;\n" n n n; - pr " args.%s.%s_val = %s;\n" n n n; - in - List.iter ( - function - | Pathname n -> - pr_args n; - pr " ABS_PATH (%s, %s, goto done);\n" - n (if is_filein then "cancel_receive ()" else "0"); - | Device n -> - pr_args n; - pr " RESOLVE_DEVICE (%s, %s, goto done);\n" - n (if is_filein then "cancel_receive ()" else "0"); - | Dev_or_Path n -> - pr_args n; - pr " REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n" - n (if is_filein then "cancel_receive ()" else "0"); - | String n | Key n -> pr_args n - | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n - | StringList n -> - pr_list_handling_code n; - | DeviceList n -> - pr_list_handling_code n; - pr " /* Ensure that each is a device,\n"; - pr " * and perform device name translation.\n"; - pr " */\n"; - pr " {\n"; - pr " size_t i;\n"; - pr " for (i = 0; %s[i] != NULL; ++i)\n" n; - pr " RESOLVE_DEVICE (%s[i], %s, goto done);\n" n - (if is_filein then "cancel_receive ()" else "0"); - pr " }\n"; - | Bool n -> pr " %s = args.%s;\n" n n - | Int n -> pr " %s = args.%s;\n" n n - | Int64 n -> pr " %s = args.%s;\n" n n - | FileIn _ | FileOut _ -> () - | BufferIn n -> - pr " %s = args.%s.%s_val;\n" n n n; - pr " %s_size = args.%s.%s_len;\n" n n n - ) args; - pr "\n" + (* Reject unknown optional arguments. + * Note this code is included even for calls with no optional + * args because the caller must not pass optargs_bitmask != 0 + * in that case. + *) + if optargs <> [] then ( + 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; + if is_filein then + pr " cancel_receive ();\n"; + pr " reply_with_error (\"unknown option in optional arguments bitmask (this can happen if a program is compiled against a newer version of libguestfs, then run against an older version of the daemon)\");\n"; + pr " goto done;\n"; + pr " }\n"; + ) else ( + pr " if (optargs_bitmask != 0) {\n"; + if is_filein then + pr " cancel_receive ();\n"; + pr " reply_with_error (\"header optargs_bitmask field must be passed as 0 for calls that don't take optional arguments\");\n"; + pr " goto done;\n"; + pr " }\n"; + ); + pr "\n"; + + (* Decode arguments. *) + if args <> [] || optargs <> [] then ( + pr " memset (&args, 0, sizeof args);\n"; + pr "\n"; + pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name; + if is_filein then + pr " cancel_receive ();\n"; + pr " reply_with_error (\"daemon failed to decode procedure arguments\");\n"; + pr " goto done;\n"; + pr " }\n"; + let pr_args n = + pr " char *%s = args.%s;\n" n n + in + let pr_list_handling_code n = + pr " %s = realloc (args.%s.%s_val,\n" n n n; + pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n; + pr " if (%s == NULL) {\n" n; + if is_filein then + pr " cancel_receive ();\n"; + pr " reply_with_perror (\"realloc\");\n"; + pr " goto done;\n"; + pr " }\n"; + pr " %s[args.%s.%s_len] = NULL;\n" n n n; + pr " args.%s.%s_val = %s;\n" n n n; + in + List.iter ( + function + | Pathname n -> + pr_args n; + pr " ABS_PATH (%s, %s, goto done);\n" + n (if is_filein then "cancel_receive ()" else ""); + | Device n -> + pr_args n; + pr " RESOLVE_DEVICE (%s, %s, goto done);\n" + n (if is_filein then "cancel_receive ()" else ""); + | Dev_or_Path n -> + pr_args n; + pr " REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n" + n (if is_filein then "cancel_receive ()" else ""); + | String n | Key n -> pr_args n + | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n + | StringList n -> + pr_list_handling_code n; + | DeviceList n -> + pr_list_handling_code n; + pr " /* Ensure that each is a device,\n"; + pr " * and perform device name translation.\n"; + pr " */\n"; + pr " {\n"; + pr " size_t i;\n"; + pr " for (i = 0; %s[i] != NULL; ++i)\n" n; + pr " RESOLVE_DEVICE (%s[i], %s, goto done);\n" n + (if is_filein then "cancel_receive ()" else ""); + pr " }\n"; + | Bool n -> pr " %s = args.%s;\n" n n + | Int n -> pr " %s = args.%s;\n" n n + | Int64 n -> pr " %s = args.%s;\n" n n + | FileIn _ | FileOut _ -> () + | BufferIn n -> + pr " %s = args.%s.%s_val;\n" n n n; + pr " %s_size = args.%s.%s_len;\n" n n n + | Pointer _ -> assert false + ) (args @ args_of_optargs optargs); + pr "\n" ); (* this is used at least for do_equal *) - if List.exists (function Pathname _ -> true | _ -> false) (snd style) then ( + if List.exists (function Pathname _ -> true | _ -> false) args then ( (* Emit NEED_ROOT just once, even when there are two or more Pathname args *) pr " NEED_ROOT (%s, goto done);\n" - (if is_filein then "cancel_receive ()" else "0"); + (if is_filein then "cancel_receive ()" else ""); ); (* Don't want to call the impl with any FileIn or FileOut * parameters, since these go "outside" the RPC protocol. *) - let args' = - List.filter (function FileIn _ | FileOut _ -> false | _ -> true) - (snd style) in - pr " r = do_%s " name; - generate_c_call_args (fst style, args'); - pr ";\n"; - - (match fst style with + let () = + let args' = + List.filter + (function FileIn _ | FileOut _ -> false | _ -> true) args in + let style = ret, args' @ args_of_optargs optargs, [] in + pr " r = do_%s " name; + generate_c_call_args style; + pr ";\n" in + + (match ret with + | RConstOptString _ -> assert false | RErr | RInt _ | RInt64 _ | RBool _ - | RConstString _ | RConstOptString _ + | RConstString _ | RString _ | RStringList _ | RHashtable _ | RStruct (_, _) | RStructList (_, _) -> - pr " if (r == %s)\n" error_code; + let errcode = + match errcode_of_ret ret with + | `CannotReturnError -> assert false + | (`ErrorIsMinusOne | `ErrorIsNULL) as e -> e in + pr " if (r == %s)\n" (string_of_errcode errcode); pr " /* do_%s has already called reply_with_error */\n" name; pr " goto done;\n"; pr "\n" @@ -206,7 +250,7 @@ and generate_daemon_actions () = pr " /* size == 0 && r == NULL could be a non-error case (just\n"; pr " * an ordinary zero-length buffer), so be careful ...\n"; pr " */\n"; - pr " if (size == 1 && r == %s)\n" error_code; + pr " if (size == 1 && r == NULL)\n"; pr " /* do_%s has already called reply_with_error */\n" name; pr " goto done;\n"; pr "\n" @@ -216,11 +260,11 @@ and generate_daemon_actions () = * send its own reply. *) let no_reply = - List.exists (function FileOut _ -> true | _ -> false) (snd style) in + List.exists (function FileOut _ -> true | _ -> false) args in if no_reply then pr " /* do_%s has already sent a reply */\n" name else ( - match fst style with + match ret with | RErr -> pr " reply (NULL, NULL);\n" | RInt n | RInt64 n | RBool n -> pr " struct guestfs_%s_ret ret;\n" name; @@ -245,6 +289,7 @@ and generate_daemon_actions () = | RStruct (n, _) -> pr " struct guestfs_%s_ret ret;\n" name; pr " ret.%s = *r;\n" n; + pr " free (r);\n"; pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name; pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" @@ -252,6 +297,7 @@ and generate_daemon_actions () = | RStructList (n, _) -> pr " struct guestfs_%s_ret ret;\n" name; pr " ret.%s = *r;\n" n; + pr " free (r);\n"; pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name; pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" @@ -267,7 +313,7 @@ and generate_daemon_actions () = (* Free the args. *) pr "done:\n"; - (match snd style with + (match args with | [] -> () | _ -> pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n" @@ -283,7 +329,7 @@ and generate_daemon_actions () = pr " switch (proc_nr) {\n"; List.iter ( - fun (name, style, _, _, _, _, _) -> + fun (name, _, _, _, _, _, _) -> pr " case GUESTFS_PROC_%s:\n" (String.uppercase name); pr " %s_stub (xdr_in);\n" name; pr " break;\n"