X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fgenerator.ml;h=9ce65417a8402966a0e74713657aa807de85dc78;hb=fa014fae5f0dd9aca6abaf8840c432864ed63287;hp=486b9d88b3d2e1b8ddb7124699c1832561ab5bee;hpb=369872b91ed50e2803dc2837183258776e9868e0;p=libguestfs.git
diff --git a/src/generator.ml b/src/generator.ml
index 486b9d8..9ce6541 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -42,6 +42,7 @@
#load "unix.cma";;
#load "str.cma";;
#directory "+xml-light";;
+#directory "+../pkg-lib/xml-light";; (* for GODI users *)
#load "xml-light.cma";;
open Unix
@@ -306,6 +307,9 @@ and test_prereq =
(* As for 'If' but the test runs _unless_ the code returns true. *)
| Unless of string
+ (* Run the test only if 'string' is available in the daemon. *)
+ | IfAvailable of string
+
(* Some initial scenarios for testing. *)
and test_init =
(* Do nothing, block devices could contain random stuff including
@@ -569,7 +573,7 @@ The first character of C string must be a C<-> (dash).
C can be NULL.");
- ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
+ ("set_qemu", (RErr, [OptString "qemu"]), -1, [FishAlias "qemu"],
[],
"set the qemu binary",
"\
@@ -581,7 +585,15 @@ configure script.
You can also override this by setting the C
environment variable.
-Setting C to C restores the default qemu binary.");
+Setting C to C restores the default qemu binary.
+
+Note that you should call this function as early as possible
+after creating the handle. This is because some pre-launch
+operations depend on testing qemu features (by running C).
+If the qemu binary changes, we don't retest features, and
+so you might see inconsistent results. Using the environment
+variable C is safest of all since that picks
+the qemu binary at the same time as the handle is created.");
("get_qemu", (RConstString "qemu", []), -1, [],
[InitNone, Always, TestRun (
@@ -593,7 +605,7 @@ 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 "searchpath"]), -1, [FishAlias "path"],
+ ("set_path", (RErr, [OptString "searchpath"]), -1, [FishAlias "path"],
[],
"set the search path",
"\
@@ -780,8 +792,9 @@ against a completely different C library.
This call was added in version C<1.0.58>. In previous
versions of libguestfs there was no way to get the version
-number. From C code you can use ELF weak linking tricks to find out if
-this symbol exists (if it doesn't, then it's an earlier version).
+number. From C code you can use dynamic linker functions
+to find out if this symbol exists (if it doesn't, then
+it's an earlier version).
The call returns a structure with four elements. The first
three (C, C and C) are numbers and
@@ -792,9 +805,13 @@ used for distro-specific information.
To construct the original version string:
C<$major.$minor.$release$extra>
+See also: L.
+
I Don't use this call to test for availability
-of features. Distro backports makes this unreliable. Use
-C instead.");
+of features. In enterprise distributions we backport
+features from later versions into earlier versions,
+making this an unreliable way to test for features.
+Use C instead.");
("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
[InitNone, Always, TestOutputTrue (
@@ -942,8 +959,15 @@ exist.
The mounted filesystem is writable, if we have sufficient permissions
on the underlying device.
-The filesystem options C and C are set with this
-call, in order to improve reliability.");
+B
+When you use this call, the filesystem options C and C
+are set implicitly. This was originally done because we thought it
+would improve reliability, but it turns out that I<-o sync> has a
+very large negative performance impact and negligible effect on
+reliability. Therefore we recommend that you avoid using
+C in any code that needs performance, and instead
+use C (use an empty string for the first
+parameter if you don't want any options).");
("sync", (RErr, []), 2, [],
[ InitEmpty, Always, TestRun [["sync"]]],
@@ -1369,7 +1393,9 @@ numeric modes are supported.
I: When using this command from guestfish, C
by default would be decimal, unless you prefix it with
-C<0> to get octal, ie. use C<0700> not C<700>.");
+C<0> to get octal, ie. use C<0700> not C<700>.
+
+The mode actually set is affected by the umask.");
("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
[], (* XXX Need stat command to test *)
@@ -1398,9 +1424,9 @@ See also C, C, C.");
[["is_file"; "/known-1"]]);
InitISOFS, Always, TestOutputFalse (
[["is_file"; "/directory"]])],
- "test if file exists",
+ "test if a regular file",
"\
-This returns C if and only if there is a file
+This returns C if and only if there is a regular file
with the given C name. Note that it returns false for
other objects like directories.
@@ -1462,9 +1488,9 @@ from the non-empty list of physical volumes C.");
["lvs"]],
["/dev/VG1/LV1"; "/dev/VG1/LV2";
"/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
- "create an LVM volume group",
+ "create an LVM logical volume",
"\
-This creates an LVM volume group called C
+This creates an LVM logical volume called C
on the volume group C, with C megabytes.");
("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
@@ -1527,7 +1553,10 @@ C");
["cat"; "/new"]], "\n\n\n");
InitBasicFS, Always, TestOutput (
[["write_file"; "/new"; "\n"; "0"];
- ["cat"; "/new"]], "\n")],
+ ["cat"; "/new"]], "\n");
+ (* Regression test for RHBZ#597135. *)
+ InitBasicFS, Always, TestLastFail
+ [["write_file"; "/new"; "abc"; "10000"]]],
"create a file",
"\
This call creates a file called C. The contents of the
@@ -2066,7 +2095,11 @@ mounts the filesystem with the read-only (I<-o ro>) flag.");
"\
This is the same as the C command, but it
allows you to set the mount options as for the
-L I<-o> flag.");
+L I<-o> flag.
+
+If the C parameter is an empty string, then
+no options are passed (all options default to whatever
+the filesystem uses).");
("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
[],
@@ -2295,7 +2328,18 @@ See also: C.");
"install GRUB",
"\
This command installs GRUB (the Grand Unified Bootloader) on
-C, with the root directory being C.");
+C, with the root directory being C.
+
+Note: If grub-install reports the error
+\"No suitable drive was found in the generated device map.\"
+it may be that you need to create a C
+file first that contains the mapping between grub device names
+and Linux device names. It is usually sufficient to create
+a file containing:
+
+ (hd0) /dev/vda
+
+replacing C with the name of the installation device.");
("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
[InitBasicFS, Always, TestOutput (
@@ -2418,12 +2462,41 @@ the list of printable strings found.");
"print the printable strings in a file",
"\
This is like the C command, but allows you to
-specify the encoding.
+specify the encoding of strings that are looked for in
+the source file C.
+
+Allowed encodings are:
+
+=over 4
+
+=item s
+
+Single 7-bit-byte characters like ASCII and the ASCII-compatible
+parts of ISO-8859-X (this is what C uses).
+
+=item S
-See the L manpage for the full list of encodings.
+Single 8-bit-byte characters.
-Commonly useful encodings are C (lower case L) which will
-show strings inside Windows/x86 files.
+=item b
+
+16-bit big endian strings such as those encoded in
+UTF-16BE or UCS-2BE.
+
+=item l (lower case letter L)
+
+16-bit little endian such as UTF-16LE and UCS-2LE.
+This is useful for examining binaries in Windows guests.
+
+=item B
+
+32-bit big endian such as UCS-4BE.
+
+=item L
+
+32-bit little endian such as UCS-4LE.
+
+=back
The returned strings are transcoded to UTF-8.");
@@ -2556,7 +2629,14 @@ are activated or deactivated.");
["e2fsck_f"; "/dev/VG/LV"];
["resize2fs"; "/dev/VG/LV"];
["mount_options"; ""; "/dev/VG/LV"; "/"];
- ["cat"; "/new"]], "test content")],
+ ["cat"; "/new"]], "test content");
+ InitNone, Always, TestRun (
+ (* Make an LV smaller to test RHBZ#587484. *)
+ [["part_disk"; "/dev/sda"; "mbr"];
+ ["pvcreate"; "/dev/sda1"];
+ ["vgcreate"; "VG"; "/dev/sda1"];
+ ["lvcreate"; "LV"; "VG"; "20"];
+ ["lvresize"; "/dev/VG/LV"; "10"]])],
"resize an LVM logical volume",
"\
This resizes (expands or shrinks) an existing LVM logical
@@ -2565,9 +2645,9 @@ is lost.");
("resize2fs", (RErr, [Device "device"]), 106, [],
[], (* lvresize tests this *)
- "resize an ext2/ext3 filesystem",
+ "resize an ext2, ext3 or ext4 filesystem",
"\
-This resizes an ext2 or ext3 filesystem to match the size of
+This resizes an ext2, ext3 or ext4 filesystem to match the size of
the underlying device.
I It is sometimes required that you run C
@@ -2962,7 +3042,17 @@ named pipes (FIFOs).
The C parameter should be the mode, using the standard
constants. C and C are the
device major and minor numbers, only used when creating block
-and character special devices.");
+and character special devices.
+
+Note that, just like L, the mode must be bitwise
+OR'd with S_IFBLK, S_IFCHR, S_IFIFO or S_IFSOCK (otherwise this call
+just creates a regular file). These constants are
+available in the standard Linux header files, or you can use
+C, C or C
+which are wrappers around this command which bitwise OR
+in the appropriate constant for you.
+
+The mode actually set is affected by the umask.");
("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
[InitBasicFS, Always, TestOutputStruct (
@@ -2972,7 +3062,9 @@ and character special devices.");
"\
This call creates a FIFO (named pipe) called C with
mode C. It is just a convenient wrapper around
-C.");
+C.
+
+The mode actually set is affected by the umask.");
("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
[InitBasicFS, Always, TestOutputStruct (
@@ -2982,7 +3074,9 @@ C.");
"\
This call creates a block device node called C with
mode C and device major/minor C and C.
-It is just a convenient wrapper around C.");
+It is just a convenient wrapper around C.
+
+The mode actually set is affected by the umask.");
("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
[InitBasicFS, Always, TestOutputStruct (
@@ -2992,12 +3086,13 @@ It is just a convenient wrapper around C.");
"\
This call creates a char device node called C with
mode C and device major/minor C and C.
-It is just a convenient wrapper around C.");
+It is just a convenient wrapper around C.
+
+The mode actually set is affected by the umask.");
("umask", (RInt "oldmask", [Int "mask"]), 137, [],
- [], (* XXX umask is one of those stateful things that we should
- * reset between each test.
- *)
+ [InitEmpty, Always, TestOutputInt (
+ [["umask"; "0o22"]], 0o22)],
"set file mode creation mask (umask)",
"\
This function sets the mask used for creating new files and
@@ -3065,7 +3160,7 @@ Unknown file type
=item '?'
-The L returned a C field with an
+The L call returned a C field with an
unexpected value
=back
@@ -3209,7 +3304,20 @@ for full details.");
("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
[InitISOFS, Always, TestOutputBuffer (
- [["read_file"; "/known-4"]], "abc\ndef\nghi")],
+ [["read_file"; "/known-4"]], "abc\ndef\nghi");
+ (* Test various near large, large and too large files (RHBZ#589039). *)
+ InitBasicFS, Always, TestLastFail (
+ [["touch"; "/a"];
+ ["truncate_size"; "/a"; "4194303"]; (* GUESTFS_MESSAGE_MAX - 1 *)
+ ["read_file"; "/a"]]);
+ InitBasicFS, Always, TestLastFail (
+ [["touch"; "/a"];
+ ["truncate_size"; "/a"; "4194304"]; (* GUESTFS_MESSAGE_MAX *)
+ ["read_file"; "/a"]]);
+ InitBasicFS, Always, TestLastFail (
+ [["touch"; "/a"];
+ ["truncate_size"; "/a"; "41943040"]; (* GUESTFS_MESSAGE_MAX * 10 *)
+ ["read_file"; "/a"]])],
"read a file",
"\
This calls returns the contents of the file C as a
@@ -3694,8 +3802,8 @@ was built (see C in the source).");
)],
"echo arguments back to the client",
"\
-This command concatenate the list of C passed with single spaces between
-them and returns the resulting string.
+This command concatenates the list of C passed with single spaces
+between them and returns the resulting string.
You can use this command to test the connection through to the daemon.
@@ -3797,12 +3905,13 @@ See also C.");
[["vfs_type"; "/dev/sda1"]], "ext2")],
"get the Linux VFS type corresponding to a mounted device",
"\
-This command gets the block device type corresponding to
-a mounted device called C.
+This command gets the filesystem type corresponding to
+the filesystem on C.
-Usually the result is the name of the Linux VFS module that
-is used to mount this device (probably determined automatically
-if you used the C call).");
+For most filesystems, the result is the name of the Linux
+VFS module which would be used to mount this filesystem
+if you mounted it without specifying the filesystem type.
+For example a string such as C or C.");
("truncate", (RErr, [Pathname "path"]), 199, [],
[InitBasicFS, Always, TestOutputStruct (
@@ -3822,8 +3931,13 @@ file must exist already.");
"truncate a file to a particular size",
"\
This command truncates C to size C bytes. The file
-must exist already. If the file is smaller than C then
-the file is extended to the required size with null bytes.");
+must exist already.
+
+If the current file size is less than C then
+the file is extended to the required size with zero bytes.
+This creates a sparse file (ie. disk blocks are not allocated
+for the file until you write to it). To create a non-sparse
+file of zeroes, use C instead.");
("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
[InitBasicFS, Always, TestOutputStruct (
@@ -3856,7 +3970,13 @@ C<*secs> field is ignored in this case).");
"create a directory with a particular mode",
"\
This command creates a directory, setting the initial permissions
-of the directory to C. See also C.");
+of the directory to C.
+
+For common Linux filesystems, the actual mode which is set will
+be C. Non-native-Linux filesystems may
+interpret the mode in other ways.
+
+See also C, C");
("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
[], (* XXX *)
@@ -3927,7 +4047,7 @@ C is the list of files from this directory.
On return you get a list of strings, with a one-to-one
correspondence to the C list. Each string is the
-value of the symbol link.
+value of the symbolic link.
If the C operation fails on any name, then
the corresponding result string is the empty string C<\"\">.
@@ -4082,10 +4202,9 @@ but other possible values are described in C.");
This sets the bootable flag on partition numbered C on
device C. Note that partitions are numbered from 1.
-The bootable flag is used by some PC BIOSes to determine which
-partition to boot from. It is by no means universally recognized,
-and in any case if your operating system installed a boot
-sector on the device itself, then that takes precedence.");
+The bootable flag is used by some operating systems (notably
+Windows) to determine which partition to boot from. It is by
+no means universally recognized.");
("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
[InitEmpty, Always, TestRun (
@@ -4229,7 +4348,7 @@ example to duplicate a filesystem.
If the destination is a device, it must be as large or larger
than the source file or device, otherwise the copy will fail.
-This command cannot do partial copies.");
+This command cannot do partial copies (see C).");
("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
[InitBasicFS, Always, TestOutputInt (
@@ -4280,6 +4399,116 @@ contained in a Linux initrd or initramfs image:
See also C.");
+ ("pvuuid", (RString "uuid", [Device "device"]), 222, [],
+ [],
+ "get the UUID of a physical volume",
+ "\
+This command returns the UUID of the LVM PV C.");
+
+ ("vguuid", (RString "uuid", [String "vgname"]), 223, [],
+ [],
+ "get the UUID of a volume group",
+ "\
+This command returns the UUID of the LVM VG named C.");
+
+ ("lvuuid", (RString "uuid", [Device "device"]), 224, [],
+ [],
+ "get the UUID of a logical volume",
+ "\
+This command returns the UUID of the LVM LV C.");
+
+ ("vgpvuuids", (RStringList "uuids", [String "vgname"]), 225, [],
+ [],
+ "get the PV UUIDs containing the volume group",
+ "\
+Given a VG called C, this returns the UUIDs of all
+the physical volumes that this volume group resides on.
+
+You can use this along with C and C
+calls to associate physical volumes and volume groups.
+
+See also C.");
+
+ ("vglvuuids", (RStringList "uuids", [String "vgname"]), 226, [],
+ [],
+ "get the LV UUIDs of all LVs in the volume group",
+ "\
+Given a VG called C, this returns the UUIDs of all
+the logical volumes created in this volume group.
+
+You can use this along with C and C
+calls to associate logical volumes and volume groups.
+
+See also C.");
+
+ ("copy_size", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"; Int64 "size"]), 227, [],
+ [InitBasicFS, Always, TestOutputBuffer (
+ [["write_file"; "/src"; "hello, world"; "0"];
+ ["copy_size"; "/src"; "/dest"; "5"];
+ ["read_file"; "/dest"]], "hello")],
+ "copy size bytes from source to destination using dd",
+ "\
+This command copies exactly C bytes from one source device
+or file C to another destination device or file C.
+
+Note this will fail if the source is too short or if the destination
+is not large enough.");
+
+ ("part_del", (RErr, [Device "device"; Int "partnum"]), 233, [],
+ [InitEmpty, Always, TestRun (
+ [["part_init"; "/dev/sda"; "mbr"];
+ ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
+ ["part_del"; "/dev/sda"; "1"]])],
+ "delete a partition",
+ "\
+This command deletes the partition numbered C on C.
+
+Note that in the case of MBR partitioning, deleting an
+extended partition also deletes any logical partitions
+it contains.");
+
+ ("part_get_bootable", (RBool "bootable", [Device "device"; Int "partnum"]), 234, [],
+ [InitEmpty, Always, TestOutputTrue (
+ [["part_init"; "/dev/sda"; "mbr"];
+ ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
+ ["part_set_bootable"; "/dev/sda"; "1"; "true"];
+ ["part_get_bootable"; "/dev/sda"; "1"]])],
+ "return true if a partition is bootable",
+ "\
+This command returns true if the partition C on
+C has the bootable flag set.
+
+See also C.");
+
+ ("part_get_mbr_id", (RInt "idbyte", [Device "device"; Int "partnum"]), 235, [],
+ [InitEmpty, Always, TestOutputInt (
+ [["part_init"; "/dev/sda"; "mbr"];
+ ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
+ ["part_set_mbr_id"; "/dev/sda"; "1"; "0x7f"];
+ ["part_get_mbr_id"; "/dev/sda"; "1"]], 0x7f)],
+ "get the MBR type byte (ID byte) from a partition",
+ "\
+Returns the MBR type byte (also known as the ID byte) from
+the numbered partition C.
+
+Note that only MBR (old DOS-style) partitions have type bytes.
+You will get undefined results for other partition table
+types (see C).");
+
+ ("part_set_mbr_id", (RErr, [Device "device"; Int "partnum"; Int "idbyte"]), 236, [],
+ [], (* tested by part_get_mbr_id *)
+ "set the MBR type byte (ID byte) of a partition",
+ "\
+Sets the MBR type byte (also known as the ID byte) of
+the numbered partition C to C. Note
+that the type bytes quoted in most documentation are
+in fact hexadecimal numbers, but usually documented
+without any leading \"0x\" which might be confusing.
+
+Note that only MBR (old DOS-style) partitions have type bytes.
+You will get undefined results for other partition table
+types (see C).");
+
]
let all_functions = non_daemon_functions @ daemon_functions
@@ -4845,7 +5074,7 @@ let check_functions () =
failwithf "short description of %s should not end with . or \\n." name
) all_functions;
- (* Check long dscriptions. *)
+ (* Check long descriptions. *)
List.iter (
fun (name, _, _, _, _, _, longdesc) ->
if longdesc.[String.length longdesc-1] = '\n' then
@@ -4990,7 +5219,7 @@ let rec generate_actions_pod () =
let name = "guestfs_" ^ shortname in
pr "=head2 %s\n\n" name;
pr " ";
- generate_prototype ~extern:false ~handle:"handle" name style;
+ generate_prototype ~extern:false ~handle:"g" name style;
pr "\n\n";
pr "%s\n\n" longdesc;
(match fst style with
@@ -5007,7 +5236,7 @@ let rec generate_actions_pod () =
The string is owned by the guest handle and must I be freed.\n\n"
| RConstOptString _ ->
pr "This function returns a string which may be NULL.
-There is way to return an error from this function.
+There is no way to return an error from this function.
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.
@@ -5112,7 +5341,7 @@ and generate_xdr () =
generate_header CStyle LGPLv2plus;
(* This has to be defined to get around a limitation in Sun's rpcgen. *)
- pr "typedef string str<>;\n";
+ pr "typedef string guestfs_str<>;\n";
pr "\n";
(* Internal structures. *)
@@ -5147,8 +5376,8 @@ and generate_xdr () =
function
| Pathname n | Device n | Dev_or_Path n | String n ->
pr " string %s<>;\n" n
- | OptString n -> pr " str *%s;\n" n
- | StringList n | DeviceList n -> pr " str %s<>;\n" n
+ | OptString n -> pr " guestfs_str *%s;\n" n
+ | StringList n | DeviceList n -> pr " guestfs_str %s<>;\n" n
| Bool n -> pr " bool %s;\n" n
| Int n -> pr " int %s;\n" n
| Int64 n -> pr " hyper %s;\n" n
@@ -5178,7 +5407,7 @@ and generate_xdr () =
pr "};\n\n"
| RStringList n ->
pr "struct %s_ret {\n" name;
- pr " str %s<>;\n" n;
+ pr " guestfs_str %s<>;\n" n;
pr "};\n\n"
| RStruct (n, typ) ->
pr "struct %s_ret {\n" name;
@@ -5190,7 +5419,7 @@ and generate_xdr () =
pr "};\n\n"
| RHashtable n ->
pr "struct %s_ret {\n" name;
- pr " str %s<>;\n" n;
+ pr " guestfs_str %s<>;\n" n;
pr "};\n\n"
| RBufferOut n ->
pr "struct %s_ret {\n" name;
@@ -5318,7 +5547,7 @@ and generate_actions_h () =
List.iter (
fun (shortname, style, _, _, _, _, _) ->
let name = "guestfs_" ^ shortname in
- generate_prototype ~single_line:true ~newline:true ~handle:"handle"
+ generate_prototype ~single_line:true ~newline:true ~handle:"g"
name style
) all_functions
@@ -5328,7 +5557,7 @@ and generate_internal_actions_h () =
List.iter (
fun (shortname, style, _, _, _, _, _) ->
let name = "guestfs__" ^ shortname in
- generate_prototype ~single_line:true ~newline:true ~handle:"handle"
+ generate_prototype ~single_line:true ~newline:true ~handle:"g"
name style
) non_daemon_functions
@@ -5340,6 +5569,7 @@ and generate_client_actions () =
#include
#include
#include
+#include
#include
#include \"guestfs.h\"
@@ -5413,7 +5643,7 @@ check_state (guestfs_h *g, const char *caller)
| StringList _ | DeviceList _ -> true
| _ -> false) (snd style) in
if needs_i then (
- pr " int i;\n";
+ pr " size_t i;\n";
pr "\n"
);
@@ -5722,6 +5952,8 @@ and generate_linker_script () =
*)
"guestfs_safe_calloc";
"guestfs_safe_malloc";
+ "guestfs_safe_strdup";
+ "guestfs_safe_memdup";
] in
let functions =
List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
@@ -5842,9 +6074,12 @@ and generate_daemon_actions () =
| DeviceList n ->
pr_list_handling_code n;
pr " /* Ensure that each is a device,\n";
- pr " * and perform device name translation. */\n";
- pr " { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
- pr " RESOLVE_DEVICE (physvols[pvi], goto done);\n";
+ pr " * and perform device name translation.\n";
+ pr " */\n";
+ pr " {\n";
+ pr " size_t i;\n";
+ pr " for (i = 0; %s[i] != NULL; ++i)\n" n;
+ pr " RESOLVE_DEVICE (%s[i], goto done);\n" n;
pr " }\n";
| Bool n -> pr " %s = args.%s;\n" n n
| Int n -> pr " %s = args.%s;\n" n n
@@ -5989,7 +6224,7 @@ and generate_daemon_actions () =
pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
pr "{\n";
pr " char *tok, *p, *next;\n";
- pr " int i, j;\n";
+ pr " size_t i, j;\n";
pr "\n";
(*
pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
@@ -6078,7 +6313,7 @@ and generate_daemon_actions () =
pr " ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
pr "\n";
pr " r = command (&out, &err,\n";
- pr " \"/sbin/lvm\", \"%ss\",\n" typ;
+ pr " \"lvm\", \"%ss\",\n" typ;
pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
pr " if (r == -1) {\n";
@@ -6214,7 +6449,7 @@ static void print_error (guestfs_h *g, void *data, const char *msg)
/* FIXME: nearly identical code appears in fish.c */
static void print_strings (char *const *argv)
{
- int argc;
+ size_t argc;
for (argc = 0; argv[argc] != NULL; ++argc)
printf (\"\\t%%s\\n\", argv[argc]);
@@ -6223,13 +6458,26 @@ static void print_strings (char *const *argv)
/*
static void print_table (char const *const *argv)
{
- int i;
+ size_t i;
for (i = 0; argv[i] != NULL; i += 2)
printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
}
*/
+static int
+is_available (const char *group)
+{
+ const char *groups[] = { group, NULL };
+ int r;
+
+ suppress_error = 1;
+ r = guestfs_available (g, (char **) groups);
+ suppress_error = 0;
+
+ return r == 0;
+}
+
";
(* Generate a list of commands which are not tested anywhere. *)
@@ -6241,7 +6489,7 @@ static void print_table (char const *const *argv)
fun (_, _, _, _, tests, _, _) ->
let tests = filter_map (
function
- | (_, (Always|If _|Unless _), test) -> Some test
+ | (_, (Always|If _|Unless _|IfAvailable _), test) -> Some test
| (_, Disabled, _) -> None
) tests in
let seq = List.concat (List.map seq_of_test tests) in
@@ -6383,14 +6631,14 @@ int main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
+ /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
+ alarm (600);
+
if (guestfs_launch (g) == -1) {
printf (\"guestfs_launch FAILED\\n\");
exit (EXIT_FAILURE);
}
- /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
- alarm (600);
-
/* Cancel previous alarm. */
alarm (0);
@@ -6401,6 +6649,8 @@ int main (int argc, char *argv[])
iteri (
fun i test_name ->
pr " test_num++;\n";
+ pr " if (guestfs_get_verbose (g))\n";
+ pr " printf (\"-------------------------------------------------------------------------------\\n\");\n";
pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
pr " if (%s () == -1) {\n" test_name;
pr " printf (\"%s FAILED\\n\");\n" test_name;
@@ -6445,7 +6695,7 @@ static int %s_skip (void)
" test_name name (String.uppercase test_name) (String.uppercase name);
(match prereq with
- | Disabled | Always -> ()
+ | Disabled | Always | IfAvailable _ -> ()
| If code | Unless code ->
pr "static int %s_prereq (void)\n" test_name;
pr "{\n";
@@ -6470,16 +6720,9 @@ static int %s (void)
List.iter (
function
| Optional group ->
- pr " {\n";
- pr " const char *groups[] = { \"%s\", NULL };\n" group;
- pr " int r;\n";
- pr " suppress_error = 1;\n";
- pr " r = guestfs_available (g, (char **) groups);\n";
- pr " suppress_error = 0;\n";
- pr " if (r == -1) {\n";
- pr " printf (\" %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", groups[0]);\n" test_name;
- pr " return 0;\n";
- pr " }\n";
+ pr " if (!is_available (\"%s\")) {\n" group;
+ pr " printf (\" %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", \"%s\");\n" test_name group;
+ pr " return 0;\n";
pr " }\n";
| _ -> ()
) flags;
@@ -6501,6 +6744,13 @@ static int %s (void)
pr " }\n";
pr "\n";
generate_one_test_body name i test_name init test;
+ | IfAvailable group ->
+ pr " if (!is_available (\"%s\")) {\n" group;
+ pr " printf (\" %%s skipped (reason: %%s not available)\\n\", \"%s\", \"%s\");\n" test_name group;
+ pr " return 0;\n";
+ pr " }\n";
+ pr "\n";
+ generate_one_test_body name i test_name init test;
| Always ->
generate_one_test_body name i test_name init test
);
@@ -6842,7 +7092,7 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
| RString _ -> pr " char *r;\n"; "NULL"
| RStringList _ | RHashtable _ ->
pr " char **r;\n";
- pr " int i;\n";
+ pr " size_t i;\n";
"NULL"
| RStruct (_, typ) ->
pr " struct guestfs_%s *r;\n" typ; "NULL"
@@ -6971,7 +7221,7 @@ and generate_fish_cmds () =
pr "\n";
(* display_command function, which implements guestfish -h cmd *)
- pr "void display_command (const char *cmd)\n";
+ pr "int display_command (const char *cmd)\n";
pr "{\n";
List.iter (
fun (name, style, _, flags, _, shortdesc, longdesc) ->
@@ -7019,15 +7269,17 @@ and generate_fish_cmds () =
pr " || STRCASEEQ (cmd, \"%s\")" name2;
if name <> alias then
pr " || STRCASEEQ (cmd, \"%s\")" alias;
- pr ")\n";
+ pr ") {\n";
pr " pod2text (\"%s\", _(\"%s\"), %S);\n"
name2 shortdesc
("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
"=head1 DESCRIPTION\n\n" ^
longdesc ^ warnings ^ describe_alias);
+ pr " return 0;\n";
+ pr " }\n";
pr " else\n"
) all_functions;
- pr " display_builtin_command (cmd);\n";
+ pr " return display_builtin_command (cmd);\n";
pr "}\n";
pr "\n";
@@ -7236,9 +7488,10 @@ and generate_fish_cmds () =
List.iter (
function
- | Device name | String name
- | OptString name | FileIn name | FileOut name | Bool name
- | Int name | Int64 name -> ()
+ | Device _ | String _
+ | OptString _ | Bool _
+ | Int _ | Int64 _
+ | FileIn _ | FileOut _ -> ()
| Pathname name | Dev_or_Path name ->
pr " free (%s);\n" name
| StringList name | DeviceList name ->
@@ -7327,6 +7580,8 @@ and generate_fish_cmds () =
) all_functions;
pr " {\n";
pr " fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
+ pr " if (command_num == 1)\n";
+ pr " extended_help_message ();\n";
pr " return -1;\n";
pr " }\n";
pr " return 0;\n";
@@ -7384,7 +7639,7 @@ static const char *const commands[] = {
static char *
generator (const char *text, int state)
{
- static int index, len;
+ static size_t index, len;
const char *name;
if (!state) {
@@ -7405,7 +7660,16 @@ generator (const char *text, int state)
#endif /* HAVE_LIBREADLINE */
-char **do_completion (const char *text, int start, int end)
+#ifdef HAVE_RL_COMPLETION_MATCHES
+#define RL_COMPLETION_MATCHES rl_completion_matches
+#else
+#ifdef HAVE_COMPLETION_MATCHES
+#define RL_COMPLETION_MATCHES completion_matches
+#endif
+#endif /* else just fail if we don't have either symbol */
+
+char **
+do_completion (const char *text, int start, int end)
{
char **matches = NULL;
@@ -7413,9 +7677,9 @@ char **do_completion (const char *text, int start, int end)
rl_completion_append_character = ' ';
if (start == 0)
- matches = rl_completion_matches (text, generator);
+ matches = RL_COMPLETION_MATCHES (text, generator);
else if (complete_dest_paths)
- matches = rl_completion_matches (text, complete_dest_paths_generator);
+ matches = RL_COMPLETION_MATCHES (text, complete_dest_paths_generator);
#endif
return matches;
@@ -7659,7 +7923,7 @@ and generate_ocaml_c () =
#include
#include
-#include
+#include \"guestfs.h\"
#include \"guestfs_c.h\"
@@ -7672,7 +7936,7 @@ copy_table (char * const * argv)
{
CAMLparam0 ();
CAMLlocal5 (rv, pairv, kv, vv, cons);
- int i;
+ size_t i;
rv = Val_int (0);
for (i = 0; argv[i] != NULL; i += 2) {
@@ -7827,11 +8091,12 @@ copy_table (char * const * argv)
| String n
| FileIn n
| FileOut n ->
- pr " const char *%s = String_val (%sv);\n" n n
+ (* Copy strings in case the GC moves them: RHBZ#604691 *)
+ pr " char *%s = guestfs_safe_strdup (g, String_val (%sv));\n" n n
| OptString n ->
- pr " const char *%s =\n" n;
- pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
- n n
+ pr " char *%s =\n" n;
+ pr " %sv != Val_int (0) ?" n;
+ pr " guestfs_safe_strdup (g, String_val (Field (%sv, 0))) : NULL;\n" n
| StringList n | DeviceList n ->
pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
| Bool n ->
@@ -7851,7 +8116,7 @@ copy_table (char * const * argv)
pr " const char *r;\n"; "NULL"
| RString _ -> pr " char *r;\n"; "NULL"
| RStringList _ ->
- pr " int i;\n";
+ pr " size_t i;\n";
pr " char **r;\n";
"NULL"
| RStruct (_, typ) ->
@@ -7859,7 +8124,7 @@ copy_table (char * const * argv)
| RStructList (_, typ) ->
pr " struct guestfs_%s_list *r;\n" typ; "NULL"
| RHashtable _ ->
- pr " int i;\n";
+ pr " size_t i;\n";
pr " char **r;\n";
"NULL"
| RBufferOut _ ->
@@ -7874,13 +8139,15 @@ copy_table (char * const * argv)
pr ";\n";
pr " caml_leave_blocking_section ();\n";
+ (* Free strings if we copied them above. *)
List.iter (
function
+ | Pathname n | Device n | Dev_or_Path n | String n | OptString n
+ | FileIn n | FileOut n ->
+ pr " free (%s);\n" n
| StringList n | DeviceList n ->
pr " ocaml_guestfs_free_strings (%s);\n" n;
- | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
- | Bool _ | Int _ | Int64 _
- | FileIn _ | FileOut _ -> ()
+ | Bool _ | Int _ | Int64 _ -> ()
) (snd style);
pr " if (r == %s)\n" error_code;
@@ -8219,7 +8486,7 @@ DESTROY (g)
| RStringList n | RHashtable n ->
pr "PREINIT:\n";
pr " char **%s;\n" n;
- pr " int i, n;\n";
+ pr " size_t i, n;\n";
pr " PPCODE:\n";
pr " %s = guestfs_%s " n name;
generate_c_call_args ~handle:"g" style;
@@ -8251,7 +8518,7 @@ DESTROY (g)
do_cleanups ();
pr " if (%s == NULL)\n" n;
pr " croak (\"%%s\", guestfs_last_error (g));\n";
- pr " RETVAL = newSVpv (%s, size);\n" n;
+ pr " RETVAL = newSVpvn (%s, size);\n" n;
pr " free (%s);\n" n;
pr " OUTPUT:\n";
pr " RETVAL\n"
@@ -8263,7 +8530,7 @@ DESTROY (g)
and generate_perl_struct_list_code typ cols name style n do_cleanups =
pr "PREINIT:\n";
pr " struct guestfs_%s_list *%s;\n" typ n;
- pr " int i;\n";
+ pr " size_t i;\n";
pr " HV *hv;\n";
pr " PPCODE:\n";
pr " %s = guestfs_%s " n name;
@@ -8284,7 +8551,7 @@ and generate_perl_struct_list_code typ cols name style n do_cleanups =
pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
name (String.length name) n name
| name, FBuffer ->
- pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
+ pr " (void) hv_store (hv, \"%s\", %d, newSVpvn (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
name (String.length name) n name n name
| name, (FBytes|FUInt64) ->
pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
@@ -8326,7 +8593,7 @@ and generate_perl_struct_code typ cols name style n do_cleanups =
pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
n name
| name, FBuffer ->
- pr " PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
+ pr " PUSHs (sv_2mortal (newSVpvn (%s->%s, %s->%s_len)));\n"
n name n name
| name, FUUID ->
pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
@@ -8462,6 +8729,37 @@ sub new {
=back
+=head1 AVAILABILITY
+
+From time to time we add new libguestfs APIs. Also some libguestfs
+APIs won't be available in all builds of libguestfs (the Fedora
+build is full-featured, but other builds may disable features).
+How do you test whether the APIs that your Perl program needs are
+available in the version of C that you are using?
+
+To test if a particular function is available in the C
+class, use the ordinary Perl UNIVERSAL method C
+(see L). For example:
+
+ use Sys::Guestfs;
+ if (defined (Sys::Guestfs->can (\"set_verbose\"))) {
+ print \"\\$h->set_verbose is available\\n\";
+ }
+
+To test if particular features are supported by the current
+build, use the L method like the example below. Note
+that the appliance must be launched first.
+
+ $h->available ( [\"augeas\"] );
+
+Since the L method croaks if the feature is not supported,
+you might also want to wrap this in an eval and return a boolean.
+In fact this has already been done for you: use
+L.
+
+For further discussion on this topic, refer to
+L.
+
=head1 COPYRIGHT
Copyright (C) %s Red Hat Inc.
@@ -8517,6 +8815,12 @@ and generate_python_c () =
pr "\
#include
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
+
#include
#include
#include
@@ -8548,7 +8852,7 @@ put_handle (guestfs_h *g)
static char **
get_string_list (PyObject *obj)
{
- int i, len;
+ size_t i, len;
char **r;
assert (obj);
@@ -8558,7 +8862,12 @@ get_string_list (PyObject *obj)
return NULL;
}
- len = PyList_Size (obj);
+ Py_ssize_t slen = PyList_Size (obj);
+ if (slen == -1) {
+ PyErr_SetString (PyExc_RuntimeError, \"get_string_list: PyList_Size failure\");
+ return NULL;
+ }
+ len = (size_t) slen;
r = malloc (sizeof (char *) * (len+1));
if (r == NULL) {
PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
@@ -8656,7 +8965,7 @@ py_guestfs_close (PyObject *self, PyObject *args)
pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
pr "{\n";
pr " PyObject *list;\n";
- pr " int i;\n";
+ pr " size_t i;\n";
pr "\n";
pr " list = PyList_New (%ss->len);\n" typ;
pr " for (i = 0; i < %ss->len; ++i)\n" typ;
@@ -9139,7 +9448,7 @@ static VALUE ruby_guestfs_close (VALUE gv)
pr " char **%s;\n" n;
pr " Check_Type (%sv, T_ARRAY);\n" n;
pr " {\n";
- pr " int i, len;\n";
+ pr " size_t i, len;\n";
pr " len = RARRAY_LEN (%sv);\n" n;
pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
n;
@@ -9210,7 +9519,7 @@ static VALUE ruby_guestfs_close (VALUE gv)
pr " free (r);\n";
pr " return rv;\n";
| RStringList _ ->
- pr " int i, len = 0;\n";
+ pr " size_t i, len = 0;\n";
pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
pr " VALUE rv = rb_ary_new2 (len);\n";
pr " for (i = 0; r[i] != NULL; ++i) {\n";
@@ -9227,7 +9536,7 @@ static VALUE ruby_guestfs_close (VALUE gv)
generate_ruby_struct_list_code typ cols
| RHashtable _ ->
pr " VALUE rv = rb_hash_new ();\n";
- pr " int i;\n";
+ pr " size_t i;\n";
pr " for (i = 0; r[i] != NULL; i+=2) {\n";
pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
pr " free (r[i]);\n";
@@ -9296,7 +9605,7 @@ and generate_ruby_struct_code typ cols =
(* Ruby code to return a struct list. *)
and generate_ruby_struct_list_code typ cols =
pr " VALUE rv = rb_ary_new2 (r->len);\n";
- pr " int i;\n";
+ pr " size_t i;\n";
pr " for (i = 0; i < r->len; ++i) {\n";
pr " VALUE hv = rb_hash_new ();\n";
List.iter (
@@ -9696,7 +10005,7 @@ Java_com_redhat_et_libguestfs_GuestFS__1close
| DeviceList _ -> true
| _ -> false) (snd style) in
if needs_i then
- pr " int i;\n";
+ pr " size_t i;\n";
pr "\n";
@@ -10334,7 +10643,7 @@ namespace Guestfs
pr " return r != 0 ? true : false;\n"
| RHashtable _ ->
pr " Hashtable rr = new Hashtable ();\n";
- pr " for (int i = 0; i < r.Length; i += 2)\n";
+ pr " for (size_t i = 0; i < r.Length; i += 2)\n";
pr " rr.Add (r[i], r[i+1]);\n";
pr " return rr;\n"
| RInt _ | RInt64 _ | RConstString _ | RConstOptString _
@@ -10371,7 +10680,7 @@ and generate_bindtests () =
static void
print_strings (char *const *argv)
{
- int argc;
+ size_t argc;
printf (\"[\");
for (argc = 0; argv[argc] != NULL; ++argc) {