| Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
+      | Pointer _ -> assert false
     ) args;
     pr "  /* Java changes stdout line buffering so we need this: */\n";
     pr "  fflush (stdout);\n";
 
           pr "const char *%s" n;
           next ();
           pr "size_t %s_size" n
+      | Pointer (t, n) ->
+          next ();
+          pr "%s %s" t n
     ) args;
     if is_RBufferOut then (next (); pr "size_t *size_r");
     if optargs <> [] then (
       | BufferIn n
       | StringList n
       | DeviceList n
-      | Key n ->
+      | Key n
+      | Pointer (_, n) ->
           pr "  if (%s == NULL) {\n" n;
           pr "    error (g, \"%%s: %%s: parameter cannot be NULL\",\n";
           pr "           \"%s\", \"%s\");\n" shortname n;
       | BufferIn n ->                   (* RHBZ#646822 *)
           pr "    fputc (' ', stderr);\n";
           pr "    guestfs___print_BufferIn (stderr, %s, %s_size);\n" n n
+      | Pointer (t, n) ->
+          pr "    fprintf (stderr, \" (%s)%%p\", %s);\n" t n
     ) args;
 
     (* Optional arguments. *)
                  pr "  }\n";
                  pr "  args.%s.%s_val = (char *) %s;\n" n n n;
                  pr "  args.%s.%s_len = %s_size;\n" n n n
+             | Pointer _ -> assert false
            ) args;
            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
              (String.uppercase shortname);
 
             ) strs;
             pr "      NULL\n";
             pr "    };\n";
+        | Pointer _, _ ->
+            (* Difficult to make these pointers in order to run a test. *)
+            assert false
       ) (List.combine (snd style) args);
 
       let error_code =
             pr ", %Ld" i
         | Bool _, arg ->
             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
+        | Pointer _, _ -> assert false
       ) (List.combine (snd style) args);
 
       (match fst style with
 
       ) optargs
   ) all_functions;
 
+  (* Some parameter types not supported for daemon functions. *)
+  List.iter (
+    fun (name, (_, args, optargs), _, _, _, _, _) ->
+      let check_arg_type = function
+        | Pointer _ ->
+            failwithf "Pointer is not supported for daemon function %s."
+              name
+        | _ -> ()
+      in
+      List.iter check_arg_type args;
+      List.iter check_arg_type optargs;
+  ) daemon_functions;
+
   (* Check short descriptions. *)
   List.iter (
     fun (name, _, _, _, _, shortdesc, _) ->
 
               pr ", bool %s" n
           | Int n ->
               pr ", int %s" n
-          | Int64 n ->
+          | Int64 n | Pointer (_, n) ->
               pr ", long %s" n
         ) args;
         pr ");\n"
               next (); pr "bool %s" n
           | Int n ->
               next (); pr "int %s" n
-          | Int64 n ->
+          | Int64 n | Pointer (_, n) ->
               next (); pr "long %s" n
         ) args;
         pr ")\n"
 
              | BufferIn n ->
                  pr "  const char *%s;\n" n;
                  pr "  size_t %s_size;\n" n
+             | Pointer _ -> assert false
            ) args
       );
       pr "\n";
              | BufferIn n ->
                  pr "  %s = args.%s.%s_val;\n" n n n;
                  pr "  %s_size = args.%s.%s_len;\n" n n n
+             | Pointer _ -> assert false
            ) args;
            pr "\n"
       );
 
         | Bool n -> pr "  int %s;\n" n
         | Int n -> pr "  int %s;\n" n
         | Int64 n -> pr "  int64_t %s;\n" n
+        | Pointer _ -> assert false
       ) args;
 
       if optargs <> [] then (
             parse_integer "argv[i++]" "xstrtoll" "long long" "int" range name
         | Int64 name ->
             parse_integer "argv[i++]" "xstrtoll" "long long" "int64_t" None name
+        | Pointer _ -> assert false
       ) args;
 
       (* Optional arguments are prefixed with <argname>:<value> and
             pr "  free_file_in (%s);\n" name
         | StringList name | DeviceList name ->
             pr "  free_strings (%s);\n" name
+        | Pointer _ -> assert false
       ) args;
 
       (* Any output flags? *)
         | FileIn n | FileOut n -> pr " (%s|-)" n
         | BufferIn n -> pr " %s" n
         | Key _ -> () (* keys are entered at a prompt *)
+        | Pointer _ -> assert false
       ) args;
       List.iter (
         function
 
               pr "withCStringLen %s $ \\(%s, %s_size) -> " n n n
           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
-          | Bool _ | Int _ | Int64 _ -> ()
+          | Bool _ | Int _ | Int64 _ | Pointer _ -> ()
         ) args;
         (* Convert integer arguments. *)
         let args =
             function
             | Bool n -> sprintf "(fromBool %s)" n
             | Int n -> sprintf "(fromIntegral %s)" n
-            | Int64 n -> sprintf "(fromIntegral %s)" n
+            | Int64 n | Pointer (_, n) -> sprintf "(fromIntegral %s)" n
             | FileIn n | FileOut n
             | Pathname n | Device n | Dev_or_Path n
             | String n | OptString n
        | Bool _ -> pr "%s" bool
        | Int _ -> pr "%s" int
        | Int64 _ -> pr "%s" int
+       | Pointer _ -> pr "%s" int
        | FileIn _ -> pr "%s" string
        | FileOut _ -> pr "%s" string
       );
 
           pr "boolean %s" n
       | Int n ->
           pr "int %s" n
-      | Int64 n ->
+      | Int64 n | Pointer (_, n) ->
           pr "long %s" n
   ) args;
 
             pr ", jboolean j%s" n
         | Int n ->
             pr ", jint j%s" n
-        | Int64 n ->
+        | Int64 n | Pointer (_, n) ->
             pr ", jlong j%s" n
       ) args;
       if optargs <> [] then
             pr "  int %s;\n" n
         | Int64 n ->
             pr "  int64_t %s;\n" n
+        | Pointer (t, n) ->
+            pr "  %s %s;\n" t n
       ) args;
 
       let needs_i =
         | Int n
         | Int64 n ->
             pr "  %s = j%s;\n" n n
+        | Pointer (t, n) ->
+            pr "  %s = (%s) j%s;\n" n t n
       ) args;
 
       if optargs <> [] then (
             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
             pr "  }\n";
             pr "  free (%s);\n" n
-        | Bool n
-        | Int n
-        | Int64 n -> ()
+        | Bool _
+        | Int _
+        | Int64 _
+        | Pointer _ -> ()
       ) args;
 
       (* Check for errors. *)
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 
 #include <caml/config.h>
 #include <caml/alloc.h>
             pr "  int %s = Int_val (%sv);\n" n n
         | Int64 n ->
             pr "  int64_t %s = Int64_val (%sv);\n" n n
+        | Pointer (t, n) ->
+            pr "  %s %s = (%s) (intptr_t) Int64_val (%sv);\n" t n t n
       ) args;
 
       (* Optional arguments. *)
             pr "  free (%s);\n" n
         | StringList n | DeviceList n ->
             pr "  ocaml_guestfs_free_strings (%s);\n" n;
-        | Bool _ | Int _ | Int64 _ -> ()
+        | Bool _ | Int _ | Int64 _ | Pointer _ -> ()
       ) args;
       List.iter (
         function
         | Bool _ | Int _ | Int64 _
         | Pathname _ | Device _ | Dev_or_Path _ | OptString _
         | FileIn _ | FileOut _ | BufferIn _ | Key _
-        | StringList _ | DeviceList _ -> ()
+        | StringList _ | DeviceList _ | Pointer _ -> ()
       ) optargs;
 
       pr "  if (r == %s)\n" error_code;
     | StringList _ | DeviceList _ -> pr "string array -> "
     | Bool _ -> pr "bool -> "
     | Int _ -> pr "int -> "
-    | Int64 _ -> pr "int64 -> "
+    | Int64 _ | Pointer _ -> pr "int64 -> "
   ) args;
   (match ret with
    | RErr -> pr "unit" (* all errors are turned into exceptions *)
 
           | Bool n -> pr "      int %s;\n" n
           | Int n -> pr "      int %s;\n" n
           | Int64 n -> pr "      int64_t %s;\n" n
+          | Pointer (t, n) -> pr "      %s %s;\n" t n
       ) args;
 
       (* PREINIT section (local variable declarations). *)
         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
         | Bool _ | Int _ | Int64 _
         | FileIn _ | FileOut _
-        | BufferIn _ | Key _ -> ()
+        | BufferIn _ | Key _ | Pointer _ -> ()
         | StringList n | DeviceList n -> pr "      free (%s);\n" n
       ) args;
 
       match arg with
       | Pathname n | Device n | Dev_or_Path n | String n
       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n
-      | BufferIn n | Key n ->
+      | BufferIn n | Key n | Pointer (_, n) ->
           pr "$%s" n
       | StringList n | DeviceList n ->
           pr "\\@%s" n
 
             pr "  char **%s;\n" n;
         | Bool n ->
             pr "  zend_bool %s;\n" n
-        | Int n | Int64 n ->
+        | Int n | Int64 n | Pointer (_, n) ->
             pr "  long %s;\n" n
         ) args;
 
           | OptString n -> "s!"
           | StringList n | DeviceList n -> "a"
           | Bool n -> "b"
-          | Int n | Int64 n -> "l"
+          | Int n | Int64 n | Pointer (_, n) -> "l"
         ) args
       ) in
 
             pr ", &z_%s" n
         | Bool n ->
             pr ", &%s" n
-        | Int n | Int64 n ->
+        | Int n | Int64 n | Pointer (_, n) ->
             pr ", &%s" n
       ) args;
       List.iter (
             pr "    %s[c] = NULL;\n" n;
             pr "  }\n";
             pr "\n"
-        | Bool n | Int n | Int64 n -> ()
+        | Bool _ | Int _ | Int64 _ | Pointer _ -> ()
         ) args;
 
       (* Optional arguments. *)
             pr "    efree (%s);\n" n;
             pr "  }\n";
             pr "\n"
-        | Bool n | Int n | Int64 n -> ()
+        | Bool _ | Int _ | Int64 _ | Pointer _ -> ()
         ) args;
 
       (* Check for errors. *)
 
         | Bool n -> pr "  int %s;\n" n
         | Int n -> pr "  int %s;\n" n
         | Int64 n -> pr "  long long %s;\n" n
+        | Pointer (t, n) ->
+            pr "  long long %s_int64;\n" n;
+            pr "  %s %s;\n" t n
       ) args;
 
       if optargs <> [] then (
         | StringList _ | DeviceList _ -> pr "O"
         | Bool _ -> pr "i" (* XXX Python has booleans? *)
         | Int _ -> pr "i"
-        | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
-                             * emulate C's int/long/long long in Python?
-                             *)
+        | Int64 _ | Pointer _ ->
+            (* XXX Whoever thought it was a good idea to
+             * emulate C's int/long/long long in Python?
+             *)
+            pr "L"
         | BufferIn _ -> pr "s#"
       ) args;
 
         | Bool n -> pr ", &%s" n
         | Int n -> pr ", &%s" n
         | Int64 n -> pr ", &%s" n
+        | Pointer (_, n) -> pr ", &%s_int64" n
         | BufferIn n -> pr ", &%s, &%s_size" n n
       ) args;
 
         | StringList n | DeviceList n ->
             pr "  %s = get_string_list (py_%s);\n" n n;
             pr "  if (!%s) return NULL;\n" n
+        | Pointer (t, n) ->
+            pr "  %s = (%s) (intptr_t) %s_int64;\n" n t n
       ) args;
 
       pr "\n";
         function
         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
-        | BufferIn _ -> ()
+        | BufferIn _ | Pointer _ -> ()
         | StringList n | DeviceList n ->
             pr "  free (%s);\n" n
       ) args;
 
             pr "  int %s = NUM2INT (%sv);\n" n n
         | Int64 n ->
             pr "  long long %s = NUM2LL (%sv);\n" n n
+        | Pointer (t, n) ->
+            pr "  %s %s = (%s) (intptr_t) NUM2LL (%sv);\n" t n t n
       ) args;
       pr "\n";
 
         function
         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
-        | BufferIn _ -> ()
+        | BufferIn _ | Pointer _ -> ()
         | StringList n | DeviceList n ->
             pr "  free (%s);\n" n
       ) args;
 
      *)
   | FileIn of string
   | FileOut of string
+    (* This specifies an opaque pointer that is passed through
+     * untouched.  Only non-daemon functions are supported.
+     *
+     * Pointer ("foo *", "bar") translates to "foo *bar" in the
+     * C API.  The pointer ("bar") cannot be NULL.
+     *
+     * This is less well supported in other language bindings:
+     * if the pointer type is known then we may be able to produce
+     * a suitable binding, otherwise this is translated into a 64
+     * bit int.
+     *
+     * Functions with this parameter type are not supported at all
+     * in guestfish (the function must be declared "NotInFish" else
+     * you will get an error).  Also the function cannot contain
+     * tests, although we should fix this in future.
+     *)
+  | Pointer of (string * string)
 
 type flags =
   | ProtocolLimitWarning  (* display warning about protocol size limits *)
 
 let name_of_argt = function
   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
   | StringList n | DeviceList n | Bool n | Int n | Int64 n
-  | FileIn n | FileOut n | BufferIn n | Key n -> n
+  | FileIn n | FileOut n | BufferIn n | Key n | Pointer (_, n) -> n
 
 let seq_of_test = function
   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
 
              | BufferIn n ->
                  pr "  opaque %s<>;\n" n
              | FileIn _ | FileOut _ -> ()
+             | Pointer _ -> assert false
            ) args;
            pr "};\n\n"
       );