From: Olga Krishtal <okrish...@virtuozzo.com> The patch creates anonymous pipe that can be passed as stdin/stdout/stderr handle to a child process spawned using forthcoming guest-file-exec command. Working with a pipe is done using the existing guest-file-* API.
Signed-off-by: Olga Krishtal <okrish...@virtuozzo.com> Signed-off-by: Denis V. Lunev <d...@openvz.org> CC: Eric Blake <ebl...@redhat.com> CC: Michael Roth <mdr...@linux.vnet.ibm.com> --- qga/commands-win32.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 6a6939c..435a049 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -21,6 +21,7 @@ #include "qga-qmp-commands.h" #include "qapi/qmp/qerror.h" #include "qemu/queue.h" +#include "qemu/sockets.h" #ifndef SHTDN_REASON_FLAG_PLANNED #define SHTDN_REASON_FLAG_PLANNED 0x80000000 @@ -37,6 +38,7 @@ typedef struct GuestFileHandle { int64_t id; HANDLE fh; + HANDLE pipe_other_end_fd; /* if set, it's a pipe fd of the other end. */ QTAILQ_ENTRY(GuestFileHandle) next; } GuestFileHandle; @@ -84,7 +86,8 @@ static OpenFlags *find_open_flag(const char *mode_str) return NULL; } -static int64_t guest_file_handle_add(HANDLE fh, Error **errp) +static int64_t guest_file_handle_add(HANDLE fh, HANDLE pipe_other_end_fd, + Error **errp) { GuestFileHandle *gfh; int64_t handle; @@ -96,6 +99,7 @@ static int64_t guest_file_handle_add(HANDLE fh, Error **errp) gfh = g_malloc0(sizeof(GuestFileHandle)); gfh->id = handle; gfh->fh = fh; + gfh->pipe_other_end_fd = pipe_other_end_fd; QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); return handle; @@ -143,7 +147,7 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, return -1; } - fd = guest_file_handle_add(fh, errp); + fd = guest_file_handle_add(fh, INVALID_HANDLE_VALUE, errp); if (fd < 0) { CloseHandle(&fh); error_setg(errp, "failed to add handle to qmp handle table"); @@ -154,12 +158,65 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, return fd; } +/* Create an anonymous pipe. To set NOWAIT mode is done via qemu_set_nonblock * + * will fail with ERROR_NO_DATA; WriteFile() will return 0 bytes written. */ GuestPipeInfo *qmp_guest_pipe_open(GuestPipeMode mode, Error **errp) { - error_setg(errp, QERR_UNSUPPORTED); + HANDLE fd[2]; + int this_end, other_end; + int64_t handle; + GuestPipeInfo *pipe_inf; + SECURITY_ATTRIBUTES sa = { + sizeof(SECURITY_ATTRIBUTES), NULL, 0 + }; + + slog("guest-pipe-open called"); + if (mode > 2) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "Only \"r\" or \"w\" are the valid modes to open a pipe"); + return NULL; + } + + if (!CreatePipe(&fd[0], &fd[1], &sa, 0)) { + error_setg_win32(errp, GetLastError(), "CreatePipe() failed"); + return NULL; + } + + this_end = (mode == GUEST_PIPE_MODE_WRITE); + other_end = !this_end; + + qemu_set_nonblock(_open_osfhandle((intptr_t)fd[this_end], O_WRONLY)); + + handle = guest_file_handle_add(fd[this_end], fd[other_end], errp); + if (handle == -1) { + goto fail; + } + + slog("guest-pipe-open: handle: %" PRId64, handle); + + pipe_inf = g_malloc0(sizeof(*pipe_inf)); + pipe_inf->fd = handle; + pipe_inf->mode = mode; + return pipe_inf; + +fail: + CloseHandle(fd[0]); + CloseHandle(fd[1]); return NULL; } +static int guest_pipe_close_other_end(GuestFileHandle *gfh) +{ + if (gfh->pipe_other_end_fd != INVALID_HANDLE_VALUE) { + if (!CloseHandle(gfh->pipe_other_end_fd)) { + return 1; + } + gfh->pipe_other_end_fd = INVALID_HANDLE_VALUE; + } + + return 0; + } + void qmp_guest_file_close(int64_t handle, Error **errp) { bool ret; @@ -168,6 +225,12 @@ void qmp_guest_file_close(int64_t handle, Error **errp) if (gfh == NULL) { return; } + + if (guest_pipe_close_other_end(gfh) != 0) { + error_setg_win32(errp, GetLastError(), "failed to close pipe handle"); + return; + } + ret = CloseHandle(gfh->fh); if (!ret) { error_setg_win32(errp, GetLastError(), "failed close handle"); @@ -737,7 +800,7 @@ GList *ga_command_blacklist_init(GList *blacklist) "guest-get-memory-blocks", "guest-set-memory-blocks", "guest-get-memory-block-size", "guest-fsfreeze-freeze-list", "guest-get-fsinfo", - "guest-fstrim", "guest-pipe-open", "guest-exec-status", + "guest-fstrim", "guest-exec-status", "guest-exec", NULL}; char **p = (char **)list_unsupported; -- 2.1.4