+
+ ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
+ [], (* 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 (can be expensive).
+
+=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, [],
+ [], (* 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, [],
+ [], (* 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", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [],
+ [], (* 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 "path"]), 19, [],
+ [], (* 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 "path"; String "val"]), 20, [],
+ [], (* XXX Augeas code needs tests. *)
+ "set Augeas path to value",
+ "\
+Set the value associated with C<path> to C<value>.");
+
+ ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
+ [], (* 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 "path"]), 22, [],
+ [], (* 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, [],
+ [], (* 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 "path"]), 24, [],
+ [], (* XXX Augeas code needs tests. *)
+ "return Augeas nodes which match path",
+ "\
+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, [],
+ [], (* 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, [],
+ [], (* 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 "path"]), 28, [],
+ [], (* XXX Augeas code needs tests. *)
+ "list Augeas nodes under a path",
+ "\
+This is just a shortcut for listing C<guestfs_aug_match>
+C<path/*> and sorting the resulting nodes into alphabetical order.");
+
+ ("rm", (RErr, [String "path"]), 29, [],
+ [InitBasicFS, TestRun
+ [["touch"; "/new"];
+ ["rm"; "/new"]];
+ InitBasicFS, TestLastFail
+ [["rm"; "/new"]];
+ InitBasicFS, TestLastFail
+ [["mkdir"; "/new"];
+ ["rm"; "/new"]]],
+ "remove a file",
+ "\
+Remove the single file C<path>.");
+
+ ("rmdir", (RErr, [String "path"]), 30, [],
+ [InitBasicFS, TestRun
+ [["mkdir"; "/new"];
+ ["rmdir"; "/new"]];
+ InitBasicFS, TestLastFail
+ [["rmdir"; "/new"]];
+ InitBasicFS, TestLastFail
+ [["touch"; "/new"];
+ ["rmdir"; "/new"]]],
+ "remove a directory",
+ "\
+Remove the single directory C<path>.");
+
+ ("rm_rf", (RErr, [String "path"]), 31, [],
+ [InitBasicFS, TestOutputFalse
+ [["mkdir"; "/new"];
+ ["mkdir"; "/new/foo"];
+ ["touch"; "/new/foo/bar"];
+ ["rm_rf"; "/new"];
+ ["exists"; "/new"]]],
+ "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, [String "path"]), 32, [],
+ [InitBasicFS, TestOutputTrue
+ [["mkdir"; "/new"];
+ ["is_dir"; "/new"]];
+ InitBasicFS, TestLastFail
+ [["mkdir"; "/new/foo/bar"]]],
+ "create a directory",
+ "\
+Create a directory named C<path>.");
+
+ ("mkdir_p", (RErr, [String "path"]), 33, [],
+ [InitBasicFS, TestOutputTrue
+ [["mkdir_p"; "/new/foo/bar"];
+ ["is_dir"; "/new/foo/bar"]];
+ InitBasicFS, TestOutputTrue
+ [["mkdir_p"; "/new/foo/bar"];
+ ["is_dir"; "/new/foo"]];
+ InitBasicFS, TestOutputTrue
+ [["mkdir_p"; "/new/foo/bar"];
+ ["is_dir"; "/new"]]],
+ "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"; String "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.");
+
+ ("chown", (RErr, [Int "owner"; Int "group"; String "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", [String "path"]), 36, [],
+ [InitBasicFS, TestOutputTrue (
+ [["touch"; "/new"];
+ ["exists"; "/new"]]);
+ InitBasicFS, TestOutputTrue (
+ [["mkdir"; "/new"];
+ ["exists"; "/new"]])],
+ "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", [String "path"]), 37, [],
+ [InitBasicFS, TestOutputTrue (
+ [["touch"; "/new"];
+ ["is_file"; "/new"]]);
+ InitBasicFS, TestOutputFalse (
+ [["mkdir"; "/new"];
+ ["is_file"; "/new"]])],
+ "test if file exists",
+ "\
+This returns C<true> if and only if there is a 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", [String "path"]), 38, [],
+ [InitBasicFS, TestOutputFalse (
+ [["touch"; "/new"];
+ ["is_dir"; "/new"]]);
+ InitBasicFS, TestOutputTrue (
+ [["mkdir"; "/new"];
+ ["is_dir"; "/new"]])],
+ "test if file exists",
+ "\
+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, [String "device"]), 39, [],
+ [InitEmpty, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
+ ["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"; StringList "physvols"]), 40, [],
+ [InitEmpty, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
+ ["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, [],
+ [InitEmpty, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
+ ["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 volume group",
+ "\
+This creates an LVM volume group called C<logvol>
+on the volume group C<volgroup>, with C<size> megabytes.");
+
+ ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
+ [InitEmpty, TestOutput (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount"; "/dev/sda1"; "/"];
+ ["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents")],
+ "make a filesystem",
+ "\
+This creates a filesystem on C<device> (usually a partition
+of LVM logical volume). The filesystem type is C<fstype>, for
+example C<ext3>.");
+
+ ("sfdisk", (RErr, [String "device";
+ Int "cyls"; Int "heads"; Int "sectors";
+ StringList "lines"]), 43, [DangerWillRobinson],
+ [],
+ "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).");
+
+ ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
+ [InitEmpty, TestOutput (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount"; "/dev/sda1"; "/"];
+ ["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents")],
+ "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).");
+
+ ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
+ [InitEmpty, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount"; "/dev/sda1"; "/"];
+ ["mounts"]], ["/dev/sda1"]);
+ InitEmpty, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount"; "/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, [],
+ [InitBasicFS, TestOutputList (
+ [["mounts"]], ["/dev/sda1"])],
+ "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.");
+
+ ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
+ [InitBasicFS, TestOutputList (
+ [["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, [DangerWillRobinson],
+ [],
+ "remove all LVM LVs, VGs and PVs",
+ "\
+This command removes all LVM logical volumes, volume groups
+and physical volumes.");
+