summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-10 18:25:07 +0100
committerRichard Jones <rjones@redhat.com>2009-04-11 17:04:35 +0100
commitb4d2a01828e5de85e5eee3631f7fe3925a0312ca (patch)
tree6f77ecceccd53a84afce4cecf0fe199ba7707752 /src
parent99f68f259f92eee884c6c7396f61b9c16e2bf354 (diff)
downloadlibguestfs-b4d2a01828e5de85e5eee3631f7fe3925a0312ca.tar.gz
libguestfs-b4d2a01828e5de85e5eee3631f7fe3925a0312ca.tar.xz
libguestfs-b4d2a01828e5de85e5eee3631f7fe3925a0312ca.zip
Added test suite.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/generator.ml1046
-rw-r--r--src/guestfs-actions.c931
-rw-r--r--src/guestfs-actions.h13
-rw-r--r--src/guestfs_protocol.c208
-rw-r--r--src/guestfs_protocol.h132
-rw-r--r--src/guestfs_protocol.x79
6 files changed, 2271 insertions, 138 deletions
diff --git a/src/generator.ml b/src/generator.ml
index 06a638e6..6792e07a 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -77,59 +77,74 @@ and args = argt list (* Function parameters, guestfs handle is implicit. *)
and argt =
| String of string (* const char *name, cannot be NULL *)
| OptString of string (* const char *name, may be NULL *)
+ | StringList of string(* list of strings (each string cannot be NULL) *)
| Bool of string (* boolean *)
| Int of string (* int (smallish ints, signed, <= 31 bits) *)
type flags =
| ProtocolLimitWarning (* display warning about protocol size limits *)
+ | DangerWillRobinson (* flags particularly dangerous commands *)
| FishAlias of string (* provide an alias for this cmd in guestfish *)
| FishAction of string (* call this function in guestfish *)
| NotInFish (* do not export via guestfish *)
+let protocol_limit_warning =
+ "Because of the message protocol, there is a transfer limit
+of somewhere between 2MB and 4MB. To transfer large files you should use
+FTP."
+
+let danger_will_robinson =
+ "B<This command is dangerous. Without careful use you
+can easily destroy all your data>."
+
(* You can supply zero or as many tests as you want per API call.
*
- * Note that the test environment has 3 block devices, of size 10M, 20M
- * and 30M (respectively /dev/sda, /dev/sdb, /dev/sdc). To run the
- * tests in a reasonable amount of time, the virtual machine and
- * block devices are reused between tests. So don't try testing
- * kill_subprocess :-x
+ * Note that the test environment has 3 block devices, of size 500MB,
+ * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc).
+ * Note for partitioning purposes, the 500MB device has 63 cylinders.
+ *
+ * To be able to run the tests in a reasonable amount of time,
+ * 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.
*
* Don't assume anything about the previous contents of the block
* devices. Use 'Init*' to create some initial scenarios.
*)
-type tests = test list
+type tests = (test_init * test) list
and test =
(* Run the command sequence and just expect nothing to fail. *)
- | TestRun of test_init * seq
+ | TestRun of seq
(* Run the command sequence and expect the output of the final
* command to be the string.
*)
- | TestOutput of test_init * seq * string
+ | TestOutput of seq * string
(* Run the command sequence and expect the output of the final
* command to be the list of strings.
*)
- | TestOutputList of test_init * seq * string list
+ | TestOutputList of seq * string list
(* Run the command sequence and expect the output of the final
* command to be the integer.
*)
- | TestOutputInt of test_init * seq * int
+ | TestOutputInt of seq * int
(* Run the command sequence and expect the output of the final
* command to be a true value (!= 0 or != NULL).
*)
- | TestOutputTrue of test_init * seq
+ | TestOutputTrue of seq
(* Run the command sequence and expect the output of the final
* command to be a false value (== 0 or == NULL, but not an error).
*)
- | TestOutputFalse of test_init * seq
+ | TestOutputFalse of seq
(* Run the command sequence and expect the output of the final
* command to be a list of the given length (but don't care about
* content).
*)
- | TestOutputLength of test_init * seq * int
+ | TestOutputLength of seq * int
(* Run the command sequence and expect the final command (only)
* to fail.
*)
- | TestLastFail of test_init * seq
+ | TestLastFail of seq
(* Some initial scenarios for testing. *)
and test_init =
@@ -143,7 +158,7 @@ and test_init =
| InitEmpty
(* /dev/sda:
* /dev/sda1 (is a PV):
- * /dev/VG/LV:
+ * /dev/VG/LV (size 8MB):
* formatted as ext2, empty [except for lost+found], mounted on /
* /dev/sdb and /dev/sdc may have random content.
*)
@@ -281,9 +296,8 @@ This returns the verbose messages flag.")
let daemon_functions = [
("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
- [TestOutput (
- InitNone,
- [["sfdisk"];
+ [InitNone, TestOutput (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
["mkfs"; "ext2"; "/dev/sda1"];
["mount"; "/dev/sda1"; "/"];
["write_file"; "/new"; "new file contents"; "0"];
@@ -308,7 +322,7 @@ The filesystem options C<sync> and C<noatime> are set with this
call, in order to improve reliability.");
("sync", (RErr, []), 2, [],
- [ TestRun (InitNone, [["sync"]])],
+ [ InitNone, 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
@@ -318,8 +332,7 @@ You should always call this if you have modified a disk image, before
closing the handle.");
("touch", (RErr, [String "path"]), 3, [],
- [TestOutputTrue (
- InitEmpty,
+ [InitEmpty, TestOutputTrue (
[["touch"; "/new"];
["exists"; "/new"]])],
"update file timestamps or create a new file",
@@ -329,8 +342,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],
- [TestOutput (
- InitEmpty,
+ [InitEmpty, TestOutput (
[["write_file"; "/new"; "new file contents"; "0"];
["cat"; "/new"]], "new file contents")],
"list the contents of a file",
@@ -355,8 +367,7 @@ This command is mostly useful for interactive sessions. It
is I<not> intended that you try to parse the output string.");
("ls", (RStringList "listing", [String "directory"]), 6, [],
- [TestOutputList (
- InitEmpty,
+ [InitEmpty, TestOutputList (
[["touch"; "/new"];
["touch"; "/newer"];
["touch"; "/newest"];
@@ -371,8 +382,7 @@ This command is mostly useful for interactive sessions. Programs
should probably use C<guestfs_readdir> instead.");
("list_devices", (RStringList "devices", []), 7, [],
- [TestOutputList (
- InitNone,
+ [InitNone, TestOutputList (
[["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])],
"list the block devices",
"\
@@ -381,12 +391,10 @@ List all the block devices.
The full block device names are returned, eg. C</dev/sda>");
("list_partitions", (RStringList "partitions", []), 8, [],
- [TestOutputList (
- InitEmpty,
+ [InitEmpty, TestOutputList (
[["list_partitions"]], ["/dev/sda1"]);
- TestOutputList (
- InitEmpty,
- [["sfdisk"];
+ InitNone, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
"list the partitions",
"\
@@ -398,12 +406,10 @@ This does not return logical volumes. For that you will need to
call C<guestfs_lvs>.");
("pvs", (RStringList "physvols", []), 9, [],
- [TestOutputList (
- InitEmptyLVM,
+ [InitEmptyLVM, TestOutputList (
[["pvs"]], ["/dev/sda1"]);
- TestOutputList (
- InitNone,
- [["sfdisk"];
+ InitNone, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
["pvcreate"; "/dev/sda3"];
@@ -419,12 +425,10 @@ PVs (eg. C</dev/sda2>).
See also C<guestfs_pvs_full>.");
("vgs", (RStringList "volgroups", []), 10, [],
- [TestOutputList (
- InitEmptyLVM,
+ [InitEmptyLVM, TestOutputList (
[["vgs"]], ["VG"]);
- TestOutputList (
- InitNone,
- [["sfdisk"];
+ InitNone, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
["pvcreate"; "/dev/sda1"];
["pvcreate"; "/dev/sda2"];
["pvcreate"; "/dev/sda3"];
@@ -442,21 +446,19 @@ detected (eg. C<VolGroup00>).
See also C<guestfs_vgs_full>.");
("lvs", (RStringList "logvols", []), 11, [],
- [TestOutputList (
- InitEmptyLVM,
+ [InitEmptyLVM, TestOutputList (
[["lvs"]], ["/dev/VG/LV"]);
- TestOutputList (
- InitNone,
- [["sfdisk"];
+ InitNone, 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"; "5000"];
- ["lvcreate"; "LV2"; "VG1"; "5000"];
- ["lvcreate"; "LV3"; "VG2"; "5000"];
- ["lvs"]], ["LV1"; "LV2"; "LV3"])],
+ ["lvcreate"; "LV1"; "VG1"; "50"];
+ ["lvcreate"; "LV2"; "VG1"; "50"];
+ ["lvcreate"; "LV3"; "VG2"; "50"];
+ ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
"list the LVM logical volumes (LVs)",
"\
List all the logical volumes detected. This is the equivalent
@@ -468,8 +470,7 @@ This returns a list of the logical volume device names
See also C<guestfs_lvs_full>.");
("pvs_full", (RPVList "physvols", []), 12, [],
- [TestOutputLength (
- InitEmptyLVM,
+ [InitEmptyLVM, TestOutputLength (
[["pvs"]], 1)],
"list the LVM physical volumes (PVs)",
"\
@@ -477,8 +478,7 @@ List all the physical volumes detected. This is the equivalent
of the L<pvs(8)> command. The \"full\" version includes all fields.");
("vgs_full", (RVGList "volgroups", []), 13, [],
- [TestOutputLength (
- InitEmptyLVM,
+ [InitEmptyLVM, TestOutputLength (
[["pvs"]], 1)],
"list the LVM volume groups (VGs)",
"\
@@ -486,8 +486,7 @@ List all the volumes groups detected. This is the equivalent
of the L<vgs(8)> command. The \"full\" version includes all fields.");
("lvs_full", (RLVList "logvols", []), 14, [],
- [TestOutputLength (
- InitEmptyLVM,
+ [InitEmptyLVM, TestOutputLength (
[["pvs"]], 1)],
"list the LVM logical volumes (LVs)",
"\
@@ -495,12 +494,10 @@ List all the logical volumes detected. This is the equivalent
of the L<lvs(8)> command. The \"full\" version includes all fields.");
("read_lines", (RStringList "lines", [String "path"]), 15, [],
- [TestOutputList (
- InitEmpty,
+ [InitEmpty, TestOutputList (
[["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
- TestOutputList (
- InitEmpty,
+ InitEmpty, TestOutputList (
[["write_file"; "/new"; ""; "0"];
["read_lines"; "/new"]], [])],
"read file as lines",
@@ -675,45 +672,38 @@ 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, [],
- [TestRun (
- InitEmpty,
+ [InitEmpty, TestRun
[["touch"; "/new"];
- ["rm"; "/new"]]);
- TestLastFail (
- InitEmpty,
- [["rm"; "/new"]]);
- TestLastFail (
- InitEmpty,
+ ["rm"; "/new"]];
+ InitEmpty, TestLastFail
+ [["rm"; "/new"]];
+ InitEmpty, TestLastFail
[["mkdir"; "/new"];
- ["rm"; "/new"]])],
+ ["rm"; "/new"]]],
"remove a file",
"\
Remove the single file C<path>.");
("rmdir", (RErr, [String "path"]), 30, [],
- [TestRun (
- InitEmpty,
+ [InitEmpty, TestRun
[["mkdir"; "/new"];
- ["rmdir"; "/new"]]);
- TestLastFail (
- InitEmpty,
- [["rmdir"; "/new"]]);
- TestLastFail (
- InitEmpty,
+ ["rmdir"; "/new"]];
+ InitEmpty, TestLastFail
+ [["rmdir"; "/new"]];
+ InitEmpty, TestLastFail
[["touch"; "/new"];
- ["rmdir"; "/new"]])],
+ ["rmdir"; "/new"]]],
"remove a directory",
"\
Remove the single directory C<path>.");
("rm_rf", (RErr, [String "path"]), 31, [],
- [TestOutputFalse (
- InitEmpty,
+ [InitEmpty, TestOutputFalse
[["mkdir"; "/new"];
["mkdir"; "/new/foo"];
["touch"; "/new/foo/bar"];
["rm_rf"; "/new"];
- ["exists"; "/new"]])],
+ ["exists"; "/new"]]],
"remove a file or directory recursively",
"\
Remove the file or directory C<path>, recursively removing the
@@ -721,27 +711,25 @@ contents if its a directory. This is like the C<rm -rf> shell
command.");
("mkdir", (RErr, [String "path"]), 32, [],
- [TestOutputTrue (
- InitEmpty,
+ [InitEmpty, TestOutputTrue
[["mkdir"; "/new"];
- ["is_dir"; "/new"]])],
+ ["is_dir"; "/new"]];
+ InitEmpty, TestLastFail
+ [["mkdir"; "/new/foo/bar"]]],
"create a directory",
"\
Create a directory named C<path>.");
("mkdir_p", (RErr, [String "path"]), 33, [],
- [TestOutputTrue (
- InitEmpty,
+ [InitEmpty, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
- ["is_dir"; "/new/foo/bar"]]);
- TestOutputTrue (
- InitEmpty,
+ ["is_dir"; "/new/foo/bar"]];
+ InitEmpty, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
- ["is_dir"; "/new/foo"]]);
- TestOutputTrue (
- InitEmpty,
+ ["is_dir"; "/new/foo"]];
+ InitEmpty, TestOutputTrue
[["mkdir_p"; "/new/foo/bar"];
- ["is_dir"; "/new"]])],
+ ["is_dir"; "/new"]]],
"create a directory and parents",
"\
Create a directory named C<path>, creating any parent directories
@@ -763,6 +751,200 @@ 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, [],
+ [InitEmpty, TestOutputTrue (
+ [["touch"; "/new"];
+ ["exists"; "/new"]]);
+ InitEmpty, 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, [],
+ [InitEmpty, TestOutputTrue (
+ [["touch"; "/new"];
+ ["is_file"; "/new"]]);
+ InitEmpty, 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, [],
+ [InitEmpty, TestOutputFalse (
+ [["touch"; "/new"];
+ ["is_dir"; "/new"]]);
+ InitEmpty, 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, [],
+ [InitNone, 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, [],
+ [InitNone, 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, [],
+ [InitNone, 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, [],
+ [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")],
+ "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],
+ [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")],
+ "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"],
+ [InitNone, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount"; "/dev/sda1"; "/"];
+ ["mounts"]], ["/dev/sda1"]);
+ InitNone, 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, [],
+ [InitEmpty, 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"],
+ [InitEmpty, 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.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
@@ -884,6 +1066,17 @@ let rec replace_str s s1 s2 =
s' ^ s2 ^ replace_str s'' s1 s2
)
+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''
+ )
+
let rec find_map f = function
| [] -> raise Not_found
| x :: xs ->
@@ -898,7 +1091,15 @@ let iteri f xs =
in
loop 0 xs
-let name_of_argt = function String n | OptString n | Bool n | Int n -> n
+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
+
+let name_of_argt = function
+ | String n | OptString n | StringList n | Bool n | Int n -> n
(* Check function names etc. for consistency. *)
let check_functions () =
@@ -1089,9 +1290,9 @@ I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
);
if List.mem ProtocolLimitWarning flags then
- pr "Because of the message protocol, there is a transfer limit
-of somewhere between 2MB and 4MB. To transfer large files you should use
-FTP.\n\n";
+ pr "%s\n\n" protocol_limit_warning;
+ if List.mem DangerWillRobinson flags then
+ pr "%s\n\n" danger_will_robinson;
) all_functions_sorted
and generate_structs_pod () =
@@ -1169,6 +1370,7 @@ and generate_xdr () =
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;
@@ -1427,6 +1629,9 @@ and generate_client_actions () =
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 ->
@@ -1556,6 +1761,7 @@ and generate_daemon_actions () =
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
@@ -1575,6 +1781,10 @@ and generate_daemon_actions () =
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;
@@ -1586,8 +1796,8 @@ and generate_daemon_actions () =
pr ";\n";
pr " if (r == %s)\n" error_code;
- pr " /* do_%s has already called reply_with_error, so just return */\n" name;
- pr " return;\n";
+ pr " /* do_%s has already called reply_with_error */\n" name;
+ pr " goto done;\n";
pr "\n";
(match fst style with
@@ -1633,6 +1843,16 @@ and generate_daemon_actions () =
pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
);
+ (* 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
+ );
+
pr "}\n\n";
) daemon_functions;
@@ -1823,20 +2043,459 @@ and generate_daemon_actions () =
and generate_tests () =
generate_header CStyle GPLv2;
- pr "#include <stdio.h>\n";
- pr "#include <stdlib.h>\n";
- pr "#include <string.h>\n";
- pr "\n";
- pr "#include \"guestfs.h\"\n";
+ pr "\
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include \"guestfs.h\"
+
+static guestfs_h *g;
+static int suppress_error = 0;
+
+static void print_error (guestfs_h *g, void *data, const char *msg)
+{
+ if (!suppress_error)
+ fprintf (stderr, \"%%s\\n\", msg);
+}
+
+static void print_strings (char * const * const argv)
+{
+ int argc;
+
+ for (argc = 0; argv[argc] != NULL; ++argc)
+ printf (\"\\t%%s\\n\", argv[argc]);
+}
+
+";
+
+ let test_names =
+ List.map (
+ fun (name, _, _, _, tests, _, _) ->
+ mapi (generate_one_test name) tests
+ ) all_functions in
+ let test_names = List.concat test_names in
+ let nr_tests = List.length test_names in
+
+ pr "\
+int main (int argc, char *argv[])
+{
+ char c = 0;
+ int failed = 0;
+ const char *srcdir;
+ int fd;
+ char buf[256];
+
+ g = guestfs_create ();
+ if (g == NULL) {
+ printf (\"guestfs_create FAILED\\n\");
+ exit (1);
+ }
+
+ guestfs_set_error_handler (g, print_error, NULL);
+
+ srcdir = getenv (\"srcdir\");
+ if (!srcdir) srcdir = \".\";
+ guestfs_set_path (g, srcdir);
+
+ snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);
+ fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ if (fd == -1) {
+ perror (buf);
+ exit (1);
+ }
+ if (lseek (fd, %d, SEEK_SET) == -1) {
+ perror (\"lseek\");
+ close (fd);
+ unlink (buf);
+ exit (1);
+ }
+ if (write (fd, &c, 1) == -1) {
+ perror (\"write\");
+ close (fd);
+ unlink (buf);
+ exit (1);
+ }
+ if (close (fd) == -1) {
+ perror (buf);
+ unlink (buf);
+ exit (1);
+ }
+ if (guestfs_add_drive (g, buf) == -1) {
+ printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
+ exit (1);
+ }
+
+ snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);
+ fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ if (fd == -1) {
+ perror (buf);
+ exit (1);
+ }
+ if (lseek (fd, %d, SEEK_SET) == -1) {
+ perror (\"lseek\");
+ close (fd);
+ unlink (buf);
+ exit (1);
+ }
+ if (write (fd, &c, 1) == -1) {
+ perror (\"write\");
+ close (fd);
+ unlink (buf);
+ exit (1);
+ }
+ if (close (fd) == -1) {
+ perror (buf);
+ unlink (buf);
+ exit (1);
+ }
+ if (guestfs_add_drive (g, buf) == -1) {
+ printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
+ exit (1);
+ }
+
+ snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);
+ fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
+ if (fd == -1) {
+ perror (buf);
+ exit (1);
+ }
+ if (lseek (fd, %d, SEEK_SET) == -1) {
+ perror (\"lseek\");
+ close (fd);
+ unlink (buf);
+ exit (1);
+ }
+ if (write (fd, &c, 1) == -1) {
+ perror (\"write\");
+ close (fd);
+ unlink (buf);
+ exit (1);
+ }
+ if (close (fd) == -1) {
+ perror (buf);
+ unlink (buf);
+ exit (1);
+ }
+ if (guestfs_add_drive (g, buf) == -1) {
+ printf (\"guestfs_add_drive %%s FAILED\\n\", buf);
+ exit (1);
+ }
+
+ if (guestfs_launch (g) == -1) {
+ printf (\"guestfs_launch FAILED\\n\");
+ exit (1);
+ }
+ if (guestfs_wait_ready (g) == -1) {
+ printf (\"guestfs_wait_ready FAILED\\n\");
+ exit (1);
+ }
+
+" (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024);
+
+ iteri (
+ fun i test_name ->
+ pr " printf (\"%3d/%3d %s\\n\");\n" (i+1) nr_tests test_name;
+ pr " if (%s () == -1) {\n" test_name;
+ pr " printf (\"%s FAILED\\n\");\n" test_name;
+ pr " failed++;\n";
+ pr " }\n";
+ ) test_names;
pr "\n";
+ pr " guestfs_close (g);\n";
+ pr " snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n";
+ pr " unlink (buf);\n";
+ pr " snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n";
+ pr " unlink (buf);\n";
+ pr " snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n";
+ pr " unlink (buf);\n";
+ pr "\n";
+ pr " if (failed > 0) {\n";
+ pr " printf (\"***** %%d / %d tests FAILED *****\\n\", failed);\n"
+ nr_tests;
+ pr " exit (1);\n";
+ pr " }\n";
+ pr "\n";
- pr "int main (int argc, char *argv[])\n";
- pr "{\n";
pr " exit (0);\n";
pr "}\n"
+and generate_one_test name i (init, test) =
+ let test_name = sprintf "test_%s_%d" name i in
+
+ pr "static int %s (void)\n" test_name;
+ pr "{\n";
+
+ (match init with
+ | InitNone ->
+ pr " /* InitNone for %s (%d) */\n" name i;
+ List.iter (generate_test_command_call test_name)
+ [["umount_all"];
+ ["lvm_remove_all"]]
+ | InitEmpty ->
+ pr " /* InitEmpty for %s (%d): create ext2 on /dev/sda1 */\n" name i;
+ List.iter (generate_test_command_call test_name)
+ [["umount_all"];
+ ["lvm_remove_all"];
+ ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mount"; "/dev/sda1"; "/"]]
+ | InitEmptyLVM ->
+ pr " /* InitEmptyLVM for %s (%d): create ext2 on /dev/VG/LV */\n"
+ name i;
+ List.iter (generate_test_command_call test_name)
+ [["umount_all"];
+ ["lvm_remove_all"];
+ ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV"; "VG"; "8"];
+ ["mkfs"; "ext2"; "/dev/VG/LV"];
+ ["mount"; "/dev/VG/LV"; "/"]]
+ );
+
+ let get_seq_last = function
+ | [] ->
+ failwithf "%s: you cannot use [] (empty list) when expecting a command"
+ test_name
+ | seq ->
+ let seq = List.rev seq in
+ List.rev (List.tl seq), List.hd seq
+ in
+
+ (match test with
+ | TestRun seq ->
+ pr " /* TestRun for %s (%d) */\n" name i;
+ List.iter (generate_test_command_call test_name) seq
+ | TestOutput (seq, expected) ->
+ pr " /* TestOutput for %s (%d) */\n" name i;
+ let seq, last = get_seq_last seq in
+ let test () =
+ pr " if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected);
+ pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected);
+ pr " return -1;\n";
+ pr " }\n"
+ in
+ List.iter (generate_test_command_call test_name) seq;
+ generate_test_command_call ~test test_name last
+ | TestOutputList (seq, expected) ->
+ pr " /* TestOutputList for %s (%d) */\n" name i;
+ let seq, last = get_seq_last seq in
+ let test () =
+ iteri (
+ fun i str ->
+ pr " if (!r[%d]) {\n" i;
+ pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
+ pr " print_strings (r);\n";
+ pr " return -1;\n";
+ pr " }\n";
+ pr " if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str);
+ pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i;
+ pr " return -1;\n";
+ pr " }\n"
+ ) expected;
+ pr " if (r[%d] != NULL) {\n" (List.length expected);
+ pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
+ test_name;
+ pr " print_strings (r);\n";
+ pr " return -1;\n";
+ pr " }\n"
+ in
+ List.iter (generate_test_command_call test_name) seq;
+ generate_test_command_call ~test test_name last
+ | TestOutputInt (seq, expected) ->
+ pr " /* TestOutputInt for %s (%d) */\n" name i;
+ let seq, last = get_seq_last seq in
+ let test () =
+ pr " if (r != %d) {\n" expected;
+ pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\", r);\n"
+ test_name expected;
+ pr " return -1;\n";
+ pr " }\n"
+ in
+ List.iter (generate_test_command_call test_name) seq;
+ generate_test_command_call ~test test_name last
+ | TestOutputTrue seq ->
+ pr " /* TestOutputTrue for %s (%d) */\n" name i;
+ let seq, last = get_seq_last seq in
+ let test () =
+ pr " if (!r) {\n";
+ pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
+ test_name;
+ pr " return -1;\n";
+ pr " }\n"
+ in
+ List.iter (generate_test_command_call test_name) seq;
+ generate_test_command_call ~test test_name last
+ | TestOutputFalse seq ->
+ pr " /* TestOutputFalse for %s (%d) */\n" name i;
+ let seq, last = get_seq_last seq in
+ let test () =
+ pr " if (r) {\n";
+ pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
+ test_name;
+ pr " return -1;\n";
+ pr " }\n"
+ in
+ List.iter (generate_test_command_call test_name) seq;
+ generate_test_command_call ~test test_name last
+ | TestOutputLength (seq, expected) ->
+ pr " /* TestOutputLength for %s (%d) */\n" name i;
+ let seq, last = get_seq_last seq in
+ let test () =
+ pr " int j;\n";
+ pr " for (j = 0; j < %d; ++j)\n" expected;
+ pr " if (r[j] == NULL) {\n";
+ pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
+ test_name;
+ pr " print_strings (r);\n";
+ pr " return -1;\n";
+ pr " }\n";
+ pr " if (r[j] != NULL) {\n";
+ pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
+ test_name;
+ pr " print_strings (r);\n";
+ pr " return -1;\n";
+ pr " }\n"
+ in
+ List.iter (generate_test_command_call test_name) seq;
+ generate_test_command_call ~test test_name last
+ | TestLastFail seq ->
+ pr " /* TestLastFail for %s (%d) */\n" name i;
+ let seq, last = get_seq_last seq in
+ List.iter (generate_test_command_call test_name) seq;
+ generate_test_command_call test_name ~expect_error:true last
+ );
+
+ pr " return 0;\n";
+ pr "}\n";
+ pr "\n";
+ test_name
+
+(* Generate the code to run a command, leaving the result in 'r'.
+ * If you expect to get an error then you should set expect_error:true.
+ *)
+and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
+ match cmd with
+ | [] -> assert false
+ | name :: args ->
+ (* Look up the command to find out what args/ret it has. *)
+ let style =
+ try
+ let _, style, _, _, _, _, _ =
+ List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
+ style
+ with Not_found ->
+ failwithf "%s: in test, command %s was not found" test_name name in
+
+ if List.length (snd style) <> List.length args then
+ failwithf "%s: in test, wrong number of args given to %s"
+ test_name name;
+
+ pr " {\n";
+
+ List.iter (
+ function
+ | String _, _
+ | OptString _, _
+ | Int _, _
+ | Bool _, _ -> ()
+ | StringList n, arg ->
+ pr " char *%s[] = {\n" n;
+ let strs = string_split " " arg in
+ List.iter (
+ fun str -> pr " \"%s\",\n" (c_quote str)
+ ) strs;
+ pr " NULL\n";
+ pr " };\n";
+ ) (List.combine (snd style) args);
+
+ let error_code =
+ match fst style with
+ | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
+ | RConstString _ -> pr " const char *r;\n"; "NULL"
+ | RString _ -> pr " char *r;\n"; "NULL"
+ | RStringList _ ->
+ pr " char **r;\n";
+ pr " int i;\n";
+ "NULL"
+ | RIntBool _ ->
+ pr " struct guestfs_int_bool *r;\n";
+ "NULL"
+ | RPVList _ ->
+ pr " struct guestfs_lvm_pv_list *r;\n";
+ "NULL"
+ | RVGList _ ->
+ pr " struct guestfs_lvm_vg_list *r;\n";
+ "NULL"
+ | RLVList _ ->
+ pr " struct guestfs_lvm_lv_list *r;\n";
+ "NULL" in
+
+ pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
+ pr " r = guestfs_%s (g" name;
+
+ (* Generate the parameters. *)
+ List.iter (
+ function
+ | String _, arg -> pr ", \"%s\"" (c_quote arg)
+ | OptString _, arg ->
+ if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg)
+ | StringList n, _ ->
+ pr ", %s" n
+ | Int _, arg ->
+ let i =
+ try int_of_string arg
+ with Failure "int_of_string" ->
+ failwithf "%s: expecting an int, but got '%s'" test_name arg in
+ pr ", %d" i
+ | Bool _, arg ->
+ let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
+ ) (List.combine (snd style) args);
+
+ pr ");\n";
+ if not expect_error then
+ pr " if (r == %s)\n" error_code
+ else
+ pr " if (r != %s)\n" error_code;
+ pr " return -1;\n";
+
+ (* Insert the test code. *)
+ (match test with
+ | None -> ()
+ | Some f -> f ()
+ );
+
+ (match fst style with
+ | RErr | RInt _ | RBool _ | RConstString _ -> ()
+ | RString _ -> pr " free (r);\n"
+ | RStringList _ ->
+ pr " for (i = 0; r[i] != NULL; ++i)\n";
+ pr " free (r[i]);\n";
+ pr " free (r);\n"
+ | RIntBool _ ->
+ pr " guestfs_free_int_bool (r);\n"
+ | RPVList _ ->
+ pr " guestfs_free_lvm_pv_list (r);\n"
+ | RVGList _ ->
+ pr " guestfs_free_lvm_vg_list (r);\n"
+ | RLVList _ ->
+ pr " guestfs_free_lvm_lv_list (r);\n"
+ );
+
+ pr " }\n"
+
+and c_quote str =
+ let str = replace_str str "\r" "\\r" in
+ let str = replace_str str "\n" "\\n" in
+ let str = replace_str str "\t" "\\t" in
+ str
+
(* Generate a lot of different functions for guestfish. *)
and generate_fish_cmds () =
generate_header CStyle GPLv2;
@@ -1893,11 +2552,19 @@ and generate_fish_cmds () =
let warnings =
if List.mem ProtocolLimitWarning flags then
- "\n\nBecause of the message protocol, there is a transfer limit
-of somewhere between 2MB and 4MB. To transfer large files you should use
-FTP."
+ ("\n\n" ^ protocol_limit_warning)
else "" in
+ (* For DangerWillRobinson commands, we should probably have
+ * guestfish prompt before allowing you to use them (especially
+ * in interactive mode). XXX
+ *)
+ let warnings =
+ warnings ^
+ if List.mem DangerWillRobinson flags then
+ ("\n\n" ^ danger_will_robinson)
+ else "" in
+
let describe_alias =
if name <> alias then
sprintf "\n\nYou can use '%s' as an alias for this command." alias
@@ -1977,8 +2644,9 @@ FTP."
);
List.iter (
function
- | String n -> pr " const char *%s;\n" n
+ | 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
) (snd style);
@@ -1998,6 +2666,8 @@ FTP."
| OptString name ->
pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
name i i
+ | StringList name ->
+ pr " %s = parse_string_list (argv[%d]);\n" name i
| Bool name ->
pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
| Int name ->
@@ -2115,12 +2785,19 @@ and generate_fish_actions_pod () =
function
| String n -> pr " %s" n
| OptString n -> pr " %s" n
+ | StringList n -> pr " %s,..." n
| Bool _ -> pr " true|false"
| Int n -> pr " %s" n
) (snd style);
pr "\n";
pr "\n";
- pr "%s\n\n" longdesc
+ pr "%s\n\n" longdesc;
+
+ 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
(* Generate a C function prototype. *)
@@ -2169,6 +2846,7 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
function
| String n -> next (); pr "const char *%s" n
| OptString n -> next (); pr "const char *%s" n
+ | StringList n -> next (); pr "char * const* const %s" n
| Bool n -> next (); pr "int %s" n
| Int n -> next (); pr "int %s" n
) (snd style);
@@ -2190,9 +2868,10 @@ and generate_call_args ?handle style =
if !comma then pr ", ";
comma := true;
match arg with
- | String n -> pr "%s" n
- | OptString n -> pr "%s" n
- | Bool n -> pr "%s" n
+ | String n
+ | OptString n
+ | StringList n
+ | Bool n
| Int n -> pr "%s" n
) (snd style);
pr ")"
@@ -2339,18 +3018,23 @@ and generate_ocaml_c () =
List.iter (
fun (name, style, _, _, _, _, _) ->
+ let params =
+ "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
+
pr "CAMLprim value\n";
- pr "ocaml_guestfs_%s (value gv" name;
- List.iter (
- fun arg -> pr ", value %sv" (name_of_argt arg)
- ) (snd style);
+ pr "ocaml_guestfs_%s (value %s" name (List.hd params);
+ List.iter (pr ", value %s") (List.tl params);
pr ")\n";
pr "{\n";
- pr " CAMLparam%d (gv" (1 + (List.length (snd style)));
- List.iter (
- fun arg -> pr ", %sv" (name_of_argt arg)
- ) (snd style);
- pr ");\n";
+
+ (match params with
+ | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
+ pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
+ pr " CAMLxparam%d (%s);\n"
+ (List.length rest) (String.concat ", " rest)
+ | ps ->
+ pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
+ );
pr " CAMLlocal1 (rv);\n";
pr "\n";
@@ -2367,6 +3051,8 @@ and generate_ocaml_c () =
pr " const char *%s =\n" n;
pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
n n
+ | StringList n ->
+ pr " char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
| Bool n ->
pr " int %s = Bool_val (%sv);\n" n n
| Int n ->
@@ -2402,6 +3088,14 @@ and generate_ocaml_c () =
generate_call_args ~handle:"g" style;
pr ";\n";
pr " caml_leave_blocking_section ();\n";
+
+ List.iter (
+ function
+ | StringList n ->
+ pr " ocaml_guestfs_free_strings (%s);\n" n;
+ | String _ | OptString _ | Bool _ | Int _ -> ()
+ ) (snd style);
+
pr " if (r == %s)\n" error_code;
pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
pr "\n";
@@ -2436,7 +3130,18 @@ and generate_ocaml_c () =
pr " CAMLreturn (rv);\n";
pr "}\n";
- pr "\n"
+ pr "\n";
+
+ if List.length params > 5 then (
+ pr "CAMLprim value\n";
+ pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
+ pr "{\n";
+ pr " return ocaml_guestfs_%s (argv[0]" name;
+ iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
+ pr ");\n";
+ pr "}\n";
+ pr "\n"
+ )
) all_functions
and generate_ocaml_lvm_structure_decls () =
@@ -2462,6 +3167,7 @@ and generate_ocaml_prototype ?(is_external = false) name style =
function
| String _ -> pr "string -> "
| OptString _ -> pr "string option -> "
+ | StringList _ -> pr "string array -> "
| Bool _ -> pr "bool -> "
| Int _ -> pr "int -> "
) (snd style);
@@ -2477,7 +3183,12 @@ and generate_ocaml_prototype ?(is_external = false) name style =
| RVGList _ -> pr "lvm_vg array"
| RLVList _ -> pr "lvm_lv array"
);
- if is_external then pr " = \"ocaml_guestfs_%s\"" name;
+ if is_external then (
+ pr " = ";
+ if List.length (snd style) + 1 > 5 then
+ pr "\"ocaml_guestfs_%s_byte\" " name;
+ pr "\"ocaml_guestfs_%s\"" name
+ );
pr "\n"
(* Generate Perl xs code, a sort of crazy variation of C with macros. *)
@@ -2539,6 +3250,35 @@ error_handler (guestfs_h *g,
last_error = strdup (msg);
}
+/* http://www.perlmonks.org/?node_id=680842 */
+static char **
+XS_unpack_charPtrPtr (SV *arg) {
+ char **ret;
+ AV *av;
+ I32 i;
+
+ if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
+ croak (\"array reference expected\");
+ }
+
+ av = (AV *)SvRV (arg);
+ ret = (char **)malloc (av_len (av) + 1 + 1);
+
+ for (i = 0; i <= av_len (av); i++) {
+ SV **elem = av_fetch (av, i, 0);
+
+ if (!elem || !*elem) {
+ croak (\"missing element in list\");
+ }
+
+ ret[i] = SvPV_nolen (*elem);
+ }
+
+ ret[i + 1] = NULL;
+
+ return ret;
+}
+
MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
guestfs_h *
@@ -2581,17 +3321,32 @@ DESTROY (g)
function
| String n -> pr " char *%s;\n" n
| OptString n -> pr " 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
) (snd style);
+
+ let do_cleanups () =
+ List.iter (
+ function
+ | String _
+ | OptString _
+ | Bool _
+ | Int _ -> ()
+ | StringList n -> pr " free (%s);\n" n
+ ) (snd style)
+ in
+
(* Code. *)
(match fst style with
| RErr ->
pr " PPCODE:\n";
pr " if (guestfs_%s " name;
generate_call_args ~handle:"g" style;
- pr " == -1)\n";
- pr " croak (\"%s: %%s\", last_error);\n" name
+ pr " == -1) {\n";
+ do_cleanups ();
+ pr " croak (\"%s: %%s\", last_error);\n" name;
+ pr " }\n"
| RInt n
| RBool n ->
pr "PREINIT:\n";
@@ -2600,8 +3355,10 @@ DESTROY (g)
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (%s == -1)\n" n;
+ pr " if (%s == -1) {\n" n;
+ do_cleanups ();
pr " croak (\"%s: %%s\", last_error);\n" name;
+ pr " }\n";
pr " RETVAL = newSViv (%s);\n" n;
pr " OUTPUT:\n";
pr " RETVAL\n"
@@ -2612,8 +3369,10 @@ DESTROY (g)
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (%s == NULL)\n" n;
+ pr " if (%s == NULL) {\n" n;
+ do_cleanups ();
pr " croak (\"%s: %%s\", last_error);\n" name;
+ pr " }\n";
pr " RETVAL = newSVpv (%s, 0);\n" n;
pr " OUTPUT:\n";
pr " RETVAL\n"
@@ -2624,8 +3383,10 @@ DESTROY (g)
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (%s == NULL)\n" n;
+ pr " if (%s == NULL) {\n" n;
+ do_cleanups ();
pr " croak (\"%s: %%s\", last_error);\n" name;
+ pr " }\n";
pr " RETVAL = newSVpv (%s, 0);\n" n;
pr " free (%s);\n" n;
pr " OUTPUT:\n";
@@ -2638,8 +3399,10 @@ DESTROY (g)
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (%s == NULL)\n" n;
+ pr " if (%s == NULL) {\n" n;
+ do_cleanups ();
pr " croak (\"%s: %%s\", last_error);\n" name;
+ pr " }\n";
pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
pr " EXTEND (SP, n);\n";
pr " for (i = 0; i < n; ++i) {\n";
@@ -2654,8 +3417,10 @@ DESTROY (g)
pr " r = guestfs_%s " name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (r == NULL)\n";
+ pr " if (r == NULL) {\n";
+ do_cleanups ();
pr " croak (\"%s: %%s\", last_error);\n" name;
+ pr " }\n";
pr " EXTEND (SP, 2);\n";
pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
@@ -2667,6 +3432,9 @@ DESTROY (g)
| RLVList n ->
generate_perl_lvm_code "lv" lv_cols name style n;
);
+
+ do_cleanups ();
+
pr "\n"
) all_functions
@@ -2797,9 +3565,9 @@ sub new {
pr "\n\n";
pr "%s\n\n" longdesc;
if List.mem ProtocolLimitWarning flags then
- pr "Because of the message protocol, there is a transfer limit
-of somewhere between 2MB and 4MB. To transfer large files you should use
-FTP.\n\n";
+ pr "%s\n\n" protocol_limit_warning;
+ if List.mem DangerWillRobinson flags then
+ pr "%s\n\n" danger_will_robinson
) all_functions_sorted;
(* End of file. *)
@@ -2844,7 +3612,11 @@ and generate_perl_prototype name style =
fun arg ->
if !comma then pr ", ";
comma := true;
- pr "%s" (name_of_argt arg)
+ match arg with
+ | String n | OptString n | Bool n | Int n ->
+ pr "$%s" n
+ | StringList n ->
+ pr "\\@%s" n
) (snd style);
pr ");"
diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c
index 25892cd0..669ca767 100644
--- a/src/guestfs-actions.c
+++ b/src/guestfs-actions.c
@@ -2540,3 +2540,934 @@ int guestfs_chown (guestfs_h *g,
return 0;
}
+struct exists_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_exists_ret ret;
+};
+
+static void exists_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct exists_rv *rv = (struct exists_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_exists: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_exists: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_exists_ret (xdr, &rv->ret)) {
+ error (g, "guestfs_exists: failed to parse reply");
+ return;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_exists (guestfs_h *g,
+ const char *path)
+{
+ struct guestfs_exists_args args;
+ struct exists_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_exists called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.path = (char *) path;
+ serial = dispatch (g, GUESTFS_PROC_EXISTS,
+ (xdrproc_t) xdr_guestfs_exists_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = exists_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_exists failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_EXISTS, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return rv.ret.existsflag;
+}
+
+struct is_file_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_is_file_ret ret;
+};
+
+static void is_file_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct is_file_rv *rv = (struct is_file_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_is_file: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_is_file: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_is_file_ret (xdr, &rv->ret)) {
+ error (g, "guestfs_is_file: failed to parse reply");
+ return;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_is_file (guestfs_h *g,
+ const char *path)
+{
+ struct guestfs_is_file_args args;
+ struct is_file_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_is_file called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.path = (char *) path;
+ serial = dispatch (g, GUESTFS_PROC_IS_FILE,
+ (xdrproc_t) xdr_guestfs_is_file_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = is_file_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_is_file failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_IS_FILE, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return rv.ret.fileflag;
+}
+
+struct is_dir_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_is_dir_ret ret;
+};
+
+static void is_dir_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct is_dir_rv *rv = (struct is_dir_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_is_dir: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_is_dir: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_is_dir_ret (xdr, &rv->ret)) {
+ error (g, "guestfs_is_dir: failed to parse reply");
+ return;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_is_dir (guestfs_h *g,
+ const char *path)
+{
+ struct guestfs_is_dir_args args;
+ struct is_dir_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_is_dir called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.path = (char *) path;
+ serial = dispatch (g, GUESTFS_PROC_IS_DIR,
+ (xdrproc_t) xdr_guestfs_is_dir_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = is_dir_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_is_dir failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_IS_DIR, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return rv.ret.dirflag;
+}
+
+struct pvcreate_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void pvcreate_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct pvcreate_rv *rv = (struct pvcreate_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_pvcreate: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_pvcreate: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_pvcreate (guestfs_h *g,
+ const char *device)
+{
+ struct guestfs_pvcreate_args args;
+ struct pvcreate_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_pvcreate called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.device = (char *) device;
+ serial = dispatch (g, GUESTFS_PROC_PVCREATE,
+ (xdrproc_t) xdr_guestfs_pvcreate_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = pvcreate_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_pvcreate failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_PVCREATE, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+struct vgcreate_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void vgcreate_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct vgcreate_rv *rv = (struct vgcreate_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_vgcreate: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_vgcreate: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_vgcreate (guestfs_h *g,
+ const char *volgroup,
+ char * const* const physvols)
+{
+ struct guestfs_vgcreate_args args;
+ struct vgcreate_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_vgcreate called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.volgroup = (char *) volgroup;
+ args.physvols.physvols_val = (char **) physvols;
+ for (args.physvols.physvols_len = 0; physvols[args.physvols.physvols_len]; args.physvols.physvols_len++) ;
+ serial = dispatch (g, GUESTFS_PROC_VGCREATE,
+ (xdrproc_t) xdr_guestfs_vgcreate_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = vgcreate_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_vgcreate failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_VGCREATE, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+struct lvcreate_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void lvcreate_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct lvcreate_rv *rv = (struct lvcreate_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_lvcreate: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_lvcreate: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_lvcreate (guestfs_h *g,
+ const char *logvol,
+ const char *volgroup,
+ int mbytes)
+{
+ struct guestfs_lvcreate_args args;
+ struct lvcreate_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_lvcreate called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.logvol = (char *) logvol;
+ args.volgroup = (char *) volgroup;
+ args.mbytes = mbytes;
+ serial = dispatch (g, GUESTFS_PROC_LVCREATE,
+ (xdrproc_t) xdr_guestfs_lvcreate_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = lvcreate_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_lvcreate failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVCREATE, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+struct mkfs_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void mkfs_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct mkfs_rv *rv = (struct mkfs_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_mkfs: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_mkfs: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_mkfs (guestfs_h *g,
+ const char *fstype,
+ const char *device)
+{
+ struct guestfs_mkfs_args args;
+ struct mkfs_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_mkfs called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.fstype = (char *) fstype;
+ args.device = (char *) device;
+ serial = dispatch (g, GUESTFS_PROC_MKFS,
+ (xdrproc_t) xdr_guestfs_mkfs_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = mkfs_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_mkfs failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MKFS, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+struct sfdisk_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void sfdisk_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct sfdisk_rv *rv = (struct sfdisk_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_sfdisk: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_sfdisk: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_sfdisk (guestfs_h *g,
+ const char *device,
+ int cyls,
+ int heads,
+ int sectors,
+ char * const* const lines)
+{
+ struct guestfs_sfdisk_args args;
+ struct sfdisk_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_sfdisk called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.device = (char *) device;
+ args.cyls = cyls;
+ args.heads = heads;
+ args.sectors = sectors;
+ args.lines.lines_val = (char **) lines;
+ for (args.lines.lines_len = 0; lines[args.lines.lines_len]; args.lines.lines_len++) ;
+ serial = dispatch (g, GUESTFS_PROC_SFDISK,
+ (xdrproc_t) xdr_guestfs_sfdisk_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = sfdisk_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_sfdisk failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_SFDISK, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+struct write_file_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void write_file_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct write_file_rv *rv = (struct write_file_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_write_file: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_write_file: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_write_file (guestfs_h *g,
+ const char *path,
+ const char *content,
+ int size)
+{
+ struct guestfs_write_file_args args;
+ struct write_file_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_write_file called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.path = (char *) path;
+ args.content = (char *) content;
+ args.size = size;
+ serial = dispatch (g, GUESTFS_PROC_WRITE_FILE,
+ (xdrproc_t) xdr_guestfs_write_file_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = write_file_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_write_file failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_WRITE_FILE, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+struct umount_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void umount_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct umount_rv *rv = (struct umount_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_umount: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_umount: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_umount (guestfs_h *g,
+ const char *pathordevice)
+{
+ struct guestfs_umount_args args;
+ struct umount_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_umount called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.pathordevice = (char *) pathordevice;
+ serial = dispatch (g, GUESTFS_PROC_UMOUNT,
+ (xdrproc_t) xdr_guestfs_umount_args, (char *) &args);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = umount_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_umount failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_UMOUNT, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+struct mounts_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_mounts_ret ret;
+};
+
+static void mounts_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct mounts_rv *rv = (struct mounts_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_mounts: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_mounts: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_mounts_ret (xdr, &rv->ret)) {
+ error (g, "guestfs_mounts: failed to parse reply");
+ return;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+char **guestfs_mounts (guestfs_h *g)
+{
+ struct mounts_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_mounts called from the wrong state, %d != READY",
+ g->state);
+ return NULL;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ serial = dispatch (g, GUESTFS_PROC_MOUNTS, NULL, NULL);
+ if (serial == -1)
+ return NULL;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = mounts_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_mounts failed, see earlier error messages");
+ return NULL;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MOUNTS, serial) == -1)
+ return NULL;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return NULL;
+ }
+
+ /* caller will free this, but we need to add a NULL entry */
+ rv.ret.devices.devices_val = safe_realloc (g, rv.ret.devices.devices_val,
+ sizeof (char *) * (rv.ret.devices.devices_len + 1));
+ rv.ret.devices.devices_val[rv.ret.devices.devices_len] = NULL;
+ return rv.ret.devices.devices_val;
+}
+
+struct umount_all_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void umount_all_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct umount_all_rv *rv = (struct umount_all_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_umount_all: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_umount_all: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_umount_all (guestfs_h *g)
+{
+ struct umount_all_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_umount_all called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ serial = dispatch (g, GUESTFS_PROC_UMOUNT_ALL, NULL, NULL);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = umount_all_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_umount_all failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_UMOUNT_ALL, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
+struct lvm_remove_all_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+};
+
+static void lvm_remove_all_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct lvm_remove_all_rv *rv = (struct lvm_remove_all_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_lvm_remove_all: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_lvm_remove_all: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+int guestfs_lvm_remove_all (guestfs_h *g)
+{
+ struct lvm_remove_all_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_lvm_remove_all called from the wrong state, %d != READY",
+ g->state);
+ return -1;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ serial = dispatch (g, GUESTFS_PROC_LVM_REMOVE_ALL, NULL, NULL);
+ if (serial == -1)
+ return -1;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = lvm_remove_all_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_lvm_remove_all failed, see earlier error messages");
+ return -1;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVM_REMOVE_ALL, serial) == -1)
+ return -1;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h
index 06f1485b..d40ef150 100644
--- a/src/guestfs-actions.h
+++ b/src/guestfs-actions.h
@@ -66,3 +66,16 @@ extern int guestfs_mkdir (guestfs_h *handle, const char *path);
extern int guestfs_mkdir_p (guestfs_h *handle, const char *path);
extern int guestfs_chmod (guestfs_h *handle, int mode, const char *path);
extern int guestfs_chown (guestfs_h *handle, int owner, int group, const char *path);
+extern int guestfs_exists (guestfs_h *handle, const char *path);
+extern int guestfs_is_file (guestfs_h *handle, const char *path);
+extern int guestfs_is_dir (guestfs_h *handle, const char *path);
+extern int guestfs_pvcreate (guestfs_h *handle, const char *device);
+extern int guestfs_vgcreate (guestfs_h *handle, const char *volgroup, char * const* const physvols);
+extern int guestfs_lvcreate (guestfs_h *handle, const char *logvol, const char *volgroup, int mbytes);
+extern int guestfs_mkfs (guestfs_h *handle, const char *fstype, const char *device);
+extern int guestfs_sfdisk (guestfs_h *handle, const char *device, int cyls, int heads, int sectors, char * const* const lines);
+extern int guestfs_write_file (guestfs_h *handle, const char *path, const char *content, int size);
+extern int guestfs_umount (guestfs_h *handle, const char *pathordevice);
+extern char **guestfs_mounts (guestfs_h *handle);
+extern int guestfs_umount_all (guestfs_h *handle);
+extern int guestfs_lvm_remove_all (guestfs_h *handle);
diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c
index 781c2daf..8e868126 100644
--- a/src/guestfs_protocol.c
+++ b/src/guestfs_protocol.c
@@ -619,6 +619,214 @@ xdr_guestfs_chown_args (XDR *xdrs, guestfs_chown_args *objp)
}
bool_t
+xdr_guestfs_exists_args (XDR *xdrs, guestfs_exists_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->path, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_exists_ret (XDR *xdrs, guestfs_exists_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_bool (xdrs, &objp->existsflag))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_is_file_args (XDR *xdrs, guestfs_is_file_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->path, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_is_file_ret (XDR *xdrs, guestfs_is_file_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_bool (xdrs, &objp->fileflag))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_is_dir_args (XDR *xdrs, guestfs_is_dir_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->path, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_is_dir_ret (XDR *xdrs, guestfs_is_dir_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_bool (xdrs, &objp->dirflag))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_pvcreate_args (XDR *xdrs, guestfs_pvcreate_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->device, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_vgcreate_args (XDR *xdrs, guestfs_vgcreate_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->volgroup, ~0))
+ return FALSE;
+ if (!xdr_array (xdrs, (char **)&objp->physvols.physvols_val, (u_int *) &objp->physvols.physvols_len, ~0,
+ sizeof (str), (xdrproc_t) xdr_str))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_lvcreate_args (XDR *xdrs, guestfs_lvcreate_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->logvol, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->volgroup, ~0))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->mbytes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_mkfs_args (XDR *xdrs, guestfs_mkfs_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->fstype, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->device, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_sfdisk_args (XDR *xdrs, guestfs_sfdisk_args *objp)
+{
+ register int32_t *buf;
+
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!xdr_string (xdrs, &objp->device, ~0))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->cyls))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->heads))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->sectors))
+ return FALSE;
+
+ } else {
+ IXDR_PUT_LONG(buf, objp->cyls);
+ IXDR_PUT_LONG(buf, objp->heads);
+ IXDR_PUT_LONG(buf, objp->sectors);
+ }
+ if (!xdr_array (xdrs, (char **)&objp->lines.lines_val, (u_int *) &objp->lines.lines_len, ~0,
+ sizeof (str), (xdrproc_t) xdr_str))
+ return FALSE;
+ return TRUE;
+ } else if (xdrs->x_op == XDR_DECODE) {
+ if (!xdr_string (xdrs, &objp->device, ~0))
+ return FALSE;
+ buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_int (xdrs, &objp->cyls))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->heads))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->sectors))
+ return FALSE;
+
+ } else {
+ objp->cyls = IXDR_GET_LONG(buf);
+ objp->heads = IXDR_GET_LONG(buf);
+ objp->sectors = IXDR_GET_LONG(buf);
+ }
+ if (!xdr_array (xdrs, (char **)&objp->lines.lines_val, (u_int *) &objp->lines.lines_len, ~0,
+ sizeof (str), (xdrproc_t) xdr_str))
+ return FALSE;
+ return TRUE;
+ }
+
+ if (!xdr_string (xdrs, &objp->device, ~0))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->cyls))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->heads))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->sectors))
+ return FALSE;
+ if (!xdr_array (xdrs, (char **)&objp->lines.lines_val, (u_int *) &objp->lines.lines_len, ~0,
+ sizeof (str), (xdrproc_t) xdr_str))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_write_file_args (XDR *xdrs, guestfs_write_file_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->path, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->content, ~0))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->size))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_umount_args (XDR *xdrs, guestfs_umount_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->pathordevice, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_mounts_ret (XDR *xdrs, guestfs_mounts_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->devices.devices_val, (u_int *) &objp->devices.devices_len, ~0,
+ sizeof (str), (xdrproc_t) xdr_str))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
{
register int32_t *buf;
diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h
index 508bc4e3..fedd0074 100644
--- a/src/guestfs_protocol.h
+++ b/src/guestfs_protocol.h
@@ -337,6 +337,95 @@ struct guestfs_chown_args {
};
typedef struct guestfs_chown_args guestfs_chown_args;
+struct guestfs_exists_args {
+ char *path;
+};
+typedef struct guestfs_exists_args guestfs_exists_args;
+
+struct guestfs_exists_ret {
+ bool_t existsflag;
+};
+typedef struct guestfs_exists_ret guestfs_exists_ret;
+
+struct guestfs_is_file_args {
+ char *path;
+};
+typedef struct guestfs_is_file_args guestfs_is_file_args;
+
+struct guestfs_is_file_ret {
+ bool_t fileflag;
+};
+typedef struct guestfs_is_file_ret guestfs_is_file_ret;
+
+struct guestfs_is_dir_args {
+ char *path;
+};
+typedef struct guestfs_is_dir_args guestfs_is_dir_args;
+
+struct guestfs_is_dir_ret {
+ bool_t dirflag;
+};
+typedef struct guestfs_is_dir_ret guestfs_is_dir_ret;
+
+struct guestfs_pvcreate_args {
+ char *device;
+};
+typedef struct guestfs_pvcreate_args guestfs_pvcreate_args;
+
+struct guestfs_vgcreate_args {
+ char *volgroup;
+ struct {
+ u_int physvols_len;
+ str *physvols_val;
+ } physvols;
+};
+typedef struct guestfs_vgcreate_args guestfs_vgcreate_args;
+
+struct guestfs_lvcreate_args {
+ char *logvol;
+ char *volgroup;
+ int mbytes;
+};
+typedef struct guestfs_lvcreate_args guestfs_lvcreate_args;
+
+struct guestfs_mkfs_args {
+ char *fstype;
+ char *device;
+};
+typedef struct guestfs_mkfs_args guestfs_mkfs_args;
+
+struct guestfs_sfdisk_args {
+ char *device;
+ int cyls;
+ int heads;
+ int sectors;
+ struct {
+ u_int lines_len;
+ str *lines_val;
+ } lines;
+};
+typedef struct guestfs_sfdisk_args guestfs_sfdisk_args;
+
+struct guestfs_write_file_args {
+ char *path;
+ char *content;
+ int size;
+};
+typedef struct guestfs_write_file_args guestfs_write_file_args;
+
+struct guestfs_umount_args {
+ char *pathordevice;
+};
+typedef struct guestfs_umount_args guestfs_umount_args;
+
+struct guestfs_mounts_ret {
+ struct {
+ u_int devices_len;
+ str *devices_val;
+ } devices;
+};
+typedef struct guestfs_mounts_ret guestfs_mounts_ret;
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -373,7 +462,20 @@ enum guestfs_procedure {
GUESTFS_PROC_MKDIR_P = 33,
GUESTFS_PROC_CHMOD = 34,
GUESTFS_PROC_CHOWN = 35,
- GUESTFS_PROC_dummy = 35 + 1,
+ GUESTFS_PROC_EXISTS = 36,
+ GUESTFS_PROC_IS_FILE = 37,
+ GUESTFS_PROC_IS_DIR = 38,
+ GUESTFS_PROC_PVCREATE = 39,
+ GUESTFS_PROC_VGCREATE = 40,
+ GUESTFS_PROC_LVCREATE = 41,
+ GUESTFS_PROC_MKFS = 42,
+ GUESTFS_PROC_SFDISK = 43,
+ GUESTFS_PROC_WRITE_FILE = 44,
+ GUESTFS_PROC_UMOUNT = 45,
+ GUESTFS_PROC_MOUNTS = 46,
+ GUESTFS_PROC_UMOUNT_ALL = 47,
+ GUESTFS_PROC_LVM_REMOVE_ALL = 48,
+ GUESTFS_PROC_dummy = 48 + 1,
};
typedef enum guestfs_procedure guestfs_procedure;
#define GUESTFS_MESSAGE_MAX 4194304
@@ -459,6 +561,20 @@ extern bool_t xdr_guestfs_mkdir_args (XDR *, guestfs_mkdir_args*);
extern bool_t xdr_guestfs_mkdir_p_args (XDR *, guestfs_mkdir_p_args*);
extern bool_t xdr_guestfs_chmod_args (XDR *, guestfs_chmod_args*);
extern bool_t xdr_guestfs_chown_args (XDR *, guestfs_chown_args*);
+extern bool_t xdr_guestfs_exists_args (XDR *, guestfs_exists_args*);
+extern bool_t xdr_guestfs_exists_ret (XDR *, guestfs_exists_ret*);
+extern bool_t xdr_guestfs_is_file_args (XDR *, guestfs_is_file_args*);
+extern bool_t xdr_guestfs_is_file_ret (XDR *, guestfs_is_file_ret*);
+extern bool_t xdr_guestfs_is_dir_args (XDR *, guestfs_is_dir_args*);
+extern bool_t xdr_guestfs_is_dir_ret (XDR *, guestfs_is_dir_ret*);
+extern bool_t xdr_guestfs_pvcreate_args (XDR *, guestfs_pvcreate_args*);
+extern bool_t xdr_guestfs_vgcreate_args (XDR *, guestfs_vgcreate_args*);
+extern bool_t xdr_guestfs_lvcreate_args (XDR *, guestfs_lvcreate_args*);
+extern bool_t xdr_guestfs_mkfs_args (XDR *, guestfs_mkfs_args*);
+extern bool_t xdr_guestfs_sfdisk_args (XDR *, guestfs_sfdisk_args*);
+extern bool_t xdr_guestfs_write_file_args (XDR *, guestfs_write_file_args*);
+extern bool_t xdr_guestfs_umount_args (XDR *, guestfs_umount_args*);
+extern bool_t xdr_guestfs_mounts_ret (XDR *, guestfs_mounts_ret*);
extern bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*);
extern bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*);
extern bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
@@ -514,6 +630,20 @@ extern bool_t xdr_guestfs_mkdir_args ();
extern bool_t xdr_guestfs_mkdir_p_args ();
extern bool_t xdr_guestfs_chmod_args ();
extern bool_t xdr_guestfs_chown_args ();
+extern bool_t xdr_guestfs_exists_args ();
+extern bool_t xdr_guestfs_exists_ret ();
+extern bool_t xdr_guestfs_is_file_args ();
+extern bool_t xdr_guestfs_is_file_ret ();
+extern bool_t xdr_guestfs_is_dir_args ();
+extern bool_t xdr_guestfs_is_dir_ret ();
+extern bool_t xdr_guestfs_pvcreate_args ();
+extern bool_t xdr_guestfs_vgcreate_args ();
+extern bool_t xdr_guestfs_lvcreate_args ();
+extern bool_t xdr_guestfs_mkfs_args ();
+extern bool_t xdr_guestfs_sfdisk_args ();
+extern bool_t xdr_guestfs_write_file_args ();
+extern bool_t xdr_guestfs_umount_args ();
+extern bool_t xdr_guestfs_mounts_ret ();
extern bool_t xdr_guestfs_procedure ();
extern bool_t xdr_guestfs_message_direction ();
extern bool_t xdr_guestfs_message_status ();
diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x
index 41116b53..c547d0b3 100644
--- a/src/guestfs_protocol.x
+++ b/src/guestfs_protocol.x
@@ -262,6 +262,72 @@ struct guestfs_chown_args {
string path<>;
};
+struct guestfs_exists_args {
+ string path<>;
+};
+
+struct guestfs_exists_ret {
+ bool existsflag;
+};
+
+struct guestfs_is_file_args {
+ string path<>;
+};
+
+struct guestfs_is_file_ret {
+ bool fileflag;
+};
+
+struct guestfs_is_dir_args {
+ string path<>;
+};
+
+struct guestfs_is_dir_ret {
+ bool dirflag;
+};
+
+struct guestfs_pvcreate_args {
+ string device<>;
+};
+
+struct guestfs_vgcreate_args {
+ string volgroup<>;
+ str physvols<>;
+};
+
+struct guestfs_lvcreate_args {
+ string logvol<>;
+ string volgroup<>;
+ int mbytes;
+};
+
+struct guestfs_mkfs_args {
+ string fstype<>;
+ string device<>;
+};
+
+struct guestfs_sfdisk_args {
+ string device<>;
+ int cyls;
+ int heads;
+ int sectors;
+ str lines<>;
+};
+
+struct guestfs_write_file_args {
+ string path<>;
+ string content<>;
+ int size;
+};
+
+struct guestfs_umount_args {
+ string pathordevice<>;
+};
+
+struct guestfs_mounts_ret {
+ str devices<>;
+};
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -298,6 +364,19 @@ enum guestfs_procedure {
GUESTFS_PROC_MKDIR_P = 33,
GUESTFS_PROC_CHMOD = 34,
GUESTFS_PROC_CHOWN = 35,
+ GUESTFS_PROC_EXISTS = 36,
+ GUESTFS_PROC_IS_FILE = 37,
+ GUESTFS_PROC_IS_DIR = 38,
+ GUESTFS_PROC_PVCREATE = 39,
+ GUESTFS_PROC_VGCREATE = 40,
+ GUESTFS_PROC_LVCREATE = 41,
+ GUESTFS_PROC_MKFS = 42,
+ GUESTFS_PROC_SFDISK = 43,
+ GUESTFS_PROC_WRITE_FILE = 44,
+ GUESTFS_PROC_UMOUNT = 45,
+ GUESTFS_PROC_MOUNTS = 46,
+ GUESTFS_PROC_UMOUNT_ALL = 47,
+ GUESTFS_PROC_LVM_REMOVE_ALL = 48,
GUESTFS_PROC_dummy
};