X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fgenerator.ml;h=4c8c2e1bdd87612e3004375421d948f800505eaf;hb=76758f42b1abc89d5857697c87ead5036ed81b13;hp=6ef8e1b3435cd28d1f83abe4001a31d14ca5a507;hpb=d268e64fe76944dc042e7ec68a65e59a6cff16ce;p=libguestfs.git
diff --git a/src/generator.ml b/src/generator.ml
index 6ef8e1b..4c8c2e1 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -33,6 +33,7 @@
*)
#load "unix.cma";;
+#load "str.cma";;
open Printf
@@ -43,9 +44,15 @@ and ret =
*)
| RErr
(* "RInt" as a return value means an int which is -1 for error
- * or any value >= 0 on success.
+ * or any value >= 0 on success. Only use this for smallish
+ * positive ints (0 <= i < 2^30).
*)
| RInt of string
+ (* "RInt64" is the same as RInt, but is guaranteed to be able
+ * to return a full 64 bit value, _except_ that -1 means error
+ * (so -1 cannot be a valid, non-error return value).
+ *)
+ | RInt64 of string
(* "RBool" is a bool return value which can be true/false or
* -1 for error.
*)
@@ -65,6 +72,18 @@ and ret =
| RPVList of string
| RVGList of string
| RLVList of string
+ (* Stat buffers. *)
+ | RStat of string
+ | RStatVFS of string
+ (* Key-value pairs of untyped strings. Turns into a hashtable or
+ * dictionary in languages which support it. DON'T use this as a
+ * general "bucket" for results. Prefer a stronger typed return
+ * value if one is available, or write a custom struct. Don't use
+ * this if the list could potentially be very long, since it is
+ * inefficient. Keys should be unique. NULLs are not permitted.
+ *)
+ | RHashtable of string
+
and args = argt list (* Function parameters, guestfs handle is implicit. *)
(* Note in future we should allow a "variable args" parameter as
@@ -80,6 +99,16 @@ and argt =
| StringList of string(* list of strings (each string cannot be NULL) *)
| Bool of string (* boolean *)
| Int of string (* int (smallish ints, signed, <= 31 bits) *)
+ (* These are treated as filenames (simple string parameters) in
+ * the C API and bindings. But in the RPC protocol, we transfer
+ * the actual file content up to or down from the daemon.
+ * FileIn: local machine -> daemon (in request)
+ * FileOut: daemon -> local machine (in reply)
+ * In guestfish (only), the special name "-" means read from
+ * stdin or write to stdout.
+ *)
+ | FileIn of string
+ | FileOut of string
type flags =
| ProtocolLimitWarning (* display warning about protocol size limits *)
@@ -107,7 +136,7 @@ can easily destroy all your data>."
* the virtual machine and block devices are reused between tests.
* So don't try testing kill_subprocess :-x
*
- * Between each test we umount-all and lvm-remove-all.
+ * Between each test we umount-all and lvm-remove-all (except InitNone).
*
* Don't assume anything about the previous contents of the block
* devices. Use 'Init*' to create some initial scenarios.
@@ -141,11 +170,21 @@ and test =
* content).
*)
| TestOutputLength of seq * int
+ (* Run the command sequence and expect the output of the final
+ * command to be a structure.
+ *)
+ | TestOutputStruct of seq * test_field_compare list
(* Run the command sequence and expect the final command (only)
* to fail.
*)
| TestLastFail of seq
+and test_field_compare =
+ | CompareWithInt of string * int
+ | CompareWithString of string * string
+ | CompareFieldsIntEq of string * string
+ | CompareFieldsStrEq of string * string
+
(* Some initial scenarios for testing. *)
and test_init =
(* Do nothing, block devices could contain random stuff including
@@ -246,6 +285,32 @@ The first character of C string must be a C<-> (dash).
C can be NULL.");
+ ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
+ [],
+ "set the qemu binary",
+ "\
+Set the qemu binary that we will use.
+
+The default is chosen when the library was compiled by the
+configure script.
+
+You can also override this by setting the C
+environment variable.
+
+The string C is stashed in the libguestfs handle, so the caller
+must make sure it remains valid for the lifetime of the handle.
+
+Setting C to C restores the default qemu binary.");
+
+ ("get_qemu", (RConstString "qemu", []), -1, [],
+ [],
+ "get the qemu binary",
+ "\
+Return the current qemu binary.
+
+This is always non-NULL. If it wasn't set already, then this will
+return the default qemu binary name.");
+
("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
[],
"set the search path",
@@ -274,8 +339,12 @@ return the default path.");
"set autosync mode",
"\
If C is true, this enables autosync. Libguestfs will make a
-best effort attempt to run C when the handle is closed
-(also if the program exits without closing handles).");
+best effort attempt to run C followed by
+C when the handle is closed
+(also if the program exits without closing handles).
+
+This is disabled by default (except in guestfish where it is
+enabled by default).");
("get_autosync", (RBool "autosync", []), -1, [],
[],
@@ -296,7 +365,71 @@ C is defined and set to C<1>.");
[],
"get verbose mode",
"\
-This returns the verbose messages flag.")
+This returns the verbose messages flag.");
+
+ ("is_ready", (RBool "ready", []), -1, [],
+ [],
+ "is ready to accept commands",
+ "\
+This returns true iff this handle is ready to accept commands
+(in the C state).
+
+For more information on states, see L.");
+
+ ("is_config", (RBool "config", []), -1, [],
+ [],
+ "is in configuration state",
+ "\
+This returns true iff this handle is being configured
+(in the C state).
+
+For more information on states, see L.");
+
+ ("is_launching", (RBool "launching", []), -1, [],
+ [],
+ "is launching subprocess",
+ "\
+This returns true iff this handle is launching the subprocess
+(in the C state).
+
+For more information on states, see L.");
+
+ ("is_busy", (RBool "busy", []), -1, [],
+ [],
+ "is busy processing a command",
+ "\
+This returns true iff this handle is busy processing a command
+(in the C state).
+
+For more information on states, see L.");
+
+ ("get_state", (RInt "state", []), -1, [],
+ [],
+ "get the current state",
+ "\
+This returns the current state as an opaque integer. This is
+only useful for printing debug and internal error messages.
+
+For more information on states, see L.");
+
+ ("set_busy", (RErr, []), -1, [NotInFish],
+ [],
+ "set state to busy",
+ "\
+This sets the state to C. This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L.");
+
+ ("set_ready", (RErr, []), -1, [NotInFish],
+ [],
+ "set state to ready",
+ "\
+This sets the state to C. This is only used when implementing
+actions using the low-level API.
+
+For more information on states, see L.");
+
]
let daemon_functions = [
@@ -356,7 +489,7 @@ Return the contents of the file named C.
Note that this function cannot correctly handle binary files
(specifically, files containing C<\\0> character which is treated
-as end of string). For those you need to use the C
+as end of string). For those you need to use the C
function which has a more complex interface.");
("ll", (RString "listing", [String "directory"]), 5, [],
@@ -475,24 +608,21 @@ This returns a list of the logical volume device names
See also C.");
("pvs_full", (RPVList "physvols", []), 12, [],
- [InitBasicFSonLVM, TestOutputLength (
- [["pvs"]], 1)],
+ [], (* XXX how to test? *)
"list the LVM physical volumes (PVs)",
"\
List all the physical volumes detected. This is the equivalent
of the L command. The \"full\" version includes all fields.");
("vgs_full", (RVGList "volgroups", []), 13, [],
- [InitBasicFSonLVM, TestOutputLength (
- [["pvs"]], 1)],
+ [], (* XXX how to test? *)
"list the LVM volume groups (VGs)",
"\
List all the volumes groups detected. This is the equivalent
of the L command. The \"full\" version includes all fields.");
("lvs_full", (RLVList "logvols", []), 14, [],
- [InitBasicFSonLVM, TestOutputLength (
- [["pvs"]], 1)],
+ [], (* XXX how to test? *)
"list the LVM logical volumes (LVs)",
"\
List all the logical volumes detected. This is the equivalent
@@ -859,7 +989,7 @@ on the volume group C, with C megabytes.");
"make a filesystem",
"\
This creates a filesystem on C (usually a partition
-of LVM logical volume). The filesystem type is C, for
+or LVM logical volume). The filesystem type is C, for
example C.");
("sfdisk", (RErr, [String "device";
@@ -889,12 +1019,24 @@ pass C as a single element list, when the single element being
the string C<,> (comma).");
("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
- [InitEmpty, TestOutput (
- [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
- ["mkfs"; "ext2"; "/dev/sda1"];
- ["mount"; "/dev/sda1"; "/"];
- ["write_file"; "/new"; "new file contents"; "0"];
- ["cat"; "/new"]], "new file contents")],
+ [InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "new file contents"; "0"];
+ ["cat"; "/new"]], "new file contents");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "\nnew file contents\n"; "0"];
+ ["cat"; "/new"]], "\nnew file contents\n");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "\n\n"; "0"];
+ ["cat"; "/new"]], "\n\n");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; ""; "0"];
+ ["cat"; "/new"]], "");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "\n\n\n"; "0"];
+ ["cat"; "/new"]], "\n\n\n");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "\n"; "0"];
+ ["cat"; "/new"]], "\n")],
"create a file",
"\
This call creates a file called C. The contents of the
@@ -936,6 +1078,20 @@ Some internal mounts are not shown.");
("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
[InitBasicFS, TestOutputList (
[["umount_all"];
+ ["mounts"]], []);
+ (* check that umount_all can unmount nested mounts correctly: *)
+ InitEmpty, TestOutputList (
+ [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"];
+ ["mkfs"; "ext2"; "/dev/sda1"];
+ ["mkfs"; "ext2"; "/dev/sda2"];
+ ["mkfs"; "ext2"; "/dev/sda3"];
+ ["mount"; "/dev/sda1"; "/"];
+ ["mkdir"; "/mp1"];
+ ["mount"; "/dev/sda2"; "/mp1"];
+ ["mkdir"; "/mp1/mp2"];
+ ["mount"; "/dev/sda3"; "/mp1/mp2"];
+ ["mkdir"; "/mp1/mp2/mp3"];
+ ["umount_all"];
["mounts"]], [])],
"unmount all filesystems",
"\
@@ -1001,1359 +1157,2351 @@ locations.");
This is the same as C, but splits the
result into a list of lines.");
-]
+ ("stat", (RStat "statbuf", [String "path"]), 52, [],
+ [InitBasicFS, TestOutputStruct (
+ [["touch"; "/new"];
+ ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
+ "get file information",
+ "\
+Returns file information for the given C.
-let all_functions = non_daemon_functions @ daemon_functions
+This is the same as the C system call.");
-(* In some places we want the functions to be displayed sorted
- * alphabetically, so this is useful:
- *)
-let all_functions_sorted =
- List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
- compare n1 n2) all_functions
+ ("lstat", (RStat "statbuf", [String "path"]), 53, [],
+ [InitBasicFS, TestOutputStruct (
+ [["touch"; "/new"];
+ ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
+ "get file information for a symbolic link",
+ "\
+Returns file information for the given C.
-(* Column names and types from LVM PVs/VGs/LVs. *)
-let pv_cols = [
- "pv_name", `String;
- "pv_uuid", `UUID;
- "pv_fmt", `String;
- "pv_size", `Bytes;
- "dev_size", `Bytes;
- "pv_free", `Bytes;
- "pv_used", `Bytes;
- "pv_attr", `String (* XXX *);
- "pv_pe_count", `Int;
- "pv_pe_alloc_count", `Int;
- "pv_tags", `String;
- "pe_start", `Bytes;
- "pv_mda_count", `Int;
- "pv_mda_free", `Bytes;
-(* Not in Fedora 10:
- "pv_mda_size", `Bytes;
-*)
-]
-let vg_cols = [
- "vg_name", `String;
- "vg_uuid", `UUID;
- "vg_fmt", `String;
- "vg_attr", `String (* XXX *);
- "vg_size", `Bytes;
- "vg_free", `Bytes;
- "vg_sysid", `String;
- "vg_extent_size", `Bytes;
- "vg_extent_count", `Int;
- "vg_free_count", `Int;
- "max_lv", `Int;
- "max_pv", `Int;
- "pv_count", `Int;
- "lv_count", `Int;
- "snap_count", `Int;
- "vg_seqno", `Int;
- "vg_tags", `String;
- "vg_mda_count", `Int;
- "vg_mda_free", `Bytes;
-(* Not in Fedora 10:
- "vg_mda_size", `Bytes;
-*)
-]
-let lv_cols = [
- "lv_name", `String;
- "lv_uuid", `UUID;
- "lv_attr", `String (* XXX *);
- "lv_major", `Int;
- "lv_minor", `Int;
- "lv_kernel_major", `Int;
- "lv_kernel_minor", `Int;
- "lv_size", `Bytes;
- "seg_count", `Int;
- "origin", `String;
- "snap_percent", `OptPercent;
- "copy_percent", `OptPercent;
- "move_pv", `String;
- "lv_tags", `String;
- "mirror_log", `String;
- "modules", `String;
-]
+This is the same as C except that if C
+is a symbolic link, then the link is stat-ed, not the file it
+refers to.
-(* Useful functions.
- * Note we don't want to use any external OCaml libraries which
- * makes this a bit harder than it should be.
- *)
-let failwithf fs = ksprintf failwith fs
+This is the same as the C system call.");
-let replace_char s c1 c2 =
- let s2 = String.copy s in
- let r = ref false in
- for i = 0 to String.length s2 - 1 do
- if String.unsafe_get s2 i = c1 then (
- String.unsafe_set s2 i c2;
- r := true
- )
- done;
- if not !r then s else s2
+ ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
+ [InitBasicFS, TestOutputStruct (
+ [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
+ CompareWithInt ("blocks", 490020);
+ CompareWithInt ("bsize", 1024)])],
+ "get file system statistics",
+ "\
+Returns file system statistics for any mounted file system.
+C should be a file or directory in the mounted file system
+(typically it is the mount point itself, but it doesn't need to be).
-let rec find s sub =
- let len = String.length s in
- let sublen = String.length sub in
- let rec loop i =
- if i <= len-sublen then (
- let rec loop2 j =
- if j < sublen then (
- if s.[i+j] = sub.[j] then loop2 (j+1)
- else -1
- ) else
- i (* found *)
- in
- let r = loop2 0 in
- if r = -1 then loop (i+1) else r
- ) else
- -1 (* not found *)
- in
- loop 0
+This is the same as the C system call.");
-let rec replace_str s s1 s2 =
- let len = String.length s in
- let sublen = String.length s1 in
- let i = find s s1 in
- if i = -1 then s
- else (
- let s' = String.sub s 0 i in
- let s'' = String.sub s (i+sublen) (len-i-sublen) in
- s' ^ s2 ^ replace_str s'' s1 s2
- )
+ ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
+ [], (* XXX test *)
+ "get ext2/ext3/ext4 superblock details",
+ "\
+This returns the contents of the ext2, ext3 or ext4 filesystem
+superblock on C.
+
+It is the same as running C. See L
+manpage for more details. The list of fields returned isn't
+clearly defined, and depends on both the version of C
+that libguestfs was built against, and the filesystem itself.");
+
+ ("blockdev_setro", (RErr, [String "device"]), 56, [],
+ [InitEmpty, TestOutputTrue (
+ [["blockdev_setro"; "/dev/sda"];
+ ["blockdev_getro"; "/dev/sda"]])],
+ "set block device to read-only",
+ "\
+Sets the block device named C to read-only.
-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''
- )
+This uses the L command.");
-let rec find_map f = function
- | [] -> raise Not_found
- | x :: xs ->
- match f x with
- | Some y -> y
- | None -> find_map f xs
+ ("blockdev_setrw", (RErr, [String "device"]), 57, [],
+ [InitEmpty, TestOutputFalse (
+ [["blockdev_setrw"; "/dev/sda"];
+ ["blockdev_getro"; "/dev/sda"]])],
+ "set block device to read-write",
+ "\
+Sets the block device named C to read-write.
-let iteri f xs =
- let rec loop i = function
- | [] -> ()
- | x :: xs -> f i x; loop (i+1) xs
- in
- loop 0 xs
+This uses the L command.");
-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
+ ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
+ [InitEmpty, TestOutputTrue (
+ [["blockdev_setro"; "/dev/sda"];
+ ["blockdev_getro"; "/dev/sda"]])],
+ "is block device set to read-only",
+ "\
+Returns a boolean indicating if the block device is read-only
+(true if read-only, false if not).
-let name_of_argt = function
- | String n | OptString n | StringList n | Bool n | Int n -> n
+This uses the L command.");
-(* Check function names etc. for consistency. *)
-let check_functions () =
- let contains_uppercase str =
- let len = String.length str in
- let rec loop i =
- if i >= len then false
- else (
- let c = str.[i] in
- if c >= 'A' && c <= 'Z' then true
- else loop (i+1)
- )
- in
- loop 0
- in
+ ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
+ [InitEmpty, TestOutputInt (
+ [["blockdev_getss"; "/dev/sda"]], 512)],
+ "get sectorsize of block device",
+ "\
+This returns the size of sectors on a block device.
+Usually 512, but can be larger for modern devices.
- (* Check function names. *)
- List.iter (
- fun (name, _, _, _, _, _, _) ->
- if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
- failwithf "function name %s does not need 'guestfs' prefix" name;
- if contains_uppercase name then
- failwithf "function name %s should not contain uppercase chars" name;
- if String.contains name '-' then
- failwithf "function name %s should not contain '-', use '_' instead."
- name
- ) all_functions;
+(Note, this is not the size in sectors, use C
+for that).
- (* Check function parameter/return names. *)
- List.iter (
- fun (name, style, _, _, _, _, _) ->
- let check_arg_ret_name n =
- if contains_uppercase n then
- failwithf "%s param/ret %s should not contain uppercase chars"
- name n;
- if String.contains n '-' || String.contains n '_' then
- failwithf "%s param/ret %s should not contain '-' or '_'"
- name n;
- if n = "value" then
- failwithf "%s has a param/ret called 'value', which causes conflicts in the OCaml bindings, use something like 'val' or a more descriptive name" n;
- if n = "argv" || n = "args" then
- failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
- in
+This uses the L command.");
- (match fst style with
- | RErr -> ()
- | RInt n | RBool n | RConstString n | RString n
- | RStringList n | RPVList n | RVGList n | RLVList n ->
- check_arg_ret_name n
- | RIntBool (n,m) ->
- check_arg_ret_name n;
- check_arg_ret_name m
- );
- List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
- ) all_functions;
+ ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
+ [InitEmpty, TestOutputInt (
+ [["blockdev_getbsz"; "/dev/sda"]], 4096)],
+ "get blocksize of block device",
+ "\
+This returns the block size of a device.
- (* Check short descriptions. *)
- List.iter (
- fun (name, _, _, _, _, shortdesc, _) ->
- if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
- failwithf "short description of %s should begin with lowercase." name;
- let c = shortdesc.[String.length shortdesc-1] in
- if c = '\n' || c = '.' then
- failwithf "short description of %s should not end with . or \\n." name
- ) all_functions;
+(Note this is different from both I and
+I).
- (* Check long dscriptions. *)
- List.iter (
- fun (name, _, _, _, _, _, longdesc) ->
- if longdesc.[String.length longdesc-1] = '\n' then
- failwithf "long description of %s should not end with \\n." name
- ) all_functions;
+This uses the L command.");
- (* Check proc_nrs. *)
- List.iter (
- fun (name, _, proc_nr, _, _, _, _) ->
- if proc_nr <= 0 then
- failwithf "daemon function %s should have proc_nr > 0" name
- ) daemon_functions;
+ ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
+ [], (* XXX test *)
+ "set blocksize of block device",
+ "\
+This sets the block size of a device.
- List.iter (
- fun (name, _, proc_nr, _, _, _, _) ->
- if proc_nr <> -1 then
- failwithf "non-daemon function %s should have proc_nr -1" name
- ) non_daemon_functions;
+(Note this is different from both I and
+I).
- let proc_nrs =
- List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
- daemon_functions in
- let proc_nrs =
- List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
- let rec loop = function
- | [] -> ()
- | [_] -> ()
- | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
- loop rest
- | (name1,nr1) :: (name2,nr2) :: _ ->
- failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
- name1 name2 nr1 nr2
- in
- loop proc_nrs
+This uses the L command.");
-(* 'pr' prints to the current output file. *)
-let chan = ref stdout
-let pr fs = ksprintf (output_string !chan) fs
+ ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
+ [InitEmpty, TestOutputInt (
+ [["blockdev_getsz"; "/dev/sda"]], 1024000)],
+ "get total size of device in 512-byte sectors",
+ "\
+This returns the size of the device in units of 512-byte sectors
+(even if the sectorsize isn't 512 bytes ... weird).
-(* Generate a header block in a number of standard styles. *)
-type comment_style = CStyle | HashStyle | OCamlStyle
-type license = GPLv2 | LGPLv2
+See also C for the real sector size of
+the device, and C for the more
+useful I.
-let generate_header comment license =
- let c = match comment with
- | CStyle -> pr "/* "; " *"
- | HashStyle -> pr "# "; "#"
- | OCamlStyle -> pr "(* "; " *" in
- pr "libguestfs generated file\n";
- pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
- pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
- pr "%s\n" c;
- pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
- pr "%s\n" c;
- (match license with
- | GPLv2 ->
- pr "%s This program is free software; you can redistribute it and/or modify\n" c;
- pr "%s it under the terms of the GNU General Public License as published by\n" c;
- pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
- pr "%s (at your option) any later version.\n" c;
- pr "%s\n" c;
- pr "%s This program is distributed in the hope that it will be useful,\n" c;
- pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
- pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
- pr "%s GNU General Public License for more details.\n" c;
- pr "%s\n" c;
- pr "%s You should have received a copy of the GNU General Public License along\n" c;
- pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
- pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
+This uses the L command.");
- | LGPLv2 ->
- pr "%s This library is free software; you can redistribute it and/or\n" c;
- pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
- pr "%s License as published by the Free Software Foundation; either\n" c;
- pr "%s version 2 of the License, or (at your option) any later version.\n" c;
- pr "%s\n" c;
- pr "%s This library is distributed in the hope that it will be useful,\n" c;
- pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
- pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
- pr "%s Lesser General Public License for more details.\n" c;
- pr "%s\n" c;
- pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
- pr "%s License along with this library; if not, write to the Free Software\n" c;
- pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
- );
- (match comment with
- | CStyle -> pr " */\n"
- | HashStyle -> ()
- | OCamlStyle -> pr " *)\n"
- );
- pr "\n"
+ ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
+ [InitEmpty, TestOutputInt (
+ [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
+ "get total size of device in bytes",
+ "\
+This returns the size of the device in bytes.
-(* Start of main code generation functions below this line. *)
+See also C.
-(* Generate the pod documentation for the C API. *)
-let rec generate_actions_pod () =
- List.iter (
- fun (shortname, style, _, flags, _, _, longdesc) ->
- let name = "guestfs_" ^ shortname in
- pr "=head2 %s\n\n" name;
- pr " ";
- generate_prototype ~extern:false ~handle:"handle" name style;
- pr "\n\n";
- pr "%s\n\n" longdesc;
- (match fst style with
- | RErr ->
- pr "This function returns 0 on success or -1 on error.\n\n"
- | RInt _ ->
- pr "On error this function returns -1.\n\n"
- | RBool _ ->
- pr "This function returns a C truth value on success or -1 on error.\n\n"
- | RConstString _ ->
- pr "This function returns a string, or NULL on error.
-The string is owned by the guest handle and must I be freed.\n\n"
- | RString _ ->
- pr "This function returns a string, or NULL on error.
-I.\n\n"
- | RStringList _ ->
- pr "This function returns a NULL-terminated array of strings
-(like L), or NULL if there was an error.
-I.\n\n"
- | RIntBool _ ->
- pr "This function returns a C.
-I after use>.\n\n"
- | RPVList _ ->
- pr "This function returns a C.
-I after use>.\n\n"
- | RVGList _ ->
- pr "This function returns a C.
-I after use>.\n\n"
- | RLVList _ ->
- pr "This function returns a C.
-I after use>.\n\n"
- );
- if List.mem ProtocolLimitWarning flags then
- pr "%s\n\n" protocol_limit_warning;
- if List.mem DangerWillRobinson flags then
- pr "%s\n\n" danger_will_robinson;
- ) all_functions_sorted
+This uses the L command.");
-and generate_structs_pod () =
- (* LVM structs documentation. *)
- List.iter (
- fun (typ, cols) ->
- pr "=head2 guestfs_lvm_%s\n" typ;
- pr "\n";
- pr " struct guestfs_lvm_%s {\n" typ;
- List.iter (
- function
- | name, `String -> pr " char *%s;\n" name
- | name, `UUID ->
- pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
- pr " char %s[32];\n" name
- | name, `Bytes -> pr " uint64_t %s;\n" name
- | name, `Int -> pr " int64_t %s;\n" name
- | name, `OptPercent ->
- pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
- pr " float %s;\n" name
- ) cols;
- pr " \n";
- pr " struct guestfs_lvm_%s_list {\n" typ;
- pr " uint32_t len; /* Number of elements in list. */\n";
- pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
- pr " };\n";
- pr " \n";
- pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
- typ typ;
- pr "\n"
- ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
+ ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
+ [InitEmpty, TestRun
+ [["blockdev_flushbufs"; "/dev/sda"]]],
+ "flush device buffers",
+ "\
+This tells the kernel to flush internal buffers associated
+with C.
-(* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
- * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
- *
- * We have to use an underscore instead of a dash because otherwise
- * rpcgen generates incorrect code.
- *
- * This header is NOT exported to clients, but see also generate_structs_h.
- *)
-and generate_xdr () =
- generate_header CStyle LGPLv2;
+This uses the L command.");
- (* This has to be defined to get around a limitation in Sun's rpcgen. *)
- pr "typedef string str<>;\n";
- pr "\n";
+ ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
+ [InitEmpty, TestRun
+ [["blockdev_rereadpt"; "/dev/sda"]]],
+ "reread partition table",
+ "\
+Reread the partition table on C.
- (* LVM internal structures. *)
- List.iter (
- function
- | typ, cols ->
- pr "struct guestfs_lvm_int_%s {\n" typ;
- List.iter (function
- | name, `String -> pr " string %s<>;\n" name
- | name, `UUID -> pr " opaque %s[32];\n" name
- | name, `Bytes -> pr " hyper %s;\n" name
- | name, `Int -> pr " hyper %s;\n" name
- | name, `OptPercent -> pr " float %s;\n" name
- ) cols;
- pr "};\n";
- pr "\n";
- pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
- pr "\n";
- ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
+This uses the L command.");
- List.iter (
- fun (shortname, style, _, _, _, _, _) ->
- let name = "guestfs_" ^ shortname in
+ ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
+ [InitBasicFS, TestOutput (
+ (* Pick a file from cwd which isn't likely to change. *)
+ [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
+ ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
+ "upload a file from the local machine",
+ "\
+Upload local file C to C on the
+filesystem.
- (match snd style with
- | [] -> ()
- | args ->
- pr "struct %s_args {\n" name;
- List.iter (
- function
- | String n -> pr " string %s<>;\n" n
- | OptString n -> pr " str *%s;\n" n
- | StringList n -> pr " str %s<>;\n" n
- | Bool n -> pr " bool %s;\n" n
- | Int n -> pr " int %s;\n" n
- ) args;
- pr "};\n\n"
- );
- (match fst style with
- | RErr -> ()
- | RInt n ->
- pr "struct %s_ret {\n" name;
- pr " int %s;\n" n;
- pr "};\n\n"
- | RBool n ->
- pr "struct %s_ret {\n" name;
- pr " bool %s;\n" n;
- pr "};\n\n"
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RString n ->
- pr "struct %s_ret {\n" name;
- pr " string %s<>;\n" n;
- pr "};\n\n"
- | RStringList n ->
- pr "struct %s_ret {\n" name;
- pr " str %s<>;\n" n;
- pr "};\n\n"
- | RIntBool (n,m) ->
- pr "struct %s_ret {\n" name;
- pr " int %s;\n" n;
- pr " bool %s;\n" m;
- pr "};\n\n"
- | RPVList n ->
- pr "struct %s_ret {\n" name;
- pr " guestfs_lvm_int_pv_list %s;\n" n;
- pr "};\n\n"
- | RVGList n ->
- pr "struct %s_ret {\n" name;
- pr " guestfs_lvm_int_vg_list %s;\n" n;
- pr "};\n\n"
- | RLVList n ->
- pr "struct %s_ret {\n" name;
- pr " guestfs_lvm_int_lv_list %s;\n" n;
- pr "};\n\n"
- );
- ) daemon_functions;
+C can also be a named pipe.
- (* Table of procedure numbers. *)
- pr "enum guestfs_procedure {\n";
- List.iter (
- fun (shortname, _, proc_nr, _, _, _, _) ->
- pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
- ) daemon_functions;
- pr " GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
- pr "};\n";
- pr "\n";
+See also C.");
- (* Having to choose a maximum message size is annoying for several
- * reasons (it limits what we can do in the API), but it (a) makes
- * the protocol a lot simpler, and (b) provides a bound on the size
- * of the daemon which operates in limited memory space. For large
- * file transfers you should use FTP.
- *)
- pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
- pr "\n";
+ ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
+ [InitBasicFS, TestOutput (
+ (* Pick a file from cwd which isn't likely to change. *)
+ [["upload"; "COPYING.LIB"; "/COPYING.LIB"];
+ ["download"; "/COPYING.LIB"; "testdownload.tmp"];
+ ["upload"; "testdownload.tmp"; "/upload"];
+ ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
+ "download a file to the local machine",
+ "\
+Download file C and save it as C
+on the local machine.
- (* Message header, etc. *)
- pr "\
-const GUESTFS_PROGRAM = 0x2000F5F5;
-const GUESTFS_PROTOCOL_VERSION = 1;
+C can also be a named pipe.
-enum guestfs_message_direction {
- GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
- GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
-};
+See also C, C.");
-enum guestfs_message_status {
- GUESTFS_STATUS_OK = 0,
- GUESTFS_STATUS_ERROR = 1
-};
+ ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
+ [InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "crc"; "/new"]], "935282863");
+ InitBasicFS, TestLastFail (
+ [["checksum"; "crc"; "/new"]]);
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "test\n"; "0"];
+ ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123")],
+ "compute MD5, SHAx or CRC checksum of file",
+ "\
+This call computes the MD5, SHAx or CRC checksum of the
+file named C.
-const GUESTFS_ERROR_LEN = 256;
+The type of checksum to compute is given by the C
+parameter which must have one of the following values:
-struct guestfs_message_error {
- string error; /* error message */
-};
+=over 4
-struct guestfs_message_header {
- unsigned prog; /* GUESTFS_PROGRAM */
- unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
- guestfs_procedure proc; /* GUESTFS_PROC_x */
- guestfs_message_direction direction;
- unsigned serial; /* message serial number */
- guestfs_message_status status;
-};
-"
+=item C
-(* Generate the guestfs-structs.h file. *)
-and generate_structs_h () =
- generate_header CStyle LGPLv2;
+Compute the cyclic redundancy check (CRC) specified by POSIX
+for the C command.
- (* This is a public exported header file containing various
- * structures. The structures are carefully written to have
- * exactly the same in-memory format as the XDR structures that
- * we use on the wire to the daemon. The reason for creating
- * copies of these structures here is just so we don't have to
- * export the whole of guestfs_protocol.h (which includes much
- * unrelated and XDR-dependent stuff that we don't want to be
- * public, or required by clients).
- *
- * To reiterate, we will pass these structures to and from the
- * client with a simple assignment or memcpy, so the format
- * must be identical to what rpcgen / the RFC defines.
- *)
+=item C
- (* guestfs_int_bool structure. *)
- pr "struct guestfs_int_bool {\n";
- pr " int32_t i;\n";
- pr " int32_t b;\n";
- pr "};\n";
- pr "\n";
+Compute the MD5 hash (using the C program).
- (* LVM public structures. *)
- List.iter (
- function
- | typ, cols ->
- pr "struct guestfs_lvm_%s {\n" typ;
- List.iter (
- function
- | name, `String -> pr " char *%s;\n" name
- | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
- | name, `Bytes -> pr " uint64_t %s;\n" name
- | name, `Int -> pr " int64_t %s;\n" name
- | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
- ) cols;
- pr "};\n";
- pr "\n";
- pr "struct guestfs_lvm_%s_list {\n" typ;
- pr " uint32_t len;\n";
- pr " struct guestfs_lvm_%s *val;\n" typ;
- pr "};\n";
- pr "\n"
- ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
+=item C
-(* Generate the guestfs-actions.h file. *)
-and generate_actions_h () =
- generate_header CStyle LGPLv2;
- List.iter (
- fun (shortname, style, _, _, _, _, _) ->
- let name = "guestfs_" ^ shortname in
- generate_prototype ~single_line:true ~newline:true ~handle:"handle"
- name style
- ) all_functions
+Compute the SHA1 hash (using the C program).
-(* Generate the client-side dispatch stubs. *)
-and generate_client_actions () =
- generate_header CStyle LGPLv2;
+=item C
- (* Client-side stubs for each function. *)
- List.iter (
- fun (shortname, style, _, _, _, _, _) ->
- let name = "guestfs_" ^ shortname in
+Compute the SHA224 hash (using the C program).
- (* Generate the return value struct. *)
- pr "struct %s_rv {\n" shortname;
- pr " int cb_done; /* flag to indicate callback was called */\n";
- pr " struct guestfs_message_header hdr;\n";
- pr " struct guestfs_message_error err;\n";
- (match fst style with
- | RErr -> ()
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RInt _
- | RBool _ | RString _ | RStringList _
- | RIntBool _
- | RPVList _ | RVGList _ | RLVList _ ->
- pr " struct %s_ret ret;\n" name
- );
- pr "};\n\n";
+=item C
- (* Generate the callback function. *)
- pr "static void %s_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
- pr "{\n";
- pr " struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
- pr "\n";
- pr " if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {\n";
- pr " error (g, \"%s: failed to parse reply header\");\n" name;
- pr " return;\n";
- pr " }\n";
- pr " if (rv->hdr.status == GUESTFS_STATUS_ERROR) {\n";
- pr " if (!xdr_guestfs_message_error (xdr, &rv->err)) {\n";
- pr " error (g, \"%s: failed to parse reply error\");\n" name;
- pr " return;\n";
- pr " }\n";
- pr " goto done;\n";
- pr " }\n";
+Compute the SHA256 hash (using the C program).
- (match fst style with
- | RErr -> ()
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RInt _
- | RBool _ | RString _ | RStringList _
- | RIntBool _
- | RPVList _ | RVGList _ | RLVList _ ->
- pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
- pr " error (g, \"%s: failed to parse reply\");\n" name;
- pr " return;\n";
- pr " }\n";
- );
+=item C
- pr " done:\n";
- pr " rv->cb_done = 1;\n";
- pr " main_loop.main_loop_quit (g);\n";
- pr "}\n\n";
+Compute the SHA384 hash (using the C program).
- (* Generate the action stub. *)
- generate_prototype ~extern:false ~semicolon:false ~newline:true
- ~handle:"g" name style;
+=item C
- let error_code =
- match fst style with
- | RErr | RInt _ | RBool _ -> "-1"
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RString _ | RStringList _ | RIntBool _
- | RPVList _ | RVGList _ | RLVList _ ->
- "NULL" in
+Compute the SHA512 hash (using the C program).
- pr "{\n";
+=back
- (match snd style with
- | [] -> ()
- | _ -> pr " struct %s_args args;\n" name
- );
+The checksum is returned as a printable string.");
- pr " struct %s_rv rv;\n" shortname;
- pr " int serial;\n";
- pr "\n";
- pr " if (g->state != READY) {\n";
- pr " error (g, \"%s called from the wrong state, %%d != READY\",\n"
- name;
- pr " g->state);\n";
- pr " return %s;\n" error_code;
- pr " }\n";
- pr "\n";
- pr " memset (&rv, 0, sizeof rv);\n";
- pr "\n";
+ ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
+ [InitBasicFS, TestOutput (
+ [["tar_in"; "images/helloworld.tar"; "/"];
+ ["cat"; "/hello"]], "hello\n")],
+ "unpack tarfile to directory",
+ "\
+This command uploads and unpacks local file C (an
+I tar file) into C.
- (match snd style with
- | [] ->
- pr " serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
- (String.uppercase shortname)
- | args ->
- List.iter (
- function
- | String n ->
- pr " args.%s = (char *) %s;\n" n n
- | OptString n ->
- pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
- | StringList n ->
- pr " args.%s.%s_val = (char **) %s;\n" n n n;
- pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
- | Bool n ->
- pr " args.%s = %s;\n" n n
- | Int n ->
- pr " args.%s = %s;\n" n n
- ) args;
- pr " serial = dispatch (g, GUESTFS_PROC_%s,\n"
- (String.uppercase shortname);
- pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
- name;
- );
- pr " if (serial == -1)\n";
- pr " return %s;\n" error_code;
- pr "\n";
+To upload a compressed tarball, use C.");
- pr " rv.cb_done = 0;\n";
- pr " g->reply_cb_internal = %s_cb;\n" shortname;
- pr " g->reply_cb_internal_data = &rv;\n";
- pr " main_loop.main_loop_run (g);\n";
- pr " g->reply_cb_internal = NULL;\n";
- pr " g->reply_cb_internal_data = NULL;\n";
- pr " if (!rv.cb_done) {\n";
- pr " error (g, \"%s failed, see earlier error messages\");\n" name;
- pr " return %s;\n" error_code;
- pr " }\n";
- pr "\n";
+ ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
+ [],
+ "pack directory into tarfile",
+ "\
+This command packs the contents of C and downloads
+it to local file C.
- pr " if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_%s, serial) == -1)\n"
- (String.uppercase shortname);
- pr " return %s;\n" error_code;
- pr "\n";
+To download a compressed tarball, use C.");
- pr " if (rv.hdr.status == GUESTFS_STATUS_ERROR) {\n";
- pr " error (g, \"%%s\", rv.err.error);\n";
- pr " return %s;\n" error_code;
- pr " }\n";
- pr "\n";
+ ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
+ [InitBasicFS, TestOutput (
+ [["tgz_in"; "images/helloworld.tar.gz"; "/"];
+ ["cat"; "/hello"]], "hello\n")],
+ "unpack compressed tarball to directory",
+ "\
+This command uploads and unpacks local file C (a
+I tar file) into C.
- (match fst style with
- | RErr -> pr " return 0;\n"
- | RInt n
- | RBool n -> pr " return rv.ret.%s;\n" n
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RString n ->
- pr " return rv.ret.%s; /* caller will free */\n" n
- | RStringList n ->
- pr " /* caller will free this, but we need to add a NULL entry */\n";
- pr " rv.ret.%s.%s_val =" n n;
- pr " safe_realloc (g, rv.ret.%s.%s_val,\n" n n;
- pr " sizeof (char *) * (rv.ret.%s.%s_len + 1));\n"
- n n;
- pr " rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
- pr " return rv.ret.%s.%s_val;\n" n n
- | RIntBool _ ->
- pr " /* caller with free this */\n";
- pr " return safe_memdup (g, &rv.ret, sizeof (rv.ret));\n"
- | RPVList n ->
- pr " /* caller will free this */\n";
- pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
- | RVGList n ->
- pr " /* caller will free this */\n";
- pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
- | RLVList n ->
- pr " /* caller will free this */\n";
- pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
- );
+To upload an uncompressed tarball, use C.");
- pr "}\n\n"
- ) daemon_functions
+ ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
+ [],
+ "pack directory into compressed tarball",
+ "\
+This command packs the contents of C and downloads
+it to local file C.
-(* Generate daemon/actions.h. *)
-and generate_daemon_actions_h () =
- generate_header CStyle GPLv2;
+To download an uncompressed tarball, use C.");
- pr "#include \"../src/guestfs_protocol.h\"\n";
- pr "\n";
+ ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
+ [InitBasicFS, TestLastFail (
+ [["umount"; "/"];
+ ["mount_ro"; "/dev/sda1"; "/"];
+ ["touch"; "/new"]]);
+ InitBasicFS, TestOutput (
+ [["write_file"; "/new"; "data"; "0"];
+ ["umount"; "/"];
+ ["mount_ro"; "/dev/sda1"; "/"];
+ ["cat"; "/new"]], "data")],
+ "mount a guest disk, read-only",
+ "\
+This is the same as the C command, but it
+mounts the filesystem with the read-only (I<-o ro>) flag.");
- List.iter (
- fun (name, style, _, _, _, _, _) ->
- generate_prototype
- ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
- name style;
- ) daemon_functions
+ ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
+ [],
+ "mount a guest disk with mount options",
+ "\
+This is the same as the C command, but it
+allows you to set the mount options as for the
+L I<-o> flag.");
-(* Generate the server-side stubs. *)
-and generate_daemon_actions () =
- generate_header CStyle GPLv2;
+ ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
+ [],
+ "mount a guest disk with mount options and vfstype",
+ "\
+This is the same as the C command, but it
+allows you to set both the mount options and the vfstype
+as for the L I<-o> and I<-t> flags.");
- pr "#define _GNU_SOURCE // for strchrnul\n";
- pr "\n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "#include \n";
- pr "\n";
- pr "#include \"daemon.h\"\n";
- pr "#include \"../src/guestfs_protocol.h\"\n";
- pr "#include \"actions.h\"\n";
- pr "\n";
+ ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
+ [],
+ "debugging and internals",
+ "\
+The C command exposes some internals of
+C (the guestfs daemon) that runs inside the
+qemu subprocess.
- List.iter (
- fun (name, style, _, _, _, _, _) ->
- (* Generate server-side stubs. *)
- pr "static void %s_stub (XDR *xdr_in)\n" name;
- pr "{\n";
- let error_code =
- match fst style with
- | RErr | RInt _ -> pr " int r;\n"; "-1"
- | RBool _ -> pr " int r;\n"; "-1"
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RString _ -> pr " char *r;\n"; "NULL"
- | RStringList _ -> pr " char **r;\n"; "NULL"
- | RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
- | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
- | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
- | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL" in
+There is no comprehensive help for this command. You have
+to look at the file C in the libguestfs source
+to find out what you can do.");
- (match snd style with
- | [] -> ()
- | args ->
- pr " struct guestfs_%s_args args;\n" name;
- List.iter (
- function
- | String n
- | OptString n -> pr " const char *%s;\n" n
- | StringList n -> pr " char **%s;\n" n
- | Bool n -> pr " int %s;\n" n
- | Int n -> pr " int %s;\n" n
- ) args
- );
- pr "\n";
+ ("lvremove", (RErr, [String "device"]), 77, [],
+ [InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG/LV1"];
+ ["lvs"]], ["/dev/VG/LV2"]);
+ InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG"];
+ ["lvs"]], []);
+ InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["lvremove"; "/dev/VG"];
+ ["vgs"]], ["VG"])],
+ "remove an LVM logical volume",
+ "\
+Remove an LVM logical volume C, where C is
+the path to the LV, such as C.
- (match snd style with
- | [] -> ()
- | args ->
- pr " memset (&args, 0, sizeof args);\n";
- pr "\n";
- pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
- pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
- pr " return;\n";
- pr " }\n";
- List.iter (
- function
- | String n -> pr " %s = args.%s;\n" n n
- | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
- | StringList n ->
- pr " args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n;
- pr " args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n;
- pr " %s = args.%s.%s_val;\n" n n n
- | Bool n -> pr " %s = args.%s;\n" n n
- | Int n -> pr " %s = args.%s;\n" n n
- ) args;
- pr "\n"
- );
+You can also remove all LVs in a volume group by specifying
+the VG name, C.");
- pr " r = do_%s " name;
- generate_call_args style;
- pr ";\n";
+ ("vgremove", (RErr, [String "vgname"]), 78, [],
+ [InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["lvs"]], []);
+ InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["vgs"]], [])],
+ "remove an LVM volume group",
+ "\
+Remove an LVM volume group C, (for example C).
- pr " if (r == %s)\n" error_code;
- pr " /* do_%s has already called reply_with_error */\n" name;
- pr " goto done;\n";
- pr "\n";
+This also forcibly removes all logical volumes in the volume
+group (if any).");
- (match fst style with
- | RErr -> pr " reply (NULL, NULL);\n"
- | RInt n ->
- pr " struct guestfs_%s_ret ret;\n" name;
- pr " ret.%s = r;\n" n;
- pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
- | RBool n ->
- pr " struct guestfs_%s_ret ret;\n" name;
- pr " ret.%s = r;\n" n;
- pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name
- | RConstString _ ->
- failwithf "RConstString cannot be returned from a daemon function"
- | RString n ->
- pr " struct guestfs_%s_ret ret;\n" name;
- pr " ret.%s = r;\n" n;
- pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
- pr " free (r);\n"
- | RStringList n ->
- pr " struct guestfs_%s_ret ret;\n" name;
- pr " ret.%s.%s_len = count_strings (r);\n" n n;
- pr " ret.%s.%s_val = r;\n" n n;
- pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
- pr " free_strings (r);\n"
- | RIntBool _ ->
- pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
- pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
- | RPVList n ->
- pr " struct guestfs_%s_ret ret;\n" name;
- pr " ret.%s = *r;\n" n;
- pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
- pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
- | RVGList n ->
- pr " struct guestfs_%s_ret ret;\n" name;
- pr " ret.%s = *r;\n" n;
- pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
- pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
- | RLVList n ->
- pr " struct guestfs_%s_ret ret;\n" name;
- pr " ret.%s = *r;\n" n;
- pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
- pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
- );
+ ("pvremove", (RErr, [String "device"]), 79, [],
+ [InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda"];
+ ["lvs"]], []);
+ InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda"];
+ ["vgs"]], []);
+ InitEmpty, TestOutputList (
+ [["pvcreate"; "/dev/sda"];
+ ["vgcreate"; "VG"; "/dev/sda"];
+ ["lvcreate"; "LV1"; "VG"; "50"];
+ ["lvcreate"; "LV2"; "VG"; "50"];
+ ["vgremove"; "VG"];
+ ["pvremove"; "/dev/sda"];
+ ["pvs"]], [])],
+ "remove an LVM physical volume",
+ "\
+This wipes a physical volume C so that LVM will no longer
+recognise it.
- (* 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
- );
+The implementation uses the C command which refuses to
+wipe physical volumes that contain any volume groups, so you have
+to remove those first.");
- pr "}\n\n";
- ) daemon_functions;
+ ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
+ [InitBasicFS, TestOutput (
+ [["set_e2label"; "/dev/sda1"; "testlabel"];
+ ["get_e2label"; "/dev/sda1"]], "testlabel")],
+ "set the ext2/3/4 filesystem label",
+ "\
+This sets the ext2/3/4 filesystem label of the filesystem on
+C to C