X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fgenerator.ml;h=009b9804594685fb51aa3196df39eb277cc303c0;hp=c32b0ed8e0c9da80c13190b03eba486eab7d37ae;hb=17fa7abbb83024deb639aebf27686848e232e085;hpb=212a55d483c2a20e61f42211c0c64aab3645cb09;ds=sidebyside
diff --git a/src/generator.ml b/src/generator.ml
index c32b0ed..009b980 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -33,6 +33,7 @@
*)
#load "unix.cma";;
+#load "str.cma";;
open Printf
@@ -43,9 +44,15 @@ and ret =
*)
| 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.
*)
@@ -68,6 +75,15 @@ and ret =
(* 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
@@ -83,6 +99,16 @@ and argt =
| StringList of string(* list of strings (each string cannot be NULL) *)
| Bool of string (* boolean *)
| Int of string (* int (smallish ints, signed, <= 31 bits) *)
+ (* These are treated as filenames (simple string parameters) in
+ * the C API and bindings. But in the RPC protocol, we transfer
+ * the actual file content up to or down from the daemon.
+ * FileIn: local machine -> daemon (in request)
+ * FileOut: daemon -> local machine (in reply)
+ * In guestfish (only), the special name "-" means read from
+ * stdin or write to stdout.
+ *)
+ | FileIn of string
+ | FileOut of string
type flags =
| ProtocolLimitWarning (* display warning about protocol size limits *)
@@ -110,12 +136,26 @@ can easily destroy all your data>."
* 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.
+ *
+ * You can add a prerequisite clause to any individual test. This
+ * is a run-time check, which, if it fails, causes the test to be
+ * skipped. Useful if testing a command which might not work on
+ * all variations of libguestfs builds. A test that has prerequisite
+ * of 'Always' is run unconditionally.
*)
-type tests = (test_init * test) list
+type tests = (test_init * test_prereq * test) list
and test =
(* Run the command sequence and just expect nothing to fail. *)
| TestRun of seq
@@ -159,6 +199,15 @@ and test_field_compare =
| CompareFieldsIntEq of string * string
| CompareFieldsStrEq of string * string
+(* Test prerequisites. *)
+and test_prereq =
+ (* Test always runs. *)
+ | Always
+ (* Test is currently disabled - eg. it fails, or it tests some
+ * unimplemented feature.
+ *)
+ | Disabled
+
(* Some initial scenarios for testing. *)
and test_init =
(* Do nothing, block devices could contain random stuff including
@@ -259,6 +308,29 @@ The first character of C string must be a C<-> (dash).
C can be NULL.");
+ ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
+ [],
+ "set the qemu binary",
+ "\
+Set the qemu binary that we will use.
+
+The default is chosen when the library was compiled by the
+configure script.
+
+You can also override this by setting the C
+environment variable.
+
+Setting C to C restores the default qemu binary.");
+
+ ("get_qemu", (RConstString "qemu", []), -1, [],
+ [],
+ "get the qemu binary",
+ "\
+Return the current qemu binary.
+
+This is always non-NULL. If it wasn't set already, then this will
+return the default qemu binary name.");
+
("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
[],
"set the search path",
@@ -268,9 +340,6 @@ Set the path that libguestfs searches for kernel and initrd.img.
The default is C<$libdir/guestfs> unless overridden by setting
C environment variable.
-The string C is stashed in the libguestfs handle, so the caller
-must make sure it remains valid for the lifetime of the handle.
-
Setting C to C restores the default path.");
("get_path", (RConstString "path", []), -1, [],
@@ -282,13 +351,39 @@ Return the current search path.
This is always non-NULL. If it wasn't set already, then this will
return the default path.");
+ ("set_append", (RErr, [String "append"]), -1, [FishAlias "append"],
+ [],
+ "add options to kernel command line",
+ "\
+This function is used to add additional options to the
+guest kernel command line.
+
+The default is C unless overridden by setting
+C environment variable.
+
+Setting C to C means I additional options
+are passed (libguestfs always adds a few of its own).");
+
+ ("get_append", (RConstString "append", []), -1, [],
+ [],
+ "get the additional kernel options",
+ "\
+Return the additional kernel options which are added to the
+guest kernel command line.
+
+If C then no options are added.");
+
("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
[],
"set autosync mode",
"\
If C is true, this enables autosync. Libguestfs will make a
-best effort attempt to run C when the handle is closed
-(also if the program exits without closing handles).");
+best effort attempt to run C followed by
+C when the handle is closed
+(also if the program exits without closing handles).
+
+This is disabled by default (except in guestfish where it is
+enabled by default).");
("get_autosync", (RBool "autosync", []), -1, [],
[],
@@ -309,12 +404,86 @@ C is defined and set to C<1>.");
[],
"get verbose mode",
"\
-This returns the verbose messages flag.")
+This returns the verbose messages flag.");
+
+ ("is_ready", (RBool "ready", []), -1, [],
+ [],
+ "is ready to accept commands",
+ "\
+This returns true iff this handle is ready to accept commands
+(in the C state).
+
+For more information on states, see L.");
+
+ ("is_config", (RBool "config", []), -1, [],
+ [],
+ "is in configuration state",
+ "\
+This returns true iff this handle is being configured
+(in the C state).
+
+For more information on states, see L.");
+
+ ("is_launching", (RBool "launching", []), -1, [],
+ [],
+ "is launching subprocess",
+ "\
+This returns true iff this handle is launching the subprocess
+(in the C state).
+
+For more information on states, see L.");
+
+ ("is_busy", (RBool "busy", []), -1, [],
+ [],
+ "is busy processing a command",
+ "\
+This returns true iff this handle is busy processing a command
+(in the C state).
+
+For more information on states, see L.");
+
+ ("get_state", (RInt "state", []), -1, [],
+ [],
+ "get the current state",
+ "\
+This returns the current state as an opaque integer. This is
+only useful for printing debug and internal error messages.
+
+For more information on states, see L.");
+
+ ("set_busy", (RErr, []), -1, [NotInFish],
+ [],
+ "set state to busy",
+ "\
+This sets the state to C. This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L.");
+
+ ("set_ready", (RErr, []), -1, [NotInFish],
+ [],
+ "set state to ready",
+ "\
+This sets the state to C. This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L.");
+
+ ("end_busy", (RErr, []), -1, [NotInFish],
+ [],
+ "leave the busy state",
+ "\
+This sets the state to C, or if in C then it leaves the
+state as is. This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L.");
+
]
let daemon_functions = [
("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
- [InitEmpty, TestOutput (
+ [InitEmpty, Always, TestOutput (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
@@ -340,7 +509,7 @@ The filesystem options C and C are set with this
call, in order to improve reliability.");
("sync", (RErr, []), 2, [],
- [ InitEmpty, TestRun [["sync"]]],
+ [ InitEmpty, Always, TestRun [["sync"]]],
"sync disks, writes are flushed through to the disk image",
"\
This syncs the disk, so that any writes are flushed through to the
@@ -350,7 +519,7 @@ You should always call this if you have modified a disk image, before
closing the handle.");
("touch", (RErr, [String "path"]), 3, [],
- [InitBasicFS, TestOutputTrue (
+ [InitBasicFS, Always, TestOutputTrue (
[["touch"; "/new"];
["exists"; "/new"]])],
"update file timestamps or create a new file",
@@ -360,7 +529,7 @@ update the timestamps on a file, or, if the file does not exist,
to create a new zero-length file.");
("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
- [InitBasicFS, TestOutput (
+ [InitBasicFS, Always, TestOutput (
[["write_file"; "/new"; "new file contents"; "0"];
["cat"; "/new"]], "new file contents")],
"list the contents of a file",
@@ -369,7 +538,7 @@ Return the contents of the file named C.
Note that this function cannot correctly handle binary files
(specifically, files containing C<\\0> character which is treated
-as end of string). For those you need to use the C
+as end of string). For those you need to use the C
function which has a more complex interface.");
("ll", (RString "listing", [String "directory"]), 5, [],
@@ -385,7 +554,7 @@ This command is mostly useful for interactive sessions. It
is I intended that you try to parse the output string.");
("ls", (RStringList "listing", [String "directory"]), 6, [],
- [InitBasicFS, TestOutputList (
+ [InitBasicFS, Always, TestOutputList (
[["touch"; "/new"];
["touch"; "/newer"];
["touch"; "/newest"];
@@ -400,7 +569,7 @@ This command is mostly useful for interactive sessions. Programs
should probably use C instead.");
("list_devices", (RStringList "devices", []), 7, [],
- [InitEmpty, TestOutputList (
+ [InitEmpty, Always, TestOutputList (
[["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
"list the block devices",
"\
@@ -409,9 +578,9 @@ List all the block devices.
The full block device names are returned, eg. C");
("list_partitions", (RStringList "partitions", []), 8, [],
- [InitBasicFS, TestOutputList (
+ [InitBasicFS, Always, TestOutputList (
[["list_partitions"]], ["/dev/sda1"]);
- InitEmpty, TestOutputList (
+ InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
"list the partitions",
@@ -424,9 +593,9 @@ This does not return logical volumes. For that you will need to
call C.");
("pvs", (RStringList "physvols", []), 9, [],
- [InitBasicFSonLVM, TestOutputList (
+ [InitBasicFSonLVM, Always, TestOutputList (
[["pvs"]], ["/dev/sda1"]);
- InitEmpty, TestOutputList (
+ InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -443,9 +612,9 @@ PVs (eg. C).
See also C.");
("vgs", (RStringList "volgroups", []), 10, [],
- [InitBasicFSonLVM, TestOutputList (
+ [InitBasicFSonLVM, Always, TestOutputList (
[["vgs"]], ["VG"]);
- InitEmpty, TestOutputList (
+ InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -464,9 +633,9 @@ detected (eg. C).
See also C.");
("lvs", (RStringList "logvols", []), 11, [],
- [InitBasicFSonLVM, TestOutputList (
+ [InitBasicFSonLVM, Always, TestOutputList (
[["lvs"]], ["/dev/VG/LV"]);
- InitEmpty, TestOutputList (
+ InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -509,10 +678,10 @@ List all the logical volumes detected. This is the equivalent
of the L command. The \"full\" version includes all fields.");
("read_lines", (RStringList "lines", [String "path"]), 15, [],
- [InitBasicFS, TestOutputList (
+ [InitBasicFS, Always, TestOutputList (
[["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
- InitBasicFS, TestOutputList (
+ InitBasicFS, Always, TestOutputList (
[["write_file"; "/new"; ""; "0"];
["read_lines"; "/new"]], [])],
"read file as lines",
@@ -687,12 +856,12 @@ This is just a shortcut for listing C
C and sorting the resulting nodes into alphabetical order.");
("rm", (RErr, [String "path"]), 29, [],
- [InitBasicFS, TestRun
+ [InitBasicFS, Always, TestRun
[["touch"; "/new"];
["rm"; "/new"]];
- InitBasicFS, TestLastFail
+ InitBasicFS, Always, TestLastFail
[["rm"; "/new"]];
- InitBasicFS, TestLastFail
+ InitBasicFS, Always, TestLastFail
[["mkdir"; "/new"];
["rm"; "/new"]]],
"remove a file",
@@ -700,12 +869,12 @@ C and sorting the resulting nodes into alphabetical order.");
Remove the single file C.");
("rmdir", (RErr, [String "path"]), 30, [],
- [InitBasicFS, TestRun
+ [InitBasicFS, Always, TestRun
[["mkdir"; "/new"];
["rmdir"; "/new"]];
- InitBasicFS, TestLastFail
+ InitBasicFS, Always, TestLastFail
[["rmdir"; "/new"]];
- InitBasicFS, TestLastFail
+ InitBasicFS, Always, TestLastFail
[["touch"; "/new"];
["rmdir"; "/new"]]],
"remove a directory",
@@ -713,7 +882,7 @@ Remove the single file C.");
Remove the single directory C.");
("rm_rf", (RErr, [String "path"]), 31, [],
- [InitBasicFS, TestOutputFalse
+ [InitBasicFS, Always, TestOutputFalse
[["mkdir"; "/new"];
["mkdir"; "/new/foo"];
["touch"; "/new/foo/bar"];
@@ -726,23 +895,23 @@ contents if its a directory. This is like the C shell
command.");
("mkdir", (RErr, [String "path"]), 32, [],
- [InitBasicFS, TestOutputTrue
+ [InitBasicFS, Always, TestOutputTrue
[["mkdir"; "/new"];
["is_dir"; "/new"]];
- InitBasicFS, TestLastFail
+ InitBasicFS, Always, TestLastFail
[["mkdir"; "/new/foo/bar"]]],
"create a directory",
"\
Create a directory named C.");
("mkdir_p", (RErr, [String "path"]), 33, [],
- [InitBasicFS, TestOutputTrue
+ [InitBasicFS, Always, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
["is_dir"; "/new/foo/bar"]];
- InitBasicFS, TestOutputTrue
+ InitBasicFS, Always, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
["is_dir"; "/new/foo"]];
- InitBasicFS, TestOutputTrue
+ InitBasicFS, Always, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
["is_dir"; "/new"]]],
"create a directory and parents",
@@ -768,10 +937,10 @@ names, you will need to locate and parse the password file
yourself (Augeas support makes this relatively easy).");
("exists", (RBool "existsflag", [String "path"]), 36, [],
- [InitBasicFS, TestOutputTrue (
+ [InitBasicFS, Always, TestOutputTrue (
[["touch"; "/new"];
["exists"; "/new"]]);
- InitBasicFS, TestOutputTrue (
+ InitBasicFS, Always, TestOutputTrue (
[["mkdir"; "/new"];
["exists"; "/new"]])],
"test if file or directory exists",
@@ -782,10 +951,10 @@ This returns C if and only if there is a file, directory
See also C, C, C.");
("is_file", (RBool "fileflag", [String "path"]), 37, [],
- [InitBasicFS, TestOutputTrue (
+ [InitBasicFS, Always, TestOutputTrue (
[["touch"; "/new"];
["is_file"; "/new"]]);
- InitBasicFS, TestOutputFalse (
+ InitBasicFS, Always, TestOutputFalse (
[["mkdir"; "/new"];
["is_file"; "/new"]])],
"test if file exists",
@@ -797,10 +966,10 @@ other objects like directories.
See also C.");
("is_dir", (RBool "dirflag", [String "path"]), 38, [],
- [InitBasicFS, TestOutputFalse (
+ [InitBasicFS, Always, TestOutputFalse (
[["touch"; "/new"];
["is_dir"; "/new"]]);
- InitBasicFS, TestOutputTrue (
+ InitBasicFS, Always, TestOutputTrue (
[["mkdir"; "/new"];
["is_dir"; "/new"]])],
"test if file exists",
@@ -812,7 +981,7 @@ other objects like files.
See also C.");
("pvcreate", (RErr, [String "device"]), 39, [],
- [InitEmpty, TestOutputList (
+ [InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -825,7 +994,7 @@ where C should usually be a partition name such
as C.");
("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
- [InitEmpty, TestOutputList (
+ [InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -839,7 +1008,7 @@ This creates an LVM volume group called C
from the non-empty list of physical volumes C.");
("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
- [InitEmpty, TestOutputList (
+ [InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -860,7 +1029,7 @@ This creates an LVM volume group called C
on the volume group C, with C megabytes.");
("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
- [InitEmpty, TestOutput (
+ [InitEmpty, Always, TestOutput (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
@@ -869,7 +1038,7 @@ on the volume group C, with C megabytes.");
"make a filesystem",
"\
This creates a filesystem on C (usually a partition
-of LVM logical volume). The filesystem type is C, for
+or LVM logical volume). The filesystem type is C, for
example C.");
("sfdisk", (RErr, [String "device";
@@ -899,12 +1068,24 @@ pass C as a single element list, when the single element being
the string C<,> (comma).");
("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
- [InitEmpty, TestOutput (
- [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
- ["mkfs"; "ext2"; "/dev/sda1"];
- ["mount"; "/dev/sda1"; "/"];
- ["write_file"; "/new"; "new file contents"; "0"];
- ["cat"; "/new"]], "new file contents")],
+ [InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "\nnew file contents\n"; "0"];
+ ["cat"; "/new"]], "\nnew file contents\n");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "\n\n"; "0"];
+ ["cat"; "/new"]], "\n\n");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; ""; "0"];
+ ["cat"; "/new"]], "");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "\n\n\n"; "0"];
+ ["cat"; "/new"]], "\n\n\n");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "\n"; "0"];
+ ["cat"; "/new"]], "\n")],
"create a file",
"\
This call creates a file called C. The contents of the
@@ -913,15 +1094,20 @@ with length C.
As a special case, if C is C<0>
then the length is calculated using C (so in this case
-the content cannot contain embedded ASCII NULs).");
+the content cannot contain embedded ASCII NULs).
+
+I Owing to a bug, writing content containing ASCII NUL
+characters does I work, even if the length is specified.
+We hope to resolve this bug in a future version. In the meantime
+use C.");
("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
- [InitEmpty, TestOutputList (
+ [InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
["mounts"]], ["/dev/sda1"]);
- InitEmpty, TestOutputList (
+ InitEmpty, Always, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
@@ -934,7 +1120,7 @@ specified either by its mountpoint (path) or the device which
contains the filesystem.");
("mounts", (RStringList "devices", []), 46, [],
- [InitBasicFS, TestOutputList (
+ [InitBasicFS, Always, TestOutputList (
[["mounts"]], ["/dev/sda1"])],
"show mounted filesystems",
"\
@@ -944,8 +1130,22 @@ the list of devices (eg. C, C).
Some internal mounts are not shown.");
("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
- [InitBasicFS, TestOutputList (
+ [InitBasicFS, Always, TestOutputList (
[["umount_all"];
+ ["mounts"]], []);
+ (* check that umount_all can unmount nested mounts correctly: *)
+ InitEmpty, Always, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mkfs"; "ext2"; "/dev/sda2"];
+ ["mkfs"; "ext2"; "/dev/sda3"];
+ ["mount"; "/dev/sda1"; "/"];
+ ["mkdir"; "/mp1"];
+ ["mount"; "/dev/sda2"; "/mp1"];
+ ["mkdir"; "/mp1/mp2"];
+ ["mount"; "/dev/sda3"; "/mp1/mp2"];
+ ["mkdir"; "/mp1/mp2/mp3"];
+ ["umount_all"];
["mounts"]], [])],
"unmount all filesystems",
"\
@@ -961,13 +1161,13 @@ This command removes all LVM logical volumes, volume groups
and physical volumes.");
("file", (RString "description", [String "path"]), 49, [],
- [InitBasicFS, TestOutput (
+ [InitBasicFS, Always, TestOutput (
[["touch"; "/new"];
["file"; "/new"]], "empty");
- InitBasicFS, TestOutput (
+ InitBasicFS, Always, TestOutput (
[["write_file"; "/new"; "some content\n"; "0"];
["file"; "/new"]], "ASCII text");
- InitBasicFS, TestLastFail (
+ InitBasicFS, Always, TestLastFail (
[["file"; "/nofile"]])],
"determine file type",
"\
@@ -979,8 +1179,55 @@ The exact command which runs is C. Note in
particular that the filename is not prepended to the output
(the C<-b> option).");
- ("command", (RString "output", [StringList "arguments"]), 50, [],
- [], (* XXX how to test? *)
+ ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
+ [InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 1"]], "Result1");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 2"]], "Result2\n");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 3"]], "\nResult3");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 4"]], "\nResult4\n");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 5"]], "\nResult5\n\n");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 6"]], "\n\nResult6\n\n");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 7"]], "");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 8"]], "\n");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 9"]], "\n\n");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
+ InitBasicFS, Always, TestOutput (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
+ InitBasicFS, Always, TestLastFail (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command"; "/test-command"]])],
"run a command from the guest filesystem",
"\
This call runs a command from the guest filesystem. The
@@ -993,6 +1240,13 @@ The first element is the name of the program to run.
Subsequent elements are parameters. The list must be
non-empty (ie. must contain a program name).
+The return value is anything printed to I by
+the command.
+
+If the command returns a non-zero exit status, then
+this function returns an error message. The error message
+string is the content of I from the command.
+
The C<$PATH> environment variable will contain at least
C and C. If you require a program from
another location, you should provide the full path in the
@@ -1004,15 +1258,58 @@ correct places. It is the caller's responsibility to ensure
all filesystems that are needed are mounted at the right
locations.");
- ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [],
- [], (* XXX how to test? *)
+ ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
+ [InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 1"]], ["Result1"]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 2"]], ["Result2"]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 3"]], ["";"Result3"]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 4"]], ["";"Result4"]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 7"]], []);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 8"]], [""]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 9"]], ["";""]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
+ InitBasicFS, Always, TestOutputList (
+ [["upload"; "test-command"; "/test-command"];
+ ["chmod"; "493"; "/test-command"];
+ ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
"run a command, returning lines",
"\
This is the same as C, but splits the
result into a list of lines.");
("stat", (RStat "statbuf", [String "path"]), 52, [],
- [InitBasicFS, TestOutputStruct (
+ [InitBasicFS, Always, TestOutputStruct (
[["touch"; "/new"];
["stat"; "/new"]], [CompareWithInt ("size", 0)])],
"get file information",
@@ -1022,7 +1319,7 @@ Returns file information for the given C.
This is the same as the C system call.");
("lstat", (RStat "statbuf", [String "path"]), 53, [],
- [InitBasicFS, TestOutputStruct (
+ [InitBasicFS, Always, TestOutputStruct (
[["touch"; "/new"];
["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
"get file information for a symbolic link",
@@ -1036,7 +1333,7 @@ refers to.
This is the same as the C system call.");
("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
- [InitBasicFS, TestOutputStruct (
+ [InitBasicFS, Always, TestOutputStruct (
[["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
CompareWithInt ("blocks", 490020);
CompareWithInt ("bsize", 1024)])],
@@ -1048,6 +1345,646 @@ C should be a file or directory in the mounted file system
This is the same as the C system call.");
+ ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
+ [], (* XXX test *)
+ "get ext2/ext3/ext4 superblock details",
+ "\
+This returns the contents of the ext2, ext3 or ext4 filesystem
+superblock on C.
+
+It is the same as running C. See L
+manpage for more details. The list of fields returned isn't
+clearly defined, and depends on both the version of C
+that libguestfs was built against, and the filesystem itself.");
+
+ ("blockdev_setro", (RErr, [String "device"]), 56, [],
+ [InitEmpty, Always, TestOutputTrue (
+ [["blockdev_setro"; "/dev/sda"];
+ ["blockdev_getro"; "/dev/sda"]])],
+ "set block device to read-only",
+ "\
+Sets the block device named C to read-only.
+
+This uses the L command.");
+
+ ("blockdev_setrw", (RErr, [String "device"]), 57, [],
+ [InitEmpty, Always, TestOutputFalse (
+ [["blockdev_setrw"; "/dev/sda"];
+ ["blockdev_getro"; "/dev/sda"]])],
+ "set block device to read-write",
+ "\
+Sets the block device named C to read-write.
+
+This uses the L command.");
+
+ ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
+ [InitEmpty, Always, 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 command.");
+
+ ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
+ [InitEmpty, Always, 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
+for that).
+
+This uses the L command.");
+
+ ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
+ [InitEmpty, Always, 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 and
+I).
+
+This uses the L 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 and
+I).
+
+This uses the L command.");
+
+ ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
+ [InitEmpty, Always, 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 for the real sector size of
+the device, and C for the more
+useful I.
+
+This uses the L command.");
+
+ ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
+ [InitEmpty, Always, 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.
+
+This uses the L command.");
+
+ ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
+ [InitEmpty, Always, TestRun
+ [["blockdev_flushbufs"; "/dev/sda"]]],
+ "flush device buffers",
+ "\
+This tells the kernel to flush internal buffers associated
+with C.
+
+This uses the L command.");
+
+ ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
+ [InitEmpty, Always, TestRun
+ [["blockdev_rereadpt"; "/dev/sda"]]],
+ "reread partition table",
+ "\
+Reread the partition table on C.
+
+This uses the L command.");
+
+ ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
+ [InitBasicFS, Always, TestOutput (
+ (* Pick a file from cwd which isn't likely to change. *)
+ [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
+ ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
+ "upload a file from the local machine",
+ "\
+Upload local file C to C on the
+filesystem.
+
+C can also be a named pipe.
+
+See also C.");
+
+ ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
+ [InitBasicFS, Always, TestOutput (
+ (* Pick a file from cwd which isn't likely to change. *)
+ [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
+ ["download"; "/COPYING.LIB"; "testdownload.tmp"];
+ ["upload"; "testdownload.tmp"; "/upload"];
+ ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
+ "download a file to the local machine",
+ "\
+Download file C and save it as C
+on the local machine.
+
+C can also be a named pipe.
+
+See also C, C.");
+
+ ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
+ [InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "crc"; "/new"]], "935282863");
+ InitBasicFS, Always, TestLastFail (
+ [["checksum"; "crc"; "/new"]]);
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123")],
+ "compute MD5, SHAx or CRC checksum of file",
+ "\
+This call computes the MD5, SHAx or CRC checksum of the
+file named C.
+
+The type of checksum to compute is given by the C
+parameter which must have one of the following values:
+
+=over 4
+
+=item C
+
+Compute the cyclic redundancy check (CRC) specified by POSIX
+for the C command.
+
+=item C
+
+Compute the MD5 hash (using the C program).
+
+=item C
+
+Compute the SHA1 hash (using the C program).
+
+=item C
+
+Compute the SHA224 hash (using the C program).
+
+=item C
+
+Compute the SHA256 hash (using the C program).
+
+=item C
+
+Compute the SHA384 hash (using the C program).
+
+=item C
+
+Compute the SHA512 hash (using the C program).
+
+=back
+
+The checksum is returned as a printable string.");
+
+ ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
+ [InitBasicFS, Always, TestOutput (
+ [["tar_in"; "images/helloworld.tar"; "/"];
+ ["cat"; "/hello"]], "hello\n")],
+ "unpack tarfile to directory",
+ "\
+This command uploads and unpacks local file C (an
+I tar file) into C.
+
+To upload a compressed tarball, use C.");
+
+ ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
+ [],
+ "pack directory into tarfile",
+ "\
+This command packs the contents of C and downloads
+it to local file C.
+
+To download a compressed tarball, use C.");
+
+ ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
+ [InitBasicFS, Always, TestOutput (
+ [["tgz_in"; "images/helloworld.tar.gz"; "/"];
+ ["cat"; "/hello"]], "hello\n")],
+ "unpack compressed tarball to directory",
+ "\
+This command uploads and unpacks local file C (a
+I tar file) into C.
+
+To upload an uncompressed tarball, use C.");
+
+ ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
+ [],
+ "pack directory into compressed tarball",
+ "\
+This command packs the contents of C and downloads
+it to local file C.
+
+To download an uncompressed tarball, use C.");
+
+ ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
+ [InitBasicFS, Always, TestLastFail (
+ [["umount"; "/"];
+ ["mount_ro"; "/dev/sda1"; "/"];
+ ["touch"; "/new"]]);
+ InitBasicFS, Always, TestOutput (
+ [["write_file"; "/new"; "data"; "0"];
+ ["umount"; "/"];
+ ["mount_ro"; "/dev/sda1"; "/"];
+ ["cat"; "/new"]], "data")],
+ "mount a guest disk, read-only",
+ "\
+This is the same as the C command, but it
+mounts the filesystem with the read-only (I<-o ro>) flag.");
+
+ ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
+ [],
+ "mount a guest disk with mount options",
+ "\
+This is the same as the C command, but it
+allows you to set the mount options as for the
+L I<-o> flag.");
+
+ ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
+ [],
+ "mount a guest disk with mount options and vfstype",
+ "\
+This is the same as the C command, but it
+allows you to set both the mount options and the vfstype
+as for the L I<-o> and I<-t> flags.");
+
+ ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
+ [],
+ "debugging and internals",
+ "\
+The C command exposes some internals of
+C (the guestfs daemon) that runs inside the
+qemu subprocess.
+
+There is no comprehensive help for this command. You have
+to look at the file C in the libguestfs source
+to find out what you can do.");
+
+ ("lvremove", (RErr, [String "device"]), 77, [],
+ [InitEmpty, Always, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG/LV1"];
+ ["lvs"]], ["/dev/VG/LV2"]);
+ InitEmpty, Always, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG"];
+ ["lvs"]], []);
+ InitEmpty, Always, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG"];
+ ["vgs"]], ["VG"])],
+ "remove an LVM logical volume",
+ "\
+Remove an LVM logical volume C, where C is
+the path to the LV, such as C.
+
+You can also remove all LVs in a volume group by specifying
+the VG name, C.");
+
+ ("vgremove", (RErr, [String "vgname"]), 78, [],
+ [InitEmpty, Always, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["lvs"]], []);
+ InitEmpty, Always, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["vgs"]], [])],
+ "remove an LVM volume group",
+ "\
+Remove an LVM volume group C, (for example C).
+
+This also forcibly removes all logical volumes in the volume
+group (if any).");
+
+ ("pvremove", (RErr, [String "device"]), 79, [],
+ [InitEmpty, Always, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda"];
+ ["lvs"]], []);
+ InitEmpty, Always, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda"];
+ ["vgs"]], []);
+ InitEmpty, Always, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda"];
+ ["pvs"]], [])],
+ "remove an LVM physical volume",
+ "\
+This wipes a physical volume C so that LVM will no longer
+recognise it.
+
+The implementation uses the C command which refuses to
+wipe physical volumes that contain any volume groups, so you have
+to remove those first.");
+
+ ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
+ [InitBasicFS, Always, TestOutput (
+ [["set_e2label"; "/dev/sda1"; "testlabel"];
+ ["get_e2label"; "/dev/sda1"]], "testlabel")],
+ "set the ext2/3/4 filesystem label",
+ "\
+This sets the ext2/3/4 filesystem label of the filesystem on
+C to C