X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fgenerator.ml;h=d427558c8715db3249e779ed2fce48be187c5bae;hp=939f1f60e8202ace0aa91eeedef90ecf6874f659;hb=321ca1ef91a90cec5b94058b84420e8018e3f1d8;hpb=cbe80b2bcfdee437d195f25aaf6f5d96329ab360 diff --git a/src/generator.ml b/src/generator.ml index 939f1f6..d427558 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -309,6 +309,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 @@ -989,7 +992,10 @@ closing the handle."); "\ Touch acts like the L command. It can be used to update the timestamps on a file, or, if the file does not exist, -to create a new zero-length file."); +to create a new zero-length file. + +This command only works on regular files, and will fail on other +file types such as directories, symbolic links, block special etc."); ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning], [InitISOFS, Always, TestOutput ( @@ -1626,19 +1632,32 @@ and physical volumes."); InitISOFS, Always, TestOutput ( [["file"; "/known-1"]], "ASCII text"); InitISOFS, Always, TestLastFail ( - [["file"; "/notexists"]])], + [["file"; "/notexists"]]); + InitISOFS, Always, TestOutput ( + [["file"; "/abssymlink"]], "symbolic link"); + InitISOFS, Always, TestOutput ( + [["file"; "/directory"]], "directory")], "determine file type", "\ This call uses the standard L command to determine -the type or contents of the file. This also works on devices, -for example to find out whether a partition contains a filesystem. +the type or contents of the file. This call will also transparently look inside various types of compressed file. -The exact command which runs is C. Note in +The exact command which runs is C. Note in particular that the filename is not prepended to the output -(the C<-b> option)."); +(the C<-b> option). + +This command can also be used on C devices +(and partitions, LV names). You can for example use this +to determine if a device contains a filesystem, although +it's usually better to use C. + +If the C does not begin with C then +this command only works for the content of regular files. +For other file types (directory, symbolic link etc) it +will just return the string C etc."); ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning], [InitBasicFS, Always, TestOutput ( @@ -3729,13 +3748,28 @@ and C"); ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"]; ["mount_options"; ""; "/dev/sda1"; "/"]; ["write"; "/new"; "new file contents"]; - ["cat"; "/new"]], "new file contents")], + ["cat"; "/new"]], "new file contents"); + InitEmpty, Always, TestRun ( + [["part_disk"; "/dev/sda"; "mbr"]; + ["mkfs_b"; "vfat"; "32768"; "/dev/sda1"]]); + InitEmpty, Always, TestLastFail ( + [["part_disk"; "/dev/sda"; "mbr"]; + ["mkfs_b"; "vfat"; "32769"; "/dev/sda1"]]); + InitEmpty, Always, TestLastFail ( + [["part_disk"; "/dev/sda"; "mbr"]; + ["mkfs_b"; "vfat"; "33280"; "/dev/sda1"]]); + InitEmpty, IfAvailable "ntfsprogs", TestRun ( + [["part_disk"; "/dev/sda"; "mbr"]; + ["mkfs_b"; "ntfs"; "32768"; "/dev/sda1"]])], "make a filesystem with block size", "\ This call is similar to C, but it allows you to control the block size of the resulting filesystem. Supported block sizes depend on the filesystem type, but typically they -are C<1024>, C<2048> or C<4096> only."); +are C<1024>, C<2048> or C<4096> only. + +For VFAT and NTFS the C parameter is treated as +the requested cluster size."); ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [], [InitEmpty, Always, TestOutput ( @@ -6000,7 +6034,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" ); @@ -6303,6 +6337,7 @@ and generate_linker_script () = "guestfs_get_error_handler"; "guestfs_get_out_of_memory_handler"; "guestfs_last_error"; + "guestfs_set_close_callback"; "guestfs_set_error_handler"; "guestfs_set_launch_done_callback"; "guestfs_set_log_message_callback"; @@ -6314,6 +6349,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) @@ -6447,9 +6484,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], %s, 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], %s, goto done);\n" n (if is_filein then "cancel_receive ()" else "0"); pr " }\n"; | Bool n -> pr " %s = args.%s;\n" n n @@ -6597,7 +6637,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"; @@ -6822,7 +6862,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]); @@ -6831,7 +6871,7 @@ 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]); @@ -6851,6 +6891,13 @@ is_available (const char *group) return r == 0; } +static void +incr (guestfs_h *g, void *iv) +{ + int *i = (int *) iv; + (*i)++; +} + "; (* Generate a list of commands which are not tested anywhere. *) @@ -6862,7 +6909,7 @@ is_available (const char *group) 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 @@ -7032,11 +7079,22 @@ int main (int argc, char *argv[]) ) test_names; pr "\n"; - pr " guestfs_close (g);\n"; - pr " unlink (\"test1.img\");\n"; - pr " unlink (\"test2.img\");\n"; - pr " unlink (\"test3.img\");\n"; - pr "\n"; + pr " /* Check close callback is called. */ + int close_sentinel = 1; + guestfs_set_close_callback (g, incr, &close_sentinel); + + guestfs_close (g); + + if (close_sentinel != 2) { + fprintf (stderr, \"close callback was not called\\n\"); + exit (EXIT_FAILURE); + } + + unlink (\"test1.img\"); + unlink (\"test2.img\"); + unlink (\"test3.img\"); + +"; pr " if (n_failed > 0) {\n"; pr " printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n"; @@ -7068,7 +7126,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"; @@ -7117,6 +7175,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 ); @@ -7461,7 +7526,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" @@ -8041,7 +8106,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) { @@ -8335,7 +8400,7 @@ and generate_ocaml_c () = #include #include -#include +#include \"guestfs.h\" #include \"guestfs_c.h\" @@ -8348,7 +8413,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) { @@ -8503,14 +8568,15 @@ 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 | BufferIn n -> - pr " const char *%s = String_val (%sv);\n" n n; - pr " size_t %s_size = caml_string_length (%sv);\n" n n + pr " size_t %s_size = caml_string_length (%sv);\n" n n; + pr " char *%s = guestfs_safe_memdup (g, String_val (%sv), %s_size);\n" n n n | StringList n | DeviceList n -> pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n | Bool n -> @@ -8530,7 +8596,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) -> @@ -8538,7 +8604,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 _ -> @@ -8553,13 +8619,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 | BufferIn 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 _ | BufferIn _ -> () + | Bool _ | Int _ | Int64 _ -> () ) (snd style); pr " if (r == %s)\n" error_code; @@ -8761,10 +8829,30 @@ _create () RETVAL void -DESTROY (g) +DESTROY (sv) + SV *sv; + PPCODE: + /* For the 'g' argument above we do the conversion explicitly and + * don't rely on the typemap, because if the handle has been + * explicitly closed we don't want the typemap conversion to + * display an error. + */ + HV *hv = (HV *) SvRV (sv); + SV **svp = hv_fetch (hv, \"_g\", 2, 0); + if (svp != NULL) { + guestfs_h *g = (guestfs_h *) SvIV (*svp); + assert (g != NULL); + guestfs_close (g); + } + +void +close (g) guestfs_h *g; PPCODE: guestfs_close (g); + /* Avoid double-free in DESTROY method. */ + HV *hv = (HV *) SvRV (ST(0)); + (void) hv_delete (hv, \"_g\", 2, G_DISCARD); "; @@ -8906,7 +8994,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; @@ -8950,7 +9038,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; @@ -9119,11 +9207,28 @@ sub new { my $proto = shift; my $class = ref ($proto) || $proto; - my $self = Sys::Guestfs::_create (); + my $g = Sys::Guestfs::_create (); + my $self = { _g => $g }; bless $self, $class; return $self; } +=item $h->close (); + +Explicitly close the guestfs handle. + +B You should not usually call this function. The handle will +be closed implicitly when its reference count goes to zero (eg. +when it goes out of scope or the program ends). This call is +only required in some exceptional cases, such as where the program +may contain cached references to the handle 'somewhere' and you +really have to have the close happen right away. After calling +C the program must not call any method (including C) +on the handle (but the implicit call to C that happens +when the final reference is cleaned up is OK). + +=cut + " max_proc_nr; (* Actions. We only need to print documentation for these as @@ -9249,7 +9354,7 @@ put_handle (guestfs_h *g) static char ** get_string_list (PyObject *obj) { - int i, len; + size_t i, len; char **r; assert (obj); @@ -9259,7 +9364,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\"); @@ -9357,7 +9467,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; @@ -9855,7 +9965,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; @@ -9927,7 +10037,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"; @@ -9944,7 +10054,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"; @@ -10013,7 +10123,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 ( @@ -10420,7 +10530,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"; @@ -11072,7 +11182,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 _ @@ -11109,7 +11219,7 @@ and generate_bindtests () = static void print_strings (char *const *argv) { - int argc; + size_t argc; printf (\"[\"); for (argc = 0; argv[argc] != NULL; ++argc) {