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@xxxxxxxxxx> --- server/red-record-qxl.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/server/red-record-qxl.c b/server/red-record-qxl.c index a0607a0..3bd36a9 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 "memslot.h" @@ -829,11 +831,22 @@ void red_record_qxl_command(SpiceRecord *record, RedMemSlotInfo *slots, } } +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); +} + bool red_record_open(SpiceRecord *record) { static const char header[] = "SPICE_REPLAY 1\n"; const char *filename; + const char *filter; FILE *f; filename = getenv("SPICE_WORKER_RECORD_FILENAME"); @@ -844,6 +857,33 @@ bool red_record_open(SpiceRecord *record) if (!f) goto error; + 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); + goto error; + } + while (dup2(fd_in, fileno(f)) < 0 && errno == EINTR) + continue; + close(fd_in); + } + if (fwrite(header, sizeof(header)-1, 1, f) != 1) { spice_error("failed to write replay header"); } -- 2.4.3 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel