* inefficient. Keys should be unique. NULLs are not permitted.
*)
| RHashtable of string
+(* Not implemented:
+ (* "RBufferOut" is handled almost exactly like RString, but
+ * it allows the string to contain arbitrary 8 bit data including
+ * ASCII NUL. In the C API this causes an implicit extra parameter
+ * to be added of type <size_t *size_r>. Other programming languages
+ * support strings with arbitrary 8 bit data. At the RPC layer
+ * we have to use the opaque<> type instead of string<>.
+ *)
+ | RBufferOut of string
+*)
and args = argt list (* Function parameters, guestfs handle is implicit. *)
*)
| FileIn of string
| FileOut of string
+(* Not implemented:
+ (* Opaque buffer which can contain arbitrary 8 bit data.
+ * In the C API, this is expressed as <char *, int> pair.
+ * Most other languages have a string type which can contain
+ * ASCII NUL. We use whatever type is appropriate for each
+ * language.
+ * Buffers are limited by the total message size. To transfer
+ * large blocks of data, use FileIn/FileOut parameters instead.
+ * To return an arbitrary buffer, use RBufferOut.
+ *)
+ | BufferIn of string
+*)
type flags =
| ProtocolLimitWarning (* display warning about protocol size limits *)
*)
| TestOutputInt of seq * int
(* Run the command sequence and expect the output of the final
+ * command to be <op> <int>, eg. ">=", "1".
+ *)
+ | TestOutputIntOp of seq * string * int
+ (* Run the command sequence and expect the output of the final
* command to be a true value (!= 0 or != NULL).
*)
| TestOutputTrue of seq
and test_field_compare =
| CompareWithInt of string * int
+ | CompareWithIntOp of string * string * int
| CompareWithString of string * string
| CompareFieldsIntEq of string * string
| CompareFieldsStrEq of string * string
Setting C<qemu> to C<NULL> restores the default qemu binary.");
("get_qemu", (RConstString "qemu", []), -1, [],
- [],
+ [InitNone, Always, TestRun (
+ [["get_qemu"]])],
"get the qemu binary",
"\
Return the current qemu binary.
Setting C<path> to C<NULL> restores the default path.");
("get_path", (RConstString "path", []), -1, [],
- [],
+ [InitNone, Always, TestRun (
+ [["get_path"]])],
"get the search path",
"\
Return the current search path.
are passed (libguestfs always adds a few of its own).");
("get_append", (RConstString "append", []), -1, [],
+ (* This cannot be tested with the current framework. The
+ * function can return NULL in normal operations, which the
+ * test framework interprets as an error.
+ *)
[],
"get the additional kernel options",
"\
enabled by default).");
("get_autosync", (RBool "autosync", []), -1, [],
- [],
+ [InitNone, Always, TestRun (
+ [["get_autosync"]])],
"get autosync mode",
"\
Get the autosync flag.");
This returns the verbose messages flag.");
("is_ready", (RBool "ready", []), -1, [],
- [],
+ [InitNone, Always, TestOutputTrue (
+ [["is_ready"]])],
"is ready to accept commands",
"\
This returns true iff this handle is ready to accept commands
For more information on states, see L<guestfs(3)>.");
("is_config", (RBool "config", []), -1, [],
- [],
+ [InitNone, Always, TestOutputFalse (
+ [["is_config"]])],
"is in configuration state",
"\
This returns true iff this handle is being configured
For more information on states, see L<guestfs(3)>.");
("is_launching", (RBool "launching", []), -1, [],
- [],
+ [InitNone, Always, TestOutputFalse (
+ [["is_launching"]])],
"is launching subprocess",
"\
This returns true iff this handle is launching the subprocess
For more information on states, see L<guestfs(3)>.");
("is_busy", (RBool "busy", []), -1, [],
- [],
+ [InitNone, Always, TestOutputFalse (
+ [["is_busy"]])],
"is busy processing a command",
"\
This returns true iff this handle is busy processing a command
For more information on states, see L<guestfs(3)>.");
("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
- [],
+ [InitNone, Always, TestOutputInt (
+ [["set_memsize"; "500"];
+ ["get_memsize"]], 500)],
"set memory allocated to the qemu subprocess",
"\
This sets the memory size in megabytes allocated to the
see L<guestfs(3)>.");
("get_memsize", (RInt "memsize", []), -1, [],
- [],
+ [InitNone, Always, TestOutputIntOp (
+ [["get_memsize"]], ">=", 256)],
"get memory allocated to the qemu subprocess",
"\
This gets the memory size in megabytes allocated to the
see L<guestfs(3)>.");
("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
- [],
+ [InitNone, Always, TestOutputIntOp (
+ [["get_pid"]], ">=", 1)],
"get PID of qemu subprocess",
"\
Return the process ID of the qemu subprocess. If there is no
This is an internal call used for debugging and testing.");
+ ("version", (RStruct ("version", "version"), []), -1, [],
+ [InitNone, Always, TestOutputStruct (
+ [["version"]], [CompareWithInt ("major", 1)])],
+ "get the library version number",
+ "\
+Return the libguestfs version number that the program is linked
+against.
+
+Note that because of dynamic linking this is not necessarily
+the version of libguestfs that you compiled against. You can
+compile the program, and then at runtime dynamically link
+against a completely different C<libguestfs.so> library.
+
+This call was added in version C<1.0.58>. In previous
+versions of libguestfs there was no way to get the version
+number. From C code you can use ELF weak linking tricks to find out if
+this symbol exists (if it doesn't, then it's an earlier version).
+
+The call returns a structure with four elements. The first
+three (C<major>, C<minor> and C<release>) are numbers and
+correspond to the usual version triplet. The fourth element
+(C<extra>) is a string and is normally empty, but may be
+used for distro-specific information.
+
+To construct the original version string:
+C<$major.$minor.$release$extra>
+
+I<Note:> Don't use this call to test for availability
+of features. Distro backports makes this unreliable.");
+
]
(* daemon_functions are any functions which cause some action
"ftyp", FChar;
"name", FString;
];
+
+ (* Version numbers. *)
+ "version", [
+ "major", FInt64;
+ "minor", FInt64;
+ "release", FInt64;
+ "extra", FString;
+ ];
] (* end of structs *)
(* Ugh, Java has to be different ..
"lvm_lv", "LV";
"stat", "Stat";
"statvfs", "StatVFS";
- "dirent", "Dirent"
+ "dirent", "Dirent";
+ "version", "Version";
]
(* Used for testing language bindings. *)
let seq_of_test = function
| TestRun s | TestOutput (s, _) | TestOutputList (s, _)
| TestOutputListOfDevices (s, _)
- | TestOutputInt (s, _) | TestOutputTrue s | TestOutputFalse s
+ | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
+ | TestOutputTrue s | TestOutputFalse s
| TestOutputLength (s, _) | TestOutputStruct (s, _)
| TestLastFail s -> s
and generate_one_test_body name i test_name init test =
(match init with
- | InitNone
+ | InitNone (* XXX at some point, InitNone and InitEmpty became
+ * folded together as the same thing. Really we should
+ * make InitNone do nothing at all, but the tests may
+ * need to be checked to make sure this is OK.
+ *)
| InitEmpty ->
pr " /* InitNone|InitEmpty for %s */\n" test_name;
List.iter (generate_test_command_call test_name)
in
List.iter (generate_test_command_call test_name) seq;
generate_test_command_call ~test test_name last
+ | TestOutputIntOp (seq, op, expected) ->
+ pr " /* TestOutputIntOp for %s (%d) */\n" name i;
+ let seq, last = get_seq_last seq in
+ let test () =
+ pr " if (! (r %s %d)) {\n" op expected;
+ pr " fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
+ test_name op expected;
+ pr " (int) r);\n";
+ pr " return -1;\n";
+ pr " }\n"
+ in
+ List.iter (generate_test_command_call test_name) seq;
+ generate_test_command_call ~test test_name last
| TestOutputTrue seq ->
pr " /* TestOutputTrue for %s (%d) */\n" name i;
let seq, last = get_seq_last seq in
pr " (int) r->%s);\n" field;
pr " return -1;\n";
pr " }\n"
+ | CompareWithIntOp (field, op, expected) ->
+ pr " if (!(r->%s %s %d)) {\n" field op expected;
+ pr " fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
+ test_name field op expected;
+ pr " (int) r->%s);\n" field;
+ pr " return -1;\n";
+ pr " }\n"
| CompareWithString (field, expected) ->
pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
do_cleanups ();
pr " if (%s == NULL)\n" n;
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
- pr " EXTEND (SP, %d);\n" (List.length cols);
+ pr " EXTEND (SP, 2 * %d);\n" (List.length cols);
List.iter (
- function
- | name, FString ->
- pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
- n name
- | name, FUUID ->
- pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
- n name
- | name, (FBytes|FUInt64) ->
- pr " PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
- n name
- | name, FInt64 ->
- pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
- n name
- | name, (FInt32|FUInt32) ->
- pr " PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
- n name
- | name, FChar ->
- pr " PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
- n name
- | name, FOptPercent ->
- pr " PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
- n name
+ fun ((name, _) as col) ->
+ pr " PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
+
+ match col with
+ | name, FString ->
+ pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
+ n name
+ | name, FUUID ->
+ pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
+ n name
+ | name, (FBytes|FUInt64) ->
+ pr " PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
+ n name
+ | name, FInt64 ->
+ pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
+ n name
+ | name, (FInt32|FUInt32) ->
+ pr " PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
+ n name
+ | name, FChar ->
+ pr " PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
+ n name
+ | name, FOptPercent ->
+ pr " PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
+ n name
) cols;
pr " free (%s);\n" n