fish: Make 'launch' function static.
[libguestfs.git] / src / generator.ml
index b5b24cf..31ef313 100755 (executable)
@@ -447,7 +447,7 @@ You probably don't want to call this function.")]
  *)
 
 let non_daemon_functions = test_functions @ [
-  ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
+  ("launch", (RErr, []), -1, [FishAlias "run"],
    [],
    "launch the qemu subprocess",
    "\
@@ -958,8 +958,15 @@ exist.
 The mounted filesystem is writable, if we have sufficient permissions
 on the underlying device.
 
-The filesystem options C<sync> and C<noatime> are set with this
-call, in order to improve reliability.");
+B<Important note:>
+When you use this call, the filesystem options C<sync> and C<noatime>
+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<guestfs_mount> in any code that needs performance, and instead
+use C<guestfs_mount_options> (use an empty string for the first
+parameter if you don't want any options).");
 
   ("sync", (RErr, []), 2, [],
    [ InitEmpty, Always, TestRun [["sync"]]],
@@ -1984,7 +1991,10 @@ See also C<guestfs_upload>, C<guestfs_cat>.");
     InitISOFS, Always, TestOutput (
       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
     InitISOFS, Always, TestOutput (
-      [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
+      [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6");
+    (* Test for RHBZ#579608, absolute symbolic links. *)
+    InitISOFS, Always, TestOutput (
+      [["checksum"; "sha512"; "/abssymlink"]], "5f57d0639bc95081c53afc63a449403883818edc64da48930ad6b1a4fb49be90404686877743fbcd7c99811f3def7df7bc22635c885c6a8cf79c806b43451c1a")],
    "compute MD5, SHAx or CRC checksum of file",
    "\
 This call computes the MD5, SHAx or CRC checksum of the
@@ -2026,9 +2036,13 @@ Compute the SHA512 hash (using the C<sha512sum> program).
 
 =back
 
-The checksum is returned as a printable string.");
+The checksum is returned as a printable string.
+
+To get the checksum for a device, use C<guestfs_checksum_device>.
+
+To get the checksums for many files, use C<guestfs_checksums_out>.");
 
-  ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
+  ("tar_in", (RErr, [FileIn "tarfile"; Pathname "directory"]), 69, [],
    [InitBasicFS, Always, TestOutput (
       [["tar_in"; "../images/helloworld.tar"; "/"];
        ["cat"; "/hello"]], "hello\n")],
@@ -2050,7 +2064,7 @@ it to local file C<tarfile>.
 To download a compressed tarball, use C<guestfs_tgz_out>
 or C<guestfs_txz_out>.");
 
-  ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
+  ("tgz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 71, [],
    [InitBasicFS, Always, TestOutput (
       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
        ["cat"; "/hello"]], "hello\n")],
@@ -2091,7 +2105,11 @@ mounts the filesystem with the read-only (I<-o ro>) flag.");
    "\
 This is the same as the C<guestfs_mount> command, but it
 allows you to set the mount options as for the
-L<mount(8)> I<-o> flag.");
+L<mount(8)> I<-o> flag.
+
+If the C<options> 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, [],
    [],
@@ -2428,7 +2446,10 @@ The external L<cmp(1)> program is used for the comparison.");
    [InitISOFS, Always, TestOutputList (
       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
     InitISOFS, Always, TestOutputList (
-      [["strings"; "/empty"]], [])],
+      [["strings"; "/empty"]], []);
+    (* Test for RHBZ#579608, absolute symbolic links. *)
+    InitISOFS, Always, TestRun (
+      [["strings"; "/abssymlink"]])],
    "print the printable strings in a file",
    "\
 This runs the L<strings(1)> command on a file and returns
@@ -2459,7 +2480,10 @@ The returned strings are transcoded to UTF-8.");
      * commands to segfault.
      *)
     InitISOFS, Always, TestRun (
-      [["hexdump"; "/100krandom"]])],
+      [["hexdump"; "/100krandom"]]);
+    (* Test for RHBZ#579608, absolute symbolic links. *)
+    InitISOFS, Always, TestRun (
+      [["hexdump"; "/abssymlink"]])],
    "dump a file in hexadecimal",
    "\
 This runs C<hexdump -C> on the given C<path>.  The result is
@@ -2581,7 +2605,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
@@ -2807,7 +2838,10 @@ See also: L<mkdtemp(3)>");
 
   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
    [InitISOFS, Always, TestOutputInt (
-      [["wc_l"; "/10klines"]], 10000)],
+      [["wc_l"; "/10klines"]], 10000);
+    (* Test for RHBZ#579608, absolute symbolic links. *)
+    InitISOFS, Always, TestOutputInt (
+      [["wc_l"; "/abssymlink"]], 10000)],
    "count lines in a file",
    "\
 This command counts the lines in a file, using the
@@ -2831,7 +2865,10 @@ C<wc -c> external command.");
 
   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
    [InitISOFS, Always, TestOutputList (
-      [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
+      [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"]);
+    (* Test for RHBZ#579608, absolute symbolic links. *)
+    InitISOFS, Always, TestOutputList (
+      [["head"; "/abssymlink"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
    "return first 10 lines of a file",
    "\
 This command returns up to the first 10 lines of a file as
@@ -2989,6 +3026,14 @@ constants.  C<devmajor> and C<devminor> are the
 device major and minor numbers, only used when creating block
 and character special devices.
 
+Note that, just like L<mknod(2)>, 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<guestfs_mknod_b>, C<guestfs_mknod_c> or C<guestfs_mkfifo>
+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"],
@@ -3242,7 +3287,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<path> as a
@@ -3257,7 +3315,10 @@ in the total size of file that can be handled.");
    [InitISOFS, Always, TestOutputList (
       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
     InitISOFS, Always, TestOutputList (
-      [["grep"; "nomatch"; "/test-grep.txt"]], [])],
+      [["grep"; "nomatch"; "/test-grep.txt"]], []);
+    (* Test for RHBZ#579608, absolute symbolic links. *)
+    InitISOFS, Always, TestOutputList (
+      [["grep"; "nomatch"; "/abssymlink"]], [])],
    "return lines matching a pattern",
    "\
 This calls the external C<grep> program and returns the
@@ -4382,7 +4443,7 @@ This command writes zeroes over the entire C<device>.  Compare
 with C<guestfs_zero> which just zeroes the first few blocks of
 a device.");
 
-  ("txz_in", (RErr, [FileIn "tarball"; String "directory"]), 229, [],
+  ("txz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 229, [],
    [InitBasicFS, Always, TestOutput (
       [["txz_in"; "../images/helloworld.tar.xz"; "/"];
        ["cat"; "/hello"]], "hello\n")],
@@ -4509,6 +4570,49 @@ is the same as the L<augtool(1)> C<clear> command.");
 Return the current umask.  By default the umask is C<022>
 unless it has been set by calling C<guestfs_umask>.");
 
+  ("debug_upload", (RErr, [FileIn "filename"; String "tmpname"; Int "mode"]), 241, [],
+   [],
+   "upload a file to the appliance (internal use only)",
+   "\
+The C<guestfs_debug_upload> command uploads a file to
+the libguestfs appliance.
+
+There is no comprehensive help for this command.  You have
+to look at the file C<daemon/debug.c> in the libguestfs source
+to find out what it is for.");
+
+  ("base64_in", (RErr, [FileIn "base64file"; Pathname "filename"]), 242, [],
+   [InitBasicFS, Always, TestOutput (
+      [["base64_in"; "../images/hello.b64"; "/hello"];
+       ["cat"; "/hello"]], "hello\n")],
+   "upload base64-encoded data to file",
+   "\
+This command uploads base64-encoded data from C<base64file>
+to C<filename>.");
+
+  ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [],
+   [],
+   "download file and encode as base64",
+   "\
+This command downloads the contents of C<filename>, writing
+it out to local file C<base64file> encoded as base64.");
+
+  ("checksums_out", (RErr, [String "csumtype"; Pathname "directory"; FileOut "sumsfile"]), 244, [],
+   [],
+   "compute MD5, SHAx or CRC checksum of files in a directory",
+   "\
+This command computes the checksums of all regular files in
+C<directory> and then emits a list of those checksums to
+the local output file C<sumsfile>.
+
+This can be used for verifying the integrity of a virtual
+machine.  However to be properly secure you should pay
+attention to the output of the checksum command (it uses
+the ones from GNU coreutils).  In particular when the
+filename is not printable, coreutils uses a special
+backslash syntax.  For more information, see the GNU
+coreutils info file.");
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
@@ -5219,7 +5323,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
@@ -5547,7 +5651,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
 
@@ -5557,7 +5661,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
 
@@ -5742,7 +5846,8 @@ check_state (guestfs_h *g, const char *caller)
       pr "  int r;\n";
       pr "\n";
       trace_call shortname style;
-      pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
+      pr "  if (check_state (g, \"%s\") == -1) return %s;\n"
+        shortname error_code;
       pr "  guestfs___set_busy (g);\n";
       pr "\n";
 
@@ -6032,14 +6137,19 @@ and generate_daemon_actions () =
       );
       pr "\n";
 
+      let is_filein =
+        List.exists (function FileIn _ -> true | _ -> false) (snd style) in
+
       (match snd style with
        | [] -> ()
        | args ->
            pr "  memset (&args, 0, sizeof args);\n";
            pr "\n";
            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
+           if is_filein then
+             pr "    cancel_receive ();\n";
            pr "    reply_with_error (\"daemon failed to decode procedure arguments\");\n";
-           pr "    return;\n";
+           pr "    goto done;\n";
            pr "  }\n";
            let pr_args n =
              pr "  char *%s = args.%s;\n" n n
@@ -6048,6 +6158,8 @@ and generate_daemon_actions () =
              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;
+             if is_filein then
+               pr "    cancel_receive ();\n";
              pr "    reply_with_perror (\"realloc\");\n";
              pr "    goto done;\n";
              pr "  }\n";
@@ -6058,13 +6170,16 @@ and generate_daemon_actions () =
              function
              | Pathname n ->
                  pr_args n;
-                 pr "  ABS_PATH (%s, goto done);\n" n;
+                 pr "  ABS_PATH (%s, %s, goto done);\n"
+                   n (if is_filein then "cancel_receive ()" else "");
              | Device n ->
                  pr_args n;
-                 pr "  RESOLVE_DEVICE (%s, goto done);\n" n;
+                 pr "  RESOLVE_DEVICE (%s, %s, goto done);\n"
+                   n (if is_filein then "cancel_receive ()" else "");
              | Dev_or_Path n ->
                  pr_args n;
-                 pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);\n" n;
+                 pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
+                   n (if is_filein then "cancel_receive ()" else "");
              | String n -> pr_args n
              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
              | StringList n ->
@@ -6074,7 +6189,8 @@ and generate_daemon_actions () =
                  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 "    RESOLVE_DEVICE (physvols[pvi], %s, goto done);\n"
+                   (if is_filein then "cancel_receive ()" else "");
                  pr "  }\n";
              | Bool n -> pr "  %s = args.%s;\n" n n
              | Int n -> pr "  %s = args.%s;\n" n n
@@ -6089,7 +6205,8 @@ and generate_daemon_actions () =
       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
         (* Emit NEED_ROOT just once, even when there are two or
            more Pathname args *)
-        pr "  NEED_ROOT (goto done);\n";
+        pr "  NEED_ROOT (%s, goto done);\n"
+          (if is_filein then "cancel_receive ()" else "");
       );
 
       (* Don't want to call the impl with any FileIn or FileOut
@@ -6175,15 +6292,14 @@ and generate_daemon_actions () =
       );
 
       (* Free the args. *)
+      pr "done:\n";
       (match snd style with
-       | [] ->
-           pr "done: ;\n";
+       | [] -> ()
        | _ ->
-           pr "done:\n";
            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
              name
       );
-
+      pr "  return;\n";
       pr "}\n\n";
   ) daemon_functions;
 
@@ -6631,6 +6747,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;
@@ -7373,11 +7491,11 @@ and generate_fish_cmds () =
         function
         | Device n
         | String n
-        | OptString n
-        | FileIn n
-        | FileOut n -> pr "  const char *%s;\n" n
+        | OptString n -> pr "  const char *%s;\n" n
         | Pathname n
-        | Dev_or_Path n -> pr "  char *%s;\n" n
+        | Dev_or_Path n
+        | FileIn n
+        | FileOut n -> pr "  char *%s;\n" n
         | StringList n | DeviceList n -> pr "  char **%s;\n" n
         | Bool n -> pr "  int %s;\n" n
         | Int n -> pr "  int %s;\n" n
@@ -7434,11 +7552,11 @@ and generate_fish_cmds () =
               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
                 name i i
           | FileIn name ->
-              pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdin\";\n"
-                name i i
+              pr "  %s = file_in (argv[%d]);\n" name i;
+              pr "  if (%s == NULL) return -1;\n" name
           | FileOut name ->
-              pr "  %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdout\";\n"
-                name i i
+              pr "  %s = file_out (argv[%d]);\n" name i;
+              pr "  if (%s == NULL) return -1;\n" name
           | StringList name | DeviceList name ->
               pr "  %s = parse_string_list (argv[%d]);\n" name i;
               pr "  if (%s == NULL) return -1;\n" name;
@@ -7467,10 +7585,12 @@ and generate_fish_cmds () =
       List.iter (
         function
         | Device name | String name
-        | OptString name | FileIn name | FileOut name | Bool name
+        | OptString name | Bool name
         | Int name | Int64 name -> ()
-        | Pathname name | Dev_or_Path name ->
+        | Pathname name | Dev_or_Path name | FileOut name ->
             pr "  free (%s);\n" name
+        | FileIn name ->
+            pr "  free_file_in (%s);\n" name
         | StringList name | DeviceList name ->
             pr "  free_strings (%s);\n" name
       ) (snd style);