[Spice-devel] [PATCH 4/4] replay: allows to specify a filter for record output

Frediano Ziglio fziglio at redhat.com
Mon Aug 24 06:20:30 PDT 2015


This allows compressions using external programs or any type
of filters.

To use it set SPICE_WORKER_RECORD_FILTER environment to the
filter command you want to use. The command is executed with
g_spawn_async_with_pipes (which uses execve) so is not a shell
command although the command is parsed using g_shell_parse_argv
which split arguments as shell does.

One easy way to use it is to just use a compressor like gzip with

  export SPICE_WORKER_RECORD_FILENAME=/tmp/qemu_record.gz
  export SPICE_WORKER_RECORD_FILTER=gzip
  qemu ...

The filter will receive the recording on standard input and is
supposed to write in output filename (which is the standard output).
Nothing forbid to close and delete the file and do something else
use additional argument in SPICE_WORKER_RECORD_FILTER to specify
for instance compression level. Note however that even if you don't
use the output file is always opened and SPICE_WORKER_RECORD_FILENAME
have to be defined to enable recording.

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 server/red_record_qxl.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
 server/red_record_qxl.h |  2 ++
 server/red_worker.c     |  2 +-
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/server/red_record_qxl.c b/server/red_record_qxl.c
index d96fb79..85daf7f 100644
--- a/server/red_record_qxl.c
+++ b/server/red_record_qxl.c
@@ -21,6 +21,8 @@
 
 #include <stdbool.h>
 #include <inttypes.h>
+#include <fcntl.h>
+#include <glib.h>
 #include "red_worker.h"
 #include "red_common.h"
 #include "red_memslots.h"
@@ -825,3 +827,51 @@ void red_record_qxl_command(FILE *fd, RedMemSlotInfo *slots,
         break;
     }
 }
+
+static void out_setup(gpointer user_data)
+{
+    int fd = GPOINTER_TO_INT(user_data);
+
+    while (dup2(fd, 1) < 0 && errno == EINTR)
+        continue;
+    close(fd);
+    fcntl(1, F_SETFD, 0);
+}
+
+FILE *red_record_open_file(const char *record_filename)
+{
+    const char *filter;
+    FILE *f;
+
+    f = fopen(record_filename, "w+");
+    if (!f)
+        return NULL;
+
+    filter = getenv("SPICE_WORKER_RECORD_FILTER");
+    if (filter) {
+        gint argc;
+        gchar **argv = NULL;
+        GError *error = NULL;
+        GPid child_pid;
+        gboolean ret;
+        gint fd_in;
+
+        ret = g_shell_parse_argv(filter, &argc, &argv, &error);
+
+        if (ret)
+            ret = g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
+                               out_setup, GINT_TO_POINTER(fileno(f)), &child_pid,
+                               &fd_in, NULL, NULL, &error);
+
+        g_strfreev(argv);
+        if (!ret) {
+            g_error_free(error);
+            fclose(f);
+            return NULL;
+        }
+        while (dup2(fd_in, fileno(f)) < 0 && errno == EINTR)
+            continue;
+        close(fd_in);
+    }
+    return f;
+}
diff --git a/server/red_record_qxl.h b/server/red_record_qxl.h
index b737db8..0b74dc4 100644
--- a/server/red_record_qxl.h
+++ b/server/red_record_qxl.h
@@ -31,4 +31,6 @@ void red_record_event(FILE *fd, int what, uint32_t type, unsigned long ts);
 void red_record_qxl_command(FILE *fd, RedMemSlotInfo *slots,
                             QXLCommandExt ext_cmd, unsigned long ts);
 
+FILE *red_record_open_file(const char *record_filename);
+
 #endif
diff --git a/server/red_worker.c b/server/red_worker.c
index 9c6921b..0dcd7d3 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -12104,7 +12104,7 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
     if (record_filename) {
         static const char header[] = "SPICE_REPLAY 1\n";
 
-        worker->record_fd = fopen(record_filename, "w+");
+        worker->record_fd = red_record_open_file(record_filename);
         if (worker->record_fd == NULL) {
             spice_error("failed to open recording file %s\n", record_filename);
         }
-- 
2.4.3



More information about the Spice-devel mailing list