+Note that this function cannot correctly handle binary files
+(specifically, files containing C<\\0> character which is treated
+as end of line). For those you need to use the C<guestfs_read_file>
+function which has a more complex interface.");
+
+ ("aug_init", (RErr, [Pathname "root"; Int "flags"], []), 16, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "create a new Augeas handle",
+ "\
+Create a new Augeas handle for editing configuration files.
+If there was any previous Augeas handle associated with this
+guestfs session, then it is closed.
+
+You must call this before using any other C<guestfs_aug_*>
+commands.
+
+C<root> is the filesystem root. C<root> must not be NULL,
+use C</> instead.
+
+The flags are the same as the flags defined in
+E<lt>augeas.hE<gt>, the logical I<or> of the following
+integers:
+
+=over 4
+
+=item C<AUG_SAVE_BACKUP> = 1
+
+Keep the original file with a C<.augsave> extension.
+
+=item C<AUG_SAVE_NEWFILE> = 2
+
+Save changes into a file with extension C<.augnew>, and
+do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
+
+=item C<AUG_TYPE_CHECK> = 4
+
+Typecheck lenses.
+
+This option is only useful when debugging Augeas lenses. Use
+of this option may require additional memory for the libguestfs
+appliance. You may need to set the C<LIBGUESTFS_MEMSIZE>
+environment variable or call C<guestfs_set_memsize>.
+
+=item C<AUG_NO_STDINC> = 8
+
+Do not use standard load path for modules.
+
+=item C<AUG_SAVE_NOOP> = 16
+
+Make save a no-op, just record what would have been changed.
+
+=item C<AUG_NO_LOAD> = 32
+
+Do not load the tree in C<guestfs_aug_init>.
+
+=back
+
+To close the handle, you can call C<guestfs_aug_close>.
+
+To find out more about Augeas, see L<http://augeas.net/>.");
+
+ ("aug_close", (RErr, [], []), 26, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "close the current Augeas handle",
+ "\
+Close the current Augeas handle and free up any resources
+used by it. After calling this, you have to call
+C<guestfs_aug_init> again before you can use any other
+Augeas functions.");
+
+ ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"], []), 17, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "define an Augeas variable",
+ "\
+Defines an Augeas variable C<name> whose value is the result
+of evaluating C<expr>. If C<expr> is NULL, then C<name> is
+undefined.
+
+On success this returns the number of nodes in C<expr>, or
+C<0> if C<expr> evaluates to something which is not a nodeset.");
+
+ ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"], []), 18, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "define an Augeas node",
+ "\
+Defines a variable C<name> whose value is the result of
+evaluating C<expr>.
+
+If C<expr> evaluates to an empty nodeset, a node is created,
+equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
+C<name> will be the nodeset containing that single node.
+
+On success this returns a pair containing the
+number of nodes in the nodeset, and a boolean flag
+if a node was created.");
+
+ ("aug_get", (RString "val", [String "augpath"], []), 19, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "look up the value of an Augeas path",
+ "\
+Look up the value associated with C<path>. If C<path>
+matches exactly one node, the C<value> is returned.");
+
+ ("aug_set", (RErr, [String "augpath"; String "val"], []), 20, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "set Augeas path to value",
+ "\
+Set the value associated with C<path> to C<val>.
+
+In the Augeas API, it is possible to clear a node by setting
+the value to NULL. Due to an oversight in the libguestfs API
+you cannot do that with this call. Instead you must use the
+C<guestfs_aug_clear> call.");
+
+ ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"], []), 21, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "insert a sibling Augeas node",
+ "\
+Create a new sibling C<label> for C<path>, inserting it into
+the tree before or after C<path> (depending on the boolean
+flag C<before>).
+
+C<path> must match exactly one existing node in the tree, and
+C<label> must be a label, ie. not contain C</>, C<*> or end
+with a bracketed index C<[N]>.");
+
+ ("aug_rm", (RInt "nrnodes", [String "augpath"], []), 22, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "remove an Augeas path",
+ "\
+Remove C<path> and all of its children.
+
+On success this returns the number of entries which were removed.");
+
+ ("aug_mv", (RErr, [String "src"; String "dest"], []), 23, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "move Augeas node",
+ "\
+Move the node C<src> to C<dest>. C<src> must match exactly
+one node. C<dest> is overwritten if it exists.");
+
+ ("aug_match", (RStringList "matches", [String "augpath"], []), 24, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "return Augeas nodes which match augpath",
+ "\
+Returns a list of paths which match the path expression C<path>.
+The returned paths are sufficiently qualified so that they match
+exactly one node in the current tree.");
+
+ ("aug_save", (RErr, [], []), 25, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "write all pending Augeas changes to disk",
+ "\
+This writes all pending changes to disk.
+
+The flags which were passed to C<guestfs_aug_init> affect exactly
+how files are saved.");
+
+ ("aug_load", (RErr, [], []), 27, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "load files into the tree",
+ "\
+Load files into the tree.
+
+See C<aug_load> in the Augeas documentation for the full gory
+details.");
+
+ ("aug_ls", (RStringList "matches", [String "augpath"], []), 28, [Optional "augeas"],
+ [], (* XXX Augeas code needs tests. *)
+ "list Augeas nodes under augpath",
+ "\
+This is just a shortcut for listing C<guestfs_aug_match>
+C<path/*> and sorting the resulting nodes into alphabetical order.");
+
+ ("rm", (RErr, [Pathname "path"], []), 29, [],
+ [InitScratchFS, Always, TestRun
+ [["mkdir"; "/rm"];
+ ["touch"; "/rm/new"];
+ ["rm"; "/rm/new"]];
+ InitScratchFS, Always, TestLastFail
+ [["rm"; "/nosuchfile"]];
+ InitScratchFS, Always, TestLastFail
+ [["mkdir"; "/rm2"];
+ ["rm"; "/rm2"]]],
+ "remove a file",
+ "\
+Remove the single file C<path>.");
+
+ ("rmdir", (RErr, [Pathname "path"], []), 30, [],
+ [InitScratchFS, Always, TestRun
+ [["mkdir"; "/rmdir"];
+ ["rmdir"; "/rmdir"]];
+ InitScratchFS, Always, TestLastFail
+ [["rmdir"; "/rmdir2"]];
+ InitScratchFS, Always, TestLastFail
+ [["mkdir"; "/rmdir3"];
+ ["touch"; "/rmdir3/new"];
+ ["rmdir"; "/rmdir3/new"]]],
+ "remove a directory",
+ "\
+Remove the single directory C<path>.");
+
+ ("rm_rf", (RErr, [Pathname "path"], []), 31, [],
+ [InitScratchFS, Always, TestOutputFalse
+ [["mkdir"; "/rm_rf"];
+ ["mkdir"; "/rm_rf/foo"];
+ ["touch"; "/rm_rf/foo/bar"];
+ ["rm_rf"; "/rm_rf"];
+ ["exists"; "/rm_rf"]]],
+ "remove a file or directory recursively",
+ "\
+Remove the file or directory C<path>, recursively removing the
+contents if its a directory. This is like the C<rm -rf> shell
+command.");
+
+ ("mkdir", (RErr, [Pathname "path"], []), 32, [],
+ [InitScratchFS, Always, TestOutputTrue
+ [["mkdir"; "/mkdir"];
+ ["is_dir"; "/mkdir"]];
+ InitScratchFS, Always, TestLastFail
+ [["mkdir"; "/mkdir2/foo/bar"]]],
+ "create a directory",
+ "\
+Create a directory named C<path>.");
+
+ ("mkdir_p", (RErr, [Pathname "path"], []), 33, [],
+ [InitScratchFS, Always, TestOutputTrue
+ [["mkdir_p"; "/mkdir_p/foo/bar"];
+ ["is_dir"; "/mkdir_p/foo/bar"]];
+ InitScratchFS, Always, TestOutputTrue
+ [["mkdir_p"; "/mkdir_p2/foo/bar"];
+ ["is_dir"; "/mkdir_p2/foo"]];
+ InitScratchFS, Always, TestOutputTrue
+ [["mkdir_p"; "/mkdir_p3/foo/bar"];
+ ["is_dir"; "/mkdir_p3"]];
+ (* Regression tests for RHBZ#503133: *)
+ InitScratchFS, Always, TestRun
+ [["mkdir"; "/mkdir_p4"];
+ ["mkdir_p"; "/mkdir_p4"]];
+ InitScratchFS, Always, TestLastFail
+ [["touch"; "/mkdir_p5"];
+ ["mkdir_p"; "/mkdir_p5"]]],
+ "create a directory and parents",
+ "\
+Create a directory named C<path>, creating any parent directories
+as necessary. This is like the C<mkdir -p> shell command.");
+
+ ("chmod", (RErr, [Int "mode"; Pathname "path"], []), 34, [],
+ [], (* XXX Need stat command to test *)
+ "change file mode",
+ "\
+Change the mode (permissions) of C<path> to C<mode>. Only
+numeric modes are supported.
+
+I<Note>: When using this command from guestfish, C<mode>
+by default would be decimal, unless you prefix it with
+C<0> to get octal, ie. use C<0700> not C<700>.
+
+The mode actually set is affected by the umask.");
+
+ ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"], []), 35, [],
+ [], (* XXX Need stat command to test *)
+ "change file owner and group",
+ "\
+Change the file owner to C<owner> and group to C<group>.
+
+Only numeric uid and gid are supported. If you want to use
+names, you will need to locate and parse the password file
+yourself (Augeas support makes this relatively easy).");
+
+ ("exists", (RBool "existsflag", [Pathname "path"], []), 36, [],
+ [InitISOFS, Always, TestOutputTrue (
+ [["exists"; "/empty"]]);
+ InitISOFS, Always, TestOutputTrue (
+ [["exists"; "/directory"]])],
+ "test if file or directory exists",
+ "\
+This returns C<true> if and only if there is a file, directory
+(or anything) with the given C<path> name.
+
+See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
+
+ ("is_file", (RBool "fileflag", [Pathname "path"], []), 37, [],
+ [InitISOFS, Always, TestOutputTrue (
+ [["is_file"; "/known-1"]]);
+ InitISOFS, Always, TestOutputFalse (
+ [["is_file"; "/directory"]])],
+ "test if a regular file",
+ "\
+This returns C<true> if and only if there is a regular file
+with the given C<path> name. Note that it returns false for
+other objects like directories.
+
+See also C<guestfs_stat>.");
+
+ ("is_dir", (RBool "dirflag", [Pathname "path"], []), 38, [],
+ [InitISOFS, Always, TestOutputFalse (
+ [["is_dir"; "/known-3"]]);
+ InitISOFS, Always, TestOutputTrue (
+ [["is_dir"; "/directory"]])],
+ "test if a directory",
+ "\
+This returns C<true> if and only if there is a directory
+with the given C<path> name. Note that it returns false for
+other objects like files.
+
+See also C<guestfs_stat>.");
+
+ ("pvcreate", (RErr, [Device "device"], []), 39, [Optional "lvm2"],
+ [InitEmpty, Always, TestOutputListOfDevices (
+ [["part_init"; "/dev/sda"; "mbr"];
+ ["part_add"; "/dev/sda"; "p"; "64"; "204799"];
+ ["part_add"; "/dev/sda"; "p"; "204800"; "409599"];
+ ["part_add"; "/dev/sda"; "p"; "409600"; "-64"];
+ ["pvcreate"; "/dev/sda1"];
+ ["pvcreate"; "/dev/sda2"];
+ ["pvcreate"; "/dev/sda3"];
+ ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
+ "create an LVM physical volume",
+ "\
+This creates an LVM physical volume on the named C<device>,
+where C<device> should usually be a partition name such
+as C</dev/sda1>.");
+
+ ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"], []), 40, [Optional "lvm2"],
+ [InitEmpty, Always, TestOutputList (
+ [["part_init"; "/dev/sda"; "mbr"];
+ ["part_add"; "/dev/sda"; "p"; "64"; "204799"];
+ ["part_add"; "/dev/sda"; "p"; "204800"; "409599"];
+ ["part_add"; "/dev/sda"; "p"; "409600"; "-64"];
+ ["pvcreate"; "/dev/sda1"];
+ ["pvcreate"; "/dev/sda2"];
+ ["pvcreate"; "/dev/sda3"];
+ ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
+ ["vgcreate"; "VG2"; "/dev/sda3"];
+ ["vgs"]], ["VG1"; "VG2"])],
+ "create an LVM volume group",
+ "\
+This creates an LVM volume group called C<volgroup>
+from the non-empty list of physical volumes C<physvols>.");
+
+ ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"], []), 41, [Optional "lvm2"],
+ [InitEmpty, Always, TestOutputList (
+ [["part_init"; "/dev/sda"; "mbr"];
+ ["part_add"; "/dev/sda"; "p"; "64"; "204799"];
+ ["part_add"; "/dev/sda"; "p"; "204800"; "409599"];
+ ["part_add"; "/dev/sda"; "p"; "409600"; "-64"];
+ ["pvcreate"; "/dev/sda1"];
+ ["pvcreate"; "/dev/sda2"];
+ ["pvcreate"; "/dev/sda3"];
+ ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
+ ["vgcreate"; "VG2"; "/dev/sda3"];
+ ["lvcreate"; "LV1"; "VG1"; "50"];
+ ["lvcreate"; "LV2"; "VG1"; "50"];
+ ["lvcreate"; "LV3"; "VG2"; "50"];
+ ["lvcreate"; "LV4"; "VG2"; "50"];
+ ["lvcreate"; "LV5"; "VG2"; "50"];
+ ["lvs"]],
+ ["/dev/VG1/LV1"; "/dev/VG1/LV2";
+ "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
+ "create an LVM logical volume",
+ "\
+This creates an LVM logical volume called C<logvol>
+on the volume group C<volgroup>, with C<size> megabytes.");
+
+ ("mkfs", (RErr, [String "fstype"; Device "device"], []), 42, [],
+ [InitEmpty, Always, TestOutput (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount_options"; ""; "/dev/sda1"; "/"];
+ ["write"; "/new"; "new file contents"];
+ ["cat"; "/new"]], "new file contents")],
+ "make a filesystem",
+ "\
+This creates a filesystem on C<device> (usually a partition
+or LVM logical volume). The filesystem type is C<fstype>, for
+example C<ext3>.");
+
+ ("sfdisk", (RErr, [Device "device";
+ Int "cyls"; Int "heads"; Int "sectors";
+ StringList "lines"], []), 43, [DeprecatedBy "part_add"],
+ [],
+ "create partitions on a block device",
+ "\
+This is a direct interface to the L<sfdisk(8)> program for creating
+partitions on block devices.
+
+C<device> should be a block device, for example C</dev/sda>.
+
+C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
+and sectors on the device, which are passed directly to sfdisk as
+the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
+of these, then the corresponding parameter is omitted. Usually for
+'large' disks, you can just pass C<0> for these, but for small
+(floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
+out the right geometry and you will need to tell it.
+
+C<lines> is a list of lines that we feed to C<sfdisk>. For more
+information refer to the L<sfdisk(8)> manpage.
+
+To create a single partition occupying the whole disk, you would
+pass C<lines> as a single element list, when the single element being
+the string C<,> (comma).
+
+See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
+C<guestfs_part_init>");
+
+ ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"], []), 44, [ProtocolLimitWarning; DeprecatedBy "write"],
+ (* Regression test for RHBZ#597135. *)
+ [InitScratchFS, Always, TestLastFail
+ [["write_file"; "/write_file"; "abc"; "10000"]]],
+ "create a file",
+ "\
+This call creates a file called C<path>. The contents of the
+file is the string C<content> (which can contain any 8 bit data),
+with length C<size>.
+
+As a special case, if C<size> is C<0>
+then the length is calculated using C<strlen> (so in this case
+the content cannot contain embedded ASCII NULs).
+
+I<NB.> Owing to a bug, writing content containing ASCII NUL
+characters does I<not> work, even if the length is specified.");
+
+ ("umount", (RErr, [String "pathordevice"], []), 45, [FishAlias "unmount"],
+ [InitEmpty, Always, TestOutputListOfDevices (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount_options"; ""; "/dev/sda1"; "/"];
+ ["mounts"]], ["/dev/sda1"]);
+ InitEmpty, Always, TestOutputList (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount_options"; ""; "/dev/sda1"; "/"];
+ ["umount"; "/"];
+ ["mounts"]], [])],
+ "unmount a filesystem",
+ "\
+This unmounts the given filesystem. The filesystem may be
+specified either by its mountpoint (path) or the device which
+contains the filesystem.");
+
+ ("mounts", (RStringList "devices", [], []), 46, [],
+ [InitScratchFS, Always, TestOutputListOfDevices (
+ [["mounts"]], ["/dev/sdb1"])],
+ "show mounted filesystems",
+ "\
+This returns the list of currently mounted filesystems. It returns
+the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
+
+Some internal mounts are not shown.
+
+See also: C<guestfs_mountpoints>");
+
+ ("umount_all", (RErr, [], []), 47, [FishAlias "unmount-all"],
+ [InitScratchFS, Always, TestOutputList (
+ [["umount_all"];
+ ["mounts"]], []);
+ (* check that umount_all can unmount nested mounts correctly: *)
+ InitEmpty, Always, TestOutputList (
+ [["part_init"; "/dev/sda"; "mbr"];
+ ["part_add"; "/dev/sda"; "p"; "64"; "204799"];
+ ["part_add"; "/dev/sda"; "p"; "204800"; "409599"];
+ ["part_add"; "/dev/sda"; "p"; "409600"; "-64"];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mkfs"; "ext2"; "/dev/sda2"];
+ ["mkfs"; "ext2"; "/dev/sda3"];
+ ["mount_options"; ""; "/dev/sda1"; "/"];
+ ["mkdir"; "/mp1"];
+ ["mount_options"; ""; "/dev/sda2"; "/mp1"];
+ ["mkdir"; "/mp1/mp2"];
+ ["mount_options"; ""; "/dev/sda3"; "/mp1/mp2"];
+ ["mkdir"; "/mp1/mp2/mp3"];
+ ["umount_all"];
+ ["mounts"]], [])],
+ "unmount all filesystems",
+ "\
+This unmounts all mounted filesystems.
+
+Some internal mounts are not unmounted by this call.");
+
+ ("lvm_remove_all", (RErr, [], []), 48, [Optional "lvm2"],
+ [],
+ "remove all LVM LVs, VGs and PVs",
+ "\
+This command removes all LVM logical volumes, volume groups
+and physical volumes.");
+
+ ("file", (RString "description", [Dev_or_Path "path"], []), 49, [],
+ [InitISOFS, Always, TestOutput (
+ [["file"; "/empty"]], "empty");
+ InitISOFS, Always, TestOutput (
+ [["file"; "/known-1"]], "ASCII text");
+ InitISOFS, Always, TestLastFail (
+ [["file"; "/notexists"]]);
+ InitISOFS, Always, TestOutput (
+ [["file"; "/abssymlink"]], "symbolic link");
+ InitISOFS, Always, TestOutput (
+ [["file"; "/directory"]], "directory")],
+ "determine file type",
+ "\
+This call uses the standard L<file(1)> command to determine
+the type or contents of the file.
+
+This call will also transparently look inside various types
+of compressed file.
+
+The exact command which runs is C<file -zb path>. Note in
+particular that the filename is not prepended to the output
+(the I<-b> option).
+
+The output depends on the output of the underlying L<file(1)>
+command and it can change in future in ways beyond our control.
+In other words, the output is not guaranteed by the ABI.
+
+See also: L<file(1)>, C<guestfs_vfs_type>, C<guestfs_lstat>,
+C<guestfs_is_file>, C<guestfs_is_blockdev> (etc), C<guestfs_is_zero>.");
+
+ ("command", (RString "output", [StringList "arguments"], []), 50, [ProtocolLimitWarning],
+ [InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command"];
+ ["upload"; "test-command"; "/command/test-command"];
+ ["chmod"; "0o755"; "/command/test-command"];
+ ["command"; "/command/test-command 1"]], "Result1");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command2"];
+ ["upload"; "test-command"; "/command2/test-command"];
+ ["chmod"; "0o755"; "/command2/test-command"];
+ ["command"; "/command2/test-command 2"]], "Result2\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command3"];
+ ["upload"; "test-command"; "/command3/test-command"];
+ ["chmod"; "0o755"; "/command3/test-command"];
+ ["command"; "/command3/test-command 3"]], "\nResult3");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command4"];
+ ["upload"; "test-command"; "/command4/test-command"];
+ ["chmod"; "0o755"; "/command4/test-command"];
+ ["command"; "/command4/test-command 4"]], "\nResult4\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command5"];
+ ["upload"; "test-command"; "/command5/test-command"];
+ ["chmod"; "0o755"; "/command5/test-command"];
+ ["command"; "/command5/test-command 5"]], "\nResult5\n\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command6"];
+ ["upload"; "test-command"; "/command6/test-command"];
+ ["chmod"; "0o755"; "/command6/test-command"];
+ ["command"; "/command6/test-command 6"]], "\n\nResult6\n\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command7"];
+ ["upload"; "test-command"; "/command7/test-command"];
+ ["chmod"; "0o755"; "/command7/test-command"];
+ ["command"; "/command7/test-command 7"]], "");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command8"];
+ ["upload"; "test-command"; "/command8/test-command"];
+ ["chmod"; "0o755"; "/command8/test-command"];
+ ["command"; "/command8/test-command 8"]], "\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command9"];
+ ["upload"; "test-command"; "/command9/test-command"];
+ ["chmod"; "0o755"; "/command9/test-command"];
+ ["command"; "/command9/test-command 9"]], "\n\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command10"];
+ ["upload"; "test-command"; "/command10/test-command"];
+ ["chmod"; "0o755"; "/command10/test-command"];
+ ["command"; "/command10/test-command 10"]], "Result10-1\nResult10-2\n");
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/command11"];
+ ["upload"; "test-command"; "/command11/test-command"];
+ ["chmod"; "0o755"; "/command11/test-command"];
+ ["command"; "/command11/test-command 11"]], "Result11-1\nResult11-2");
+ InitScratchFS, Always, TestLastFail (
+ [["mkdir"; "/command12"];
+ ["upload"; "test-command"; "/command12/test-command"];
+ ["chmod"; "0o755"; "/command12/test-command"];
+ ["command"; "/command12/test-command"]])],
+ "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). Note that
+the command runs directly, and is I<not> invoked via
+the shell (see C<guestfs_sh>).
+
+The return value is anything printed to I<stdout> 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<stderr> from the command.
+
+The C<$PATH> environment variable will contain at least
+C</usr/bin> and C</bin>. 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, [ProtocolLimitWarning],
+ [InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines"];
+ ["upload"; "test-command"; "/command_lines/test-command"];
+ ["chmod"; "0o755"; "/command_lines/test-command"];
+ ["command_lines"; "/command_lines/test-command 1"]], ["Result1"]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines2"];
+ ["upload"; "test-command"; "/command_lines2/test-command"];
+ ["chmod"; "0o755"; "/command_lines2/test-command"];
+ ["command_lines"; "/command_lines2/test-command 2"]], ["Result2"]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines3"];
+ ["upload"; "test-command"; "/command_lines3/test-command"];
+ ["chmod"; "0o755"; "/command_lines3/test-command"];
+ ["command_lines"; "/command_lines3/test-command 3"]], ["";"Result3"]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines4"];
+ ["upload"; "test-command"; "/command_lines4/test-command"];
+ ["chmod"; "0o755"; "/command_lines4/test-command"];
+ ["command_lines"; "/command_lines4/test-command 4"]], ["";"Result4"]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines5"];
+ ["upload"; "test-command"; "/command_lines5/test-command"];
+ ["chmod"; "0o755"; "/command_lines5/test-command"];
+ ["command_lines"; "/command_lines5/test-command 5"]], ["";"Result5";""]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines6"];
+ ["upload"; "test-command"; "/command_lines6/test-command"];
+ ["chmod"; "0o755"; "/command_lines6/test-command"];
+ ["command_lines"; "/command_lines6/test-command 6"]], ["";"";"Result6";""]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines7"];
+ ["upload"; "test-command"; "/command_lines7/test-command"];
+ ["chmod"; "0o755"; "/command_lines7/test-command"];
+ ["command_lines"; "/command_lines7/test-command 7"]], []);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines8"];
+ ["upload"; "test-command"; "/command_lines8/test-command"];
+ ["chmod"; "0o755"; "/command_lines8/test-command"];
+ ["command_lines"; "/command_lines8/test-command 8"]], [""]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines9"];
+ ["upload"; "test-command"; "/command_lines9/test-command"];
+ ["chmod"; "0o755"; "/command_lines9/test-command"];
+ ["command_lines"; "/command_lines9/test-command 9"]], ["";""]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines10"];
+ ["upload"; "test-command"; "/command_lines10/test-command"];
+ ["chmod"; "0o755"; "/command_lines10/test-command"];
+ ["command_lines"; "/command_lines10/test-command 10"]], ["Result10-1";"Result10-2"]);
+ InitScratchFS, Always, TestOutputList (
+ [["mkdir"; "/command_lines11"];
+ ["upload"; "test-command"; "/command_lines11/test-command"];
+ ["chmod"; "0o755"; "/command_lines11/test-command"];
+ ["command_lines"; "/command_lines11/test-command 11"]], ["Result11-1";"Result11-2"])],
+ "run a command, returning lines",
+ "\
+This is the same as C<guestfs_command>, but splits the
+result into a list of lines.
+
+See also: C<guestfs_sh_lines>");
+
+ ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"], []), 52, [],
+ [InitISOFS, Always, TestOutputStruct (
+ [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
+ "get file information",
+ "\
+Returns file information for the given C<path>.
+
+This is the same as the C<stat(2)> system call.");
+
+ ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"], []), 53, [],
+ [InitISOFS, Always, TestOutputStruct (
+ [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
+ "get file information for a symbolic link",
+ "\
+Returns file information for the given C<path>.
+
+This is the same as C<guestfs_stat> except that if C<path>
+is a symbolic link, then the link is stat-ed, not the file it
+refers to.
+
+This is the same as the C<lstat(2)> system call.");
+
+ ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"], []), 54, [],
+ [InitISOFS, Always, TestOutputStruct (
+ [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
+ "get file system statistics",
+ "\
+Returns file system statistics for any mounted file system.
+C<path> 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).
+
+This is the same as the C<statvfs(2)> system call.");
+
+ ("tune2fs_l", (RHashtable "superblock", [Device "device"], []), 55, [],
+ [InitScratchFS, Always, TestOutputHashtable (
+ [["tune2fs_l"; "/dev/sdb1"]],
+ ["Filesystem magic number", "0xEF53";
+ "Filesystem OS type", "Linux"])],
+ "get ext2/ext3/ext4 superblock details",
+ "\
+This returns the contents of the ext2, ext3 or ext4 filesystem
+superblock on C<device>.
+
+It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
+manpage for more details. The list of fields returned isn't
+clearly defined, and depends on both the version of C<tune2fs>
+that libguestfs was built against, and the filesystem itself.");
+
+ ("blockdev_setro", (RErr, [Device "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<device> to read-only.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_setrw", (RErr, [Device "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<device> to read-write.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getro", (RBool "ro", [Device "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<blockdev(8)> command.");
+
+ ("blockdev_getss", (RInt "sectorsize", [Device "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<guestfs_blockdev_getsz>
+for that).
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getbsz", (RInt "blocksize", [Device "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<size in blocks> and
+I<filesystem block size>).
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"], []), 61, [],
+ [], (* XXX test *)
+ "set blocksize of block device",
+ "\
+This sets the block size of a device.
+
+(Note this is different from both I<size in blocks> and
+I<filesystem block size>).
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "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<guestfs_blockdev_getss> for the real sector size of
+the device, and C<guestfs_blockdev_getsize64> for the more
+useful I<size in bytes>.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "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<guestfs_blockdev_getsz>.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_flushbufs", (RErr, [Device "device"], []), 64, [],
+ [InitEmpty, Always, TestRun
+ [["blockdev_flushbufs"; "/dev/sda"]]],
+ "flush device buffers",
+ "\
+This tells the kernel to flush internal buffers associated
+with C<device>.
+
+This uses the L<blockdev(8)> command.");
+
+ ("blockdev_rereadpt", (RErr, [Device "device"], []), 65, [],
+ [InitEmpty, Always, TestRun
+ [["blockdev_rereadpt"; "/dev/sda"]]],
+ "reread partition table",
+ "\
+Reread the partition table on C<device>.
+
+This uses the L<blockdev(8)> command.");
+
+ ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"], []), 66, [Progress],
+ [InitScratchFS, Always, TestOutput (
+ (* Pick a file from cwd which isn't likely to change. *)
+ [["mkdir"; "/upload"];
+ ["upload"; "../COPYING.LIB"; "/upload/COPYING.LIB"];
+ ["checksum"; "md5"; "/upload/COPYING.LIB"]],
+ Digest.to_hex (Digest.file "COPYING.LIB"))],
+ "upload a file from the local machine",
+ "\
+Upload local file C<filename> to C<remotefilename> on the
+filesystem.
+
+C<filename> can also be a named pipe.
+
+See also C<guestfs_download>.");
+
+ ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"], []), 67, [Progress],
+ [InitScratchFS, Always, TestOutput (
+ (* Pick a file from cwd which isn't likely to change. *)
+ [["mkdir"; "/download"];
+ ["upload"; "../COPYING.LIB"; "/download/COPYING.LIB"];
+ ["download"; "/download/COPYING.LIB"; "testdownload.tmp"];
+ ["upload"; "testdownload.tmp"; "/download/upload"];
+ ["checksum"; "md5"; "/download/upload"]],
+ Digest.to_hex (Digest.file "COPYING.LIB"))],
+ "download a file to the local machine",
+ "\
+Download file C<remotefilename> and save it as C<filename>
+on the local machine.
+
+C<filename> can also be a named pipe.
+
+See also C<guestfs_upload>, C<guestfs_cat>.");
+
+ ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"], []), 68, [],
+ [InitISOFS, Always, TestOutput (
+ [["checksum"; "crc"; "/known-3"]], "2891671662");
+ InitISOFS, Always, TestLastFail (
+ [["checksum"; "crc"; "/notexists"]]);
+ InitISOFS, Always, TestOutput (
+ [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
+ InitISOFS, Always, TestOutput (
+ [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
+ InitISOFS, Always, TestOutput (
+ [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
+ InitISOFS, Always, TestOutput (
+ [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
+ InitISOFS, Always, TestOutput (
+ [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
+ InitISOFS, Always, TestOutput (
+ [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6");
+ (* Test for RHBZ#579608, absolute symbolic links. *)
+ InitISOFS, Always, TestOutput (
+ [["checksum"; "sha512"; "/abssymlink"]], "5f57d0639bc95081c53afc63a449403883818edc64da48930ad6b1a4fb49be90404686877743fbcd7c99811f3def7df7bc22635c885c6a8cf79c806b43451c1a")],
+ "compute MD5, SHAx or CRC checksum of file",
+ "\
+This call computes the MD5, SHAx or CRC checksum of the
+file named C<path>.
+
+The type of checksum to compute is given by the C<csumtype>
+parameter which must have one of the following values:
+
+=over 4
+
+=item C<crc>
+
+Compute the cyclic redundancy check (CRC) specified by POSIX
+for the C<cksum> command.
+
+=item C<md5>
+
+Compute the MD5 hash (using the C<md5sum> program).
+
+=item C<sha1>
+
+Compute the SHA1 hash (using the C<sha1sum> program).
+
+=item C<sha224>
+
+Compute the SHA224 hash (using the C<sha224sum> program).
+
+=item C<sha256>
+
+Compute the SHA256 hash (using the C<sha256sum> program).
+
+=item C<sha384>
+
+Compute the SHA384 hash (using the C<sha384sum> program).
+
+=item C<sha512>
+
+Compute the SHA512 hash (using the C<sha512sum> program).
+
+=back
+
+The checksum is returned as a printable string.
+
+To get the checksum for a device, use C<guestfs_checksum_device>.
+
+To get the checksums for many files, use C<guestfs_checksums_out>.");
+
+ ("tar_in", (RErr, [FileIn "tarfile"; Pathname "directory"], []), 69, [],
+ [InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/tar_in"];
+ ["tar_in"; "../images/helloworld.tar"; "/tar_in"];
+ ["cat"; "/tar_in/hello"]], "hello\n")],
+ "unpack tarfile to directory",
+ "\
+This command uploads and unpacks local file C<tarfile> (an
+I<uncompressed> tar file) into C<directory>.
+
+To upload a compressed tarball, use C<guestfs_tgz_in>
+or C<guestfs_txz_in>.");
+
+ ("tar_out", (RErr, [String "directory"; FileOut "tarfile"], []), 70, [],
+ [],
+ "pack directory into tarfile",
+ "\
+This command packs the contents of C<directory> and downloads
+it to local file C<tarfile>.
+
+To download a compressed tarball, use C<guestfs_tgz_out>
+or C<guestfs_txz_out>.");
+
+ ("tgz_in", (RErr, [FileIn "tarball"; Pathname "directory"], []), 71, [],
+ [InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/tgz_in"];
+ ["tgz_in"; "../images/helloworld.tar.gz"; "/tgz_in"];
+ ["cat"; "/tgz_in/hello"]], "hello\n")],
+ "unpack compressed tarball to directory",
+ "\
+This command uploads and unpacks local file C<tarball> (a
+I<gzip compressed> tar file) into C<directory>.
+
+To upload an uncompressed tarball, use C<guestfs_tar_in>.");
+
+ ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"], []), 72, [],
+ [],
+ "pack directory into compressed tarball",
+ "\
+This command packs the contents of C<directory> and downloads
+it to local file C<tarball>.
+
+To download an uncompressed tarball, use C<guestfs_tar_out>.");
+
+ ("mount_ro", (RErr, [Device "device"; String "mountpoint"], []), 73, [],
+ [InitBasicFS, Always, TestLastFail (
+ [["umount"; "/"];
+ ["mount_ro"; "/dev/sda1"; "/"];
+ ["touch"; "/new"]]);
+ InitBasicFS, Always, TestOutput (
+ [["write"; "/new"; "data"];
+ ["umount"; "/"];
+ ["mount_ro"; "/dev/sda1"; "/"];
+ ["cat"; "/new"]], "data")],
+ "mount a guest disk, read-only",
+ "\
+This is the same as the C<guestfs_mount> command, but it
+mounts the filesystem with the read-only (I<-o ro>) flag.");
+
+ ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"], []), 74, [],
+ [],
+ "mount a guest disk with mount options",
+ "\
+This is the same as the C<guestfs_mount> command, but it
+allows you to set the mount options as for the
+L<mount(8)> I<-o> flag.
+
+If the C<options> parameter is an empty string, then
+no options are passed (all options default to whatever
+the filesystem uses).");
+
+ ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"], []), 75, [],
+ [],
+ "mount a guest disk with mount options and vfstype",
+ "\
+This is the same as the C<guestfs_mount> command, but it
+allows you to set both the mount options and the vfstype
+as for the L<mount(8)> I<-o> and I<-t> flags.");
+
+ ("debug", (RString "result", [String "subcmd"; StringList "extraargs"], []), 76, [NotInDocs],
+ [],
+ "debugging and internals",
+ "\
+The C<guestfs_debug> command exposes some internals of
+C<guestfsd> (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<daemon/debug.c> in the libguestfs source
+to find out what you can do.");
+
+ ("lvremove", (RErr, [Device "device"], []), 77, [Optional "lvm2"],
+ [InitEmpty, Always, TestOutputList (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG/LV1"];
+ ["lvs"]], ["/dev/VG/LV2"]);
+ InitEmpty, Always, TestOutputList (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG"];
+ ["lvs"]], []);
+ InitEmpty, Always, TestOutputList (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG"];
+ ["vgs"]], ["VG"])],
+ "remove an LVM logical volume",
+ "\
+Remove an LVM logical volume C<device>, where C<device> is
+the path to the LV, such as C</dev/VG/LV>.
+
+You can also remove all LVs in a volume group by specifying
+the VG name, C</dev/VG>.");
+
+ ("vgremove", (RErr, [String "vgname"], []), 78, [Optional "lvm2"],
+ [InitEmpty, Always, TestOutputList (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["lvs"]], []);
+ InitEmpty, Always, TestOutputList (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["vgs"]], [])],
+ "remove an LVM volume group",
+ "\
+Remove an LVM volume group C<vgname>, (for example C<VG>).
+
+This also forcibly removes all logical volumes in the volume
+group (if any).");
+
+ ("pvremove", (RErr, [Device "device"], []), 79, [Optional "lvm2"],
+ [InitEmpty, Always, TestOutputListOfDevices (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda1"];
+ ["lvs"]], []);
+ InitEmpty, Always, TestOutputListOfDevices (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda1"];
+ ["vgs"]], []);
+ InitEmpty, Always, TestOutputListOfDevices (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda1"];
+ ["pvs"]], [])],
+ "remove an LVM physical volume",
+ "\
+This wipes a physical volume C<device> so that LVM will no longer
+recognise it.
+
+The implementation uses the C<pvremove> command which refuses to
+wipe physical volumes that contain any volume groups, so you have
+to remove those first.");
+
+ ("set_e2label", (RErr, [Device "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<device> to C<label>. Filesystem labels are limited to
+16 characters.
+
+You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
+to return the existing label on a filesystem.");
+
+ ("get_e2label", (RString "label", [Device "device"], []), 81, [DeprecatedBy "vfs_label"],
+ [],
+ "get the ext2/3/4 filesystem label",
+ "\
+This returns the ext2/3/4 filesystem label of the filesystem on
+C<device>.");
+
+ ("set_e2uuid", (RErr, [Device "device"; String "uuid"], []), 82, [],
+ (let uuid = uuidgen () in
+ [InitBasicFS, Always, TestOutput (
+ [["set_e2uuid"; "/dev/sda1"; uuid];
+ ["get_e2uuid"; "/dev/sda1"]], uuid);
+ InitBasicFS, Always, TestOutput (
+ [["set_e2uuid"; "/dev/sda1"; "clear"];
+ ["get_e2uuid"; "/dev/sda1"]], "");
+ (* We can't predict what UUIDs will be, so just check the commands run. *)
+ InitBasicFS, Always, TestRun (
+ [["set_e2uuid"; "/dev/sda1"; "random"]]);
+ InitBasicFS, Always, TestRun (
+ [["set_e2uuid"; "/dev/sda1"; "time"]])]),
+ "set the ext2/3/4 filesystem UUID",
+ "\
+This sets the ext2/3/4 filesystem UUID of the filesystem on
+C<device> to C<uuid>. The format of the UUID and alternatives
+such as C<clear>, C<random> and C<time> are described in the
+L<tune2fs(8)> manpage.
+
+You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
+to return the existing UUID of a filesystem.");
+
+ ("get_e2uuid", (RString "uuid", [Device "device"], []), 83, [DeprecatedBy "vfs_uuid"],
+ (* Regression test for RHBZ#597112. *)
+ (let uuid = uuidgen () in
+ [InitNone, Always, TestOutput (
+ [["mke2journal"; "1024"; "/dev/sdc"];
+ ["set_e2uuid"; "/dev/sdc"; uuid];
+ ["get_e2uuid"; "/dev/sdc"]], uuid)]),
+ "get the ext2/3/4 filesystem UUID",
+ "\
+This returns the ext2/3/4 filesystem UUID of the filesystem on
+C<device>.");
+
+ ("fsck", (RInt "status", [String "fstype"; Device "device"], []), 84, [FishOutput FishOutputHexadecimal],
+ [InitBasicFS, Always, TestOutputInt (
+ [["umount"; "/dev/sda1"];
+ ["fsck"; "ext2"; "/dev/sda1"]], 0);
+ InitBasicFS, Always, TestOutputInt (
+ [["umount"; "/dev/sda1"];
+ ["zero"; "/dev/sda1"];
+ ["fsck"; "ext2"; "/dev/sda1"]], 8)],
+ "run the filesystem checker",
+ "\
+This runs the filesystem checker (fsck) on C<device> which
+should have filesystem type C<fstype>.
+
+The returned integer is the status. See L<fsck(8)> for the
+list of status codes from C<fsck>.
+
+Notes:
+
+=over 4
+
+=item *
+
+Multiple status codes can be summed together.
+
+=item *
+
+A non-zero return code can mean \"success\", for example if
+errors have been corrected on the filesystem.
+
+=item *
+
+Checking or repairing NTFS volumes is not supported
+(by linux-ntfs).
+
+=back
+
+This command is entirely equivalent to running C<fsck -a -t fstype device>.");
+
+ ("zero", (RErr, [Device "device"], []), 85, [Progress],
+ [InitBasicFS, Always, TestRun (
+ [["umount"; "/dev/sda1"];
+ ["zero"; "/dev/sda1"]])],
+ "write zeroes to the device",
+ "\
+This command writes zeroes over the first few blocks of C<device>.
+
+How many blocks are zeroed isn't specified (but it's I<not> enough
+to securely wipe the device). It should be sufficient to remove
+any partition tables, filesystem superblocks and so on.
+
+If blocks are already zero, then this command avoids writing
+zeroes. This prevents the underlying device from becoming non-sparse
+or growing unnecessarily.
+
+See also: C<guestfs_zero_device>, C<guestfs_scrub_device>,
+C<guestfs_is_zero_device>");
+
+ ("grub_install", (RErr, [Pathname "root"; Device "device"], []), 86, [Optional "grub"],
+ (* See:
+ * https://bugzilla.redhat.com/show_bug.cgi?id=484986
+ * https://bugzilla.redhat.com/show_bug.cgi?id=479760
+ *)
+ [InitBasicFS, Always, TestOutputTrue (
+ [["mkdir_p"; "/boot/grub"];
+ ["write"; "/boot/grub/device.map"; "(hd0) /dev/vda"];
+ ["grub_install"; "/"; "/dev/vda"];
+ ["is_dir"; "/boot"]])],
+ "install GRUB 1",
+ "\
+This command installs GRUB 1 (the Grand Unified Bootloader) on
+C<device>, with the root directory being C<root>.
+
+Notes:
+
+=over 4
+
+=item *
+
+There is currently no way in the API to install grub2, which
+is used by most modern Linux guests. It is possible to run
+the grub2 command from the guest, although see the
+caveats in L<guestfs(3)/RUNNING COMMANDS>.
+
+=item *
+
+This uses C<grub-install> from the host. Unfortunately grub is
+not always compatible with itself, so this only works in rather
+narrow circumstances. Careful testing with each guest version
+is advisable.
+
+=item *
+
+If grub-install reports the error
+\"No suitable drive was found in the generated device map.\"
+it may be that you need to create a C</boot/grub/device.map>
+file first that contains the mapping between grub device names
+and Linux device names. It is usually sufficient to create
+a file containing:
+
+ (hd0) /dev/vda
+
+replacing C</dev/vda> with the name of the installation device.
+
+=back");
+
+ ("cp", (RErr, [Pathname "src"; Pathname "dest"], []), 87, [],
+ [InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/cp"];
+ ["write"; "/cp/old"; "file content"];
+ ["cp"; "/cp/old"; "/cp/new"];
+ ["cat"; "/cp/new"]], "file content");
+ InitScratchFS, Always, TestOutputTrue (
+ [["mkdir"; "/cp2"];
+ ["write"; "/cp2/old"; "file content"];
+ ["cp"; "/cp2/old"; "/cp2/new"];
+ ["is_file"; "/cp2/old"]]);
+ InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/cp3"];
+ ["write"; "/cp3/old"; "file content"];
+ ["mkdir"; "/cp3/dir"];
+ ["cp"; "/cp3/old"; "/cp3/dir/new"];
+ ["cat"; "/cp3/dir/new"]], "file content")],
+ "copy a file",
+ "\
+This copies a file from C<src> to C<dest> where C<dest> is
+either a destination filename or destination directory.");
+
+ ("cp_a", (RErr, [Pathname "src"; Pathname "dest"], []), 88, [],
+ [InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/cp_a1"];
+ ["mkdir"; "/cp_a2"];
+ ["write"; "/cp_a1/file"; "file content"];
+ ["cp_a"; "/cp_a1"; "/cp_a2"];
+ ["cat"; "/cp_a2/cp_a1/file"]], "file content")],
+ "copy a file or directory recursively",
+ "\
+This copies a file or directory from C<src> to C<dest>
+recursively using the C<cp -a> command.");
+
+ ("mv", (RErr, [Pathname "src"; Pathname "dest"], []), 89, [],
+ [InitScratchFS, Always, TestOutput (
+ [["mkdir"; "/mv"];
+ ["write"; "/mv/old"; "file content"];
+ ["mv"; "/mv/old"; "/mv/new"];
+ ["cat"; "/mv/new"]], "file content");
+ InitScratchFS, Always, TestOutputFalse (
+ [["mkdir"; "/mv2"];
+ ["write"; "/mv2/old"; "file content"];
+ ["mv"; "/mv2/old"; "/mv2/new"];
+ ["is_file"; "/mv2/old"]])],
+ "move a file",
+ "\
+This moves a file from C<src> to C<dest> where C<dest> is
+either a destination filename or destination directory.");
+
+ ("drop_caches", (RErr, [Int "whattodrop"], []), 90, [],
+ [InitEmpty, Always, TestRun (
+ [["drop_caches"; "3"]])],
+ "drop kernel page cache, dentries and inodes",
+ "\
+This instructs the guest kernel to drop its page cache,
+and/or dentries and inode caches. The parameter C<whattodrop>
+tells the kernel what precisely to drop, see
+L<http://linux-mm.org/Drop_Caches>
+
+Setting C<whattodrop> to 3 should drop everything.
+
+This automatically calls L<sync(2)> before the operation,
+so that the maximum guest memory is freed.");
+
+ ("dmesg", (RString "kmsgs", [], []), 91, [],
+ [InitEmpty, Always, TestRun (
+ [["dmesg"]])],
+ "return kernel messages",
+ "\
+This returns the kernel messages (C<dmesg> output) from
+the guest kernel. This is sometimes useful for extended
+debugging of problems.
+
+Another way to get the same information is to enable
+verbose messages with C<guestfs_set_verbose> or by setting
+the environment variable C<LIBGUESTFS_DEBUG=1> before
+running the program.");
+
+ ("ping_daemon", (RErr, [], []), 92, [],
+ [InitEmpty, Always, TestRun (
+ [["ping_daemon"]])],
+ "ping the guest daemon",
+ "\
+This is a test probe into the guestfs daemon running inside
+the qemu subprocess. Calling this function checks that the
+daemon responds to the ping message, without affecting the daemon
+or attached block device(s) in any other way.");
+
+ ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"], []), 93, [],
+ [InitScratchFS, Always, TestOutputTrue (
+ [["mkdir"; "/equal"];
+ ["write"; "/equal/file1"; "contents of a file"];
+ ["cp"; "/equal/file1"; "/equal/file2"];
+ ["equal"; "/equal/file1"; "/equal/file2"]]);
+ InitScratchFS, Always, TestOutputFalse (
+ [["mkdir"; "/equal2"];
+ ["write"; "/equal2/file1"; "contents of a file"];
+ ["write"; "/equal2/file2"; "contents of another file"];
+ ["equal"; "/equal2/file1"; "/equal2/file2"]]);
+ InitScratchFS, Always, TestLastFail (
+ [["mkdir"; "/equal3"];
+ ["equal"; "/equal3/file1"; "/equal3/file2"]])],
+ "test if two files have equal contents",
+ "\
+This compares the two files C<file1> and C<file2> and returns
+true if their content is exactly equal, or false otherwise.
+
+The external L<cmp(1)> program is used for the comparison.");
+
+ ("strings", (RStringList "stringsout", [Pathname "path"], []), 94, [ProtocolLimitWarning],
+ [InitISOFS, Always, TestOutputList (
+ [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
+ InitISOFS, Always, TestOutputList (
+ [["strings"; "/empty"]], []);
+ (* Test for RHBZ#579608, absolute symbolic links. *)
+ InitISOFS, Always, TestRun (
+ [["strings"; "/abssymlink"]])],
+ "print the printable strings in a file",
+ "\
+This runs the L<strings(1)> command on a file and returns
+the list of printable strings found.");
+
+ ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"], []), 95, [ProtocolLimitWarning],
+ [InitISOFS, Always, TestOutputList (
+ [["strings_e"; "b"; "/known-5"]], []);
+ InitScratchFS, Always, TestOutputList (
+ [["write"; "/strings_e"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"];
+ ["strings_e"; "b"; "/strings_e"]], ["hello"; "world"])],
+ "print the printable strings in a file",
+ "\
+This is like the C<guestfs_strings> command, but allows you to
+specify the encoding of strings that are looked for in
+the source file C<path>.
+
+Allowed encodings are:
+
+=over 4
+
+=item s
+
+Single 7-bit-byte characters like ASCII and the ASCII-compatible
+parts of ISO-8859-X (this is what C<guestfs_strings> uses).
+
+=item S
+
+Single 8-bit-byte characters.
+
+=item b
+
+16-bit big endian strings such as those encoded in
+UTF-16BE or UCS-2BE.
+
+=item l (lower case letter L)
+
+16-bit little endian such as UTF-16LE and UCS-2LE.
+This is useful for examining binaries in Windows guests.
+
+=item B
+
+32-bit big endian such as UCS-4BE.
+
+=item L
+
+32-bit little endian such as UCS-4LE.
+
+=back
+
+The returned strings are transcoded to UTF-8.");
+
+ ("hexdump", (RString "dump", [Pathname "path"], []), 96, [ProtocolLimitWarning],
+ [InitISOFS, Always, TestOutput (
+ [["hexdump"; "/known-4"]], "00000000 61 62 63 0a 64 65 66 0a 67 68 69 |abc.def.ghi|\n0000000b\n");
+ (* Test for RHBZ#501888c2 regression which caused large hexdump
+ * commands to segfault.
+ *)
+ InitISOFS, Always, TestRun (
+ [["hexdump"; "/100krandom"]]);
+ (* Test for RHBZ#579608, absolute symbolic links. *)
+ InitISOFS, Always, TestRun (
+ [["hexdump"; "/abssymlink"]])],
+ "dump a file in hexadecimal",
+ "\
+This runs C<hexdump -C> on the given C<path>. The result is
+the human-readable, canonical hex dump of the file.");
+
+ ("zerofree", (RErr, [Device "device"], []), 97, [Optional "zerofree"],
+ [InitNone, Always, TestOutput (
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["mkfs"; "ext3"; "/dev/sda1"];
+ ["mount_options"; ""; "/dev/sda1"; "/"];
+ ["write"; "/new"; "test file"];
+ ["umount"; "/dev/sda1"];
+ ["zerofree"; "/dev/sda1"];
+ ["mount_options"; ""; "/dev/sda1"; "/"];
+ ["cat"; "/new"]], "test file")],
+ "zero unused inodes and disk blocks on ext2/3 filesystem",
+ "\
+This runs the I<zerofree> program on C<device>. This program
+claims to zero unused inodes and disk blocks on an ext2/3
+filesystem, thus making it possible to compress the filesystem
+more effectively.
+
+You should B<not> run this program if the filesystem is
+mounted.
+
+It is possible that using this program can damage the filesystem
+or data on the filesystem.");
+
+ ("pvresize", (RErr, [Device "device"], []), 98, [Optional "lvm2"],