summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--guestfish.pod4
-rw-r--r--guestfs.pod5
-rwxr-xr-xsrc/generator.ml74
-rw-r--r--src/guestfs.c17
4 files changed, 100 insertions, 0 deletions
diff --git a/guestfish.pod b/guestfish.pod
index 2e50873f..d24c1628 100644
--- a/guestfish.pod
+++ b/guestfish.pod
@@ -568,6 +568,10 @@ Set the default qemu binary that libguestfs uses. If not set, then
the qemu which was found at compile time by the configure script is
used.
+=item LIBGUESTFS_TRACE
+
+Set C<LIBGUESTFS_TRACE=1> to enable command traces.
+
=item PAGER
The C<more> command uses C<$PAGER> as the pager. If not
diff --git a/guestfs.pod b/guestfs.pod
index d8e4da3b..b8379d04 100644
--- a/guestfs.pod
+++ b/guestfs.pod
@@ -983,6 +983,11 @@ used.
See also L</QEMU WRAPPERS> above.
+=item LIBGUESTFS_TRACE
+
+Set C<LIBGUESTFS_TRACE=1> to enable command traces. This
+has the same effect as calling C<guestfs_set_trace (handle, 1)>.
+
=item TMPDIR
Location of temporary directory, defaults to C</tmp>.
diff --git a/src/generator.ml b/src/generator.ml
index b0f95436..71aeeed8 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -805,6 +805,32 @@ is passed to the appliance at boot time. See C<guestfs_set_selinux>.
For more information on the architecture of libguestfs,
see L<guestfs(3)>.");
+ ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
+ [InitNone, Always, TestOutputTrue (
+ [["set_trace"; "true"];
+ ["get_trace"]])],
+ "enable or disable command traces",
+ "\
+If the command trace flag is set to 1, then commands are
+printed on stdout before they are executed in a format
+which is very similar to the one used by guestfish. In
+other words, you can run a program with this enabled, and
+you will get out a script which you can feed to guestfish
+to perform the same set of actions.
+
+If you want to trace C API calls into libguestfs (and
+other libraries) then possibly a better way is to use
+the external ltrace(1) command.
+
+Command traces are disabled unless the environment variable
+C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
+
+ ("get_trace", (RBool "trace", []), -1, [],
+ [],
+ "get command trace enabled flag",
+ "\
+Return the command trace flag.");
+
]
(* daemon_functions are any functions which cause some action
@@ -4643,6 +4669,52 @@ check_state (guestfs_h *g, const char *caller)
";
+ (* Generate code to generate guestfish call traces. *)
+ let trace_call shortname style =
+ pr " if (guestfs__get_trace (g)) {\n";
+
+ let needs_i =
+ List.exists (function
+ | StringList _ | DeviceList _ -> true
+ | _ -> false) (snd style) in
+ if needs_i then (
+ pr " int i;\n";
+ pr "\n"
+ );
+
+ pr " printf (\"%s\");\n" shortname;
+ List.iter (
+ function
+ | String n (* strings *)
+ | Device n
+ | Pathname n
+ | Dev_or_Path n
+ | FileIn n
+ | FileOut n ->
+ (* guestfish doesn't support string escaping, so neither do we *)
+ pr " printf (\" \\\"%%s\\\"\", %s);\n" n
+ | OptString n -> (* string option *)
+ pr " if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
+ pr " else printf (\" null\");\n"
+ | StringList n
+ | DeviceList n -> (* string list *)
+ pr " putchar (' ');\n";
+ pr " putchar ('\"');\n";
+ pr " for (i = 0; %s[i]; ++i) {\n" n;
+ pr " if (i > 0) putchar (' ');\n";
+ pr " fputs (%s[i], stdout);\n" n;
+ pr " }\n";
+ pr " putchar ('\"');\n";
+ | Bool n -> (* boolean *)
+ pr " fputs (%s ? \" true\" : \" false\", stdout);\n" n
+ | Int n -> (* int *)
+ pr " printf (\" %%d\", %s);\n" n
+ ) (snd style);
+ pr " putchar ('\\n');\n";
+ pr " }\n";
+ pr "\n";
+ in
+
(* For non-daemon functions, generate a wrapper around each function. *)
List.iter (
fun (shortname, style, _, _, _, _, _) ->
@@ -4651,6 +4723,7 @@ check_state (guestfs_h *g, const char *caller)
generate_prototype ~extern:false ~semicolon:false ~newline:true
~handle:"g" name style;
pr "{\n";
+ trace_call shortname style;
pr " return guestfs__%s " shortname;
generate_c_call_args ~handle:"g" style;
pr ";\n";
@@ -4758,6 +4831,7 @@ check_state (guestfs_h *g, const char *caller)
pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
pr " int serial;\n";
pr "\n";
+ trace_call shortname style;
pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
pr " guestfs_set_busy (g);\n";
pr "\n";
diff --git a/src/guestfs.c b/src/guestfs.c
index 571205f2..98d99b84 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -170,6 +170,7 @@ struct guestfs_h
int cmdline_size;
int verbose;
+ int trace;
int autosync;
char *path; /* Path to kernel, initrd. */
@@ -238,6 +239,9 @@ guestfs_create (void)
str = getenv ("LIBGUESTFS_DEBUG");
g->verbose = str != NULL && strcmp (str, "1") == 0;
+ str = getenv ("LIBGUESTFS_TRACE");
+ g->trace = str != NULL && strcmp (str, "1") == 0;
+
str = getenv ("LIBGUESTFS_PATH");
g->path = str != NULL ? strdup (str) : strdup (GUESTFS_DEFAULT_PATH);
if (!g->path) goto error;
@@ -734,6 +738,19 @@ guestfs__version (guestfs_h *g)
return r;
}
+int
+guestfs__set_trace (guestfs_h *g, int t)
+{
+ g->trace = !!t;
+ return 0;
+}
+
+int
+guestfs__get_trace (guestfs_h *g)
+{
+ return g->trace;
+}
+
/* Add a string to the current command line. */
static void
incr_cmdline_size (guestfs_h *g)