*)
| RErr
(* "RInt" as a return value means an int which is -1 for error
- * or any value >= 0 on success.
+ * or any value >= 0 on success. Only use this for smallish
+ * positive ints (0 <= i < 2^30).
*)
| RInt of string
+ (* "RInt64" is the same as RInt, but is guaranteed to be able
+ * to return a full 64 bit value, _except_ that -1 means error
+ * (so -1 cannot be a valid, non-error return value).
+ *)
+ | RInt64 of string
(* "RBool" is a bool return value which can be true/false or
* -1 for error.
*)
(* Stat buffers. *)
| RStat of string
| RStatVFS of string
+ (* Key-value pairs of untyped strings. Turns into a hashtable or
+ * dictionary in languages which support it. DON'T use this as a
+ * general "bucket" for results. Prefer a stronger typed return
+ * value if one is available, or write a custom struct. Don't use
+ * this if the list could potentially be very long, since it is
+ * inefficient. Keys should be unique. NULLs are not permitted.
+ *)
+ | RHashtable of string
+
and args = argt list (* Function parameters, guestfs handle is implicit. *)
(* Note in future we should allow a "variable args" parameter as
This is the same as the C<statvfs(2)> system call.");
+ ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
+ [], (* XXX test *)
+ "get ext2/ext3 superblock details",
+ "\
+This returns the contents of the ext2 or ext3 filesystem superblock
+on C<device>.
+
+It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
+manpage for more details. The list of fields returned isn't
+clearly defined, and depends on both the version of C<tune2fs>
+that libguestfs was built against, and the filesystem itself.");
+
+ ("blockdev_setro", (RErr, [String "device"]), 56, [],
+ [InitEmpty, TestOutputTrue (
+ [["blockdev_setro"; "/dev/sda"];
+ ["blockdev_getro"; "/dev/sda"]])],
+ "set block device to read-only",
+ "\
+Sets the block device named C<device> to read-only.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_setrw", (RErr, [String "device"]), 57, [],
+ [InitEmpty, TestOutputFalse (
+ [["blockdev_setrw"; "/dev/sda"];
+ ["blockdev_getro"; "/dev/sda"]])],
+ "set block device to read-write",
+ "\
+Sets the block device named C<device> to read-write.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
+ [InitEmpty, TestOutputTrue (
+ [["blockdev_setro"; "/dev/sda"];
+ ["blockdev_getro"; "/dev/sda"]])],
+ "is block device set to read-only",
+ "\
+Returns a boolean indicating if the block device is read-only
+(true if read-only, false if not).
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
+ [InitEmpty, TestOutputInt (
+ [["blockdev_getss"; "/dev/sda"]], 512)],
+ "get sectorsize of block device",
+ "\
+This returns the size of sectors on a block device.
+Usually 512, but can be larger for modern devices.
+
+(Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
+for that).
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
+ [InitEmpty, TestOutputInt (
+ [["blockdev_getbsz"; "/dev/sda"]], 4096)],
+ "get blocksize of block device",
+ "\
+This returns the block size of a device.
+
+(Note this is different from both I<size in blocks> and
+I<filesystem block size>).
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
+ [], (* XXX test *)
+ "set blocksize of block device",
+ "\
+This sets the block size of a device.
+
+(Note this is different from both I<size in blocks> and
+I<filesystem block size>).
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
+ [InitEmpty, TestOutputInt (
+ [["blockdev_getsz"; "/dev/sda"]], 1024000)],
+ "get total size of device in 512-byte sectors",
+ "\
+This returns the size of the device in units of 512-byte sectors
+(even if the sectorsize isn't 512 bytes ... weird).
+
+See also C<guestfs_blockdev_getss> for the real sector size of
+the device, and C<guestfs_blockdev_getsize64> for the more
+useful I<size in bytes>.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
+ [InitEmpty, TestOutputInt (
+ [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
+ "get total size of device in bytes",
+ "\
+This returns the size of the device in bytes.
+
+See also C<guestfs_blockdev_getsz>.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
+ [InitEmpty, TestRun
+ [["blockdev_flushbufs"; "/dev/sda"]]],
+ "flush device buffers",
+ "\
+This tells the kernel to flush internal buffers associated
+with C<device>.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
+ [InitEmpty, TestRun
+ [["blockdev_rereadpt"; "/dev/sda"]]],
+ "reread partition table",
+ "\
+Reread the partition table on C<device>.
+
+This uses the L<blockdev(8)> command.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
let name_of_argt = function
| String n | OptString n | StringList n | Bool n | Int n -> n
+let seq_of_test = function
+ | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
+ | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
+ | TestOutputLength (s, _) | TestOutputStruct (s, _)
+ | TestLastFail s -> s
+
(* Check function names etc. for consistency. *)
let check_functions () =
let contains_uppercase str =
(match fst style with
| RErr -> ()
- | RInt n | RBool n | RConstString n | RString n
+ | RInt n | RInt64 n | RBool n | RConstString n | RString n
| RStringList n | RPVList n | RVGList n | RLVList n
- | RStat n | RStatVFS n ->
+ | RStat n | RStatVFS n
+ | RHashtable n ->
check_arg_ret_name n
| RIntBool (n,m) ->
check_arg_ret_name n;
failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
name1 name2 nr1 nr2
in
- loop proc_nrs
+ loop proc_nrs;
+
+ (* Check tests. *)
+ List.iter (
+ function
+ (* Ignore functions that have no tests. We generate a
+ * warning when the user does 'make check' instead.
+ *)
+ | name, _, _, _, [], _, _ -> ()
+ | name, _, _, _, tests, _, _ ->
+ let funcs =
+ List.map (
+ fun (_, test) ->
+ match seq_of_test test with
+ | [] ->
+ failwithf "%s has a test containing an empty sequence" name
+ | cmds -> List.map List.hd cmds
+ ) tests in
+ let funcs = List.flatten funcs in
+
+ let tested = List.mem name funcs in
+
+ if not tested then
+ failwithf "function %s has tests but does not test itself" name
+ ) all_functions
(* 'pr' prints to the current output file. *)
let chan = ref stdout
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 _ ->
(see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
or NULL if there was an error.
I<The caller must call C<free> after use>.\n\n"
+ | 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"
);
if List.mem ProtocolLimitWarning flags then
pr "%s\n\n" protocol_limit_warning;
pr "struct %s_ret {\n" name;
pr " int %s;\n" n;
pr "};\n\n"
+ | RInt64 n ->
+ pr "struct %s_ret {\n" name;
+ pr " hyper %s;\n" n;
+ pr "};\n\n"
| RBool n ->
pr "struct %s_ret {\n" name;
pr " bool %s;\n" n;
| RStat n ->
pr "struct %s_ret {\n" name;
pr " guestfs_int_stat %s;\n" n;
- pr "};\n\n";
+ pr "};\n\n"
| RStatVFS n ->
pr "struct %s_ret {\n" name;
pr " guestfs_int_statvfs %s;\n" n;
- pr "};\n\n";
+ pr "};\n\n"
+ | RHashtable n ->
+ pr "struct %s_ret {\n" name;
+ pr " str %s<>;\n" n;
+ pr "};\n\n"
);
) daemon_functions;
| RErr -> ()
| RConstString _ ->
failwithf "RConstString cannot be returned from a daemon function"
- | RInt _
+ | RInt _ | RInt64 _
| RBool _ | RString _ | RStringList _
| RIntBool _
| RPVList _ | RVGList _ | RLVList _
- | RStat _ | RStatVFS _ ->
+ | RStat _ | RStatVFS _
+ | RHashtable _ ->
pr " struct %s_ret ret;\n" name
);
pr "};\n\n";
| RErr -> ()
| RConstString _ ->
failwithf "RConstString cannot be returned from a daemon function"
- | RInt _
+ | RInt _ | RInt64 _
| RBool _ | RString _ | RStringList _
| RIntBool _
| RPVList _ | RVGList _ | RLVList _
- | RStat _ | RStatVFS _ ->
+ | RStat _ | RStatVFS _
+ | RHashtable _ ->
pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
pr " error (g, \"%s: failed to parse reply\");\n" name;
pr " return;\n";
let error_code =
match fst style with
- | RErr | RInt _ | RBool _ -> "-1"
+ | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
| RConstString _ ->
failwithf "RConstString cannot be returned from a daemon function"
| RString _ | RStringList _ | RIntBool _
| RPVList _ | RVGList _ | RLVList _
- | RStat _ | RStatVFS _ ->
+ | RStat _ | RStatVFS _
+ | RHashtable _ ->
"NULL" in
pr "{\n";
(match fst style with
| RErr -> pr " return 0;\n"
- | RInt n
- | RBool n -> pr " return rv.ret.%s;\n" n
+ | RInt n | RInt64 n | RBool n ->
+ pr " return rv.ret.%s;\n" n
| RConstString _ ->
failwithf "RConstString cannot be returned from a daemon function"
| RString n ->
pr " return rv.ret.%s; /* caller will free */\n" n
- | RStringList n ->
+ | RStringList n | RHashtable n ->
pr " /* caller will free this, but we need to add a NULL entry */\n";
pr " rv.ret.%s.%s_val =" n n;
pr " safe_realloc (g, rv.ret.%s.%s_val,\n" n n;
| RIntBool _ ->
pr " /* caller with free this */\n";
pr " return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
- | RPVList n ->
- pr " /* caller will free this */\n";
- pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
- | RVGList n ->
- pr " /* caller will free this */\n";
- pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
- | RLVList n ->
- pr " /* caller will free this */\n";
- pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
- | RStat n ->
- pr " /* caller will free this */\n";
- pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
- | RStatVFS n ->
+ | RPVList n | RVGList n | RLVList n
+ | RStat n | RStatVFS n ->
pr " /* caller will free this */\n";
pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
);
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 _ ->
failwithf "RConstString cannot be returned from a daemon function"
| RString _ -> pr " char *r;\n"; "NULL"
- | RStringList _ -> pr " char **r;\n"; "NULL"
+ | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
| RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
| RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
| RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
(match fst style with
| RErr -> pr " reply (NULL, NULL);\n"
- | RInt n ->
- pr " struct guestfs_%s_ret ret;\n" name;
- pr " ret.%s = r;\n" n;
- pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
- | RBool n ->
+ | RInt n | RInt64 n | RBool n ->
pr " struct guestfs_%s_ret ret;\n" name;
pr " ret.%s = r;\n" n;
pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
pr " ret.%s = r;\n" n;
pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
pr " free (r);\n"
- | RStringList n ->
+ | RStringList n | RHashtable n ->
pr " struct guestfs_%s_ret ret;\n" name;
pr " ret.%s.%s_len = count_strings (r);\n" n n;
pr " ret.%s.%s_val = r;\n" n n;
| RIntBool _ ->
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
- | RPVList n | RVGList n | RLVList n | RStat n | RStatVFS n ->
+ | RPVList n | RVGList n | RLVList n
+ | RStat n | RStatVFS n ->
pr " struct guestfs_%s_ret ret;\n" name;
pr " ret.%s = *r;\n" n;
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
printf (\"\\t%%s\\n\", argv[argc]);
}
+/*
+static void print_table (char * const * const argv)
+{
+ int i;
+
+ for (i = 0; argv[i] != NULL; i += 2)
+ printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
+}
+*/
+
+static void no_test_warnings (void)
+{
";
+ List.iter (
+ function
+ | name, _, _, _, [], _, _ ->
+ pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
+ | name, _, _, _, tests, _, _ -> ()
+ ) all_functions;
+
+ pr "}\n";
+ pr "\n";
+
+ (* Generate the actual tests. Note that we generate the tests
+ * in reverse order, deliberately, so that (in general) the
+ * newest tests run first. This makes it quicker and easier to
+ * debug them.
+ *)
let test_names =
List.map (
fun (name, _, _, _, tests, _, _) ->
mapi (generate_one_test name) tests
- ) all_functions in
+ ) (List.rev all_functions) in
let test_names = List.concat test_names in
let nr_tests = List.length test_names in
const char *srcdir;
int fd;
char buf[256];
- int nr_tests;
+ int nr_tests, test_num = 0;
+
+ no_test_warnings ();
g = guestfs_create ();
if (g == NULL) {
}
nr_tests = %d;
+
" (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
iteri (
fun i test_name ->
- pr " printf (\"%3d/%%3d %s\\n\", nr_tests);\n" (i+1) test_name;
+ pr " test_num++;\n";
+ pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
pr " if (%s () == -1) {\n" test_name;
pr " printf (\"%s FAILED\\n\");\n" test_name;
pr " failed++;\n";
let seq, last = get_seq_last seq in
let test () =
pr " if (r != %d) {\n" expected;
- pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\", r);\n"
+ pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
test_name expected;
+ pr " (int) r);\n";
pr " return -1;\n";
pr " }\n"
in
let error_code =
match fst style with
| RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
+ | RInt64 _ -> pr " int64_t r;\n"; "-1"
| RConstString _ -> pr " const char *r;\n"; "NULL"
| RString _ -> pr " char *r;\n"; "NULL"
- | RStringList _ ->
+ | RStringList _ | RHashtable _ ->
pr " char **r;\n";
pr " int i;\n";
"NULL"
);
(match fst style with
- | RErr | RInt _ | RBool _ | RConstString _ -> ()
+ | RErr | RInt _ | RInt64 _ | RBool _ | RConstString _ -> ()
| RString _ -> pr " free (r);\n"
- | RStringList _ ->
+ | RStringList _ | RHashtable _ ->
pr " for (i = 0; r[i] != NULL; ++i)\n";
pr " free (r[i]);\n";
pr " free (r);\n"
| RErr
| RInt _
| RBool _ -> pr " int r;\n"
+ | RInt64 _ -> pr " int64_t r;\n"
| RConstString _ -> pr " const char *r;\n"
| RString _ -> pr " char *r;\n"
- | RStringList _ -> pr " char **r;\n"
+ | RStringList _ | RHashtable _ -> pr " char **r;\n"
| RIntBool _ -> pr " struct guestfs_int_bool *r;\n"
| RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
| RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
| RErr -> pr " return r;\n"
| RInt _ ->
pr " if (r == -1) return -1;\n";
- pr " if (r) printf (\"%%d\\n\", r);\n";
+ pr " printf (\"%%d\\n\", r);\n";
+ pr " return 0;\n"
+ | RInt64 _ ->
+ pr " if (r == -1) return -1;\n";
+ pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
pr " return 0;\n"
| RBool _ ->
pr " if (r == -1) return -1;\n";
pr " print_statvfs (r);\n";
pr " free (r);\n";
pr " return 0;\n"
+ | RHashtable _ ->
+ pr " if (r == NULL) return -1;\n";
+ pr " print_table (r);\n";
+ pr " free_strings (r);\n";
+ pr " return 0;\n"
);
pr "}\n";
pr "\n"
(match fst style with
| RErr -> pr "int "
| RInt _ -> pr "int "
+ | RInt64 _ -> pr "int64_t "
| RBool _ -> pr "int "
| RConstString _ -> pr "const char *"
| RString _ -> pr "char *"
- | RStringList _ -> pr "char **"
+ | RStringList _ | RHashtable _ -> pr "char **"
| RIntBool _ ->
if not in_daemon then pr "struct guestfs_int_bool *"
else pr "guestfs_%s_ret *" name
and generate_ocaml_c () =
generate_header CStyle LGPLv2;
- pr "#include <stdio.h>\n";
- pr "#include <stdlib.h>\n";
- pr "#include <string.h>\n";
- pr "\n";
- pr "#include <caml/config.h>\n";
- pr "#include <caml/alloc.h>\n";
- pr "#include <caml/callback.h>\n";
- pr "#include <caml/fail.h>\n";
- pr "#include <caml/memory.h>\n";
- pr "#include <caml/mlvalues.h>\n";
- pr "#include <caml/signals.h>\n";
- pr "\n";
- pr "#include <guestfs.h>\n";
- pr "\n";
- pr "#include \"guestfs_c.h\"\n";
- pr "\n";
+ pr "\
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <caml/config.h>
+#include <caml/alloc.h>
+#include <caml/callback.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+#include <caml/signals.h>
+
+#include <guestfs.h>
+
+#include \"guestfs_c.h\"
+
+/* Copy a hashtable of string pairs into an assoc-list. We return
+ * the list in reverse order, but hashtables aren't supposed to be
+ * ordered anyway.
+ */
+static CAMLprim value
+copy_table (char * const * argv)
+{
+ CAMLparam0 ();
+ CAMLlocal5 (rv, pairv, kv, vv, cons);
+ int i;
+
+ rv = Val_int (0);
+ for (i = 0; argv[i] != NULL; i += 2) {
+ kv = caml_copy_string (argv[i]);
+ vv = caml_copy_string (argv[i+1]);
+ pairv = caml_alloc (2, 0);
+ Store_field (pairv, 0, kv);
+ Store_field (pairv, 1, vv);
+ cons = caml_alloc (2, 0);
+ Store_field (cons, 1, rv);
+ rv = cons;
+ Store_field (cons, 0, pairv);
+ }
+
+ CAMLreturn (rv);
+}
+
+";
(* LVM struct copy functions. *)
List.iter (
match fst style with
| RErr -> pr " int r;\n"; "-1"
| RInt _ -> pr " int r;\n"; "-1"
+ | RInt64 _ -> pr " int64_t r;\n"; "-1"
| RBool _ -> pr " int r;\n"; "-1"
| RConstString _ -> pr " const char *r;\n"; "NULL"
| RString _ -> pr " char *r;\n"; "NULL"
| RStat _ ->
pr " struct guestfs_stat *r;\n"; "NULL"
| RStatVFS _ ->
- pr " struct guestfs_statvfs *r;\n"; "NULL" in
+ pr " struct guestfs_statvfs *r;\n"; "NULL"
+ | RHashtable _ ->
+ pr " int i;\n";
+ pr " char **r;\n";
+ "NULL" in
pr "\n";
pr " caml_enter_blocking_section ();\n";
(match fst style with
| RErr -> pr " rv = Val_unit;\n"
| RInt _ -> pr " rv = Val_int (r);\n"
+ | RInt64 _ ->
+ pr " rv = caml_copy_int64 (r);\n"
| RBool _ -> pr " rv = Val_bool (r);\n"
| RConstString _ -> pr " rv = caml_copy_string (r);\n"
| RString _ ->
| RStatVFS _ ->
pr " rv = copy_statvfs (r);\n";
pr " free (r);\n";
+ | RHashtable _ ->
+ pr " rv = copy_table (r);\n";
+ pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
+ pr " free (r);\n";
);
pr " CAMLreturn (rv);\n";
(match fst style with
| RErr -> pr "unit" (* all errors are turned into exceptions *)
| RInt _ -> pr "int"
+ | RInt64 _ -> pr "int64"
| RBool _ -> pr "bool"
| RConstString _ -> pr "string"
| RString _ -> pr "string"
| RLVList _ -> pr "lvm_lv array"
| RStat _ -> pr "stat"
| RStatVFS _ -> pr "statvfs"
+ | RHashtable _ -> pr "(string * string) list"
);
if is_external then (
pr " = ";
(match fst style with
| RErr -> pr "void\n"
| RInt _ -> pr "SV *\n"
+ | RInt64 _ -> pr "SV *\n"
| RBool _ -> pr "SV *\n"
| RConstString _ -> pr "SV *\n"
| RString _ -> pr "SV *\n"
| RStringList _
| RIntBool _
| RPVList _ | RVGList _ | RLVList _
- | RStat _ | RStatVFS _ ->
+ | RStat _ | RStatVFS _
+ | RHashtable _ ->
pr "void\n" (* all lists returned implictly on the stack *)
);
(* Call and arguments. *)
pr " RETVAL = newSViv (%s);\n" n;
pr " OUTPUT:\n";
pr " RETVAL\n"
+ | RInt64 n ->
+ pr "PREINIT:\n";
+ pr " int64_t %s;\n" n;
+ pr " CODE:\n";
+ pr " %s = guestfs_%s " n name;
+ generate_call_args ~handle:"g" style;
+ pr ";\n";
+ do_cleanups ();
+ pr " if (%s == -1)\n" n;
+ pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
+ pr " RETVAL = my_newSVll (%s);\n" n;
+ pr " OUTPUT:\n";
+ pr " RETVAL\n"
| RConstString n ->
pr "PREINIT:\n";
pr " const char *%s;\n" n;
pr " free (%s);\n" n;
pr " OUTPUT:\n";
pr " RETVAL\n"
- | RStringList n ->
+ | RStringList n | RHashtable n ->
pr "PREINIT:\n";
pr " char **%s;\n" n;
pr " int i, n;\n";
| RErr -> ()
| RBool n
| RInt n
+ | RInt64 n
| RConstString n
| RString n -> pr "$%s = " n
| RIntBool (n, m) -> pr "($%s, $%s) = " n m
| RVGList n
| RLVList n -> pr "@%s = " n
| RStat n
- | RStatVFS n -> pr "%%%s = " n
+ | RStatVFS n
+ | RHashtable n -> pr "%%%s = " n
);
pr "$h->%s (" name;
let comma = ref false in
return list;
}
+static PyObject *
+put_table (char * const * const argv)
+{
+ PyObject *list, *item;
+ int argc, i;
+
+ for (argc = 0; argv[argc] != NULL; ++argc)
+ ;
+
+ list = PyList_New (argc >> 1);
+ for (i = 0; i < argc; i += 2) {
+ PyObject *item;
+ item = PyTuple_New (2);
+ PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
+ PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
+ PyList_SetItem (list, i >> 1, item);
+ }
+
+ return list;
+}
+
static void
free_strings (char **argv)
{
let error_code =
match fst style with
| RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
+ | RInt64 _ -> pr " int64_t r;\n"; "-1"
| RConstString _ -> pr " const char *r;\n"; "NULL"
| RString _ -> pr " char *r;\n"; "NULL"
- | RStringList _ -> pr " char **r;\n"; "NULL"
+ | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
| RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
| RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
| RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
pr " py_r = Py_None;\n"
| RInt _
| RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
+ | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
| RConstString _ -> pr " py_r = PyString_FromString (r);\n"
| RString _ ->
pr " py_r = PyString_FromString (r);\n";
| RStatVFS n ->
pr " py_r = put_statvfs (r);\n";
pr " free (r);\n"
+ | RHashtable n ->
+ pr " py_r = put_table (r);\n";
+ pr " free_strings (r);\n"
);
pr " return py_r;\n";