"set autosync mode",
"\
If C<autosync> is true, this enables autosync. Libguestfs will make a
-best effort attempt to run C<guestfs_sync> when the handle is closed
-(also if the program exits without closing handles).");
+best effort attempt to run C<guestfs_umount_all> followed by
+C<guestfs_sync> 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, [],
[],
"make a filesystem",
"\
This creates a filesystem on C<device> (usually a partition
-of LVM logical volume). The filesystem type is C<fstype>, for
+or LVM logical volume). The filesystem type is C<fstype>, for
example C<ext3>.");
("sfdisk", (RErr, [String "device";
("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",
"\
This returns the ext2/3/4 filesystem UUID of the filesystem on
C<device>.");
+ ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
+ [InitBasicFS, TestOutputInt (
+ [["umount"; "/dev/sda1"];
+ ["fsck"; "ext2"; "/dev/sda1"]], 0);
+ InitBasicFS, TestOutputInt (
+ [["umount"; "/dev/sda1"];
+ ["zero"; "/dev/sda1"];
+ ["fsck"; "ext2"; "/dev/sda1"]], 8)],
+ "run the filesystem checker",
+ "\
+This runs the filesystem checker (fsck) on C<device> which
+should have filesystem type C<fstype>.
+
+The returned integer is the status. See L<fsck(8)> for the
+list of status codes from C<fsck>.
+
+Notes:
+
+=over 4
+
+=item *
+
+Multiple status codes can be summed together.
+
+=item *
+
+A non-zero return code can mean \"success\", for example if
+errors have been corrected on the filesystem.
+
+=item *
+
+Checking or repairing NTFS volumes is not supported
+(by linux-ntfs).
+
+=back
+
+This command is entirely equivalent to running C<fsck -a -t fstype device>.");
+
+ ("zero", (RErr, [String "device"]), 85, [],
+ [InitBasicFS, TestOutput (
+ [["umount"; "/dev/sda1"];
+ ["zero"; "/dev/sda1"];
+ ["file"; "/dev/sda1"]], "data")],
+ "write zeroes to the device",
+ "\
+This command writes zeroes over the first few blocks of C<device>.
+
+How many blocks are zeroed isn't specified (but it's I<not> enough
+to securely wipe the device). It should be sufficient to remove
+any partition tables, filesystem superblocks and so on.");
+
+ ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
+ [InitBasicFS, TestOutputTrue (
+ [["grub_install"; "/"; "/dev/sda1"];
+ ["is_dir"; "/boot"]])],
+ "install GRUB",
+ "\
+This command installs GRUB (the Grand Unified Bootloader) on
+C<device>, with the root directory being C<root>.");
+
+ ("cp", (RErr, [String "src"; String "dest"]), 87, [],
+ [InitBasicFS, TestOutput (
+ [["write_file"; "/old"; "file content"; "0"];
+ ["cp"; "/old"; "/new"];
+ ["cat"; "/new"]], "file content");
+ InitBasicFS, TestOutputTrue (
+ [["write_file"; "/old"; "file content"; "0"];
+ ["cp"; "/old"; "/new"];
+ ["is_file"; "/old"]]);
+ InitBasicFS, TestOutput (
+ [["write_file"; "/old"; "file content"; "0"];
+ ["mkdir"; "/dir"];
+ ["cp"; "/old"; "/dir/new"];
+ ["cat"; "/dir/new"]], "file content")],
+ "copy a file",
+ "\
+This copies a file from C<src> to C<dest> where C<dest> is
+either a destination filename or destination directory.");
+
+ ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
+ [InitBasicFS, TestOutput (
+ [["mkdir"; "/olddir"];
+ ["mkdir"; "/newdir"];
+ ["write_file"; "/olddir/file"; "file content"; "0"];
+ ["cp_a"; "/olddir"; "/newdir"];
+ ["cat"; "/newdir/olddir/file"]], "file content")],
+ "copy a file or directory recursively",
+ "\
+This copies a file or directory from C<src> to C<dest>
+recursively using the C<cp -a> command.");
+
+ ("mv", (RErr, [String "src"; String "dest"]), 89, [],
+ [InitBasicFS, TestOutput (
+ [["write_file"; "/old"; "file content"; "0"];
+ ["mv"; "/old"; "/new"];
+ ["cat"; "/new"]], "file content");
+ InitBasicFS, TestOutputFalse (
+ [["write_file"; "/old"; "file content"; "0"];
+ ["mv"; "/old"; "/new"];
+ ["is_file"; "/old"]])],
+ "move a file",
+ "\
+This moves a file from C<src> to C<dest> where C<dest> is
+either a destination filename or destination directory.");
+
+ ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
+ [InitEmpty, TestRun (
+ [["drop_caches"; "3"]])],
+ "drop kernel page cache, dentries and inodes",
+ "\
+This instructs the guest kernel to drop its page cache,
+and/or dentries and inode caches. The parameter C<whattodrop>
+tells the kernel what precisely to drop, see
+L<http://linux-mm.org/Drop_Caches>
+
+Setting C<whattodrop> to 3 should drop everything.
+
+This automatically calls L<sync(2)> before the operation,
+so that the maximum guest memory is freed.");
+
+ ("dmesg", (RString "kmsgs", []), 91, [],
+ [InitEmpty, TestRun (
+ [["dmesg"]])],
+ "return kernel messages",
+ "\
+This returns the kernel messages (C<dmesg> output) from
+the guest kernel. This is sometimes useful for extended
+debugging of problems.
+
+Another way to get the same information is to enable
+verbose messages with C<guestfs_set_verbose> or by setting
+the environment variable C<LIBGUESTFS_DEBUG=1> before
+running the program.");
+
+ ("ping_daemon", (RErr, []), 92, [],
+ [InitEmpty, TestRun (
+ [["ping_daemon"]])],
+ "ping the guest daemon",
+ "\
+This is a test probe into the guestfs daemon running inside
+the qemu subprocess. Calling this function checks that the
+daemon responds to the ping message, without affecting the daemon
+or attached block device(s) in any other way.");
+
+ ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
+ [InitBasicFS, TestOutputTrue (
+ [["write_file"; "/file1"; "contents of a file"; "0"];
+ ["cp"; "/file1"; "/file2"];
+ ["equal"; "/file1"; "/file2"]]);
+ InitBasicFS, TestOutputFalse (
+ [["write_file"; "/file1"; "contents of a file"; "0"];
+ ["write_file"; "/file2"; "contents of another file"; "0"];
+ ["equal"; "/file1"; "/file2"]]);
+ InitBasicFS, TestLastFail (
+ [["equal"; "/file1"; "/file2"]])],
+ "test if two files have equal contents",
+ "\
+This compares the two files C<file1> and C<file2> and returns
+true if their content is exactly equal, or false otherwise.
+
+The external L<cmp(1)> program is used for the comparison.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
s' :: string_split sep s''
)
+let files_equal n1 n2 =
+ let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
+ match Sys.command cmd with
+ | 0 -> true
+ | 1 -> false
+ | i -> failwithf "%s: failed with error code %d" cmd i
+
let rec find_map f = function
| [] -> raise Not_found
| x :: xs ->
#include \"extconf.h\"
+/* For Ruby < 1.9 */
+#ifndef RARRAY_LEN
+#define RARRAY_LEN(r) (RARRAY((r))->len)
+#endif
+
static VALUE m_guestfs; /* guestfs module */
static VALUE c_guestfs; /* guestfs_h handle */
static VALUE e_Error; /* used for all errors */
let needs_i =
(match fst style with
| RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
- | RErr _ | RBool _ | RInt _ | RInt64 _ | RConstString _
+ | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
| RString _ | RIntBool _ | RStat _ | RStatVFS _
| RHashtable _ -> false) ||
List.exists (function StringList _ -> true | _ -> false) (snd style) in
let close () =
close_out !chan;
chan := stdout;
- Unix.rename filename_new filename;
- printf "written %s\n%!" filename;
+
+ (* Is the new file different from the current file? *)
+ if Sys.file_exists filename && files_equal filename filename_new then
+ Unix.unlink filename_new (* same, so skip it *)
+ else (
+ (* different, overwrite old one *)
+ (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
+ Unix.rename filename_new filename;
+ Unix.chmod filename 0o444;
+ printf "written %s\n%!" filename;
+ )
in
close