X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fgenerator.ml;h=dac2fd1557441f945418a24946e43192a2024c9f;hb=e167a8af4070299562da8fc76e1797e3f6facad6;hp=8cfd136f4e02bb0df988e4770db40d31abacd990;hpb=6cbbecfd164fb782074ff5018a92f194b87adb94;p=libguestfs.git diff --git a/src/generator.ml b/src/generator.ml index 8cfd136..dac2fd1 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -307,6 +307,9 @@ and test_prereq = (* As for 'If' but the test runs _unless_ the code returns true. *) | Unless of string + (* Run the test only if 'string' is available in the daemon. *) + | IfAvailable of string + (* Some initial scenarios for testing. *) and test_init = (* Do nothing, block devices could contain random stuff including @@ -545,15 +548,13 @@ handle is closed. We don't currently have any method to enable changes to be committed, although qemu can support this. This is equivalent to the qemu parameter -C<-drive file=filename,snapshot=on,readonly=on,if=...>. +C<-drive file=filename,snapshot=on,if=...>. C is set at compile time by the configuration option C<./configure --with-drive-if=...>. In the rare case where you might need to change this at run time, use C or C. -C is only added where qemu supports this option. - Note that this call checks for the existence of C. This stops you from specifying other types of drive which are supported by qemu such as C and C URLs. To specify those, use @@ -807,8 +808,10 @@ C<$major.$minor.$release$extra> See also: L. I Don't use this call to test for availability -of features. Distro backports makes this unreliable. Use -C instead."); +of features. In enterprise distributions we backport +features from later versions into earlier versions, +making this an unreliable way to test for features. +Use C instead."); ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"], [InitNone, Always, TestOutputTrue ( @@ -1550,7 +1553,10 @@ C"); ["cat"; "/new"]], "\n\n\n"); InitBasicFS, Always, TestOutput ( [["write_file"; "/new"; "\n"; "0"]; - ["cat"; "/new"]], "\n")], + ["cat"; "/new"]], "\n"); + (* Regression test for RHBZ#597135. *) + InitBasicFS, Always, TestLastFail + [["write_file"; "/new"; "abc"; "10000"]]], "create a file", "\ This call creates a file called C. The contents of the @@ -2322,7 +2328,18 @@ See also: C."); "install GRUB", "\ This command installs GRUB (the Grand Unified Bootloader) on -C, with the root directory being C."); +C, with the root directory being C. + +Note: If grub-install reports the error +\"No suitable drive was found in the generated device map.\" +it may be that you need to create a C +file first that contains the mapping between grub device names +and Linux device names. It is usually sufficient to create +a file containing: + + (hd0) /dev/vda + +replacing C with the name of the installation device."); ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [], [InitBasicFS, Always, TestOutput ( @@ -2628,9 +2645,9 @@ is lost."); ("resize2fs", (RErr, [Device "device"]), 106, [], [], (* lvresize tests this *) - "resize an ext2/ext3 filesystem", + "resize an ext2, ext3 or ext4 filesystem", "\ -This resizes an ext2 or ext3 filesystem to match the size of +This resizes an ext2, ext3 or ext4 filesystem to match the size of the underlying device. I It is sometimes required that you run C @@ -3888,12 +3905,13 @@ See also C."); [["vfs_type"; "/dev/sda1"]], "ext2")], "get the Linux VFS type corresponding to a mounted device", "\ -This command gets the block device type corresponding to -a mounted device called C. +This command gets the filesystem type corresponding to +the filesystem on C. -Usually the result is the name of the Linux VFS module that -is used to mount this device (probably determined automatically -if you used the C call)."); +For most filesystems, the result is the name of the Linux +VFS module which would be used to mount this filesystem +if you mounted it without specifying the filesystem type. +For example a string such as C or C."); ("truncate", (RErr, [Pathname "path"]), 199, [], [InitBasicFS, Always, TestOutputStruct ( @@ -5218,7 +5236,7 @@ let rec generate_actions_pod () = The string is owned by the guest handle and must I be freed.\n\n" | RConstOptString _ -> pr "This function returns a string which may be NULL. -There is way to return an error from this function. +There is no way to return an error from this function. The string is owned by the guest handle and must I be freed.\n\n" | RString _ -> pr "This function returns a string, or NULL on error. @@ -5323,7 +5341,7 @@ and generate_xdr () = generate_header CStyle LGPLv2plus; (* This has to be defined to get around a limitation in Sun's rpcgen. *) - pr "typedef string str<>;\n"; + pr "typedef string guestfs_str<>;\n"; pr "\n"; (* Internal structures. *) @@ -5358,8 +5376,8 @@ and generate_xdr () = function | Pathname n | Device n | Dev_or_Path n | String n -> pr " string %s<>;\n" n - | OptString n -> pr " str *%s;\n" n - | StringList n | DeviceList n -> pr " str %s<>;\n" n + | OptString n -> pr " guestfs_str *%s;\n" n + | StringList n | DeviceList n -> pr " guestfs_str %s<>;\n" n | Bool n -> pr " bool %s;\n" n | Int n -> pr " int %s;\n" n | Int64 n -> pr " hyper %s;\n" n @@ -5389,7 +5407,7 @@ and generate_xdr () = pr "};\n\n" | RStringList n -> pr "struct %s_ret {\n" name; - pr " str %s<>;\n" n; + pr " guestfs_str %s<>;\n" n; pr "};\n\n" | RStruct (n, typ) -> pr "struct %s_ret {\n" name; @@ -5401,7 +5419,7 @@ and generate_xdr () = pr "};\n\n" | RHashtable n -> pr "struct %s_ret {\n" name; - pr " str %s<>;\n" n; + pr " guestfs_str %s<>;\n" n; pr "};\n\n" | RBufferOut n -> pr "struct %s_ret {\n" name; @@ -5625,7 +5643,7 @@ check_state (guestfs_h *g, const char *caller) | StringList _ | DeviceList _ -> true | _ -> false) (snd style) in if needs_i then ( - pr " int i;\n"; + pr " size_t i;\n"; pr "\n" ); @@ -5934,6 +5952,8 @@ and generate_linker_script () = *) "guestfs_safe_calloc"; "guestfs_safe_malloc"; + "guestfs_safe_strdup"; + "guestfs_safe_memdup"; ] in let functions = List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name) @@ -6054,9 +6074,12 @@ and generate_daemon_actions () = | DeviceList n -> pr_list_handling_code n; pr " /* Ensure that each is a device,\n"; - pr " * and perform device name translation. */\n"; - pr " { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n"; - pr " RESOLVE_DEVICE (physvols[pvi], goto done);\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], goto done);\n" n; pr " }\n"; | Bool n -> pr " %s = args.%s;\n" n n | Int n -> pr " %s = args.%s;\n" n n @@ -6201,7 +6224,7 @@ and generate_daemon_actions () = pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ; pr "{\n"; pr " char *tok, *p, *next;\n"; - pr " int i, j;\n"; + pr " size_t i, j;\n"; pr "\n"; (* pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n"; @@ -6426,7 +6449,7 @@ static void print_error (guestfs_h *g, void *data, const char *msg) /* FIXME: nearly identical code appears in fish.c */ static void print_strings (char *const *argv) { - int argc; + size_t argc; for (argc = 0; argv[argc] != NULL; ++argc) printf (\"\\t%%s\\n\", argv[argc]); @@ -6435,13 +6458,26 @@ static void print_strings (char *const *argv) /* static void print_table (char const *const *argv) { - int i; + size_t i; for (i = 0; argv[i] != NULL; i += 2) printf (\"%%s: %%s\\n\", argv[i], argv[i+1]); } */ +static int +is_available (const char *group) +{ + const char *groups[] = { group, NULL }; + int r; + + suppress_error = 1; + r = guestfs_available (g, (char **) groups); + suppress_error = 0; + + return r == 0; +} + "; (* Generate a list of commands which are not tested anywhere. *) @@ -6453,7 +6489,7 @@ static void print_table (char const *const *argv) fun (_, _, _, _, tests, _, _) -> let tests = filter_map ( function - | (_, (Always|If _|Unless _), test) -> Some test + | (_, (Always|If _|Unless _|IfAvailable _), test) -> Some test | (_, Disabled, _) -> None ) tests in let seq = List.concat (List.map seq_of_test tests) in @@ -6659,7 +6695,7 @@ static int %s_skip (void) " test_name name (String.uppercase test_name) (String.uppercase name); (match prereq with - | Disabled | Always -> () + | Disabled | Always | IfAvailable _ -> () | If code | Unless code -> pr "static int %s_prereq (void)\n" test_name; pr "{\n"; @@ -6684,16 +6720,9 @@ static int %s (void) List.iter ( function | Optional group -> - pr " {\n"; - pr " const char *groups[] = { \"%s\", NULL };\n" group; - pr " int r;\n"; - pr " suppress_error = 1;\n"; - pr " r = guestfs_available (g, (char **) groups);\n"; - pr " suppress_error = 0;\n"; - pr " if (r == -1) {\n"; - pr " printf (\" %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name; - pr " return 0;\n"; - pr " }\n"; + pr " if (!is_available (\"%s\")) {\n" group; + pr " printf (\" %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", \"%s\");\n" test_name group; + pr " return 0;\n"; pr " }\n"; | _ -> () ) flags; @@ -6715,6 +6744,13 @@ static int %s (void) pr " }\n"; pr "\n"; generate_one_test_body name i test_name init test; + | IfAvailable group -> + pr " if (!is_available (\"%s\")) {\n" group; + pr " printf (\" %%s skipped (reason: %%s not available)\\n\", \"%s\", \"%s\");\n" test_name group; + pr " return 0;\n"; + pr " }\n"; + pr "\n"; + generate_one_test_body name i test_name init test; | Always -> generate_one_test_body name i test_name init test ); @@ -7056,7 +7092,7 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd = | RString _ -> pr " char *r;\n"; "NULL" | RStringList _ | RHashtable _ -> pr " char **r;\n"; - pr " int i;\n"; + pr " size_t i;\n"; "NULL" | RStruct (_, typ) -> pr " struct guestfs_%s *r;\n" typ; "NULL" @@ -7185,7 +7221,7 @@ and generate_fish_cmds () = pr "\n"; (* display_command function, which implements guestfish -h cmd *) - pr "void display_command (const char *cmd)\n"; + pr "int display_command (const char *cmd)\n"; pr "{\n"; List.iter ( fun (name, style, _, flags, _, shortdesc, longdesc) -> @@ -7233,15 +7269,17 @@ and generate_fish_cmds () = pr " || STRCASEEQ (cmd, \"%s\")" name2; if name <> alias then pr " || STRCASEEQ (cmd, \"%s\")" alias; - pr ")\n"; + pr ") {\n"; pr " pod2text (\"%s\", _(\"%s\"), %S);\n" name2 shortdesc ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^ "=head1 DESCRIPTION\n\n" ^ longdesc ^ warnings ^ describe_alias); + pr " return 0;\n"; + pr " }\n"; pr " else\n" ) all_functions; - pr " display_builtin_command (cmd);\n"; + pr " return display_builtin_command (cmd);\n"; pr "}\n"; pr "\n"; @@ -7450,9 +7488,10 @@ and generate_fish_cmds () = List.iter ( function - | Device name | String name - | OptString name | FileIn name | FileOut name | Bool name - | Int name | Int64 name -> () + | Device _ | String _ + | OptString _ | Bool _ + | Int _ | Int64 _ + | FileIn _ | FileOut _ -> () | Pathname name | Dev_or_Path name -> pr " free (%s);\n" name | StringList name | DeviceList name -> @@ -7600,7 +7639,7 @@ static const char *const commands[] = { static char * generator (const char *text, int state) { - static int index, len; + static size_t index, len; const char *name; if (!state) { @@ -7884,7 +7923,7 @@ and generate_ocaml_c () = #include #include -#include +#include \"guestfs.h\" #include \"guestfs_c.h\" @@ -7897,7 +7936,7 @@ copy_table (char * const * argv) { CAMLparam0 (); CAMLlocal5 (rv, pairv, kv, vv, cons); - int i; + size_t i; rv = Val_int (0); for (i = 0; argv[i] != NULL; i += 2) { @@ -8052,11 +8091,12 @@ copy_table (char * const * argv) | String n | FileIn n | FileOut n -> - pr " const char *%s = String_val (%sv);\n" n n + (* Copy strings in case the GC moves them: RHBZ#604691 *) + pr " char *%s = guestfs_safe_strdup (g, String_val (%sv));\n" n n | OptString n -> - pr " const char *%s =\n" n; - pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n" - n n + pr " char *%s =\n" n; + pr " %sv != Val_int (0) ?" n; + pr " guestfs_safe_strdup (g, String_val (Field (%sv, 0))) : NULL;\n" n | StringList n | DeviceList n -> pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n | Bool n -> @@ -8076,7 +8116,7 @@ copy_table (char * const * argv) pr " const char *r;\n"; "NULL" | RString _ -> pr " char *r;\n"; "NULL" | RStringList _ -> - pr " int i;\n"; + pr " size_t i;\n"; pr " char **r;\n"; "NULL" | RStruct (_, typ) -> @@ -8084,7 +8124,7 @@ copy_table (char * const * argv) | RStructList (_, typ) -> pr " struct guestfs_%s_list *r;\n" typ; "NULL" | RHashtable _ -> - pr " int i;\n"; + pr " size_t i;\n"; pr " char **r;\n"; "NULL" | RBufferOut _ -> @@ -8099,13 +8139,15 @@ copy_table (char * const * argv) pr ";\n"; pr " caml_leave_blocking_section ();\n"; + (* Free strings if we copied them above. *) List.iter ( function + | Pathname n | Device n | Dev_or_Path n | String n | OptString n + | FileIn n | FileOut n -> + pr " free (%s);\n" n | StringList n | DeviceList n -> pr " ocaml_guestfs_free_strings (%s);\n" n; - | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _ - | Bool _ | Int _ | Int64 _ - | FileIn _ | FileOut _ -> () + | Bool _ | Int _ | Int64 _ -> () ) (snd style); pr " if (r == %s)\n" error_code; @@ -8444,7 +8486,7 @@ DESTROY (g) | RStringList n | RHashtable n -> pr "PREINIT:\n"; pr " char **%s;\n" n; - pr " int i, n;\n"; + pr " size_t i, n;\n"; pr " PPCODE:\n"; pr " %s = guestfs_%s " n name; generate_c_call_args ~handle:"g" style; @@ -8488,7 +8530,7 @@ DESTROY (g) and generate_perl_struct_list_code typ cols name style n do_cleanups = pr "PREINIT:\n"; pr " struct guestfs_%s_list *%s;\n" typ n; - pr " int i;\n"; + pr " size_t i;\n"; pr " HV *hv;\n"; pr " PPCODE:\n"; pr " %s = guestfs_%s " n name; @@ -8742,6 +8784,12 @@ and generate_python_c () = pr "\ #include +#if PY_VERSION_HEX < 0x02050000 +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#endif + #include #include #include @@ -8773,7 +8821,7 @@ put_handle (guestfs_h *g) static char ** get_string_list (PyObject *obj) { - int i, len; + size_t i, len; char **r; assert (obj); @@ -8783,7 +8831,12 @@ get_string_list (PyObject *obj) return NULL; } - len = PyList_Size (obj); + Py_ssize_t slen = PyList_Size (obj); + if (slen == -1) { + PyErr_SetString (PyExc_RuntimeError, \"get_string_list: PyList_Size failure\"); + return NULL; + } + len = (size_t) slen; r = malloc (sizeof (char *) * (len+1)); if (r == NULL) { PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\"); @@ -8881,7 +8934,7 @@ py_guestfs_close (PyObject *self, PyObject *args) pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ; pr "{\n"; pr " PyObject *list;\n"; - pr " int i;\n"; + pr " size_t i;\n"; pr "\n"; pr " list = PyList_New (%ss->len);\n" typ; pr " for (i = 0; i < %ss->len; ++i)\n" typ; @@ -9364,7 +9417,7 @@ static VALUE ruby_guestfs_close (VALUE gv) pr " char **%s;\n" n; pr " Check_Type (%sv, T_ARRAY);\n" n; pr " {\n"; - pr " int i, len;\n"; + pr " size_t i, len;\n"; pr " len = RARRAY_LEN (%sv);\n" n; pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n" n; @@ -9435,7 +9488,7 @@ static VALUE ruby_guestfs_close (VALUE gv) pr " free (r);\n"; pr " return rv;\n"; | RStringList _ -> - pr " int i, len = 0;\n"; + pr " size_t i, len = 0;\n"; pr " for (i = 0; r[i] != NULL; ++i) len++;\n"; pr " VALUE rv = rb_ary_new2 (len);\n"; pr " for (i = 0; r[i] != NULL; ++i) {\n"; @@ -9452,7 +9505,7 @@ static VALUE ruby_guestfs_close (VALUE gv) generate_ruby_struct_list_code typ cols | RHashtable _ -> pr " VALUE rv = rb_hash_new ();\n"; - pr " int i;\n"; + pr " size_t i;\n"; pr " for (i = 0; r[i] != NULL; i+=2) {\n"; pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n"; pr " free (r[i]);\n"; @@ -9521,7 +9574,7 @@ and generate_ruby_struct_code typ cols = (* Ruby code to return a struct list. *) and generate_ruby_struct_list_code typ cols = pr " VALUE rv = rb_ary_new2 (r->len);\n"; - pr " int i;\n"; + pr " size_t i;\n"; pr " for (i = 0; i < r->len; ++i) {\n"; pr " VALUE hv = rb_hash_new ();\n"; List.iter ( @@ -9921,7 +9974,7 @@ Java_com_redhat_et_libguestfs_GuestFS__1close | DeviceList _ -> true | _ -> false) (snd style) in if needs_i then - pr " int i;\n"; + pr " size_t i;\n"; pr "\n"; @@ -10559,7 +10612,7 @@ namespace Guestfs pr " return r != 0 ? true : false;\n" | RHashtable _ -> pr " Hashtable rr = new Hashtable ();\n"; - pr " for (int i = 0; i < r.Length; i += 2)\n"; + pr " for (size_t i = 0; i < r.Length; i += 2)\n"; pr " rr.Add (r[i], r[i+1]);\n"; pr " return rr;\n" | RInt _ | RInt64 _ | RConstString _ | RConstOptString _ @@ -10596,7 +10649,7 @@ and generate_bindtests () = static void print_strings (char *const *argv) { - int argc; + size_t argc; printf (\"[\"); for (argc = 0; argv[argc] != NULL; ++argc) {