X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fgenerator.ml;h=4c8c2e1bdd87612e3004375421d948f800505eaf;hb=76758f42b1abc89d5857697c87ead5036ed81b13;hp=28e1cb62646ab7f92c2757e32a3048285b9818cc;hpb=f968f6c36fda3bb66cd37cd56de250c29afa7698;p=libguestfs.git
diff --git a/src/generator.ml b/src/generator.ml
index 28e1cb6..4c8c2e1 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.
*)
@@ -65,6 +72,18 @@ and ret =
| RPVList of string
| RVGList of string
| RLVList of string
+ (* 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
@@ -80,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 *)
@@ -107,7 +136,7 @@ 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.
+ * Between each test we umount-all and lvm-remove-all (except InitNone).
*
* Don't assume anything about the previous contents of the block
* devices. Use 'Init*' to create some initial scenarios.
@@ -141,28 +170,43 @@ and test =
* content).
*)
| TestOutputLength of seq * int
+ (* Run the command sequence and expect the output of the final
+ * command to be a structure.
+ *)
+ | TestOutputStruct of seq * test_field_compare list
(* Run the command sequence and expect the final command (only)
* to fail.
*)
| TestLastFail of seq
+and test_field_compare =
+ | CompareWithInt of string * int
+ | CompareWithString of string * string
+ | CompareFieldsIntEq of string * string
+ | CompareFieldsStrEq of string * string
+
(* Some initial scenarios for testing. *)
and test_init =
- (* Do nothing, block devices could contain random stuff. *)
+ (* Do nothing, block devices could contain random stuff including
+ * LVM PVs, and some filesystems might be mounted. This is usually
+ * a bad idea.
+ *)
| InitNone
+ (* Block devices are empty and no filesystems are mounted. *)
+ | InitEmpty
(* /dev/sda contains a single partition /dev/sda1, which is formatted
* as ext2, empty [except for lost+found] and mounted on /.
* /dev/sdb and /dev/sdc may have random content.
* No LVM.
*)
- | InitEmpty
+ | InitBasicFS
(* /dev/sda:
* /dev/sda1 (is a PV):
* /dev/VG/LV (size 8MB):
* formatted as ext2, empty [except for lost+found], mounted on /
* /dev/sdb and /dev/sdc may have random content.
*)
- | InitEmptyLVM
+ | InitBasicFSonLVM
(* Sequence of commands for testing. *)
and seq = cmd list
@@ -241,6 +285,32 @@ 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.
+
+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 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",
@@ -269,8 +339,12 @@ return the default path.");
"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, [],
[],
@@ -291,12 +365,76 @@ 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.");
+
]
let daemon_functions = [
("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
- [InitNone, TestOutput (
+ [InitEmpty, TestOutput (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
@@ -322,7 +460,7 @@ The filesystem options C and C are set with this
call, in order to improve reliability.");
("sync", (RErr, []), 2, [],
- [ InitNone, TestRun [["sync"]]],
+ [ InitEmpty, 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
@@ -332,7 +470,7 @@ You should always call this if you have modified a disk image, before
closing the handle.");
("touch", (RErr, [String "path"]), 3, [],
- [InitEmpty, TestOutputTrue (
+ [InitBasicFS, TestOutputTrue (
[["touch"; "/new"];
["exists"; "/new"]])],
"update file timestamps or create a new file",
@@ -342,7 +480,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],
- [InitEmpty, TestOutput (
+ [InitBasicFS, TestOutput (
[["write_file"; "/new"; "new file contents"; "0"];
["cat"; "/new"]], "new file contents")],
"list the contents of a file",
@@ -351,7 +489,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, [],
@@ -367,7 +505,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, [],
- [InitEmpty, TestOutputList (
+ [InitBasicFS, TestOutputList (
[["touch"; "/new"];
["touch"; "/newer"];
["touch"; "/newest"];
@@ -382,7 +520,7 @@ This command is mostly useful for interactive sessions. Programs
should probably use C instead.");
("list_devices", (RStringList "devices", []), 7, [],
- [InitNone, TestOutputList (
+ [InitEmpty, TestOutputList (
[["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
"list the block devices",
"\
@@ -391,9 +529,9 @@ List all the block devices.
The full block device names are returned, eg. C");
("list_partitions", (RStringList "partitions", []), 8, [],
- [InitEmpty, TestOutputList (
+ [InitBasicFS, TestOutputList (
[["list_partitions"]], ["/dev/sda1"]);
- InitNone, TestOutputList (
+ InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
"list the partitions",
@@ -406,9 +544,9 @@ This does not return logical volumes. For that you will need to
call C.");
("pvs", (RStringList "physvols", []), 9, [],
- [InitEmptyLVM, TestOutputList (
+ [InitBasicFSonLVM, TestOutputList (
[["pvs"]], ["/dev/sda1"]);
- InitNone, TestOutputList (
+ InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -425,9 +563,9 @@ PVs (eg. C).
See also C.");
("vgs", (RStringList "volgroups", []), 10, [],
- [InitEmptyLVM, TestOutputList (
+ [InitBasicFSonLVM, TestOutputList (
[["vgs"]], ["VG"]);
- InitNone, TestOutputList (
+ InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -446,9 +584,9 @@ detected (eg. C).
See also C.");
("lvs", (RStringList "logvols", []), 11, [],
- [InitEmptyLVM, TestOutputList (
+ [InitBasicFSonLVM, TestOutputList (
[["lvs"]], ["/dev/VG/LV"]);
- InitNone, TestOutputList (
+ InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -470,34 +608,31 @@ This returns a list of the logical volume device names
See also C.");
("pvs_full", (RPVList "physvols", []), 12, [],
- [InitEmptyLVM, TestOutputLength (
- [["pvs"]], 1)],
+ [], (* XXX how to test? *)
"list the LVM physical volumes (PVs)",
"\
List all the physical volumes detected. This is the equivalent
of the L command. The \"full\" version includes all fields.");
("vgs_full", (RVGList "volgroups", []), 13, [],
- [InitEmptyLVM, TestOutputLength (
- [["pvs"]], 1)],
+ [], (* XXX how to test? *)
"list the LVM volume groups (VGs)",
"\
List all the volumes groups detected. This is the equivalent
of the L command. The \"full\" version includes all fields.");
("lvs_full", (RLVList "logvols", []), 14, [],
- [InitEmptyLVM, TestOutputLength (
- [["pvs"]], 1)],
+ [], (* XXX how to test? *)
"list the LVM logical volumes (LVs)",
"\
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, [],
- [InitEmpty, TestOutputList (
+ [InitBasicFS, TestOutputList (
[["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
- InitEmpty, TestOutputList (
+ InitBasicFS, TestOutputList (
[["write_file"; "/new"; ""; "0"];
["read_lines"; "/new"]], [])],
"read file as lines",
@@ -672,12 +807,12 @@ This is just a shortcut for listing C
C and sorting the resulting nodes into alphabetical order.");
("rm", (RErr, [String "path"]), 29, [],
- [InitEmpty, TestRun
+ [InitBasicFS, TestRun
[["touch"; "/new"];
["rm"; "/new"]];
- InitEmpty, TestLastFail
+ InitBasicFS, TestLastFail
[["rm"; "/new"]];
- InitEmpty, TestLastFail
+ InitBasicFS, TestLastFail
[["mkdir"; "/new"];
["rm"; "/new"]]],
"remove a file",
@@ -685,12 +820,12 @@ C and sorting the resulting nodes into alphabetical order.");
Remove the single file C.");
("rmdir", (RErr, [String "path"]), 30, [],
- [InitEmpty, TestRun
+ [InitBasicFS, TestRun
[["mkdir"; "/new"];
["rmdir"; "/new"]];
- InitEmpty, TestLastFail
+ InitBasicFS, TestLastFail
[["rmdir"; "/new"]];
- InitEmpty, TestLastFail
+ InitBasicFS, TestLastFail
[["touch"; "/new"];
["rmdir"; "/new"]]],
"remove a directory",
@@ -698,7 +833,7 @@ Remove the single file C.");
Remove the single directory C.");
("rm_rf", (RErr, [String "path"]), 31, [],
- [InitEmpty, TestOutputFalse
+ [InitBasicFS, TestOutputFalse
[["mkdir"; "/new"];
["mkdir"; "/new/foo"];
["touch"; "/new/foo/bar"];
@@ -711,23 +846,23 @@ contents if its a directory. This is like the C shell
command.");
("mkdir", (RErr, [String "path"]), 32, [],
- [InitEmpty, TestOutputTrue
+ [InitBasicFS, TestOutputTrue
[["mkdir"; "/new"];
["is_dir"; "/new"]];
- InitEmpty, TestLastFail
+ InitBasicFS, TestLastFail
[["mkdir"; "/new/foo/bar"]]],
"create a directory",
"\
Create a directory named C.");
("mkdir_p", (RErr, [String "path"]), 33, [],
- [InitEmpty, TestOutputTrue
+ [InitBasicFS, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
["is_dir"; "/new/foo/bar"]];
- InitEmpty, TestOutputTrue
+ InitBasicFS, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
["is_dir"; "/new/foo"]];
- InitEmpty, TestOutputTrue
+ InitBasicFS, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
["is_dir"; "/new"]]],
"create a directory and parents",
@@ -753,10 +888,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, [],
- [InitEmpty, TestOutputTrue (
+ [InitBasicFS, TestOutputTrue (
[["touch"; "/new"];
["exists"; "/new"]]);
- InitEmpty, TestOutputTrue (
+ InitBasicFS, TestOutputTrue (
[["mkdir"; "/new"];
["exists"; "/new"]])],
"test if file or directory exists",
@@ -767,10 +902,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, [],
- [InitEmpty, TestOutputTrue (
+ [InitBasicFS, TestOutputTrue (
[["touch"; "/new"];
["is_file"; "/new"]]);
- InitEmpty, TestOutputFalse (
+ InitBasicFS, TestOutputFalse (
[["mkdir"; "/new"];
["is_file"; "/new"]])],
"test if file exists",
@@ -782,10 +917,10 @@ other objects like directories.
See also C.");
("is_dir", (RBool "dirflag", [String "path"]), 38, [],
- [InitEmpty, TestOutputFalse (
+ [InitBasicFS, TestOutputFalse (
[["touch"; "/new"];
["is_dir"; "/new"]]);
- InitEmpty, TestOutputTrue (
+ InitBasicFS, TestOutputTrue (
[["mkdir"; "/new"];
["is_dir"; "/new"]])],
"test if file exists",
@@ -797,7 +932,7 @@ other objects like files.
See also C.");
("pvcreate", (RErr, [String "device"]), 39, [],
- [InitNone, TestOutputList (
+ [InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -810,7 +945,7 @@ where C should usually be a partition name such
as C.");
("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
- [InitNone, TestOutputList (
+ [InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -824,7 +959,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, [],
- [InitNone, TestOutputList (
+ [InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
@@ -845,7 +980,7 @@ This creates an LVM volume group called C
on the volume group C, with C megabytes.");
("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
- [InitNone, TestOutput (
+ [InitEmpty, TestOutput (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
@@ -854,7 +989,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";
@@ -884,12 +1019,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],
- [InitNone, 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, TestOutput (
+ [["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "\nnew file contents\n"; "0"];
+ ["cat"; "/new"]], "\nnew file contents\n");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "\n\n"; "0"];
+ ["cat"; "/new"]], "\n\n");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; ""; "0"];
+ ["cat"; "/new"]], "");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "\n\n\n"; "0"];
+ ["cat"; "/new"]], "\n\n\n");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "\n"; "0"];
+ ["cat"; "/new"]], "\n")],
"create a file",
"\
This call creates a file called C. The contents of the
@@ -901,12 +1048,12 @@ then the length is calculated using C (so in this case
the content cannot contain embedded ASCII NULs).");
("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
- [InitNone, TestOutputList (
+ [InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
["mounts"]], ["/dev/sda1"]);
- InitNone, TestOutputList (
+ InitEmpty, TestOutputList (
[["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
@@ -919,7 +1066,7 @@ specified either by its mountpoint (path) or the device which
contains the filesystem.");
("mounts", (RStringList "devices", []), 46, [],
- [InitEmpty, TestOutputList (
+ [InitBasicFS, TestOutputList (
[["mounts"]], ["/dev/sda1"])],
"show mounted filesystems",
"\
@@ -929,8 +1076,22 @@ the list of devices (eg. C, C).
Some internal mounts are not shown.");
("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
- [InitEmpty, TestOutputList (
+ [InitBasicFS, TestOutputList (
[["umount_all"];
+ ["mounts"]], []);
+ (* check that umount_all can unmount nested mounts correctly: *)
+ InitEmpty, 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",
"\
@@ -945,2690 +1106,5307 @@ Some internal mounts are not unmounted by this call.");
This command removes all LVM logical volumes, volume groups
and physical volumes.");
-]
+ ("file", (RString "description", [String "path"]), 49, [],
+ [InitBasicFS, TestOutput (
+ [["touch"; "/new"];
+ ["file"; "/new"]], "empty");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "some content\n"; "0"];
+ ["file"; "/new"]], "ASCII text");
+ InitBasicFS, TestLastFail (
+ [["file"; "/nofile"]])],
+ "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.
-let all_functions = non_daemon_functions @ daemon_functions
+The exact command which runs is C. Note in
+particular that the filename is not prepended to the output
+(the C<-b> option).");
-(* In some places we want the functions to be displayed sorted
- * alphabetically, so this is useful:
- *)
-let all_functions_sorted =
- List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
- compare n1 n2) all_functions
+ ("command", (RString "output", [StringList "arguments"]), 50, [],
+ [], (* XXX how to test? *)
+ "run a command from the guest filesystem",
+ "\
+This call runs a command from the guest filesystem. The
+filesystem must be mounted, and must contain a compatible
+operating system (ie. something Linux, with the same
+or compatible processor architecture).
+
+The single parameter is an argv-style list of arguments.
+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 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
+first parameter.
+
+Shared libraries and data files required by the program
+must be available on filesystems which are mounted in the
+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? *)
+ "run a command, returning lines",
+ "\
+This is the same as C, but splits the
+result into a list of lines.");
-(* Column names and types from LVM PVs/VGs/LVs. *)
-let pv_cols = [
- "pv_name", `String;
- "pv_uuid", `UUID;
- "pv_fmt", `String;
- "pv_size", `Bytes;
- "dev_size", `Bytes;
- "pv_free", `Bytes;
- "pv_used", `Bytes;
- "pv_attr", `String (* XXX *);
- "pv_pe_count", `Int;
- "pv_pe_alloc_count", `Int;
- "pv_tags", `String;
- "pe_start", `Bytes;
- "pv_mda_count", `Int;
- "pv_mda_free", `Bytes;
-(* Not in Fedora 10:
- "pv_mda_size", `Bytes;
-*)
-]
-let vg_cols = [
- "vg_name", `String;
- "vg_uuid", `UUID;
- "vg_fmt", `String;
- "vg_attr", `String (* XXX *);
- "vg_size", `Bytes;
- "vg_free", `Bytes;
- "vg_sysid", `String;
- "vg_extent_size", `Bytes;
- "vg_extent_count", `Int;
- "vg_free_count", `Int;
- "max_lv", `Int;
- "max_pv", `Int;
- "pv_count", `Int;
- "lv_count", `Int;
- "snap_count", `Int;
- "vg_seqno", `Int;
- "vg_tags", `String;
- "vg_mda_count", `Int;
- "vg_mda_free", `Bytes;
-(* Not in Fedora 10:
- "vg_mda_size", `Bytes;
-*)
-]
-let lv_cols = [
- "lv_name", `String;
- "lv_uuid", `UUID;
- "lv_attr", `String (* XXX *);
- "lv_major", `Int;
- "lv_minor", `Int;
- "lv_kernel_major", `Int;
- "lv_kernel_minor", `Int;
- "lv_size", `Bytes;
- "seg_count", `Int;
- "origin", `String;
- "snap_percent", `OptPercent;
- "copy_percent", `OptPercent;
- "move_pv", `String;
- "lv_tags", `String;
- "mirror_log", `String;
- "modules", `String;
-]
+ ("stat", (RStat "statbuf", [String "path"]), 52, [],
+ [InitBasicFS, TestOutputStruct (
+ [["touch"; "/new"];
+ ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
+ "get file information",
+ "\
+Returns file information for the given C.
-(* Useful functions.
- * Note we don't want to use any external OCaml libraries which
- * makes this a bit harder than it should be.
- *)
-let failwithf fs = ksprintf failwith fs
+This is the same as the C system call.");
-let replace_char s c1 c2 =
- let s2 = String.copy s in
- let r = ref false in
- for i = 0 to String.length s2 - 1 do
- if String.unsafe_get s2 i = c1 then (
- String.unsafe_set s2 i c2;
- r := true
- )
- done;
- if not !r then s else s2
+ ("lstat", (RStat "statbuf", [String "path"]), 53, [],
+ [InitBasicFS, TestOutputStruct (
+ [["touch"; "/new"];
+ ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
+ "get file information for a symbolic link",
+ "\
+Returns file information for the given C.
-let rec find s sub =
- let len = String.length s in
- let sublen = String.length sub in
- let rec loop i =
- if i <= len-sublen then (
- let rec loop2 j =
- if j < sublen then (
- if s.[i+j] = sub.[j] then loop2 (j+1)
- else -1
- ) else
- i (* found *)
- in
- let r = loop2 0 in
- if r = -1 then loop (i+1) else r
- ) else
- -1 (* not found *)
- in
- loop 0
+This is the same as C except that if C
+is a symbolic link, then the link is stat-ed, not the file it
+refers to.
-let rec replace_str s s1 s2 =
- let len = String.length s in
- let sublen = String.length s1 in
- let i = find s s1 in
- if i = -1 then s
- else (
- let s' = String.sub s 0 i in
- let s'' = String.sub s (i+sublen) (len-i-sublen) in
- s' ^ s2 ^ replace_str s'' s1 s2
- )
+This is the same as the C system call.");
-let rec string_split sep str =
- let len = String.length str in
- let seplen = String.length sep in
- let i = find str sep in
- if i = -1 then [str]
- else (
- let s' = String.sub str 0 i in
- let s'' = String.sub str (i+seplen) (len-i-seplen) in
- s' :: string_split sep s''
- )
+ ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
+ [InitBasicFS, TestOutputStruct (
+ [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
+ CompareWithInt ("blocks", 490020);
+ CompareWithInt ("bsize", 1024)])],
+ "get file system statistics",
+ "\
+Returns file system statistics for any mounted file system.
+C should be a file or directory in the mounted file system
+(typically it is the mount point itself, but it doesn't need to be).
-let rec find_map f = function
- | [] -> raise Not_found
- | x :: xs ->
- match f x with
- | Some y -> y
- | None -> find_map f xs
+This is the same as the C system call.");
-let iteri f xs =
- let rec loop i = function
- | [] -> ()
- | x :: xs -> f i x; loop (i+1) xs
- in
- loop 0 xs
+ ("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.
-let mapi f xs =
- let rec loop i = function
- | [] -> []
- | x :: xs -> let r = f i x in r :: loop (i+1) xs
- in
- loop 0 xs
+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.");
-let name_of_argt = function
- | String n | OptString n | StringList n | Bool n | Int n -> n
+ ("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 to read-only.
-(* Check function names etc. for consistency. *)
-let check_functions () =
- let contains_uppercase str =
- let len = String.length str in
- let rec loop i =
- if i >= len then false
- else (
- let c = str.[i] in
- if c >= 'A' && c <= 'Z' then true
- else loop (i+1)
- )
- in
- loop 0
- in
+This uses the L command.");
- (* Check function names. *)
- List.iter (
- fun (name, _, _, _, _, _, _) ->
- if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
- failwithf "function name %s does not need 'guestfs' prefix" name;
- if contains_uppercase name then
- failwithf "function name %s should not contain uppercase chars" name;
- if String.contains name '-' then
- failwithf "function name %s should not contain '-', use '_' instead."
- name
- ) all_functions;
+ ("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 to read-write.
- (* Check function parameter/return names. *)
- List.iter (
- fun (name, style, _, _, _, _, _) ->
- let check_arg_ret_name n =
- if contains_uppercase n then
- failwithf "%s param/ret %s should not contain uppercase chars"
- name n;
- if String.contains n '-' || String.contains n '_' then
- failwithf "%s param/ret %s should not contain '-' or '_'"
- name n;
- if n = "value" then
- failwithf "%s has a param/ret called 'value', which causes conflicts in the OCaml bindings, use something like 'val' or a more descriptive name" n
- in
+This uses the L command.");
- (match fst style with
- | RErr -> ()
- | RInt n | RBool n | RConstString n | RString n
- | RStringList n | RPVList n | RVGList n | RLVList n ->
- check_arg_ret_name n
- | RIntBool (n,m) ->
- check_arg_ret_name n;
- check_arg_ret_name m
- );
- List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
- ) all_functions;
+ ("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).
- (* Check short descriptions. *)
- List.iter (
- fun (name, _, _, _, _, shortdesc, _) ->
- if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
- failwithf "short description of %s should begin with lowercase." name;
- let c = shortdesc.[String.length shortdesc-1] in
- if c = '\n' || c = '.' then
- failwithf "short description of %s should not end with . or \\n." name
- ) all_functions;
+This uses the L command.");
- (* Check long dscriptions. *)
- List.iter (
- fun (name, _, _, _, _, _, longdesc) ->
- if longdesc.[String.length longdesc-1] = '\n' then
- failwithf "long description of %s should not end with \\n." name
- ) all_functions;
+ ("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.
- (* Check proc_nrs. *)
- List.iter (
- fun (name, _, proc_nr, _, _, _, _) ->
- if proc_nr <= 0 then
- failwithf "daemon function %s should have proc_nr > 0" name
- ) daemon_functions;
+(Note, this is not the size in sectors, use C
+for that).
- List.iter (
- fun (name, _, proc_nr, _, _, _, _) ->
- if proc_nr <> -1 then
- failwithf "non-daemon function %s should have proc_nr -1" name
- ) non_daemon_functions;
+This uses the L command.");
- let proc_nrs =
- List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
- daemon_functions in
- let proc_nrs =
- List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
- let rec loop = function
- | [] -> ()
- | [_] -> ()
- | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
- loop rest
- | (name1,nr1) :: (name2,nr2) :: _ ->
- failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
- name1 name2 nr1 nr2
- in
- loop proc_nrs
+ ("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.
-(* 'pr' prints to the current output file. *)
-let chan = ref stdout
-let pr fs = ksprintf (output_string !chan) fs
+(Note this is different from both I and
+I).
-(* Generate a header block in a number of standard styles. *)
-type comment_style = CStyle | HashStyle | OCamlStyle
-type license = GPLv2 | LGPLv2
+This uses the L command.");
-let generate_header comment license =
- let c = match comment with
- | CStyle -> pr "/* "; " *"
- | HashStyle -> pr "# "; "#"
- | OCamlStyle -> pr "(* "; " *" in
- pr "libguestfs generated file\n";
- pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
- pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
- pr "%s\n" c;
- pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
- pr "%s\n" c;
- (match license with
- | GPLv2 ->
- pr "%s This program is free software; you can redistribute it and/or modify\n" c;
- pr "%s it under the terms of the GNU General Public License as published by\n" c;
- pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
- pr "%s (at your option) any later version.\n" c;
- pr "%s\n" c;
- pr "%s This program is distributed in the hope that it will be useful,\n" c;
- pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
- pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
- pr "%s GNU General Public License for more details.\n" c;
- pr "%s\n" c;
- pr "%s You should have received a copy of the GNU General Public License along\n" c;
- pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
- pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
+ ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
+ [], (* XXX test *)
+ "set blocksize of block device",
+ "\
+This sets the block size of a device.
- | LGPLv2 ->
- pr "%s This library is free software; you can redistribute it and/or\n" c;
- pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
- pr "%s License as published by the Free Software Foundation; either\n" c;
- pr "%s version 2 of the License, or (at your option) any later version.\n" c;
- pr "%s\n" c;
- pr "%s This library is distributed in the hope that it will be useful,\n" c;
- pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
- pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
- pr "%s Lesser General Public License for more details.\n" c;
- pr "%s\n" c;
- pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
- pr "%s License along with this library; if not, write to the Free Software\n" c;
- pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
- );
- (match comment with
- | CStyle -> pr " */\n"
- | HashStyle -> ()
- | OCamlStyle -> pr " *)\n"
- );
- pr "\n"
+(Note this is different from both I and
+I).
-(* Start of main code generation functions below this line. *)
+This uses the L command.");
-(* Generate the pod documentation for the C API. *)
-let rec generate_actions_pod () =
- List.iter (
- fun (shortname, style, _, flags, _, _, longdesc) ->
- let name = "guestfs_" ^ shortname in
- pr "=head2 %s\n\n" name;
- pr " ";
- generate_prototype ~extern:false ~handle:"handle" name style;
- pr "\n\n";
- pr "%s\n\n" longdesc;
- (match fst style with
- | RErr ->
- pr "This function returns 0 on success or -1 on error.\n\n"
- | RInt _ ->
- 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 _ ->
- pr "This function returns a string or NULL on error.
-The string is owned by the guest handle and must I be freed.\n\n"
- | RString _ ->
- pr "This function returns a string or NULL on error.
-I.\n\n"
- | RStringList _ ->
- pr "This function returns a NULL-terminated array of strings
-(like L), or NULL if there was an error.
-I.\n\n"
- | RIntBool _ ->
- pr "This function returns a C.
-I after use>.\n\n"
- | RPVList _ ->
- pr "This function returns a C.
-I after use>.\n\n"
- | RVGList _ ->
- pr "This function returns a C.
-I after use>.\n\n"
- | RLVList _ ->
- pr "This function returns a C.
-I after use>.\n\n"
- );
- if List.mem ProtocolLimitWarning flags then
- pr "%s\n\n" protocol_limit_warning;
- if List.mem DangerWillRobinson flags then
- pr "%s\n\n" danger_will_robinson;
- ) all_functions_sorted
+ ("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).
-and generate_structs_pod () =
- (* LVM structs documentation. *)
- List.iter (
- fun (typ, cols) ->
- pr "=head2 guestfs_lvm_%s\n" typ;
- pr "\n";
- pr " struct guestfs_lvm_%s {\n" typ;
- List.iter (
- function
- | name, `String -> pr " char *%s;\n" name
- | name, `UUID ->
- pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
- pr " char %s[32];\n" name
- | name, `Bytes -> pr " uint64_t %s;\n" name
- | name, `Int -> pr " int64_t %s;\n" name
- | name, `OptPercent ->
- pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
- pr " float %s;\n" name
- ) cols;
- pr " \n";
- pr " struct guestfs_lvm_%s_list {\n" typ;
- pr " uint32_t len; /* Number of elements in list. */\n";
- pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
- pr " };\n";
- pr " \n";
- pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
- typ typ;
- pr "\n"
- ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
+See also C for the real sector size of
+the device, and C for the more
+useful I.
-(* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
- * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
- *
- * We have to use an underscore instead of a dash because otherwise
- * rpcgen generates incorrect code.
- *
- * This header is NOT exported to clients, but see also generate_structs_h.
- *)
-and generate_xdr () =
- generate_header CStyle LGPLv2;
+This uses the L command.");
- (* This has to be defined to get around a limitation in Sun's rpcgen. *)
- pr "typedef string str<>;\n";
- pr "\n";
+ ("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.
- (* LVM internal structures. *)
- List.iter (
- function
- | typ, cols ->
- pr "struct guestfs_lvm_int_%s {\n" typ;
- List.iter (function
- | name, `String -> pr " string %s<>;\n" name
- | name, `UUID -> pr " opaque %s[32];\n" name
- | name, `Bytes -> pr " hyper %s;\n" name
- | name, `Int -> pr " hyper %s;\n" name
- | name, `OptPercent -> pr " float %s;\n" name
- ) cols;
- pr "};\n";
- pr "\n";
- pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
- pr "\n";
- ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
+See also C.
- List.iter (
- fun (shortname, style, _, _, _, _, _) ->
- let name = "guestfs_" ^ shortname in
+This uses the L command.");
- (match snd style with
- | [] -> ()
- | args ->
- pr "struct %s_args {\n" name;
- List.iter (
- function
- | String n -> pr " string %s<>;\n" n
- | OptString n -> pr " str *%s;\n" n
- | StringList n -> pr " str %s<>;\n" n
- | Bool n -> pr " bool %s;\n" n
- | Int n -> pr " int %s;\n" n
- ) args;
- pr "};\n\n"
- );
- (match fst style with
- | RErr -> ()
- | RInt n ->
- pr "struct %s_ret {\n" name;
- pr " int %s;\n" n;
- pr "};\n\n"
- | RBool n ->
- pr "struct %s_ret {\n" name;
- pr " bool %s;\n" n;
- pr "};\n\n"
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RString n ->
- pr "struct %s_ret {\n" name;
- pr " string %s<>;\n" n;
- pr "};\n\n"
- | RStringList n ->
- pr "struct %s_ret {\n" name;
- pr " str %s<>;\n" n;
- pr "};\n\n"
- | RIntBool (n,m) ->
- pr "struct %s_ret {\n" name;
- pr " int %s;\n" n;
- pr " bool %s;\n" m;
- pr "};\n\n"
- | RPVList n ->
- pr "struct %s_ret {\n" name;
- pr " guestfs_lvm_int_pv_list %s;\n" n;
- pr "};\n\n"
- | RVGList n ->
- pr "struct %s_ret {\n" name;
- pr " guestfs_lvm_int_vg_list %s;\n" n;
- pr "};\n\n"
- | RLVList n ->
- pr "struct %s_ret {\n" name;
- pr " guestfs_lvm_int_lv_list %s;\n" n;
- pr "};\n\n"
- );
- ) daemon_functions;
-
- (* Table of procedure numbers. *)
- pr "enum guestfs_procedure {\n";
- List.iter (
- fun (shortname, _, proc_nr, _, _, _, _) ->
- pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
- ) daemon_functions;
- pr " GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
- pr "};\n";
- pr "\n";
+ ("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.
- (* Having to choose a maximum message size is annoying for several
- * reasons (it limits what we can do in the API), but it (a) makes
- * the protocol a lot simpler, and (b) provides a bound on the size
- * of the daemon which operates in limited memory space. For large
- * file transfers you should use FTP.
- *)
- pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
- pr "\n";
+This uses the L command.");
- (* Message header, etc. *)
- pr "\
-const GUESTFS_PROGRAM = 0x2000F5F5;
-const GUESTFS_PROTOCOL_VERSION = 1;
+ ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
+ [InitEmpty, TestRun
+ [["blockdev_rereadpt"; "/dev/sda"]]],
+ "reread partition table",
+ "\
+Reread the partition table on C.
-enum guestfs_message_direction {
- GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
- GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
-};
+This uses the L command.");
-enum guestfs_message_status {
- GUESTFS_STATUS_OK = 0,
- GUESTFS_STATUS_ERROR = 1
-};
+ ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
+ [InitBasicFS, 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.
-const GUESTFS_ERROR_LEN = 256;
+C can also be a named pipe.
-struct guestfs_message_error {
- string error; /* error message */
-};
+See also C.");
-struct guestfs_message_header {
- unsigned prog; /* GUESTFS_PROGRAM */
- unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
- guestfs_procedure proc; /* GUESTFS_PROC_x */
- guestfs_message_direction direction;
- unsigned serial; /* message serial number */
- guestfs_message_status status;
-};
-"
+ ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
+ [InitBasicFS, 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, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "crc"; "/new"]], "935282863");
+ InitBasicFS, TestLastFail (
+ [["checksum"; "crc"; "/new"]]);
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
+ InitBasicFS, 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.
-(* Generate the guestfs-structs.h file. *)
-and generate_structs_h () =
- generate_header CStyle LGPLv2;
+The type of checksum to compute is given by the C
+parameter which must have one of the following values:
- (* This is a public exported header file containing various
- * structures. The structures are carefully written to have
- * exactly the same in-memory format as the XDR structures that
- * we use on the wire to the daemon. The reason for creating
- * copies of these structures here is just so we don't have to
- * export the whole of guestfs_protocol.h (which includes much
- * unrelated and XDR-dependent stuff that we don't want to be
- * public, or required by clients).
- *
- * To reiterate, we will pass these structures to and from the
- * client with a simple assignment or memcpy, so the format
- * must be identical to what rpcgen / the RFC defines.
- *)
+=over 4
- (* guestfs_int_bool structure. *)
- pr "struct guestfs_int_bool {\n";
- pr " int32_t i;\n";
- pr " int32_t b;\n";
- pr "};\n";
- pr "\n";
+=item C
- (* LVM public structures. *)
- List.iter (
- function
- | typ, cols ->
- pr "struct guestfs_lvm_%s {\n" typ;
- List.iter (
- function
- | name, `String -> pr " char *%s;\n" name
- | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
- | name, `Bytes -> pr " uint64_t %s;\n" name
- | name, `Int -> pr " int64_t %s;\n" name
- | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
- ) cols;
- pr "};\n";
- pr "\n";
- pr "struct guestfs_lvm_%s_list {\n" typ;
- pr " uint32_t len;\n";
- pr " struct guestfs_lvm_%s *val;\n" typ;
- pr "};\n";
- pr "\n"
- ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
+Compute the cyclic redundancy check (CRC) specified by POSIX
+for the C command.
-(* Generate the guestfs-actions.h file. *)
-and generate_actions_h () =
- generate_header CStyle LGPLv2;
- List.iter (
- fun (shortname, style, _, _, _, _, _) ->
- let name = "guestfs_" ^ shortname in
- generate_prototype ~single_line:true ~newline:true ~handle:"handle"
- name style
- ) all_functions
+=item C
-(* Generate the client-side dispatch stubs. *)
-and generate_client_actions () =
- generate_header CStyle LGPLv2;
+Compute the MD5 hash (using the C program).
- (* Client-side stubs for each function. *)
- List.iter (
- fun (shortname, style, _, _, _, _, _) ->
- let name = "guestfs_" ^ shortname in
+=item C
- (* Generate the return value struct. *)
- pr "struct %s_rv {\n" shortname;
- pr " int cb_done; /* flag to indicate callback was called */\n";
- pr " struct guestfs_message_header hdr;\n";
- pr " struct guestfs_message_error err;\n";
- (match fst style with
- | RErr -> ()
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RInt _
- | RBool _ | RString _ | RStringList _
- | RIntBool _
- | RPVList _ | RVGList _ | RLVList _ ->
- pr " struct %s_ret ret;\n" name
- );
- pr "};\n\n";
+Compute the SHA1 hash (using the C program).
- (* Generate the callback function. *)
- pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
- pr "{\n";
- pr " struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
- pr "\n";
- pr " if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n";
- pr " error (g, \"%s: failed to parse reply header\");\n" name;
- pr " return;\n";
- pr " }\n";
- pr " if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n";
- pr " if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n";
- pr " error (g, \"%s: failed to parse reply error\");\n" name;
- pr " return;\n";
- pr " }\n";
- pr " goto done;\n";
- pr " }\n";
+=item C
- (match fst style with
- | RErr -> ()
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RInt _
- | RBool _ | RString _ | RStringList _
- | RIntBool _
- | RPVList _ | RVGList _ | RLVList _ ->
- pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
- pr " error (g, \"%s: failed to parse reply\");\n" name;
- pr " return;\n";
- pr " }\n";
- );
+Compute the SHA224 hash (using the C program).
- pr " done:\n";
- pr " rv->cb_done = 1;\n";
- pr " main_loop.main_loop_quit (g);\n";
- pr "}\n\n";
+=item C
- (* Generate the action stub. *)
- generate_prototype ~extern:false ~semicolon:false ~newline:true
- ~handle:"g" name style;
+Compute the SHA256 hash (using the C program).
- let error_code =
- match fst style with
- | RErr | RInt _ | RBool _ -> "-1"
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RString _ | RStringList _ | RIntBool _
- | RPVList _ | RVGList _ | RLVList _ ->
- "NULL" in
+=item C
- pr "{\n";
+Compute the SHA384 hash (using the C program).
- (match snd style with
- | [] -> ()
- | _ -> pr " struct %s_args args;\n" name
- );
+=item C
- pr " struct %s_rv rv;\n" shortname;
- pr " int serial;\n";
- pr "\n";
- pr " if (g->state != READY) {\n";
- pr " error (g, \"%s called from the wrong state, %%d != READY\",\n"
- name;
- pr " g->state);\n";
- pr " return %s;\n" error_code;
- pr " }\n";
- pr "\n";
- pr " memset (&rv, 0, sizeof rv);\n";
- pr "\n";
+Compute the SHA512 hash (using the C program).
- (match snd style with
- | [] ->
- pr " serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
- (String.uppercase shortname)
- | args ->
- List.iter (
- function
- | String n ->
- pr " args.%s = (char *) %s;\n" n n
- | OptString n ->
- pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
- | StringList n ->
- pr " args.%s.%s_val = (char **) %s;\n" n n n;
- pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
- | Bool n ->
- pr " args.%s = %s;\n" n n
- | Int n ->
- pr " args.%s = %s;\n" n n
- ) args;
- pr " serial = dispatch (g, GUESTFS_PROC_%s,\n"
- (String.uppercase shortname);
- pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
- name;
- );
- pr " if (serial == -1)\n";
- pr " return %s;\n" error_code;
- pr "\n";
+=back
- pr " rv.cb_done = 0;\n";
- pr " g->reply_cb_internal = %s_cb;\n" shortname;
- pr " g->reply_cb_internal_data = &rv;\n";
- pr " main_loop.main_loop_run (g);\n";
- pr " g->reply_cb_internal = NULL;\n";
- pr " g->reply_cb_internal_data = NULL;\n";
- pr " if (!rv.cb_done) {\n";
- pr " error (g, \"%s failed, see earlier error messages\");\n" name;
- pr " return %s;\n" error_code;
- pr " }\n";
- pr "\n";
+The checksum is returned as a printable string.");
- pr " if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
- (String.uppercase shortname);
- pr " return %s;\n" error_code;
- pr "\n";
+ ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
+ [InitBasicFS, 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.
- pr " if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n";
- pr " error (g, \"%%s\", rv.err.error);\n";
- pr " return %s;\n" error_code;
- pr " }\n";
- pr "\n";
+To upload a compressed tarball, use C.");
- (match fst style with
- | RErr -> pr " return 0;\n"
- | RInt 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 ->
- 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;
- pr " sizeof (char *) * (rv.ret.%s.%s_len + 1));\n"
- n n;
- pr " rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
- pr " return 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
- );
+ ("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.
- pr "}\n\n"
- ) daemon_functions
+To download a compressed tarball, use C.");
-(* Generate daemon/actions.h. *)
-and generate_daemon_actions_h () =
- generate_header CStyle GPLv2;
+ ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
+ [InitBasicFS, 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.
- pr "#include \"../src/guestfs_protocol.h\"\n";
- pr "\n";
+To upload an uncompressed tarball, use C.");
- List.iter (
- fun (name, style, _, _, _, _, _) ->
- generate_prototype
- ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
- name style;
- ) daemon_functions
+ ("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, TestLastFail (
+ [["umount"; "/"];
+ ["mount_ro"; "/dev/sda1"; "/"];
+ ["touch"; "/new"]]);
+ InitBasicFS, 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.");
-(* Generate the server-side stubs. *)
-and generate_daemon_actions () =
- generate_header CStyle GPLv2;
+ ("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.");
- pr "#define _GNU_SOURCE // for strchrnul\n";
- pr "\n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "\n";
- pr "#include \"daemon.h\"\n";
- pr "#include \"../src/guestfs_protocol.h\"\n";
- pr "#include \"actions.h\"\n";
- pr "\n";
+ ("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.");
- List.iter (
- fun (name, style, _, _, _, _, _) ->
- (* Generate server-side stubs. *)
- pr "static void %s_stub (XDR *xdr_in)\n" name;
- pr "{\n";
- let error_code =
- match fst style with
- | RErr | RInt _ -> pr " int 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"
- | 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"
- | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL" in
+ ("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.
- (match snd style with
- | [] -> ()
- | args ->
- pr " struct guestfs_%s_args args;\n" name;
- List.iter (
- function
- | String n
- | OptString n -> pr " const char *%s;\n" n
- | StringList n -> pr " char **%s;\n" n
- | Bool n -> pr " int %s;\n" n
- | Int n -> pr " int %s;\n" n
- ) args
- );
- pr "\n";
+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.");
- (match snd style with
- | [] -> ()
- | args ->
- pr " memset (&args, 0, sizeof args);\n";
- pr "\n";
- pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
- pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
- pr " return;\n";
- pr " }\n";
- List.iter (
- function
- | String n -> pr " %s = args.%s;\n" n n
- | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
- | StringList n ->
- pr " args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
- pr " args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
- pr " %s = args.%s.%s_val;\n" n n n
- | Bool n -> pr " %s = args.%s;\n" n n
- | Int n -> pr " %s = args.%s;\n" n n
- ) args;
- pr "\n"
- );
+ ("lvremove", (RErr, [String "device"]), 77, [],
+ [InitEmpty, 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, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG"];
+ ["lvs"]], []);
+ InitEmpty, 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.
- pr " r = do_%s " name;
- generate_call_args style;
- pr ";\n";
+You can also remove all LVs in a volume group by specifying
+the VG name, C.");
- pr " if (r == %s)\n" error_code;
- pr " /* do_%s has already called reply_with_error */\n" name;
- pr " goto done;\n";
- pr "\n";
+ ("vgremove", (RErr, [String "vgname"]), 78, [],
+ [InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["lvs"]], []);
+ InitEmpty, 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).
- (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 ->
- 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
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RString 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 " free (r);\n"
- | RStringList 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;
- pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
- pr " free_strings (r);\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 ->
- 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 " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
- | RVGList 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 " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
- | RLVList 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 " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
- );
+This also forcibly removes all logical volumes in the volume
+group (if any).");
- (* Free the args. *)
- (match snd style with
- | [] ->
- pr "done: ;\n";
- | _ ->
- pr "done:\n";
- pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
- name
- );
+ ("pvremove", (RErr, [String "device"]), 79, [],
+ [InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda"];
+ ["lvs"]], []);
+ InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda"];
+ ["vgs"]], []);
+ InitEmpty, 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, 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