*
* IMPORTANT: This script should NOT print any warnings. If it prints
* warnings, you should treat them as errors.
- * [Need to add -warn-error to ocaml command line]
*)
#load "unix.cma";;
| FishAction of string (* call this function in guestfish *)
| NotInFish (* do not export via guestfish *)
| NotInDocs (* do not add this function to documentation *)
-
-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>."
+ | DeprecatedBy of string (* function is deprecated, use .. instead *)
(* You can supply zero or as many tests as you want per API call.
*
and test =
(* Run the command sequence and just expect nothing to fail. *)
| TestRun of seq
+
(* Run the command sequence and expect the output of the final
* command to be the 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 seq * string list
+
(* Run the command sequence and expect the output of the final
* command to be the list of block devices (could be either
* "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
* character of each string).
*)
| TestOutputListOfDevices of seq * string list
+
(* Run the command sequence and expect the output of the final
* command to be the integer.
*)
| TestOutputInt of seq * int
+
(* Run the command sequence and expect the output of the final
* command to be <op> <int>, eg. ">=", "1".
*)
| TestOutputIntOp of seq * string * int
+
(* Run the command sequence and expect the output of the final
* command to be a true value (!= 0 or != NULL).
*)
| 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 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 seq * int
+
+ (* Run the command sequence and expect the output of the final
+ * command to be a buffer (RBufferOut), ie. string + size.
+ *)
+ | TestOutputBuffer of seq * string
+
(* 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.
*)
and test_prereq =
(* Test always runs. *)
| Always
+
(* Test is currently disabled - eg. it fails, or it tests some
* unimplemented feature.
*)
| Disabled
+
(* 'string' is some C code (a function body) that should return
* true or false. The test will run if the code returns true.
*)
| If of string
+
(* As for 'If' but the test runs _unless_ the code returns true. *)
| Unless of string
to create a new zero-length file.");
("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
- [InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "new file contents"; "0"];
- ["cat"; "/new"]], "new file contents")],
+ [InitSquashFS, Always, TestOutput (
+ [["cat"; "/known-2"]], "abcdef\n")],
"list the contents of a file",
"\
Return the contents of the file named C<path>.
of the L<lvs(8)> command. The \"full\" version includes all fields.");
("read_lines", (RStringList "lines", [String "path"]), 15, [],
- [InitBasicFS, Always, TestOutputList (
- [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"];
- ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]);
- InitBasicFS, Always, TestOutputList (
- [["write_file"; "/new"; ""; "0"];
- ["read_lines"; "/new"]], [])],
+ [InitSquashFS, Always, TestOutputList (
+ [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
+ InitSquashFS, Always, TestOutputList (
+ [["read_lines"; "/empty"]], [])],
"read file as lines",
"\
Return the contents of the file named C<path>.
yourself (Augeas support makes this relatively easy).");
("exists", (RBool "existsflag", [String "path"]), 36, [],
- [InitBasicFS, Always, TestOutputTrue (
- [["touch"; "/new"];
- ["exists"; "/new"]]);
- InitBasicFS, Always, TestOutputTrue (
- [["mkdir"; "/new"];
- ["exists"; "/new"]])],
+ [InitSquashFS, Always, TestOutputTrue (
+ [["exists"; "/empty"]]);
+ InitSquashFS, Always, TestOutputTrue (
+ [["exists"; "/directory"]])],
"test if file or directory exists",
"\
This returns C<true> if and only if there is a file, directory
See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
("is_file", (RBool "fileflag", [String "path"]), 37, [],
- [InitBasicFS, Always, TestOutputTrue (
- [["touch"; "/new"];
- ["is_file"; "/new"]]);
- InitBasicFS, Always, TestOutputFalse (
- [["mkdir"; "/new"];
- ["is_file"; "/new"]])],
+ [InitSquashFS, Always, TestOutputTrue (
+ [["is_file"; "/known-1"]]);
+ InitSquashFS, Always, TestOutputFalse (
+ [["is_file"; "/directory"]])],
"test if file exists",
"\
This returns C<true> if and only if there is a file
See also C<guestfs_stat>.");
("is_dir", (RBool "dirflag", [String "path"]), 38, [],
- [InitBasicFS, Always, TestOutputFalse (
- [["touch"; "/new"];
- ["is_dir"; "/new"]]);
- InitBasicFS, Always, TestOutputTrue (
- [["mkdir"; "/new"];
- ["is_dir"; "/new"]])],
+ [InitSquashFS, Always, TestOutputFalse (
+ [["is_dir"; "/known-3"]]);
+ InitSquashFS, Always, TestOutputTrue (
+ [["is_dir"; "/directory"]])],
"test if file exists",
"\
This returns C<true> if and only if there is a directory
and physical volumes.");
("file", (RString "description", [String "path"]), 49, [],
- [InitBasicFS, Always, TestOutput (
- [["touch"; "/new"];
- ["file"; "/new"]], "empty");
- InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "some content\n"; "0"];
- ["file"; "/new"]], "ASCII text");
- InitBasicFS, Always, TestLastFail (
- [["file"; "/nofile"]])],
+ [InitSquashFS, Always, TestOutput (
+ [["file"; "/empty"]], "empty");
+ InitSquashFS, Always, TestOutput (
+ [["file"; "/known-1"]], "ASCII text");
+ InitSquashFS, Always, TestLastFail (
+ [["file"; "/notexists"]])],
"determine file type",
"\
This call uses the standard L<file(1)> command to determine
the type or contents of the file. This also works on devices,
for example to find out whether a partition contains a filesystem.
-The exact command which runs is C<file -bsL path>. Note in
+This call will also transparently look inside various types
+of compressed file.
+
+The exact command which runs is C<file -zbsL path>. Note in
particular that the filename is not prepended to the output
(the C<-b> option).");
See also: C<guestfs_sh_lines>");
("stat", (RStruct ("statbuf", "stat"), [String "path"]), 52, [],
- [InitBasicFS, Always, TestOutputStruct (
- [["touch"; "/new"];
- ["stat"; "/new"]], [CompareWithInt ("size", 0)])],
+ [InitSquashFS, Always, TestOutputStruct (
+ [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
"get file information",
"\
Returns file information for the given C<path>.
This is the same as the C<stat(2)> system call.");
("lstat", (RStruct ("statbuf", "stat"), [String "path"]), 53, [],
- [InitBasicFS, Always, TestOutputStruct (
- [["touch"; "/new"];
- ["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
+ [InitSquashFS, Always, TestOutputStruct (
+ [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
"get file information for a symbolic link",
"\
Returns file information for the given C<path>.
This is the same as the C<lstat(2)> system call.");
("statvfs", (RStruct ("statbuf", "statvfs"), [String "path"]), 54, [],
- [InitBasicFS, Always, TestOutputStruct (
- [["statvfs"; "/"]], [CompareWithInt ("namemax", 255);
- CompareWithInt ("bsize", 1024)])],
+ [InitSquashFS, Always, TestOutputStruct (
+ [["statvfs"; "/"]], [CompareWithInt ("namemax", 256);
+ CompareWithInt ("bsize", 131072)])],
"get file system statistics",
"\
Returns file system statistics for any mounted file system.
See also C<guestfs_upload>, C<guestfs_cat>.");
("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
- [InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "test\n"; "0"];
- ["checksum"; "crc"; "/new"]], "935282863");
- InitBasicFS, Always, TestLastFail (
- [["checksum"; "crc"; "/new"]]);
- InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "test\n"; "0"];
- ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249");
- InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "test\n"; "0"];
- ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83");
- InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "test\n"; "0"];
- ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec");
- InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "test\n"; "0"];
- ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2");
- InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "test\n"; "0"];
- ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d");
- InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "test\n"; "0"];
- ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123");
+ [InitSquashFS, Always, TestOutput (
+ [["checksum"; "crc"; "/known-3"]], "2891671662");
+ InitSquashFS, Always, TestLastFail (
+ [["checksum"; "crc"; "/notexists"]]);
+ InitSquashFS, Always, TestOutput (
+ [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
+ InitSquashFS, Always, TestOutput (
+ [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
InitSquashFS, Always, TestOutput (
- [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")],
+ [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
+ InitSquashFS, Always, TestOutput (
+ [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
+ InitSquashFS, Always, TestOutput (
+ [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
+ InitSquashFS, Always, TestOutput (
+ [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
"compute MD5, SHAx or CRC checksum of file",
"\
This call computes the MD5, SHAx or CRC checksum of the
The external L<cmp(1)> program is used for the comparison.");
("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
- [InitBasicFS, Always, TestOutputList (
- [["write_file"; "/new"; "hello\nworld\n"; "0"];
- ["strings"; "/new"]], ["hello"; "world"]);
- InitBasicFS, Always, TestOutputList (
- [["touch"; "/new"];
- ["strings"; "/new"]], [])],
+ [InitSquashFS, Always, TestOutputList (
+ [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
+ InitSquashFS, Always, TestOutputList (
+ [["strings"; "/empty"]], [])],
"print the printable strings in a file",
"\
This runs the L<strings(1)> command on a file and returns
the list of printable strings found.");
("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
- [InitBasicFS, Always, TestOutputList (
- [["write_file"; "/new"; "hello\nworld\n"; "0"];
- ["strings_e"; "b"; "/new"]], []);
+ [InitSquashFS, Always, TestOutputList (
+ [["strings_e"; "b"; "/known-5"]], []);
InitBasicFS, Disabled, TestOutputList (
[["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
["strings_e"; "b"; "/new"]], ["hello"; "world"])],
The returned strings are transcoded to UTF-8.");
("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
- [InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "hello\nworld\n"; "12"];
- ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n");
+ [InitSquashFS, Always, TestOutput (
+ [["hexdump"; "/known-4"]], "00000000 61 62 63 0a 64 65 66 0a 67 68 69 |abc.def.ghi|\n0000000b\n");
(* Test for RHBZ#501888c2 regression which caused large hexdump
* commands to segfault.
*)
Use C<statvfs> from programs.");
("du", (RInt64 "sizekb", [String "path"]), 127, [],
- [InitBasicFS, Always, TestOutputInt (
- [["mkdir"; "/p"];
- ["du"; "/p"]], 1 (* ie. 1 block, so depends on ext3 blocksize *))],
+ [InitSquashFS, Always, TestOutputInt (
+ [["du"; "/directory"]], 0 (* squashfs doesn't have blocks *))],
"estimate file space usage",
"\
This command runs the C<du -s> command to estimate file space
("initrd_list", (RStringList "filenames", [String "path"]), 128, [],
[InitSquashFS, Always, TestOutputList (
- [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3"])],
+ [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
"list files in an initrd",
"\
This command lists out files contained in an initrd.
["mkswap_L"; "hello"; "/dev/sda1"]])],
"create a swap partition with a label",
"\
-Create a swap partition on C<device> with label C<label>.");
+Create a swap partition on C<device> with label C<label>.
+
+Note that you cannot attach a swap label to a block device
+(eg. C</dev/sda>), just to a partition. This appears to be
+a limitation of the kernel or swap tools.");
("mkswap_U", (RErr, [String "uuid"; String "device"]), 132, [],
[InitEmpty, Always, TestRun (
See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
- ("zfile", (RString "description", [String "method"; String "path"]), 140, [],
+ ("zfile", (RString "description", [String "method"; String "path"]), 140, [DeprecatedBy "file"],
[],
"determine file type inside a compressed file",
"\
C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
-See also: C<guestfs_file>");
+Since 1.0.63, use C<guestfs_file> instead which can now
+process compressed files.");
("getxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 141, [],
[],
for full details.");
("read_file", (RBufferOut "content", [String "path"]), 150, [ProtocolLimitWarning],
- [InitBasicFS, Always, TestOutput (
- [["write_file"; "/new"; "new file contents"; "0"];
- ["read_file"; "/new"]], "new file contents")],
+ [InitSquashFS, Always, TestOutputBuffer (
+ [["read_file"; "/known-4"]], "abc\ndef\nghi")],
"read a file",
"\
This calls returns the contents of the file C<path> as a
However unlike C<guestfs_download>, this function is limited
in the total size of file that can be handled.");
+ ("grep", (RStringList "lines", [String "regex"; String "path"]), 151, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
+ InitSquashFS, Always, TestOutputList (
+ [["grep"; "nomatch"; "/test-grep.txt"]], [])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<grep> program and returns the
+matching lines.");
+
+ ("egrep", (RStringList "lines", [String "regex"; String "path"]), 152, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<egrep> program and returns the
+matching lines.");
+
+ ("fgrep", (RStringList "lines", [String "pattern"; String "path"]), 153, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<fgrep> program and returns the
+matching lines.");
+
+ ("grepi", (RStringList "lines", [String "regex"; String "path"]), 154, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<grep -i> program and returns the
+matching lines.");
+
+ ("egrepi", (RStringList "lines", [String "regex"; String "path"]), 155, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<egrep -i> program and returns the
+matching lines.");
+
+ ("fgrepi", (RStringList "lines", [String "pattern"; String "path"]), 156, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<fgrep -i> program and returns the
+matching lines.");
+
+ ("zgrep", (RStringList "lines", [String "regex"; String "path"]), 157, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<zgrep> program and returns the
+matching lines.");
+
+ ("zegrep", (RStringList "lines", [String "regex"; String "path"]), 158, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<zegrep> program and returns the
+matching lines.");
+
+ ("zfgrep", (RStringList "lines", [String "pattern"; String "path"]), 159, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<zfgrep> program and returns the
+matching lines.");
+
+ ("zgrepi", (RStringList "lines", [String "regex"; String "path"]), 160, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<zgrep -i> program and returns the
+matching lines.");
+
+ ("zegrepi", (RStringList "lines", [String "regex"; String "path"]), 161, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<zegrep -i> program and returns the
+matching lines.");
+
+ ("zfgrepi", (RStringList "lines", [String "pattern"; String "path"]), 162, [ProtocolLimitWarning],
+ [InitSquashFS, Always, TestOutputList (
+ [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
+ "return lines matching a pattern",
+ "\
+This calls the external C<zfgrep -i> program and returns the
+matching lines.");
+
+ ("realpath", (RString "rpath", [String "path"]), 163, [],
+ [InitSquashFS, Always, TestOutput (
+ [["realpath"; "/../directory"]], "/directory")],
+ "canonicalized absolute pathname",
+ "\
+Return the canonicalized absolute pathname of C<path>. The
+returned path has no C<.>, C<..> or symbolic link path elements.");
+
+ ("ln", (RErr, [String "target"; String "linkname"]), 164, [],
+ [InitBasicFS, Always, TestOutputStruct (
+ [["touch"; "/a"];
+ ["ln"; "/a"; "/b"];
+ ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
+ "create a hard link",
+ "\
+This command creates a hard link using the C<ln> command.");
+
+ ("ln_f", (RErr, [String "target"; String "linkname"]), 165, [],
+ [InitBasicFS, Always, TestOutputStruct (
+ [["touch"; "/a"];
+ ["touch"; "/b"];
+ ["ln_f"; "/a"; "/b"];
+ ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
+ "create a hard link",
+ "\
+This command creates a hard link using the C<ln -f> command.
+The C<-f> option removes the link (C<linkname>) if it exists already.");
+
+ ("ln_s", (RErr, [String "target"; String "linkname"]), 166, [],
+ [InitBasicFS, Always, TestOutputStruct (
+ [["touch"; "/a"];
+ ["ln_s"; "a"; "/b"];
+ ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
+ "create a symbolic link",
+ "\
+This command creates a symbolic link using the C<ln -s> command.");
+
+ ("ln_sf", (RErr, [String "target"; String "linkname"]), 167, [],
+ [InitBasicFS, Always, TestOutput (
+ [["mkdir_p"; "/a/b"];
+ ["touch"; "/a/b/c"];
+ ["ln_sf"; "../d"; "/a/b/c"];
+ ["readlink"; "/a/b/c"]], "../d")],
+ "create a symbolic link",
+ "\
+This command creates a symbolic link using the C<ln -sf> command,
+The C<-f> option removes the link (C<linkname>) if it exists already.");
+
+ ("readlink", (RString "link", [String "path"]), 168, [],
+ [] (* XXX tested above *),
+ "read the target of a symbolic link",
+ "\
+This command reads the target of a symbolic link.");
+
+ ("fallocate", (RErr, [String "path"; Int "len"]), 169, [],
+ [InitBasicFS, Always, TestOutputStruct (
+ [["fallocate"; "/a"; "1000000"];
+ ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
+ "preallocate a file in the guest filesystem",
+ "\
+This command preallocates a file (containing zero bytes) named
+C<path> of size C<len> bytes. If the file exists already, it
+is overwritten.
+
+Do not confuse this with the guestfish-specific
+C<alloc> command which allocates a file in the host and
+attaches it as a device.");
+
+ ("swapon_device", (RErr, [String "device"]), 170, [],
+ [InitNone, Always, TestRun (
+ [["mkswap"; "/dev/sdb"];
+ ["swapon_device"; "/dev/sdb"];
+ ["swapoff_device"; "/dev/sdb"]])],
+ "enable swap on device",
+ "\
+This command enables the libguestfs appliance to use the
+swap device or partition named C<device>. The increased
+memory is made available for all commands, for example
+those run using C<guestfs_command> or C<guestfs_sh>.
+
+Note that you should not swap to existing guest swap
+partitions unless you know what you are doing. They may
+contain hibernation information, or other information that
+the guest doesn't want you to trash. You also risk leaking
+information about the host to the guest this way. Instead,
+attach a new host device to the guest and swap on that.");
+
+ ("swapoff_device", (RErr, [String "device"]), 171, [],
+ [], (* XXX tested by swapon_device *)
+ "disable swap on device",
+ "\
+This command disables the libguestfs appliance swap
+device or partition named C<device>.
+See C<guestfs_swapon_device>.");
+
+ ("swapon_file", (RErr, [String "file"]), 172, [],
+ [InitBasicFS, Always, TestRun (
+ [["fallocate"; "/swap"; "8388608"];
+ ["mkswap_file"; "/swap"];
+ ["swapon_file"; "/swap"];
+ ["swapoff_file"; "/swap"]])],
+ "enable swap on file",
+ "\
+This command enables swap to a file.
+See C<guestfs_swapon_device> for other notes.");
+
+ ("swapoff_file", (RErr, [String "file"]), 173, [],
+ [], (* XXX tested by swapon_file *)
+ "disable swap on file",
+ "\
+This command disables the libguestfs appliance swap on file.");
+
+ ("swapon_label", (RErr, [String "label"]), 174, [],
+ [InitEmpty, Always, TestRun (
+ [["sfdiskM"; "/dev/sdb"; ","];
+ ["mkswap_L"; "swapit"; "/dev/sdb1"];
+ ["swapon_label"; "swapit"];
+ ["swapoff_label"; "swapit"]])],
+ "enable swap on labelled swap partition",
+ "\
+This command enables swap to a labelled swap partition.
+See C<guestfs_swapon_device> for other notes.");
+
+ ("swapoff_label", (RErr, [String "label"]), 175, [],
+ [], (* XXX tested by swapon_label *)
+ "disable swap on labelled swap partition",
+ "\
+This command disables the libguestfs appliance swap on
+labelled swap partition.");
+
+ ("swapon_uuid", (RErr, [String "uuid"]), 176, [],
+ [InitEmpty, Always, TestRun (
+ [["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sdb"];
+ ["swapon_uuid"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
+ ["swapoff_uuid"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"]])],
+ "enable swap on swap partition by UUID",
+ "\
+This command enables swap to a swap partition with the given UUID.
+See C<guestfs_swapon_device> for other notes.");
+
+ ("swapoff_uuid", (RErr, [String "uuid"]), 177, [],
+ [], (* XXX tested by swapon_uuid *)
+ "disable swap on swap partition by UUID",
+ "\
+This command disables the libguestfs appliance swap partition
+with the given UUID.");
+
+ ("mkswap_file", (RErr, [String "path"]), 178, [],
+ [InitBasicFS, Always, TestRun (
+ [["fallocate"; "/swap"; "8388608"];
+ ["mkswap_file"; "/swap"]])],
+ "create a swap file",
+ "\
+Create a swap file.
+
+This command just writes a swap file signature to an existing
+file. To create the file itself, use something like C<guestfs_fallocate>.");
+
+ ("inotify_init", (RErr, [Int "maxevents"]), 179, [],
+ [InitSquashFS, Always, TestRun (
+ [["inotify_init"; "0"]])],
+ "create an inotify handle",
+ "\
+This command creates a new inotify handle.
+The inotify subsystem can be used to notify events which happen to
+objects in the guest filesystem.
+
+C<maxevents> is the maximum number of events which will be
+queued up between calls to C<guestfs_inotify_read> or
+C<guestfs_inotify_files>.
+If this is passed as C<0>, then the kernel (or previously set)
+default is used. For Linux 2.6.29 the default was 16384 events.
+Beyond this limit, the kernel throws away events, but records
+the fact that it threw them away by setting a flag
+C<IN_Q_OVERFLOW> in the returned structure list (see
+C<guestfs_inotify_read>).
+
+Before any events are generated, you have to add some
+watches to the internal watch list. See:
+C<guestfs_inotify_add_watch>,
+C<guestfs_inotify_rm_watch> and
+C<guestfs_inotify_watch_all>.
+
+Queued up events should be read periodically by calling
+C<guestfs_inotify_read>
+(or C<guestfs_inotify_files> which is just a helpful
+wrapper around C<guestfs_inotify_read>). If you don't
+read the events out often enough then you risk the internal
+queue overflowing.
+
+The handle should be closed after use by calling
+C<guestfs_inotify_close>. This also removes any
+watches automatically.
+
+See also L<inotify(7)> for an overview of the inotify interface
+as exposed by the Linux kernel, which is roughly what we expose
+via libguestfs. Note that there is one global inotify handle
+per libguestfs instance.");
+
+ ("inotify_add_watch", (RInt64 "wd", [String "path"; Int "mask"]), 180, [],
+ [InitBasicFS, Always, TestOutputList (
+ [["inotify_init"; "0"];
+ ["inotify_add_watch"; "/"; "1073741823"];
+ ["touch"; "/a"];
+ ["touch"; "/b"];
+ ["inotify_files"]], ["a"; "b"])],
+ "add an inotify watch",
+ "\
+Watch C<path> for the events listed in C<mask>.
+
+Note that if C<path> is a directory then events within that
+directory are watched, but this does I<not> happen recursively
+(in subdirectories).
+
+Note for non-C or non-Linux callers: the inotify events are
+defined by the Linux kernel ABI and are listed in
+C</usr/include/sys/inotify.h>.");
+
+ ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [],
+ [],
+ "remove an inotify watch",
+ "\
+Remove a previously defined inotify watch.
+See C<guestfs_inotify_add_watch>.");
+
+ ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [],
+ [],
+ "return list of inotify events",
+ "\
+Return the complete queue of events that have happened
+since the previous read call.
+
+If no events have happened, this returns an empty list.
+
+I<Note>: In order to make sure that all events have been
+read, you must call this function repeatedly until it
+returns an empty list. The reason is that the call will
+read events up to the maximum appliance-to-host message
+size and leave remaining events in the queue.");
+
+ ("inotify_files", (RStringList "paths", []), 183, [],
+ [],
+ "return list of watched files that had events",
+ "\
+This function is a helpful wrapper around C<guestfs_inotify_read>
+which just returns a list of pathnames of objects that were
+touched. The returned pathnames are sorted and deduplicated.");
+
+ ("inotify_close", (RErr, []), 184, [],
+ [],
+ "close the inotify handle",
+ "\
+This closes the inotify handle which was previously
+opened by inotify_init. It removes all watches, throws
+away any pending events, and deallocates all resources.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
(* Field types for structures. *)
type field =
| FChar (* C 'char' (really, a 7 bit byte). *)
- | FString (* nul-terminated ASCII string. *)
+ | FString (* nul-terminated ASCII string, NOT NULL. *)
| FBuffer (* opaque buffer of bytes, (char *, int) pair *)
| FUInt32
| FInt32
"attrname", FString;
"attrval", FBuffer;
];
+
+ (* Inotify events. *)
+ "inotify_event", [
+ "in_wd", FInt64;
+ "in_mask", FUInt32;
+ "in_cookie", FUInt32;
+ "in_name", FString;
+ ];
] (* end of structs *)
(* Ugh, Java has to be different ..
"dirent", "Dirent";
"version", "Version";
"xattr", "XAttr";
+ "inotify_event", "INotifyEvent";
]
(* Used for testing language bindings. *)
| 1 -> false
| i -> failwithf "%s: failed with error code %d" cmd i
+let rec filter_map f = function
+ | [] -> []
+ | x :: xs ->
+ match f x with
+ | Some y -> y :: filter_map f xs
+ | None -> filter_map f xs
+
let rec find_map f = function
| [] -> raise Not_found
| x :: xs ->
| TestOutputListOfDevices (s, _)
| TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
| TestOutputTrue s | TestOutputFalse s
- | TestOutputLength (s, _) | TestOutputStruct (s, _)
+ | TestOutputLength (s, _) | TestOutputBuffer (s, _)
+ | TestOutputStruct (s, _)
| TestLastFail s -> s
+(* Handling for function flags. *)
+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>."
+
+let deprecation_notice flags =
+ try
+ let alt =
+ find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
+ let txt =
+ sprintf "This function is deprecated.
+In new code, use the C<%s> call instead.
+
+Deprecated functions will not be removed from the API, but the
+fact that they are deprecated indicates that there are problems
+with correct use of these functions." alt in
+ Some txt
+ with
+ Not_found -> None
+
(* Check function names etc. for consistency. *)
let check_functions () =
let contains_uppercase str =
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
+ pr "%s\n\n" danger_will_robinson;
+ match deprecation_notice flags with
+ | None -> ()
+ | Some txt -> pr "%s\n\n" txt
)
) all_functions_sorted
}
*/
-static void no_test_warnings (void)
-{
";
+ (* Generate a list of commands which are not tested anywhere. *)
+ pr "static void no_test_warnings (void)\n";
+ pr "{\n";
+
+ let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
List.iter (
- function
- | name, _, _, _, [], _, _ ->
+ fun (_, _, _, _, tests, _, _) ->
+ let tests = filter_map (
+ function
+ | (_, (Always|If _|Unless _), test) -> Some test
+ | (_, Disabled, _) -> None
+ ) tests in
+ let seq = List.concat (List.map seq_of_test tests) in
+ let cmds_tested = List.map List.hd seq in
+ List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
+ ) all_functions;
+
+ List.iter (
+ fun (name, _, _, _, _, _, _) ->
+ if not (Hashtbl.mem hash name) then
pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
- | name, _, _, _, tests, _, _ -> ()
) all_functions;
pr "}\n";
in
List.iter (generate_test_command_call test_name) seq;
generate_test_command_call ~test test_name last
+ | TestOutputBuffer (seq, expected) ->
+ pr " /* TestOutputBuffer for %s (%d) */\n" name i;
+ pr " const char *expected = \"%s\";\n" (c_quote expected);
+ let seq, last = get_seq_last seq in
+ let len = String.length expected in
+ let test () =
+ pr " if (size != %d) {\n" len;
+ pr " fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
+ pr " return -1;\n";
+ pr " }\n";
+ pr " if (strncmp (r, expected, size) != 0) {\n";
+ pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\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
| TestOutputStruct (seq, checks) ->
pr " /* TestOutputStruct for %s (%d) */\n" name i;
let seq, last = get_seq_last seq in
(* list_commands function, which implements guestfish -h *)
pr "void list_commands (void)\n";
pr "{\n";
- pr " printf (\" %%-16s %%s\\n\", \"Command\", \"Description\");\n";
+ pr " printf (\" %%-16s %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
pr " list_builtin_commands ();\n";
List.iter (
fun (name, _, _, flags, _, shortdesc, _) ->
let name = replace_char name '_' '-' in
- pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n"
+ pr " printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
name shortdesc
) all_functions_sorted;
- pr " printf (\" Use -h <cmd> / help <cmd> to show detailed help for a command.\\n\");\n";
+ pr " printf (\" %%s\\n\",";
+ pr " _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
pr "}\n";
pr "\n";
("\n\n" ^ danger_will_robinson)
else "" in
+ let warnings =
+ warnings ^
+ match deprecation_notice flags with
+ | None -> ""
+ | Some txt -> "\n\n" ^ txt in
+
let describe_alias =
if name <> alias then
sprintf "\n\nYou can use '%s' as an alias for this command." alias
if name <> alias then
pr " || strcasecmp (cmd, \"%s\") == 0" alias;
pr ")\n";
- pr " pod2text (\"%s - %s\", %S);\n"
+ pr " pod2text (\"%s\", _(\"%s\"), %S);\n"
name2 shortdesc
(" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
pr " else\n"
let needs_i =
List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
- pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
+ pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
pr "{\n";
if needs_i then (
pr " int i;\n";
List.iter (
function
| name, FString ->
- pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
+ pr " printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
| name, FUUID ->
pr " printf (\"%s: \");\n" name;
pr " for (i = 0; i < 32; ++i)\n";
- pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
+ pr " printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
pr " printf (\"\\n\");\n"
| name, FBuffer ->
- pr " printf (\"%s: \");\n" name;
+ pr " printf (\"%%s%s: \", indent);\n" name;
pr " for (i = 0; i < %s->%s_len; ++i)\n" typ name;
pr " if (isprint (%s->%s[i]))\n" typ name;
- pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
+ pr " printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
pr " else\n";
- pr " printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
+ pr " printf (\"%%s\\\\x%%02x\", indent, %s->%s[i]);\n" typ name;
pr " printf (\"\\n\");\n"
| name, (FUInt64|FBytes) ->
- pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
+ pr " printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
+ name typ name
| name, FInt64 ->
- pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
+ pr " printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
+ name typ name
| name, FUInt32 ->
- pr " printf (\"%s: %%\" PRIu32 \"\\n\", %s->%s);\n" name typ name
+ pr " printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
+ name typ name
| name, FInt32 ->
- pr " printf (\"%s: %%\" PRIi32 \"\\n\", %s->%s);\n" name typ name
+ pr " printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
+ name typ name
| name, FChar ->
- pr " printf (\"%s: %%c\\n\", %s->%s);\n" name typ name
+ pr " printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
+ name typ name
| name, FOptPercent ->
- pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
+ pr " if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
typ name name typ name;
- pr " else printf (\"%s: \\n\");\n" name
+ pr " else printf (\"%%s%s: \\n\", indent);\n" name
) cols;
pr "}\n";
pr "\n";
+ pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
+ pr "{\n";
+ pr " print_%s_indent (%s, \"\");\n" typ typ;
+ pr "}\n";
+ pr "\n";
pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
typ typ typ;
pr "{\n";
pr " int i;\n";
pr "\n";
- pr " for (i = 0; i < %ss->len; ++i)\n" typ;
- pr " print_%s (&%ss->val[i]);\n" typ typ;
+ pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
+ pr " printf (\"[%%d] = {\\n\", i);\n";
+ pr " print_%s_indent (&%ss->val[i], \" \");\n" typ typ;
+ pr " printf (\"}\\n\");\n";
+ pr " }\n";
pr "}\n";
pr "\n";
) structs;
(* Check and convert parameters. *)
let argc_expected = List.length (snd style) in
pr " if (argc != %d) {\n" argc_expected;
- pr " fprintf (stderr, \"%%s should have %d parameter(s)\\n\", cmd);\n"
+ pr " fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
argc_expected;
- pr " fprintf (stderr, \"type 'help %%s' for help on %%s\\n\", cmd, cmd);\n";
+ pr " fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
pr " return -1;\n";
pr " }\n";
iteri (
pr " else\n";
) all_functions;
pr " {\n";
- pr " fprintf (stderr, \"%%s: unknown command\\n\", cmd);\n";
+ pr " fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
pr " return -1;\n";
pr " }\n";
pr " return 0;\n";
pr "%s\n\n" protocol_limit_warning;
if List.mem DangerWillRobinson flags then
- pr "%s\n\n" danger_will_robinson
+ pr "%s\n\n" danger_will_robinson;
+
+ match deprecation_notice flags with
+ | None -> ()
+ | Some txt -> pr "%s\n\n" txt
) all_functions_sorted
(* Generate a C function prototype. *)
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
+ pr "%s\n\n" danger_will_robinson;
+ match deprecation_notice flags with
+ | None -> ()
+ | Some txt -> pr "%s\n\n" txt
)
) all_functions_sorted;
if List.mem DangerWillRobinson flags then
doc ^ "\n\n" ^ danger_will_robinson
else doc in
+ let doc =
+ match deprecation_notice flags with
+ | None -> doc
+ | Some txt -> doc ^ "\n\n" ^ txt in
let doc = pod2text ~width:60 name doc in
let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
let doc = String.concat "\n " doc in
if List.mem DangerWillRobinson flags then
doc ^ "\n\n" ^ danger_will_robinson
else doc in
+ let doc =
+ match deprecation_notice flags with
+ | None -> doc
+ | Some txt -> doc ^ "\n\n" ^ txt in
let doc = pod2text ~width:60 name doc in
let doc = List.map ( (* RHBZ#501883 *)
function