"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, [],
[],
("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",
"\
wipe physical volumes that contain any volume groups, so you have
to remove those first.");
+ ("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<device> to C<label>. Filesystem labels are limited to
+16 characters.
+
+You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
+to return the existing label on a filesystem.");
+
+ ("get_e2label", (RString "label", [String "device"]), 81, [],
+ [],
+ "get the ext2/3/4 filesystem label",
+ "\
+This returns the ext2/3/4 filesystem label of the filesystem on
+C<device>.");
+
+ ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
+ [InitBasicFS, TestOutput (
+ [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
+ ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
+ InitBasicFS, TestOutput (
+ [["set_e2uuid"; "/dev/sda1"; "clear"];
+ ["get_e2uuid"; "/dev/sda1"]], "");
+ (* We can't predict what UUIDs will be, so just check the commands run. *)
+ InitBasicFS, TestRun (
+ [["set_e2uuid"; "/dev/sda1"; "random"]]);
+ InitBasicFS, TestRun (
+ [["set_e2uuid"; "/dev/sda1"; "time"]])],
+ "set the ext2/3/4 filesystem UUID",
+ "\
+This sets the ext2/3/4 filesystem UUID of the filesystem on
+C<device> to C<uuid>. The format of the UUID and alternatives
+such as C<clear>, C<random> and C<time> are described in the
+L<tune2fs(8)> manpage.
+
+You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
+to return the existing UUID of a filesystem.");
+
+ ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
+ [],
+ "get the ext2/3/4 filesystem UUID",
+ "\
+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.");
+
+
]
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 ->
| 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
+ pr " %s = realloc (args.%s.%s_val,\n" n n n;
+ pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
+ pr " if (%s == NULL) {\n" n;
+ pr " reply_with_perror (\"realloc\");\n";
+ pr " goto done;\n";
+ pr " }\n";
+ pr " %s[args.%s.%s_len] = NULL;\n" n n n;
+ pr " args.%s.%s_val = %s;\n" n n n;
| Bool n -> pr " %s = args.%s;\n" n n
| Int n -> pr " %s = args.%s;\n" n n
| FileIn _ | FileOut _ -> ()
#ifdef HAVE_LIBREADLINE
-static const char *commands[] = {
+static const char *const commands[] = {
";
(* Get the commands and sort them, including the aliases. *)
pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
n n
| StringList n ->
- pr " char **%s = ocaml_guestfs_strings_val (%sv);\n" n n
+ pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
| Bool n ->
pr " int %s = Bool_val (%sv);\n" n n
| Int n ->
AV *av;
I32 i;
- if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) {
+ if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
croak (\"array reference expected\");
- }
av = (AV *)SvRV (arg);
- ret = (char **)malloc (av_len (av) + 1 + 1);
+ ret = malloc (av_len (av) + 1 + 1);
+ if (!ret)
+ croak (\"malloc failed\");
for (i = 0; i <= av_len (av); i++) {
SV **elem = av_fetch (av, i, 0);
pr " {\n";
pr " int i, len;\n";
pr " len = RARRAY_LEN (%sv);\n" n;
- pr " %s = malloc (sizeof (char *) * (len+1));\n" n;
+ pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
+ n;
pr " for (i = 0; i < len; ++i) {\n";
pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
pr " %s[i] = StringValueCStr (v);\n" n;
pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
| StringList n ->
pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
- pr " %s = malloc (sizeof (char *) * (%s_len+1));\n" n n;
+ pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
pr " for (i = 0; i < %s_len; ++i) {\n" n;
pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
n;
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