daemon: debug segv correct use of dereferencing NULL.
[libguestfs.git] / generator / generator_c.ml
index 771d6a2..4324ec0 100644 (file)
@@ -135,7 +135,8 @@ let rec generate_prototype ?(extern = true) ?(static = false)
   if newline then pr "\n"
 
 (* Generate C call arguments, eg "(handle, foo, bar)" *)
-and generate_c_call_args ?handle (ret, args, optargs) =
+and generate_c_call_args ?handle ?(implicit_size_ptr = "&size")
+    (ret, args, optargs) =
   pr "(";
   let comma = ref false in
   let next () =
@@ -155,11 +156,11 @@ and generate_c_call_args ?handle (ret, args, optargs) =
         next ();
         pr "%s" (name_of_argt arg)
   ) args;
-  (* For RBufferOut calls, add implicit &size parameter. *)
+  (* For RBufferOut calls, add implicit size pointer parameter. *)
   (match ret with
    | RBufferOut _ ->
        next ();
-       pr "&size"
+       pr "%s" implicit_size_ptr
    | _ -> ()
   );
   (* For calls with optional arguments, add implicit optargs parameter. *)
@@ -179,6 +180,11 @@ and generate_actions_pod () =
         generate_prototype ~extern:false ~indent:" " ~handle:"g" name style;
         pr "\n\n";
 
+        (match deprecation_notice ~prefix:"guestfs_" flags with
+         | None -> ()
+         | Some txt -> pr "%s\n\n" txt
+        );
+
         let uc_shortname = String.uppercase shortname in
         if optargs <> [] then (
           pr "You may supply a list of optional arguments to this call.\n";
@@ -187,15 +193,14 @@ and generate_actions_pod () =
           pr "See L</CALLS WITH OPTIONAL ARGUMENTS>.\n\n";
           List.iter (
             fun argt ->
-              let n = name_of_argt argt in
+              let n = name_of_optargt argt in
               let uc_n = String.uppercase n in
               pr " GUESTFS_%s_%s, " uc_shortname uc_n;
               match argt with
-              | Bool n -> pr "int %s,\n" n
-              | Int n -> pr "int %s,\n" n
-              | Int64 n -> pr "int64_t %s,\n" n
-              | String n -> pr "const char *%s,\n" n
-              | _ -> assert false
+              | OBool n -> pr "int %s,\n" n
+              | OInt n -> pr "int %s,\n" n
+              | OInt64 n -> pr "int64_t %s,\n" n
+              | OString n -> pr "const char *%s,\n" n
           ) optargs;
           pr "\n";
         );
@@ -248,16 +253,10 @@ I<The caller must free the returned buffer after use>.\n\n"
           pr "%s\n\n" progress_message;
         if List.mem ProtocolLimitWarning flags then
           pr "%s\n\n" protocol_limit_warning;
-        if List.mem DangerWillRobinson flags then
-          pr "%s\n\n" danger_will_robinson;
-        if List.exists (function Key _ -> true | _ -> false) (args@optargs) then
+        if List.exists (function Key _ -> true | _ -> false) args then
           pr "This function takes a key or passphrase parameter which
 could contain sensitive material.  Read the section
 L</KEYS AND PASSPHRASES> for more information.\n\n";
-        (match deprecation_notice flags with
-         | None -> ()
-         | Some txt -> pr "%s\n\n" txt
-        );
         (match lookup_api_version name with
          | Some version -> pr "(Added in %s)\n\n" version
          | None -> ()
@@ -373,7 +372,7 @@ extern \"C\" {
 /* Define GUESTFS_WARN_DEPRECATED=1 to warn about deprecated API functions. */
 #define GUESTFS_DEPRECATED_BY(s)
 #if GUESTFS_WARN_DEPRECATED
-#  if defined(__GNUC__) && GUESTFS_GCC_VERSION >= 30100 /* gcc >= 3.1.0 */
+#  if defined(__GNUC__) && GUESTFS_GCC_VERSION >= 40500 /* gcc >= 4.5 */
 #    undef GUESTFS_DEPRECATED_BY
 #    define GUESTFS_DEPRECATED_BY(s) __attribute__((__deprecated__(\"change the program to use guestfs_\" s \" instead of this deprecated function\")))
 #  endif
@@ -435,13 +434,13 @@ typedef void (*guestfs_event_callback) (
 #endif
 
 #define LIBGUESTFS_HAVE_SET_EVENT_CALLBACK 1
-int guestfs_set_event_callback (guestfs_h *g,
-                                guestfs_event_callback cb,
-                                uint64_t event_bitmask,
-                                int flags,
-                                void *opaque);
+extern int guestfs_set_event_callback (guestfs_h *g,
+                                       guestfs_event_callback cb,
+                                       uint64_t event_bitmask,
+                                       int flags,
+                                       void *opaque);
 #define LIBGUESTFS_HAVE_DELETE_EVENT_CALLBACK 1
-void guestfs_delete_event_callback (guestfs_h *g, int event_handle);
+extern void guestfs_delete_event_callback (guestfs_h *g, int event_handle);
 
 /* Old-style event handling. */
 #ifndef GUESTFS_TYPEDEF_LOG_MESSAGE_CB
@@ -482,6 +481,10 @@ extern void guestfs_set_close_callback (guestfs_h *g, guestfs_close_cb cb, void
 extern void guestfs_set_progress_callback (guestfs_h *g, guestfs_progress_cb cb, void *opaque)
   GUESTFS_DEPRECATED_BY(\"set_event_callback\");
 
+/* User cancellation. */
+#define LIBGUESTFS_HAVE_USER_CANCEL 1
+extern void guestfs_user_cancel (guestfs_h *g);
+
 /* Private data area. */
 #define LIBGUESTFS_HAVE_SET_PRIVATE 1
 extern void guestfs_set_private (guestfs_h *g, const char *key, void *data);
@@ -556,6 +559,16 @@ extern void *guestfs_next_private (guestfs_h *g, const char **key_rtn);
       if deprecated = None && not test0 && not debug then
         pr "#define LIBGUESTFS_HAVE_%s 1\n" (String.uppercase shortname);
 
+      if optargs <> [] then (
+        iteri (
+          fun i argt ->
+            let uc_shortname = String.uppercase shortname in
+            let n = name_of_optargt argt in
+            let uc_n = String.uppercase n in
+            pr "#define GUESTFS_%s_%s %d\n" uc_shortname uc_n i;
+        ) optargs;
+      );
+
       generate_prototype ~single_line:true ~semicolon:false
         ~handle:"g" ~prefix:"guestfs_" shortname style;
       (match deprecated with
@@ -568,29 +581,30 @@ extern void *guestfs_next_private (guestfs_h *g, const char **key_rtn);
           ~prefix:"guestfs_" ~suffix:"_va" ~optarg_proto:VA
           shortname style;
 
+        pr "\n";
         pr "struct guestfs_%s_argv {\n" shortname;
         pr "  uint64_t bitmask;\n";
         iteri (
           fun i argt ->
             let c_type =
               match argt with
-              | Bool n -> "int "
-              | Int n -> "int "
-              | Int64 n -> "int64_t "
-              | String n -> "const char *"
-              | _ -> assert false (* checked in generator_checks *) in
+              | OBool n -> "int "
+              | OInt n -> "int "
+              | OInt64 n -> "int64_t "
+              | OString n -> "const char *" in
             let uc_shortname = String.uppercase shortname in
-            let n = name_of_argt argt in
+            let n = name_of_optargt argt in
             let uc_n = String.uppercase n in
-            pr "#define GUESTFS_%s_%s %d\n" uc_shortname uc_n i;
-            pr "#define GUESTFS_%s_%s_BITMASK (UINT64_C(1)<<%d)\n" uc_shortname uc_n i;
-            pr "/* The field below is only valid in this struct if the\n";
-            pr " * GUESTFS_%s_%s_BITMASK bit is set\n" uc_shortname uc_n;
-            pr " * in the bitmask above, otherwise the contents are ignored.\n";
-            pr " */\n";
+            pr "\n";
+            pr "# define GUESTFS_%s_%s_BITMASK (UINT64_C(1)<<%d)\n" uc_shortname uc_n i;
+            pr "  /* The field below is only valid in this struct if the\n";
+            pr "   * GUESTFS_%s_%s_BITMASK bit is set\n" uc_shortname uc_n;
+            pr "   * in the bitmask above.  If not, the field is ignored.\n";
+            pr "   */\n";
             pr "  %s%s;\n" c_type n
         ) optargs;
         pr "};\n";
+        pr "\n";
 
         generate_prototype ~single_line:true ~newline:true ~handle:"g"
           ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv
@@ -612,7 +626,7 @@ extern void *guestfs_safe_malloc (guestfs_h *g, size_t nbytes);
 extern void *guestfs_safe_calloc (guestfs_h *g, size_t n, size_t s);
 extern const char *guestfs_tmpdir (void);
 #ifdef GUESTFS_PRIVATE_FOR_EACH_DISK
-extern int guestfs___for_each_disk (guestfs_h *g, virDomainPtr dom, int (*)(guestfs_h *g, const char *filename, const char *format, void *data), void *data);
+extern int guestfs___for_each_disk (guestfs_h *g, virDomainPtr dom, int (*)(guestfs_h *g, const char *filename, const char *format, int readonly, void *data), void *data);
 #endif
 /* End of private functions. */
 
@@ -740,6 +754,13 @@ trace_send_line (guestfs_h *g)
 
 ";
 
+  (* Generate code for enter events. *)
+  let enter_event shortname =
+    pr "  guestfs___call_callbacks_message (g, GUESTFS_EVENT_ENTER,\n";
+    pr "                                    \"%s\", %d);\n"
+      shortname (String.length shortname)
+  in
+
   (* Generate code to check String-like parameters are not passed in
    * as NULL (returning an error if they are).
    *)
@@ -788,7 +809,7 @@ trace_send_line (guestfs_h *g)
     (* For optional arguments. *)
     List.iter (
       function
-      | String n ->
+      | OString n ->
           pr "  if ((optargs->bitmask & GUESTFS_%s_%s_BITMASK) &&\n"
             (String.uppercase shortname) (String.uppercase n);
           pr "      optargs->%s == NULL) {\n" n;
@@ -803,9 +824,7 @@ trace_send_line (guestfs_h *g)
           pr_newline := true
 
       (* not applicable *)
-      | Bool _ | Int _ | Int64 _ -> ()
-
-      | _ -> assert false
+      | OBool _ | OInt _ | OInt64 _ -> ()
     ) optargs;
 
     if !pr_newline then pr "\n";
@@ -888,21 +907,20 @@ trace_send_line (guestfs_h *g)
     (* Optional arguments. *)
     List.iter (
       fun argt ->
-        let n = name_of_argt argt in
+        let n = name_of_optargt argt in
         let uc_shortname = String.uppercase shortname in
         let uc_n = String.uppercase n in
         pr "    if (optargs->bitmask & GUESTFS_%s_%s_BITMASK)\n"
           uc_shortname uc_n;
         (match argt with
-         | String n ->
+         | OString n ->
              pr "      fprintf (trace_fp, \" \\\"%%s:%%s\\\"\", \"%s\", optargs->%s);\n" n n
-         | Bool n ->
+         | OBool n ->
              pr "      fprintf (trace_fp, \" \\\"%%s:%%s\\\"\", \"%s\", optargs->%s ? \"true\" : \"false\");\n" n n
-         | Int n ->
+         | OInt n ->
              pr "      fprintf (trace_fp, \" \\\"%%s:%%d\\\"\", \"%s\", optargs->%s);\n" n n
-         | Int64 n ->
+         | OInt64 n ->
              pr "      fprintf (trace_fp, \" \\\"%%s:%%\" PRIi64 \"\\\"\", \"%s\", optargs->%s);\n" n n
-         | _ -> assert false
         );
     ) optargs;
 
@@ -942,12 +960,14 @@ trace_send_line (guestfs_h *g)
      | RBufferOut _ ->
          pr "%s  guestfs___print_BufferOut (trace_fp, %s, *size_r);\n" indent rv
      | RStringList _ | RHashtable _ ->
-         pr "%s  fputs (\"[\\\"\", trace_fp);\n" indent;
+         pr "%s  fputs (\"[\", trace_fp);\n" indent;
          pr "%s  for (i = 0; %s[i]; ++i) {\n" indent rv;
-         pr "%s    if (i > 0) fputs (\"\\\", \\\"\", trace_fp);\n" indent;
+         pr "%s    if (i > 0) fputs (\", \", trace_fp);\n" indent;
+         pr "%s    fputs (\"\\\"\", trace_fp);\n" indent;
          pr "%s    fputs (%s[i], trace_fp);\n" indent rv;
+         pr "%s    fputs (\"\\\"\", trace_fp);\n" indent;
          pr "%s  }\n" indent;
-         pr "%s  fputs (\"\\\"]\", trace_fp);\n" indent;
+         pr "%s  fputs (\"]\", trace_fp);\n" indent;
      | RStruct (_, typ) ->
          (* XXX There is code generated for guestfish for printing
           * these structures.  We need to make it generally available
@@ -1007,11 +1027,12 @@ trace_send_line (guestfs_h *g)
            pr "  struct guestfs_%s_list *r;\n" typ
       );
       pr "\n";
+      enter_event shortname;
       check_null_strings shortname style;
       reject_unknown_optargs shortname style;
       trace_call shortname style;
       pr "  r = guestfs__%s " shortname;
-      generate_c_call_args ~handle:"g" style;
+      generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style;
       pr ";\n";
       pr "\n";
       (match errcode_of_ret ret with
@@ -1099,6 +1120,7 @@ trace_send_line (guestfs_h *g)
         pr "  const uint64_t progress_hint = 0;\n";
 
       pr "\n";
+      enter_event shortname;
       check_null_strings shortname style;
       reject_unknown_optargs shortname style;
       trace_call shortname style;
@@ -1162,23 +1184,22 @@ trace_send_line (guestfs_h *g)
 
         List.iter (
           fun argt ->
-            let n = name_of_argt argt in
+            let n = name_of_optargt argt in
             let uc_shortname = String.uppercase shortname in
             let uc_n = String.uppercase n in
             pr "  if ((optargs->bitmask & GUESTFS_%s_%s_BITMASK))\n"
               uc_shortname uc_n;
             (match argt with
-             | Bool n
-             | Int n
-             | Int64 n ->
+             | OBool n
+             | OInt n
+             | OInt64 n ->
                  pr "    args.%s = optargs->%s;\n" n n;
                  pr "  else\n";
                  pr "    args.%s = 0;\n" n
-             | String n ->
+             | OString n ->
                  pr "    args.%s = (char *) optargs->%s;\n" n n;
                  pr "  else\n";
                  pr "    args.%s = (char *) \"\";\n" n
-             | _ -> assert false
             )
         ) optargs;
 
@@ -1357,9 +1378,12 @@ trace_send_line (guestfs_h *g)
 
         (* Get the name of the last regular argument. *)
         let last_arg =
-          match args with
-          | [] -> "g"
-          | args -> name_of_argt (List.hd (List.rev args)) in
+          match ret with
+          | RBufferOut _ -> "size_r"
+          | _ ->
+              match args with
+              | [] -> "g"
+              | args -> name_of_argt (List.hd (List.rev args)) in
 
         let rtype =
           match ret with
@@ -1380,7 +1404,7 @@ trace_send_line (guestfs_h *g)
         pr "\n";
         pr "  va_start (optargs, %s);\n" last_arg;
         pr "  %sr = guestfs_%s_va " rtype shortname;
-        generate_c_call_args ~handle:"g" style;
+        generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style;
         pr ";\n";
         pr "  va_end (optargs);\n";
         pr "\n";
@@ -1402,15 +1426,14 @@ trace_send_line (guestfs_h *g)
 
         List.iter (
           fun argt ->
-            let n = name_of_argt argt in
+            let n = name_of_optargt argt in
             let uc_n = String.uppercase n in
             pr "    case GUESTFS_%s_%s:\n" uc_shortname uc_n;
             pr "      optargs_s.%s = va_arg (args, " n;
             (match argt with
-             | Bool _ | Int _ -> pr "int"
-             | Int64 _ -> pr "int64_t"
-             | String _ -> pr "const char *"
-             | _ -> assert false
+             | OBool _ | OInt _ -> pr "int"
+             | OInt64 _ -> pr "int64_t"
+             | OString _ -> pr "const char *"
             );
             pr ");\n";
             pr "      break;\n";
@@ -1437,7 +1460,7 @@ trace_send_line (guestfs_h *g)
         pr "  }\n";
         pr "\n";
         pr "  return guestfs_%s_argv " shortname;
-        generate_c_call_args ~handle:"g" style;
+        generate_c_call_args ~handle:"g" ~implicit_size_ptr:"size_r" style;
         pr ";\n";
         pr "}\n\n"
     | _ -> ()
@@ -1470,6 +1493,7 @@ and generate_linker_script () =
     "guestfs_set_private";
     "guestfs_set_progress_callback";
     "guestfs_set_subprocess_quit_callback";
+    "guestfs_user_cancel";
 
     (* Unofficial parts of the API: the bindings code use these
      * functions, so it is useful to export them.