* the virtual machine and block devices are reused between tests.
* So don't try testing kill_subprocess :-x
*
- * Between each test we umount-all and lvm-remove-all (except InitNone).
+ * Between each test we blockdev-setrw, umount-all, lvm-remove-all
+ * (except InitNone).
+ *
+ * If the appliance is running an older Linux kernel (eg. RHEL 5) then
+ * devices are named /dev/hda etc. To cope with this, the test suite
+ * adds some hairly logic to detect this case, and then automagically
+ * replaces all strings which match "/dev/sd.*" with "/dev/hd.*".
+ * When writing test cases you shouldn't have to worry about this
+ * difference.
*
* Don't assume anything about the previous contents of the block
* devices. Use 'Init*' to create some initial scenarios.
"make a filesystem",
"\
This creates a filesystem on C<device> (usually a partition
-of LVM logical volume). The filesystem type is C<fstype>, for
+or LVM logical volume). The filesystem type is C<fstype>, for
example C<ext3>.");
("sfdisk", (RErr, [String "device";
As a special case, if C<size> is C<0>
then the length is calculated using C<strlen> (so in this case
-the content cannot contain embedded ASCII NULs).");
+the content cannot contain embedded ASCII NULs).
+
+I<NB.> Owing to a bug, writing content containing ASCII NUL
+characters does I<not> work, even if the length is specified.
+We hope to resolve this bug in a future version. In the meantime
+use C<guestfs_upload>.");
("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
[InitEmpty, TestOutputList (
daemon responds to the ping message, without affecting the daemon
or attached block device(s) in any other way.");
+ ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
+ [InitBasicFS, TestOutputTrue (
+ [["write_file"; "/file1"; "contents of a file"; "0"];
+ ["cp"; "/file1"; "/file2"];
+ ["equal"; "/file1"; "/file2"]]);
+ InitBasicFS, TestOutputFalse (
+ [["write_file"; "/file1"; "contents of a file"; "0"];
+ ["write_file"; "/file2"; "contents of another file"; "0"];
+ ["equal"; "/file1"; "/file2"]]);
+ InitBasicFS, TestLastFail (
+ [["equal"; "/file1"; "/file2"]])],
+ "test if two files have equal contents",
+ "\
+This compares the two files C<file1> and C<file2> and returns
+true if their content is exactly equal, or false otherwise.
+
+The external L<cmp(1)> program is used for the comparison.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
static guestfs_h *g;
static int suppress_error = 0;
+/* This will be 's' or 'h' depending on whether the guest kernel
+ * names IDE devices /dev/sd* or /dev/hd*.
+ */
+static char devchar = 's';
+
static void print_error (guestfs_h *g, void *data, const char *msg)
{
if (!suppress_error)
int failed = 0;
const char *srcdir;
const char *filename;
- int fd;
+ int fd, i;
int nr_tests, test_num = 0;
+ char **devs;
no_test_warnings ();
exit (1);
}
+ /* Detect if the appliance uses /dev/sd* or /dev/hd* in device
+ * names. This changed between RHEL 5 and RHEL 6 so we have to
+ * support both.
+ */
+ devs = guestfs_list_devices (g);
+ if (devs == NULL || devs[0] == NULL) {
+ printf (\"guestfs_list_devices FAILED\\n\");
+ exit (1);
+ }
+ if (strncmp (devs[0], \"/dev/sd\", 7) == 0)
+ devchar = 's';
+ else if (strncmp (devs[0], \"/dev/hd\", 7) == 0)
+ devchar = 'h';
+ else {
+ printf (\"guestfs_list_devices returned unexpected string '%%s'\\n\",
+ devs[0]);
+ exit (1);
+ }
+ for (i = 0; devs[i] != NULL; ++i)
+ free (devs[i]);
+ free (devs);
+
nr_tests = %d;
" (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
| InitEmpty ->
pr " /* InitEmpty for %s (%d) */\n" name i;
List.iter (generate_test_command_call test_name)
- [["umount_all"];
+ [["blockdev_setrw"; "/dev/sda"];
+ ["umount_all"];
["lvm_remove_all"]]
| InitBasicFS ->
pr " /* InitBasicFS for %s (%d): create ext2 on /dev/sda1 */\n" name i;
List.iter (generate_test_command_call test_name)
- [["umount_all"];
+ [["blockdev_setrw"; "/dev/sda"];
+ ["umount_all"];
["lvm_remove_all"];
["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
pr " /* InitBasicFSonLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
name i;
List.iter (generate_test_command_call test_name)
- [["umount_all"];
+ [["blockdev_setrw"; "/dev/sda"];
+ ["umount_all"];
["lvm_remove_all"];
["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["pvcreate"; "/dev/sda1"];
List.iter (generate_test_command_call test_name) seq
| TestOutput (seq, expected) ->
pr " /* TestOutput for %s (%d) */\n" name i;
+ pr " char expected[] = \"%s\";\n" (c_quote expected);
+ if String.length expected > 7 &&
+ String.sub expected 0 7 = "/dev/sd" then
+ pr " expected[5] = devchar;\n";
let seq, last = get_seq_last seq in
let test () =
- pr " if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
- pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
+ pr " if (strcmp (r, expected) != 0) {\n";
+ pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
pr " return -1;\n";
pr " }\n"
in
pr " print_strings (r);\n";
pr " return -1;\n";
pr " }\n";
- pr " if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
- pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
- pr " return -1;\n";
+ pr " {\n";
+ pr " char expected[] = \"%s\";\n" (c_quote str);
+ if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
+ pr " expected[5] = devchar;\n";
+ pr " if (strcmp (r[%d], expected) != 0) {\n" i;
+ pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
+ pr " return -1;\n";
+ pr " }\n";
pr " }\n"
) expected;
pr " if (r[%d] != NULL) {\n" (List.length expected);
List.iter (
function
- | String _, _
- | OptString _, _
+ | OptString n, "NULL" -> ()
+ | String n, arg
+ | OptString n, arg ->
+ pr " char %s[] = \"%s\";\n" n (c_quote arg);
+ if String.length arg > 7 && String.sub arg 0 7 = "/dev/sd" then
+ pr " %s[5] = devchar;\n" n
| Int _, _
- | Bool _, _ -> ()
+ | Bool _, _
| FileIn _, _ | FileOut _, _ -> ()
| StringList n, arg ->
- pr " char *%s[] = {\n" n;
let strs = string_split " " arg in
- List.iter (
- fun str -> pr " \"%s\",\n" (c_quote str)
+ iteri (
+ fun i str ->
+ pr " char %s_%d[] = \"%s\";\n" n i (c_quote str);
+ if String.length str > 7 && String.sub str 0 7 = "/dev/sd" then
+ pr " %s_%d[5] = devchar;\n" n i
+ ) strs;
+ pr " char *%s[] = {\n" n;
+ iteri (
+ fun i _ -> pr " %s_%d,\n" n i
) strs;
pr " NULL\n";
pr " };\n";
(* Generate the parameters. *)
List.iter (
function
- | String _, arg
+ | OptString _, "NULL" -> pr ", NULL"
+ | String n, _
+ | OptString n, _ ->
+ pr ", %s" n
| FileIn _, arg | FileOut _, arg ->
pr ", \"%s\"" (c_quote arg)
- | OptString _, arg ->
- if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
| StringList n, _ ->
pr ", %s" n
| Int _, arg ->
let str = replace_str str "\r" "\\r" in
let str = replace_str str "\n" "\\n" in
let str = replace_str str "\t" "\\t" in
+ let str = replace_str str "\000" "\\0" in
str
(* Generate a lot of different functions for guestfish. *)
MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
+PROTOTYPES: ENABLE
+
guestfs_h *
_create ()
CODE:
#include \"extconf.h\"
+/* For Ruby < 1.9 */
+#ifndef RARRAY_LEN
+#define RARRAY_LEN(r) (RARRAY((r))->len)
+#endif
+
static VALUE m_guestfs; /* guestfs module */
static VALUE c_guestfs; /* guestfs_h handle */
static VALUE e_Error; /* used for all errors */
let needs_i =
(match fst style with
| RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
- | RErr _ | RBool _ | RInt _ | RInt64 _ | RConstString _
+ | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
| RString _ | RIntBool _ | RStat _ | RStatVFS _
| RHashtable _ -> false) ||
List.exists (function StringList _ -> true | _ -> false) (snd style) in