qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
@ 2015-05-21  5:49 Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 1/6] util, qga: drop guest_file_toggle_flags Denis V. Lunev
                   ` (7 more replies)
  0 siblings, 8 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-05-21  5:49 UTC (permalink / raw)
  Cc: Olga Krishtal, qemu-devel, Denis V. Lunev

These patches for guest-agent add the functionality to execute commands on
a guest UNIX machine.

These patches add the following interfaces:

guest-pipe-open
guest-exec
guest-exec-status

With these interfaces it's possible to:

* Open an anonymous pipe and work with it as with a file using already
implemented interfaces guest-file-{read,write,flush,close}.

* Execute a binary or a script on a guest machine.
We can pass arbitrary arguments and environment to a new child process.

* Pass redirected IO from/to stdin, stdout, stderr from a child process to a
local file or an anonymous pipe.

* Check the status of a child process, get its exit status if it exited or get
signal number if it was killed.

We plan to add support for Windows in the near future using the same interfaces
we introduce here.

Example of usage:

{"execute": "guest-pipe-open", "arguments":{"mode": "r"}}
{'return': 1000}

{"execute":"guest-exec", "arguments":{ "path": "id", "params": ["user"],
    "env": ["MYENV=myvalue"], "handle_stdout": 1000 }}'
{"return": 2636}

{"execute": "guest-exec-status", "arguments": {"pid": 2636}}
{"return":{"exit":0,"handle_stderr":-1,"handle_stdin":-1,"handle_stdout":1000,"signal":-1}}

{"execute": "guest-file-read", "arguments": {"handle": 1000, "count":128}}
{"return":{"count":58,"buf-b64":"dWlk...","eof":true}}

{"execute": "guest-file-close", "arguments": {"handle": 1000}}
{"return":{}}


These patches are based on the patches proposed by Michael Roth in 2011:
http://lists.gnu.org/archive/html/qemu-devel/2011-12/msg00722.html

We made several modifications to the interfaces proposed by Michael to simplify
their usage and we also added several new functions:

* Arguments to an executable file are passed as an array of strings.

    Before that we had to pass parameters like this:
    'params': [ {'param': '-b'}, {'param': '-n1'} ]

    Now we may pass them just as an array of strings:
    'params': [ '-b', '-n1' ]

* Environment can be passed to a child process.

    "env": ["MYENV=myvalue"]

* Removed "detach" argument from "guest-exec" - it never waits for a child
process to signal.  With this change it's possible to return just PID from
"guest-exec", a user must call "guest-exec-status" to get the status of a child.

* Removed "wait" argument from "guest-exec-status" - waiting for a child process
to signal is dangerous, because it may block the whole qemu-ga.  Instead, the
command polls just once a status of a child.

* "guest-exec-status" returns exit status of a child process or a signal number,
in case a process was killed.

* Simplified the command "guest-pipe-open" - the way how it stores the pipe
fd's.  No additional logic is needed about which end of pipe should be closed
with "guest-file-close".  This way we avoid modifying the interface of the
existing "guest-file-close".

In the conversation about the original patches there was a suggestion to merge
"path" and "params" into one single list.  But we didn't do so, because having
separate "path" is similar to exec*() family functions in UNIX.  That way it
looks more consistent.

Changes from v2:
- return code of commands changed to dictionary
- ported to current HEAD
- new way for moving pipe to non-blocking state (universal)

Changes from v1:
- Windows version of the patchset is added
- SIGPIPE processing is added for Unix version of the patchset
- added guest_exec_file_busy() to prevent GuestFileHandle* object from being
  deleted in case it's used in guest-exec command.

Signed-off-by: Olga Krishtal <okrishtal@parallels.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>

P.S. Michael, this is a working version and could we consider it for merging
     into 2.4? If you still want to use universal GLIB code, we could
     re-write this later using standard refactoring way.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 1/6] util, qga: drop guest_file_toggle_flags
  2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
@ 2015-05-21  5:49 ` Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 2/6] qga: implement guest-pipe-open command Denis V. Lunev
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-05-21  5:49 UTC (permalink / raw)
  Cc: Roman Kagan, Olga Krishtal, Michael Roth, qemu-devel,
	Denis V. Lunev

From: Olga Krishtal <okrishtal@parallels.com>

guest_file_toggle_flags is a copy from semi-portable qemu_set_nonblock.
The latter is not working properly for Windows due to reduced Windows
Posix implementation.

On Windows OS there is a separate API for changing flags of file, pipes
and sockets. Portable way to change file descriptor flags requires
to detect file descriptor type and proper actions depending of that
type. The patch adds wrapper qemu_set_fd_blocking into Windows specific
code to handle this stuff properly.

The only problem is that qemu_set_nonblock is void but this should not
be a problem.

Signed-off-by: Olga Krishtal <okrishtal@parallels.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Eric Blake <eblake@redhat.com>
CC: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qga/commands-posix.c | 27 ++-------------------------
 util/oslib-win32.c   | 52 +++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 49 insertions(+), 30 deletions(-)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index ba8de62..d0f371b 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -28,6 +28,7 @@
 #include "qapi/qmp/qerror.h"
 #include "qemu/queue.h"
 #include "qemu/host-utils.h"
+#include "qemu/sockets.h"
 
 #ifndef CONFIG_HAS_ENVIRON
 #ifdef __APPLE__
@@ -376,27 +377,6 @@ safe_open_or_create(const char *path, const char *mode, Error **errp)
     return NULL;
 }
 
-static int guest_file_toggle_flags(int fd, int flags, bool set, Error **err)
-{
-    int ret, old_flags;
-
-    old_flags = fcntl(fd, F_GETFL);
-    if (old_flags == -1) {
-        error_set_errno(err, errno, QERR_QGA_COMMAND_FAILED,
-                        "failed to fetch filehandle flags");
-        return -1;
-    }
-
-    ret = fcntl(fd, F_SETFL, set ? (old_flags | flags) : (old_flags & ~flags));
-    if (ret == -1) {
-        error_set_errno(err, errno, QERR_QGA_COMMAND_FAILED,
-                        "failed to set filehandle flags");
-        return -1;
-    }
-
-    return ret;
-}
-
 int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
                             Error **errp)
 {
@@ -417,10 +397,7 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
     /* set fd non-blocking to avoid common use cases (like reading from a
      * named pipe) from hanging the agent
      */
-    if (guest_file_toggle_flags(fileno(fh), O_NONBLOCK, true, errp) < 0) {
-        fclose(fh);
-        return -1;
-    }
+    qemu_set_nonblock(fileno(fh));
 
     handle = guest_file_handle_add(fh, errp);
     if (handle < 0) {
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 87cfbe0..58a2d5b 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -119,17 +119,59 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
     return p;
 }
 
-void qemu_set_block(int fd)
+static void qemu_set_fd_blocking(int fd, bool blocking)
 {
-    unsigned long opt = 0;
-    WSAEventSelect(fd, NULL, 0);
+    HANDLE handle;
+    DWORD file_type, pipe_state;
+
+    handle = (HANDLE)_get_osfhandle(fd);
+    if (handle == INVALID_HANDLE_VALUE) {
+        return;
+    }
+
+    file_type = GetFileType(handle);
+    if (file_type != FILE_TYPE_PIPE) {
+        return;
+    }
+
+    /* If file_type == FILE_TYPE_PIPE, according to msdn
+     * the specified file is socket or named pipe */
+    if (GetNamedPipeHandleState(handle, &pipe_state, NULL,
+                                NULL, NULL, NULL, 0)) {
+        /* The fd is named pipe fd */
+        if (!!blocking == !(pipe_state & PIPE_NOWAIT)) {
+            /* In this case we do not need perform any operation, because
+             * blocking = true and PIPE_NOWAIT is already set or
+             * blocking = false and PIPE_NOWAIT is not set */
+            return;
+        }
+
+        if (blocking) {
+            pipe_state |= PIPE_NOWAIT;
+        } else {
+            pipe_state &= ~PIPE_NOWAIT;
+        }
+
+        SetNamedPipeHandleState(handle, &pipe_state, NULL, NULL);
+        return;
+    }
+
+    /* The fd is socket fd */
+    unsigned long opt = (unsigned long)blocking;
+    if (!blocking) {
+        WSAEventSelect(fd, NULL, 0);
+    }
     ioctlsocket(fd, FIONBIO, &opt);
 }
 
+void qemu_set_block(int fd)
+{
+    qemu_set_fd_blocking(fd, false);
+}
+
 void qemu_set_nonblock(int fd)
 {
-    unsigned long opt = 1;
-    ioctlsocket(fd, FIONBIO, &opt);
+    qemu_set_fd_blocking(fd, true);
     qemu_fd_register(fd);
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 2/6] qga: implement guest-pipe-open command
  2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 1/6] util, qga: drop guest_file_toggle_flags Denis V. Lunev
@ 2015-05-21  5:49 ` Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 3/6] qga: guest exec functionality for Unix guests Denis V. Lunev
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-05-21  5:49 UTC (permalink / raw)
  Cc: Roman Kagan, Olga Krishtal, Michael Roth, qemu-devel,
	Denis V. Lunev

From: Olga Krishtal <okrishtal@parallels.com>

The command creates FIFO pair that can be used with existing file
read/write interfaces to communicate with processes spawned via the
forthcoming guest-file-exec interface.

Signed-off-by: Olga Krishtal <okrishtal@parallels.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Eric Blake <eblake@redhat.com>
CC: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qga/commands-posix.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++---
 qga/commands-win32.c |  8 ++++-
 qga/qapi-schema.json | 44 ++++++++++++++++++++++++
 3 files changed, 143 insertions(+), 5 deletions(-)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index d0f371b..a616996 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -212,6 +212,7 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
 typedef struct GuestFileHandle {
     uint64_t id;
     FILE *fh;
+    int pipe_other_end_fd; /* if set, it's a pipe fd of the other end. */
     QTAILQ_ENTRY(GuestFileHandle) next;
 } GuestFileHandle;
 
@@ -219,7 +220,8 @@ static struct {
     QTAILQ_HEAD(, GuestFileHandle) filehandles;
 } guest_file_state;
 
-static int64_t guest_file_handle_add(FILE *fh, Error **errp)
+static int64_t guest_file_handle_add(FILE *fh, int pipe_other_end_fd,
+                                     Error **errp)
 {
     GuestFileHandle *gfh;
     int64_t handle;
@@ -232,6 +234,7 @@ static int64_t guest_file_handle_add(FILE *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;
@@ -399,7 +402,7 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
      */
     qemu_set_nonblock(fileno(fh));
 
-    handle = guest_file_handle_add(fh, errp);
+    handle = guest_file_handle_add(fh, -1, errp);
     if (handle < 0) {
         fclose(fh);
         return -1;
@@ -409,6 +412,85 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
     return handle;
 }
 
+GuestPipeInfoList *qmp_guest_pipe_open(GuestPipeMode mode, Error **errp)
+{
+    FILE *f = NULL;
+    int fd[2], this_end, other_end;
+    int64_t handle;
+    GuestPipeInfoList *pipe_list;
+    GuestPipeInfo *pipe_inf;
+    const char *op_flag;
+
+    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 (pipe(fd) != 0) {
+        error_set_errno(errp, errno, QERR_QGA_COMMAND_FAILED, "pipe() failed");
+        return NULL;
+    }
+
+    this_end = (mode == GUEST_PIPE_MODE_WRITE);
+    other_end = !this_end;
+
+    qemu_set_nonblock(fd[this_end]);
+
+    qemu_set_cloexec(fd[this_end]);
+    qemu_set_cloexec(fd[other_end]);
+
+    if (mode == GUEST_PIPE_MODE_READ) {
+        op_flag = "r";
+    } else {
+        op_flag = "w";
+    }
+    f = fdopen(fd[this_end], op_flag);
+    if (f == NULL) {
+        error_set_errno(errp, errno, QERR_QGA_COMMAND_FAILED,
+                        "fdopen() failed to open pipe handle");
+        goto fail;
+    }
+
+    handle = guest_file_handle_add(f, 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_list = g_malloc0(sizeof(*pipe_list));
+    pipe_list->value = pipe_inf;
+    pipe_list->next = NULL;
+    return pipe_list;
+
+fail:
+    if (f != NULL) {
+        fclose(f);
+    } else {
+        close(fd[this_end]);
+    }
+    close(fd[other_end]);
+    return NULL;
+}
+
+static int guest_pipe_close_other_end(GuestFileHandle *gfh)
+{
+    if (gfh->pipe_other_end_fd != -1) {
+        if (close(gfh->pipe_other_end_fd) != 0) {
+            return 1;
+        }
+
+        gfh->pipe_other_end_fd = -1;
+    }
+
+    return 0;
+}
+
 void qmp_guest_file_close(int64_t handle, Error **errp)
 {
     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
@@ -419,6 +501,11 @@ void qmp_guest_file_close(int64_t handle, Error **errp)
         return;
     }
 
+    if (guest_pipe_close_other_end(gfh) != 0) {
+        error_setg_errno(errp, errno, "failed to close pipe handle");
+        return;
+    }
+
     ret = fclose(gfh->fh);
     if (ret == EOF) {
         error_setg_errno(errp, errno, "failed to close handle");
@@ -2395,7 +2482,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
             "guest-suspend-hybrid", "guest-network-get-interfaces",
             "guest-get-vcpus", "guest-set-vcpus",
             "guest-get-memory-blocks", "guest-set-memory-blocks",
-            "guest-get-memory-block-size", NULL};
+            "guest-get-memory-block-size", "guest-pipe-open", NULL};
         char **p = (char **)list;
 
         while (*p) {
@@ -2409,7 +2496,8 @@ GList *ga_command_blacklist_init(GList *blacklist)
         const char *list[] = {
             "guest-get-fsinfo", "guest-fsfreeze-status",
             "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
-            "guest-fsfreeze-thaw", "guest-get-fsinfo", NULL};
+            "guest-fsfreeze-thaw", "guest-get-fsinfo",
+            "guest-pipe-open", NULL};
         char **p = (char **)list;
 
         while (*p) {
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 3ef0549..685dd0f 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -154,6 +154,12 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode,
     return fd;
 }
 
+GuestPipeInfoList *qmp_guest_pipe_open(GuestPipeMode mode, Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return NULL;
+}
+
 void qmp_guest_file_close(int64_t handle, Error **errp)
 {
     bool ret;
@@ -713,7 +719,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", NULL};
+        "guest-fstrim", "guest-pipe-open", NULL};
     char **p = (char **)list_unsupported;
 
     while (*p) {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index b446dc7..8081213 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -215,12 +215,56 @@
   'returns': 'int' }
 
 ##
+# @GuestPipeMode
+#
+# An enumeration of pipe modes
+# read: pipe is opened for writing data
+# write: pipe is opened for reading data
+#
+# Since: 2.4
+##
+{ 'enum': 'GuestPipeMode',
+  'data': [ 'read', 'write' ] }
+
+##
+# @GuestPipeInfo
+#
+# Information about pipe.
+#
+# Since: 2.4
+##
+{ 'struct': 'GuestPipeInfo',
+  'data': {'fd': 'int'} }
+
+##
+# @guest-pipe-open
+#
+# Open a pipe to in the guest to associated with a qga-spawned processes
+# for communication.
+#
+# Returns: Guest file handle on success, as per guest-file-open. This
+# handle is usable with the same interfaces as a handle returned by
+# guest-file-open.
+#
+# Since: 2.4
+##
+{ 'command': 'guest-pipe-open',
+  'data':    { 'mode': 'GuestPipeMode' },
+  'returns': ['GuestPipeInfo'] }
+
+##
+##
 # @guest-file-close:
 #
 # Close an open file in the guest
 #
 # @handle: filehandle returned by guest-file-open
 #
+# Please note that closing the write side of a pipe will block until the read
+# side is closed.  If you passed the read-side of the pipe to a qga-spawned
+# process, make sure the process has exited before attempting to close the
+# write side.
+#
 # Returns: Nothing on success.
 #
 # Since: 0.15.0
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 3/6] qga: guest exec functionality for Unix guests
  2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 1/6] util, qga: drop guest_file_toggle_flags Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 2/6] qga: implement guest-pipe-open command Denis V. Lunev
@ 2015-05-21  5:49 ` Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 4/6] qga: handle possible SIGPIPE in guest-file-write Denis V. Lunev
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-05-21  5:49 UTC (permalink / raw)
  Cc: Roman Kagan, Olga Krishtal, Michael Roth, qemu-devel,
	Denis V. Lunev

From: Olga Krishtal <okrishtal@parallels.com>

Child process' stdin/stdout/stderr can be associated
with handles for communication via read/write interfaces.

The workflow should be something like this:
* Open an anonymous pipe through guest-pipe-open
* Execute a binary or a script in the guest. Arbitrary arguments and
  environment to a new child process could be passed through options
* Read/pass information from/to executed process using
  guest-file-read/write
* Collect the status of a child process

Signed-off-by: Olga Krishtal <okrishtal@parallels.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Eric Blake <eblake@redhat.com>
CC: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qga/commands-posix.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++
 qga/commands-win32.c |  21 ++++-
 qga/qapi-schema.json |  56 ++++++++++++
 3 files changed, 313 insertions(+), 1 deletion(-)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index a616996..aa11932 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -828,6 +828,242 @@ static void build_fs_mount_list(FsMountList *mounts, Error **errp)
 }
 #endif
 
+typedef struct GuestExecInfo {
+    pid_t pid;
+    GuestFileHandle *gfh_stdin;
+    GuestFileHandle *gfh_stdout;
+    GuestFileHandle *gfh_stderr;
+    QTAILQ_ENTRY(GuestExecInfo) next;
+} GuestExecInfo;
+
+static struct {
+    QTAILQ_HEAD(, GuestExecInfo) processes;
+} guest_exec_state;
+
+static void guest_exec_info_add(pid_t pid,
+                                GuestFileHandle *in, GuestFileHandle *out,
+                                GuestFileHandle *error)
+{
+    GuestExecInfo *gei;
+
+    gei = g_malloc0(sizeof(*gei));
+    gei->pid = pid;
+    gei->gfh_stdin = in;
+    gei->gfh_stdout = out;
+    gei->gfh_stderr = error;
+    QTAILQ_INSERT_TAIL(&guest_exec_state.processes, gei, next);
+}
+
+static GuestExecInfo *guest_exec_info_find(pid_t pid)
+{
+    GuestExecInfo *gei;
+
+    QTAILQ_FOREACH(gei, &guest_exec_state.processes, next) {
+        if (gei->pid == pid) {
+            return gei;
+        }
+    }
+
+    return NULL;
+}
+
+
+GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **err)
+{
+    GuestExecInfo *gei;
+    GuestExecStatus *ges;
+    int status, ret;
+
+    slog("guest-exec-status called, pid: %u", (uint32_t)pid);
+
+    gei = guest_exec_info_find(pid);
+    if (gei == NULL) {
+        error_set(err, QERR_INVALID_PARAMETER, "pid");
+        return NULL;
+    }
+
+    ret = waitpid(gei->pid, &status, WNOHANG);
+    if (ret == -1) {
+        error_setg_errno(err, errno, "waitpid() failed, pid: %u", gei->pid);
+        return NULL;
+    }
+
+    ges = g_malloc0(sizeof(GuestExecStatus));
+    ges->handle_stdin = gei->gfh_stdin ? gei->gfh_stdin->id : -1;
+    ges->handle_stdout = gei->gfh_stdout ? gei->gfh_stdout->id : -1;
+    ges->handle_stderr = gei->gfh_stderr ? gei->gfh_stderr->id : -1;
+    ges->exit = -1;
+    ges->signal = -1;
+
+    if (ret != 0) {
+        if (WIFEXITED(status)) {
+            ges->exit = WEXITSTATUS(status);
+        } else if (WIFSIGNALED(status)) {
+            ges->signal = WTERMSIG(status);
+        }
+
+        QTAILQ_REMOVE(&guest_exec_state.processes, gei, next);
+        g_free(gei);
+    }
+
+    return ges;
+}
+
+/* Get environment variables or arguments array for execve(). */
+static char **guest_exec_get_args(const strList *entry)
+{
+    const strList *it;
+    int count = 1, i = 0;  /* reserve for NULL terminator */
+    size_t argv_str_size = 0;
+    char **args;
+    char *argv_str; /* for array of arguments */
+
+    if (entry != NULL) {
+        argv_str_size = strlen(entry->value) + 1;
+    }
+    for (it = entry; it != NULL; it = it->next) {
+        count++;
+        argv_str_size += sizeof(" ") - 1 + strlen(it->value);
+    }
+
+    argv_str = g_malloc(argv_str_size);
+    args = g_malloc(count * sizeof(char *));
+    for (it = entry; it != NULL; it = it->next) {
+        args[i++] = it->value;
+        pstrcat(argv_str, argv_str_size, it->value);
+        pstrcat(argv_str, argv_str_size, " ");
+    }
+
+    slog("guest-exec called: \"%s\"", argv_str);
+    g_free(argv_str);
+
+    args[i] = NULL;
+    return args;
+
+}
+
+static int guest_exec_set_std(GuestFileHandle *gfh, int std_fd, int fd_null)
+{
+    int fd;
+
+    if (gfh == NULL) {
+        fd = fd_null;
+    } else if (gfh->pipe_other_end_fd != -1) {
+        fd = gfh->pipe_other_end_fd;
+    } else {
+        fd = fileno(gfh->fh);
+    }
+
+    if (dup2(fd, std_fd) == -1) {
+        slog("dup2() failed: %s", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+GuestExec *qmp_guest_exec(const char *path,
+                       bool has_params, strList *params,
+                       bool has_env, strList *env,
+                       bool has_handle_stdin, int64_t handle_stdin,
+                       bool has_handle_stdout, int64_t handle_stdout,
+                       bool has_handle_stderr, int64_t handle_stderr,
+                       Error **err)
+{
+    pid_t pid = -1;
+    int fd_null;
+    GuestExec *ge = NULL;
+    GuestFileHandle *gfh_stdin = NULL, *gfh_stdout = NULL, *gfh_stderr = NULL;
+    char **argv, **envp;
+    strList path_arg = {
+        .value = (char *)path,
+        .next = has_params ? params : NULL
+    };
+
+    argv = guest_exec_get_args(&path_arg);
+    envp = guest_exec_get_args(has_env ? env : NULL);
+
+    if (has_handle_stdin) {
+        gfh_stdin = guest_file_handle_find(handle_stdin, err);
+        if (gfh_stdin == NULL) {
+            goto done;
+        }
+    }
+
+    if (has_handle_stdout) {
+        gfh_stdout = guest_file_handle_find(handle_stdout, err);
+        if (gfh_stdout == NULL) {
+            goto done;
+        }
+    }
+
+    if (has_handle_stderr) {
+        gfh_stderr = guest_file_handle_find(handle_stderr, err);
+        if (gfh_stderr == NULL) {
+            goto done;
+        }
+    }
+
+    pid = fork();
+    if (pid < 0) {
+        error_set(err, QERR_UNDEFINED_ERROR);
+        goto done;
+    } else if (pid == 0) {
+        setsid();
+
+        fd_null = -1;
+        if (!has_handle_stdin || !has_handle_stdout || !has_handle_stderr) {
+            fd_null = open("/dev/null", O_RDWR);
+            if (fd_null == -1) {
+                slog("guest-exec: couldn't open /dev/null: %s",
+                     strerror(errno));
+                exit(1);
+            }
+        }
+
+        if (guest_exec_set_std(gfh_stdin, STDIN_FILENO, fd_null) < 0 ||
+            guest_exec_set_std(gfh_stdout, STDOUT_FILENO, fd_null) < 0 ||
+            guest_exec_set_std(gfh_stderr, STDERR_FILENO, fd_null) < 0) {
+
+            exit(1);
+        }
+
+        if (fd_null != -1 && close(fd_null) != 0) {
+            slog("guest-exec: couldn't close /dev/null: %s", strerror(errno));
+            /* exit(1); */
+        }
+
+        execvpe(path, (char * const *)argv, (char * const *)envp);
+        slog("guest-exec child failed: %s", strerror(errno));
+        exit(1);
+    }
+
+    if (gfh_stdin != NULL && guest_pipe_close_other_end(gfh_stdin) != 0) {
+        slog("close() failed to close stdin pipe handle: %s", strerror(errno));
+    }
+
+    if (gfh_stdout != NULL && guest_pipe_close_other_end(gfh_stdout) != 0) {
+        slog("close() failed to close stdout pipe handle: %s", strerror(errno));
+    }
+
+    if (gfh_stderr != NULL && guest_pipe_close_other_end(gfh_stderr) != 0) {
+        slog("close() failed to close stderr pipe handle: %s", strerror(errno));
+    }
+
+    guest_exec_info_add(pid, gfh_stdin, gfh_stdout, gfh_stderr);
+    ge = g_malloc(sizeof(*ge));
+    ge->pid = pid;
+
+done:
+    g_free(argv);
+    g_free(envp);
+    return ge;
+}
+
+static void guest_exec_init(void)
+{
+    QTAILQ_INIT(&guest_exec_state.processes);
+}
+
 #if defined(CONFIG_FSFREEZE)
 
 static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
@@ -2520,4 +2756,5 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
     ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
 #endif
     ga_command_state_add(cs, guest_file_init, NULL);
+    ga_command_state_add(cs, guest_exec_init, NULL);
 }
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 685dd0f..3db7255 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -388,6 +388,24 @@ static void guest_file_init(void)
     QTAILQ_INIT(&guest_file_state.filehandles);
 }
 
+GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return 0;
+}
+
+GuestExec *qmp_guest_exec(const char *path,
+                       bool has_params, strList *params,
+                       bool has_env, strList *env,
+                       bool has_handle_stdin, int64_t handle_stdin,
+                       bool has_handle_stdout, int64_t handle_stdout,
+                       bool has_handle_stderr, int64_t handle_stderr,
+                       Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return 0;
+}
+
 GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
 {
     error_set(errp, QERR_UNSUPPORTED);
@@ -719,7 +737,8 @@ 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", NULL};
+        "guest-fstrim", "guest-pipe-open", "guest-exec-status",
+        "guest-exec", NULL};
     char **p = (char **)list_unsupported;
 
     while (*p) {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 8081213..21997cf 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -935,3 +935,59 @@
 ##
 { 'command': 'guest-get-memory-block-info',
   'returns': 'GuestMemoryBlockInfo' }
+
+##
+# @guest-exec-status
+#
+# Check status of process associated with PID retrieved via guest-exec.
+# Reap the process and associated metadata if it has exited.
+#
+# @pid: pid returned from guest-exec
+#
+# Returns: GuestExecStatus on success.  If a child process exited, "exit" is set
+#          to the exit code.  If a child process was killed by a signal,
+#          "signal" is set to the signal number.  If a child process is still
+#          running, both "exit" and "signal" are set to -1. If a guest cannot
+#          reliably detect exit signals, "signal" will be -1.
+#
+# Since: 2.4
+##
+{ 'struct': 'GuestExecStatus',
+  'data': { 'exit': 'int', 'signal': 'int',
+            'handle-stdin': 'int', 'handle-stdout': 'int',
+            'handle-stderr': 'int' } }
+
+{ 'command': 'guest-exec-status',
+  'data':    { 'pid': 'int' },
+  'returns': 'GuestExecStatus' }
+
+##
+# @GuestExec:
+# @pid: pid of child process in guest OS
+#
+#Since: 2.4
+##
+{ 'struct': 'GuestExec',
+  'data': { 'pid': 'int'} }
+
+##
+# @guest-exec:
+#
+# Execute a command in the guest
+#
+# @path: path or executable name to execute
+# @params: #optional parameter list to pass to executable
+# @env: #optional environment variables to pass to executable
+# @handle_stdin: #optional handle to associate with process' stdin.
+# @handle_stdout: #optional handle to associate with process' stdout
+# @handle_stderr: #optional handle to associate with process' stderr.
+#
+# Returns: PID on success.
+#
+# Since: 2.4
+##
+{ 'command': 'guest-exec',
+  'data':    { 'path': 'str', '*params': ['str'], '*env': ['str'],
+               '*handle-stdin': 'int', '*handle-stdout': 'int',
+               '*handle-stderr': 'int' },
+  'returns': 'GuestExec' }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 4/6] qga: handle possible SIGPIPE in guest-file-write
  2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
                   ` (2 preceding siblings ...)
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 3/6] qga: guest exec functionality for Unix guests Denis V. Lunev
@ 2015-05-21  5:49 ` Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 5/6] qga: guest-pipe-open for Windows guest Denis V. Lunev
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-05-21  5:49 UTC (permalink / raw)
  Cc: Olga Krishtal, Olga Krishtal, Michael Roth, qemu-devel,
	Denis V. Lunev

From: Olga Krishtal <okrishtal@parallels.com>

qemu-ga should not exit on guest-file-write to pipe without read end
but proper error code should be returned. The behavior of the
spawned process should be default thus SIGPIPE processing should be
reset to default after fork() but before exec().

Signed-off-by: Olga Krishtal <okristal@parallels.com>
Acked-by: Roman Kagan <rkagan@parallels.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Eric Blake <eblake@redhat.com>
CC: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qga/commands-posix.c | 16 ++++++++++++++++
 qga/main.c           |  6 ++++++
 2 files changed, 22 insertions(+)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index aa11932..64d9b2d 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -961,6 +961,20 @@ static int guest_exec_set_std(GuestFileHandle *gfh, int std_fd, int fd_null)
     return 0;
 }
 
+/** Reset ignored signals back to default. */
+static void guest_exec_reset_child_sig(void)
+{
+    struct sigaction sigact;
+
+    memset(&sigact, 0, sizeof(struct sigaction));
+    sigact.sa_handler = SIG_DFL;
+
+    if (sigaction(SIGPIPE, &sigact, NULL) != 0) {
+        slog("sigaction() failed to reset child process's SIGPIPE: %s",
+             strerror(errno));
+    }
+}
+
 GuestExec *qmp_guest_exec(const char *path,
                        bool has_params, strList *params,
                        bool has_env, strList *env,
@@ -1032,6 +1046,8 @@ GuestExec *qmp_guest_exec(const char *path,
             /* exit(1); */
         }
 
+        guest_exec_reset_child_sig();
+
         execvpe(path, (char * const *)argv, (char * const *)envp);
         slog("guest-exec child failed: %s", strerror(errno));
         exit(1);
diff --git a/qga/main.c b/qga/main.c
index 9939a2b..bc6414c 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -160,6 +160,12 @@ static gboolean register_signal_handlers(void)
         g_error("error configuring signal handler: %s", strerror(errno));
     }
 
+    sigact.sa_handler = SIG_IGN;
+    if (sigaction(SIGPIPE, &sigact, NULL) != 0) {
+        g_error("error configuring SIGPIPE signal handler: %s",
+                strerror(errno));
+    }
+
     return true;
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 5/6] qga: guest-pipe-open for Windows guest
  2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
                   ` (3 preceding siblings ...)
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 4/6] qga: handle possible SIGPIPE in guest-file-write Denis V. Lunev
@ 2015-05-21  5:49 ` Denis V. Lunev
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 6/6] qga: guest exec functionality for Windows guests Denis V. Lunev
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-05-21  5:49 UTC (permalink / raw)
  Cc: Roman Kagan, Olga Krishtal, Michael Roth, qemu-devel,
	Denis V. Lunev

From: Olga Krishtal <okrishtal@parallels.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 <okrishtal@parallels.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Eric Blake <eblake@redhat.com>
CC: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qga/commands-win32.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 70 insertions(+), 4 deletions(-)

diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 3db7255..b216628 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,68 @@ 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. */
 GuestPipeInfoList *qmp_guest_pipe_open(GuestPipeMode mode, Error **errp)
 {
-    error_set(errp, QERR_UNSUPPORTED);
+    HANDLE fd[2];
+    int this_end, other_end;
+    int64_t handle;
+    GuestPipeInfoList *pipe_list;
+    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_list = g_malloc0(sizeof(*pipe_list));
+    pipe_list->value = pipe_inf;
+    pipe_list->next = NULL;
+    return pipe_list;
+
+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 +228,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 +803,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;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 6/6] qga: guest exec functionality for Windows guests
  2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
                   ` (4 preceding siblings ...)
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 5/6] qga: guest-pipe-open for Windows guest Denis V. Lunev
@ 2015-05-21  5:49 ` Denis V. Lunev
  2015-05-27  7:08 ` [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
  2015-06-08  6:42 ` Denis V. Lunev
  7 siblings, 0 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-05-21  5:49 UTC (permalink / raw)
  Cc: Roman Kagan, Olga Krishtal, Michael Roth, qemu-devel,
	Denis V. Lunev

From: Olga Krishtal <okrishtal@parallels.com>

Child process' stdin/stdout/stderr can be associated
with handles for communication via read/write interfaces.

The workflow should be something like this:
* Open an anonymous pipe through guest-pipe-open
* Execute a binary or a script in the guest. Arbitrary arguments and
  environment to a new child process could be passed through options
* Read/pass information from/to executed process using
  guest-file-read/write
* Collect the status of a child process

Signed-off-by: Olga Krishtal <okrishtal@parallels.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Roman Kagan <rkagan@parallels.com>
CC: Eric Blake <eblake@redhat.com>
CC: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 qga/commands-win32.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 303 insertions(+), 6 deletions(-)

diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index b216628..e633126 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -454,10 +454,231 @@ static void guest_file_init(void)
     QTAILQ_INIT(&guest_file_state.filehandles);
 }
 
+
+typedef struct GuestExecInfo {
+    int pid;
+    HANDLE phandle;
+    GuestFileHandle *gfh_stdin;
+    GuestFileHandle *gfh_stdout;
+    GuestFileHandle *gfh_stderr;
+    QTAILQ_ENTRY(GuestExecInfo) next;
+} GuestExecInfo;
+
+static struct {
+    QTAILQ_HEAD(, GuestExecInfo) processes;
+} guest_exec_state;
+
+static void guest_exec_init(void)
+{
+    QTAILQ_INIT(&guest_exec_state.processes);
+}
+
+static void guest_exec_info_add(int pid, HANDLE phandle,
+                                GuestFileHandle *in, GuestFileHandle *out,
+                                GuestFileHandle *error)
+{
+    GuestExecInfo *gei;
+
+    gei = g_malloc0(sizeof(GuestExecInfo));
+    gei->pid = pid;
+    gei->phandle = phandle;
+    gei->gfh_stdin = in;
+    gei->gfh_stdout = out;
+    gei->gfh_stderr = error;
+    QTAILQ_INSERT_TAIL(&guest_exec_state.processes, gei, next);
+}
+
+static GuestExecInfo *guest_exec_info_find(int64_t pid)
+{
+    GuestExecInfo *gei;
+
+    QTAILQ_FOREACH(gei, &guest_exec_state.processes, next) {
+        if (gei->pid == pid) {
+            return gei;
+        }
+    }
+
+    return NULL;
+}
+
 GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp)
 {
-    error_set(errp, QERR_UNSUPPORTED);
-    return 0;
+    GuestExecInfo *gei;
+    GuestExecStatus *ges;
+    int r;
+    DWORD exit_code;
+
+    slog("guest-exec-status called, pid: %" PRId64, pid);
+
+    gei = guest_exec_info_find(pid);
+    if (gei == NULL) {
+        error_set(errp, QERR_INVALID_PARAMETER, "pid");
+        return NULL;
+    }
+
+    r = WaitForSingleObject(gei->phandle, 0);
+    if (r != WAIT_OBJECT_0 && r != WAIT_TIMEOUT) {
+        error_setg_win32(errp, GetLastError(),
+                         "WaitForSingleObject() failed, pid: %u", gei->pid);
+        return NULL;
+    }
+
+    ges = g_malloc0(sizeof(GuestExecStatus));
+    ges->handle_stdin = (gei->gfh_stdin != NULL) ? gei->gfh_stdin->id : -1;
+    ges->handle_stdout = (gei->gfh_stdout != NULL) ? gei->gfh_stdout->id : -1;
+    ges->handle_stderr = (gei->gfh_stderr != NULL) ? gei->gfh_stderr->id : -1;
+    ges->exit = -1;
+    ges->signal = -1;
+
+    if (r == WAIT_OBJECT_0) {
+        GetExitCodeProcess(gei->phandle, &exit_code);
+        CloseHandle(gei->phandle);
+
+        ges->exit = (int)exit_code;
+
+        QTAILQ_REMOVE(&guest_exec_state.processes, gei, next);
+        g_free(gei);
+    }
+
+    return ges;
+}
+
+/* Convert UTF-8 to wide string. */
+#define utf8_to_ucs2(dst, dst_cap, src, src_len) \
+    MultiByteToWideChar(CP_UTF8, 0, src, (int)(src_len), dst, (int)(dst_cap))
+
+/* Get command-line arguments for CreateProcess().
+ * Path or arguments containing double quotes are prohibited.
+ * Arguments containing spaces are enclosed in double quotes.
+ * @wpath: @path that was converted to wchar.
+ * @argv_str: arguments in one line separated by space. */
+static WCHAR *guest_exec_get_args(const char *path, WCHAR **wpath,
+                                  const strList *params, Error **errp)
+{
+    const strList *it;
+    bool with_spaces;
+    size_t cap = 0;
+    char *argv_str;
+    WCHAR *wargs;
+    char *pargv;
+
+    if (strchr(path, '"') != NULL) {
+        error_setg(errp, "path or arguments can't contain \" quotes");
+        return NULL;
+    }
+
+    for (it = params; it != NULL; it = it->next) {
+        if (strchr(it->value, '"') != NULL) {
+            error_setg(errp, "path or arguments can't contain \" quotes");
+            return NULL;
+        }
+    }
+
+    cap += strlen(path) + sizeof("\"\"") - 1;
+    for (it = params; it != NULL; it = it->next) {
+        cap += strlen(it->value) + sizeof(" \"\"") - 1;
+    }
+    cap++;
+
+    argv_str = g_malloc(cap);
+    pargv = argv_str;
+
+    *pargv++ = '"';
+    pstrcpy(pargv, (pargv + cap) - pargv, path);
+    *pargv++ = '"';
+
+    for (it = params; it != NULL; it = it->next) {
+        with_spaces = (strchr(it->value, ' ') != NULL);
+
+        *pargv++ = ' ';
+
+        if (with_spaces) {
+            *pargv++ = '"';
+        }
+
+        pstrcpy(pargv, (pargv + cap) - pargv, it->value);
+        pargv += strlen(it->value);
+
+        if (with_spaces) {
+            *pargv++ = '"';
+        }
+    }
+    *pargv = '\0';
+
+    wargs = g_malloc(cap * sizeof(WCHAR));
+    if (utf8_to_ucs2(wargs, cap, argv_str, -1) == 0) {
+        goto fail;
+    }
+
+    cap = strlen(path) + 1;
+    *wpath = g_malloc(cap * sizeof(WCHAR));
+    if (utf8_to_ucs2(*wpath, cap, path, -1) == 0) {
+        g_free(*wpath);
+        goto fail;
+    }
+    slog("guest-exec called: %s", argv_str);
+    g_free(argv_str);
+    return wargs;
+
+fail:
+    error_setg_win32(errp, GetLastError(), "MultiByteToWideChar() failed");
+    g_free(argv_str);
+    g_free(wargs);
+    return NULL;
+}
+
+/* Prepare environment string for CreateProcess(). */
+static WCHAR *guest_exec_get_env(strList *env, Error **errp)
+{
+    const strList *it;
+    size_t r, cap = 0;
+    WCHAR *wenv, *pwenv;
+
+    for (it = env; it != NULL; it = it->next) {
+        cap += strlen(it->value) + 1;
+    }
+    cap++;
+
+    wenv = g_malloc(cap * sizeof(WCHAR));
+    pwenv = wenv;
+
+    for (it = env; it != NULL; it = it->next) {
+        r = utf8_to_ucs2(pwenv, (wenv + cap) - pwenv, it->value, -1);
+        if (r == 0) {
+            error_setg_win32(errp, GetLastError(),
+                             "MultiByteToWideChar() failed");
+            g_free(wenv);
+            return NULL;
+        }
+        pwenv += r - 1;
+
+        *pwenv++ = L'\0';
+    }
+    *pwenv = L'\0';
+
+    return wenv;
+}
+
+static HANDLE guest_exec_get_stdhandle(GuestFileHandle *gfh)
+{
+    HANDLE fd;
+
+    if (gfh == NULL) {
+        return INVALID_HANDLE_VALUE;
+    }
+
+    if (gfh->pipe_other_end_fd != INVALID_HANDLE_VALUE) {
+        fd = gfh->pipe_other_end_fd;
+    } else {
+        fd = gfh->fh;
+    }
+
+    if (!SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 1)) {
+        slog("guest-exec: SetHandleInformation() failed to set inherit flag: "
+             "%lu", GetLastError());
+    }
+
+    return fd;
 }
 
 GuestExec *qmp_guest_exec(const char *path,
@@ -468,8 +689,84 @@ GuestExec *qmp_guest_exec(const char *path,
                        bool has_handle_stderr, int64_t handle_stderr,
                        Error **errp)
 {
-    error_set(errp, QERR_UNSUPPORTED);
-    return 0;
+    int64_t pid = -1;
+    GuestExec *ge = NULL;
+    BOOL b;
+    PROCESS_INFORMATION info;
+    STARTUPINFOW si = {0};
+    WCHAR *wpath = NULL, *wargs, *wenv = NULL;
+    GuestFileHandle *gfh_stdin = NULL, *gfh_stdout = NULL, *gfh_stderr = NULL;
+
+    wargs = guest_exec_get_args(path, &wpath, has_params ? params : NULL, errp);
+    wenv = guest_exec_get_env(has_env ? env : NULL, errp);
+    if (wargs == NULL || wenv == NULL) {
+        return NULL;
+    }
+
+    if (has_handle_stdin) {
+        gfh_stdin = guest_file_handle_find(handle_stdin, errp);
+        if (gfh_stdin == NULL) {
+            goto done;
+        }
+    }
+
+    if (has_handle_stdout) {
+        gfh_stdout = guest_file_handle_find(handle_stdout, errp);
+        if (gfh_stdout == NULL) {
+            goto done;
+        }
+    }
+
+    if (has_handle_stderr) {
+        gfh_stderr = guest_file_handle_find(handle_stderr, errp);
+        if (gfh_stderr == NULL) {
+            goto done;
+        }
+    }
+
+    si.cb = sizeof(STARTUPINFOW);
+
+    if (has_handle_stdin || has_handle_stdout || has_handle_stderr) {
+        si.dwFlags = STARTF_USESTDHANDLES;
+
+        si.hStdInput = guest_exec_get_stdhandle(gfh_stdin);
+        si.hStdOutput = guest_exec_get_stdhandle(gfh_stdout);
+        si.hStdError = guest_exec_get_stdhandle(gfh_stderr);
+    }
+
+    b = CreateProcessW(wpath, wargs, NULL, NULL, 1 /*inherit handles*/,
+                       CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS,
+                       wenv, NULL /*inherited current dir*/, &si, &info);
+    if (!b) {
+        error_setg_win32(errp, GetLastError(),
+                         "CreateProcessW() failed");
+        goto done;
+    }
+
+    if (gfh_stdin != NULL && guest_pipe_close_other_end(gfh_stdin) != 0) {
+        slog("failed to close stdin pipe handle. error: %lu", GetLastError());
+    }
+
+    if (gfh_stdout != NULL && guest_pipe_close_other_end(gfh_stdout) != 0) {
+        slog("failed to close stdout pipe handle. error: %lu", GetLastError());
+    }
+
+    if (gfh_stderr != NULL && guest_pipe_close_other_end(gfh_stderr) != 0) {
+        slog("failed to close stderr pipe handle. error: %lu", GetLastError());
+    }
+
+    CloseHandle(info.hThread);
+    guest_exec_info_add(info.dwProcessId, info.hProcess, gfh_stdin, gfh_stdout,
+                        gfh_stderr);
+    pid = info.dwProcessId;
+    ge = g_malloc(sizeof(*ge));
+    ge->pid = pid;
+
+done:
+    g_free(wpath);
+    g_free(wargs);
+    g_free(wenv);
+    return ge;
 }
 
 GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
@@ -803,8 +1100,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-exec-status",
-        "guest-exec", NULL};
+        "guest-fstrim", NULL};
     char **p = (char **)list_unsupported;
 
     while (*p) {
@@ -832,4 +1128,5 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
         ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
     }
     ga_command_state_add(cs, guest_file_init, NULL);
+    ga_command_state_add(cs, guest_exec_init, NULL);
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
                   ` (5 preceding siblings ...)
  2015-05-21  5:49 ` [Qemu-devel] [PATCH 6/6] qga: guest exec functionality for Windows guests Denis V. Lunev
@ 2015-05-27  7:08 ` Denis V. Lunev
  2015-06-08  6:42 ` Denis V. Lunev
  7 siblings, 0 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-05-27  7:08 UTC (permalink / raw)
  Cc: Olga Krishtal, qemu-devel

On 21/05/15 08:49, Denis V. Lunev wrote:
> These patches for guest-agent add the functionality to execute commands on
> a guest UNIX machine.
>
> These patches add the following interfaces:
>
> guest-pipe-open
> guest-exec
> guest-exec-status
>
> With these interfaces it's possible to:
>
> * Open an anonymous pipe and work with it as with a file using already
> implemented interfaces guest-file-{read,write,flush,close}.
>
> * Execute a binary or a script on a guest machine.
> We can pass arbitrary arguments and environment to a new child process.
>
> * Pass redirected IO from/to stdin, stdout, stderr from a child process to a
> local file or an anonymous pipe.
>
> * Check the status of a child process, get its exit status if it exited or get
> signal number if it was killed.
>
> We plan to add support for Windows in the near future using the same interfaces
> we introduce here.
>
> Example of usage:
>
> {"execute": "guest-pipe-open", "arguments":{"mode": "r"}}
> {'return': 1000}
>
> {"execute":"guest-exec", "arguments":{ "path": "id", "params": ["user"],
>      "env": ["MYENV=myvalue"], "handle_stdout": 1000 }}'
> {"return": 2636}
>
> {"execute": "guest-exec-status", "arguments": {"pid": 2636}}
> {"return":{"exit":0,"handle_stderr":-1,"handle_stdin":-1,"handle_stdout":1000,"signal":-1}}
>
> {"execute": "guest-file-read", "arguments": {"handle": 1000, "count":128}}
> {"return":{"count":58,"buf-b64":"dWlk...","eof":true}}
>
> {"execute": "guest-file-close", "arguments": {"handle": 1000}}
> {"return":{}}
>
>
> These patches are based on the patches proposed by Michael Roth in 2011:
> http://lists.gnu.org/archive/html/qemu-devel/2011-12/msg00722.html
>
> We made several modifications to the interfaces proposed by Michael to simplify
> their usage and we also added several new functions:
>
> * Arguments to an executable file are passed as an array of strings.
>
>      Before that we had to pass parameters like this:
>      'params': [ {'param': '-b'}, {'param': '-n1'} ]
>
>      Now we may pass them just as an array of strings:
>      'params': [ '-b', '-n1' ]
>
> * Environment can be passed to a child process.
>
>      "env": ["MYENV=myvalue"]
>
> * Removed "detach" argument from "guest-exec" - it never waits for a child
> process to signal.  With this change it's possible to return just PID from
> "guest-exec", a user must call "guest-exec-status" to get the status of a child.
>
> * Removed "wait" argument from "guest-exec-status" - waiting for a child process
> to signal is dangerous, because it may block the whole qemu-ga.  Instead, the
> command polls just once a status of a child.
>
> * "guest-exec-status" returns exit status of a child process or a signal number,
> in case a process was killed.
>
> * Simplified the command "guest-pipe-open" - the way how it stores the pipe
> fd's.  No additional logic is needed about which end of pipe should be closed
> with "guest-file-close".  This way we avoid modifying the interface of the
> existing "guest-file-close".
>
> In the conversation about the original patches there was a suggestion to merge
> "path" and "params" into one single list.  But we didn't do so, because having
> separate "path" is similar to exec*() family functions in UNIX.  That way it
> looks more consistent.
>
> Changes from v2:
> - return code of commands changed to dictionary
> - ported to current HEAD
> - new way for moving pipe to non-blocking state (universal)
>
> Changes from v1:
> - Windows version of the patchset is added
> - SIGPIPE processing is added for Unix version of the patchset
> - added guest_exec_file_busy() to prevent GuestFileHandle* object from being
>    deleted in case it's used in guest-exec command.
>
> Signed-off-by: Olga Krishtal <okrishtal@parallels.com>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
>
> P.S. Michael, this is a working version and could we consider it for merging
>       into 2.4? If you still want to use universal GLIB code, we could
>       re-write this later using standard refactoring way.
>
ping

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
                   ` (6 preceding siblings ...)
  2015-05-27  7:08 ` [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
@ 2015-06-08  6:42 ` Denis V. Lunev
  2015-06-15  7:07   ` Denis V. Lunev
  7 siblings, 1 reply; 20+ messages in thread
From: Denis V. Lunev @ 2015-06-08  6:42 UTC (permalink / raw)
  To: Eric Blake, Michael Roth; +Cc: Olga Krishtal, qemu-devel

On 21/05/15 08:49, Denis V. Lunev wrote:
> These patches for guest-agent add the functionality to execute commands on
> a guest UNIX machine.
>
> These patches add the following interfaces:
>
> guest-pipe-open
> guest-exec
> guest-exec-status
>
> With these interfaces it's possible to:
>
> * Open an anonymous pipe and work with it as with a file using already
> implemented interfaces guest-file-{read,write,flush,close}.
>
> * Execute a binary or a script on a guest machine.
> We can pass arbitrary arguments and environment to a new child process.
>
> * Pass redirected IO from/to stdin, stdout, stderr from a child process to a
> local file or an anonymous pipe.
>
> * Check the status of a child process, get its exit status if it exited or get
> signal number if it was killed.
>
> We plan to add support for Windows in the near future using the same interfaces
> we introduce here.
>
> Example of usage:
>
> {"execute": "guest-pipe-open", "arguments":{"mode": "r"}}
> {'return': 1000}
>
> {"execute":"guest-exec", "arguments":{ "path": "id", "params": ["user"],
>      "env": ["MYENV=myvalue"], "handle_stdout": 1000 }}'
> {"return": 2636}
>
> {"execute": "guest-exec-status", "arguments": {"pid": 2636}}
> {"return":{"exit":0,"handle_stderr":-1,"handle_stdin":-1,"handle_stdout":1000,"signal":-1}}
>
> {"execute": "guest-file-read", "arguments": {"handle": 1000, "count":128}}
> {"return":{"count":58,"buf-b64":"dWlk...","eof":true}}
>
> {"execute": "guest-file-close", "arguments": {"handle": 1000}}
> {"return":{}}
>
>
> These patches are based on the patches proposed by Michael Roth in 2011:
> http://lists.gnu.org/archive/html/qemu-devel/2011-12/msg00722.html
>
> We made several modifications to the interfaces proposed by Michael to simplify
> their usage and we also added several new functions:
>
> * Arguments to an executable file are passed as an array of strings.
>
>      Before that we had to pass parameters like this:
>      'params': [ {'param': '-b'}, {'param': '-n1'} ]
>
>      Now we may pass them just as an array of strings:
>      'params': [ '-b', '-n1' ]
>
> * Environment can be passed to a child process.
>
>      "env": ["MYENV=myvalue"]
>
> * Removed "detach" argument from "guest-exec" - it never waits for a child
> process to signal.  With this change it's possible to return just PID from
> "guest-exec", a user must call "guest-exec-status" to get the status of a child.
>
> * Removed "wait" argument from "guest-exec-status" - waiting for a child process
> to signal is dangerous, because it may block the whole qemu-ga.  Instead, the
> command polls just once a status of a child.
>
> * "guest-exec-status" returns exit status of a child process or a signal number,
> in case a process was killed.
>
> * Simplified the command "guest-pipe-open" - the way how it stores the pipe
> fd's.  No additional logic is needed about which end of pipe should be closed
> with "guest-file-close".  This way we avoid modifying the interface of the
> existing "guest-file-close".
>
> In the conversation about the original patches there was a suggestion to merge
> "path" and "params" into one single list.  But we didn't do so, because having
> separate "path" is similar to exec*() family functions in UNIX.  That way it
> looks more consistent.
>
> Changes from v2:
> - return code of commands changed to dictionary
> - ported to current HEAD
> - new way for moving pipe to non-blocking state (universal)
>
> Changes from v1:
> - Windows version of the patchset is added
> - SIGPIPE processing is added for Unix version of the patchset
> - added guest_exec_file_busy() to prevent GuestFileHandle* object from being
>    deleted in case it's used in guest-exec command.
>
> Signed-off-by: Olga Krishtal <okrishtal@parallels.com>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
>
> P.S. Michael, this is a working version and could we consider it for merging
>       into 2.4? If you still want to use universal GLIB code, we could
>       re-write this later using standard refactoring way.
>
PING, 1 week till soft freeze.

Eric, Michael, can you pls consider these patches? We have
really small amount of time left.

Regards,
     Den

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-06-08  6:42 ` Denis V. Lunev
@ 2015-06-15  7:07   ` Denis V. Lunev
  2015-09-15  8:02     ` Vasiliy Tolstov
  0 siblings, 1 reply; 20+ messages in thread
From: Denis V. Lunev @ 2015-06-15  7:07 UTC (permalink / raw)
  To: Eric Blake, Michael Roth; +Cc: Olga Krishtal, qemu-devel

On 08/06/15 09:42, Denis V. Lunev wrote:
> On 21/05/15 08:49, Denis V. Lunev wrote:
>> These patches for guest-agent add the functionality to execute 
>> commands on
>> a guest UNIX machine.
>>
>> These patches add the following interfaces:
>>
>> guest-pipe-open
>> guest-exec
>> guest-exec-status
>>
>> With these interfaces it's possible to:
>>
>> * Open an anonymous pipe and work with it as with a file using already
>> implemented interfaces guest-file-{read,write,flush,close}.
>>
>> * Execute a binary or a script on a guest machine.
>> We can pass arbitrary arguments and environment to a new child process.
>>
>> * Pass redirected IO from/to stdin, stdout, stderr from a child 
>> process to a
>> local file or an anonymous pipe.
>>
>> * Check the status of a child process, get its exit status if it 
>> exited or get
>> signal number if it was killed.
>>
>> We plan to add support for Windows in the near future using the same 
>> interfaces
>> we introduce here.
>>
>> Example of usage:
>>
>> {"execute": "guest-pipe-open", "arguments":{"mode": "r"}}
>> {'return': 1000}
>>
>> {"execute":"guest-exec", "arguments":{ "path": "id", "params": ["user"],
>>      "env": ["MYENV=myvalue"], "handle_stdout": 1000 }}'
>> {"return": 2636}
>>
>> {"execute": "guest-exec-status", "arguments": {"pid": 2636}}
>> {"return":{"exit":0,"handle_stderr":-1,"handle_stdin":-1,"handle_stdout":1000,"signal":-1}} 
>>
>>
>> {"execute": "guest-file-read", "arguments": {"handle": 1000, 
>> "count":128}}
>> {"return":{"count":58,"buf-b64":"dWlk...","eof":true}}
>>
>> {"execute": "guest-file-close", "arguments": {"handle": 1000}}
>> {"return":{}}
>>
>>
>> These patches are based on the patches proposed by Michael Roth in 2011:
>> http://lists.gnu.org/archive/html/qemu-devel/2011-12/msg00722.html
>>
>> We made several modifications to the interfaces proposed by Michael 
>> to simplify
>> their usage and we also added several new functions:
>>
>> * Arguments to an executable file are passed as an array of strings.
>>
>>      Before that we had to pass parameters like this:
>>      'params': [ {'param': '-b'}, {'param': '-n1'} ]
>>
>>      Now we may pass them just as an array of strings:
>>      'params': [ '-b', '-n1' ]
>>
>> * Environment can be passed to a child process.
>>
>>      "env": ["MYENV=myvalue"]
>>
>> * Removed "detach" argument from "guest-exec" - it never waits for a 
>> child
>> process to signal.  With this change it's possible to return just PID 
>> from
>> "guest-exec", a user must call "guest-exec-status" to get the status 
>> of a child.
>>
>> * Removed "wait" argument from "guest-exec-status" - waiting for a 
>> child process
>> to signal is dangerous, because it may block the whole qemu-ga. 
>> Instead, the
>> command polls just once a status of a child.
>>
>> * "guest-exec-status" returns exit status of a child process or a 
>> signal number,
>> in case a process was killed.
>>
>> * Simplified the command "guest-pipe-open" - the way how it stores 
>> the pipe
>> fd's.  No additional logic is needed about which end of pipe should 
>> be closed
>> with "guest-file-close".  This way we avoid modifying the interface 
>> of the
>> existing "guest-file-close".
>>
>> In the conversation about the original patches there was a suggestion 
>> to merge
>> "path" and "params" into one single list.  But we didn't do so, 
>> because having
>> separate "path" is similar to exec*() family functions in UNIX. That 
>> way it
>> looks more consistent.
>>
>> Changes from v2:
>> - return code of commands changed to dictionary
>> - ported to current HEAD
>> - new way for moving pipe to non-blocking state (universal)
>>
>> Changes from v1:
>> - Windows version of the patchset is added
>> - SIGPIPE processing is added for Unix version of the patchset
>> - added guest_exec_file_busy() to prevent GuestFileHandle* object 
>> from being
>>    deleted in case it's used in guest-exec command.
>>
>> Signed-off-by: Olga Krishtal <okrishtal@parallels.com>
>> Signed-off-by: Denis V. Lunev <den@openvz.org>
>>
>> P.S. Michael, this is a working version and could we consider it for 
>> merging
>>       into 2.4? If you still want to use universal GLIB code, we could
>>       re-write this later using standard refactoring way.
>>
> PING, 1 week till soft freeze.
>
> Eric, Michael, can you pls consider these patches? We have
> really small amount of time left.
>
> Regards,
>     Den
_PING_

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-06-15  7:07   ` Denis V. Lunev
@ 2015-09-15  8:02     ` Vasiliy Tolstov
  2015-09-15  8:15       ` Denis V. Lunev
  0 siblings, 1 reply; 20+ messages in thread
From: Vasiliy Tolstov @ 2015-09-15  8:02 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Olga Krishtal, Michael Roth, qemu-devel

2015-06-15 10:07 GMT+03:00 Denis V. Lunev <den@odin.com>:
> _PING_


Any news about this feature? I'm need to run inside guest some scripts
and want non blocking exec, so this feature very useful for me.

-- 
Vasiliy Tolstov,
e-mail: v.tolstov@selfip.ru

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-09-15  8:02     ` Vasiliy Tolstov
@ 2015-09-15  8:15       ` Denis V. Lunev
  2015-09-15  8:27         ` Vasiliy Tolstov
  0 siblings, 1 reply; 20+ messages in thread
From: Denis V. Lunev @ 2015-09-15  8:15 UTC (permalink / raw)
  To: Vasiliy Tolstov; +Cc: Olga Krishtal, Michael Roth, qemu-devel

On 09/15/2015 11:02 AM, Vasiliy Tolstov wrote:
> 2015-06-15 10:07 GMT+03:00 Denis V. Lunev <den@odin.com>:
>> _PING_
>
> Any news about this feature? I'm need to run inside guest some scripts
> and want non blocking exec, so this feature very useful for me.
>
we have discussed new approach on KVM forum
with a bit reduced set (guest-pipe-open/close
code should not be in the first version) and in
progress with a rework. I think that I'll post new version
at the end of this week or next week.

Den

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-09-15  8:15       ` Denis V. Lunev
@ 2015-09-15  8:27         ` Vasiliy Tolstov
  2015-10-01  7:43           ` Denis V. Lunev
  0 siblings, 1 reply; 20+ messages in thread
From: Vasiliy Tolstov @ 2015-09-15  8:27 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Olga Krishtal, Michael Roth, qemu-devel

2015-09-15 11:15 GMT+03:00 Denis V. Lunev <den@odin.com>:
> we have discussed new approach on KVM forum
> with a bit reduced set (guest-pipe-open/close
> code should not be in the first version) and in
> progress with a rework. I think that I'll post new version
> at the end of this week or next week.


Ok, i'm wait.

-- 
Vasiliy Tolstov,
e-mail: v.tolstov@selfip.ru

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-09-15  8:27         ` Vasiliy Tolstov
@ 2015-10-01  7:43           ` Denis V. Lunev
  2015-10-01  7:47             ` Vasiliy Tolstov
  2015-10-01  7:50             ` Vasiliy Tolstov
  0 siblings, 2 replies; 20+ messages in thread
From: Denis V. Lunev @ 2015-10-01  7:43 UTC (permalink / raw)
  To: Vasiliy Tolstov, Denis V. Lunev; +Cc: Olga Krishtal, Michael Roth, qemu-devel

On 09/15/2015 11:27 AM, Vasiliy Tolstov wrote:
> 2015-09-15 11:15 GMT+03:00 Denis V. Lunev <den@odin.com>:
>> we have discussed new approach on KVM forum
>> with a bit reduced set (guest-pipe-open/close
>> code should not be in the first version) and in
>> progress with a rework. I think that I'll post new version
>> at the end of this week or next week.
>
> Ok, i'm wait.
>
new simplified version posted. Can you pls look & review?

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-10-01  7:43           ` Denis V. Lunev
@ 2015-10-01  7:47             ` Vasiliy Tolstov
  2015-10-01  7:50             ` Vasiliy Tolstov
  1 sibling, 0 replies; 20+ messages in thread
From: Vasiliy Tolstov @ 2015-10-01  7:47 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Olga Krishtal, Michael Roth, Denis V. Lunev, qemu-devel

2015-10-01 10:43 GMT+03:00 Denis V. Lunev <den-lists@parallels.com>:
> new simplified version posted. Can you pls look & review?


Thanks, i'll check it

-- 
Vasiliy Tolstov,
e-mail: v.tolstov@selfip.ru

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-10-01  7:43           ` Denis V. Lunev
  2015-10-01  7:47             ` Vasiliy Tolstov
@ 2015-10-01  7:50             ` Vasiliy Tolstov
  2015-10-01  8:00               ` Denis V. Lunev
  1 sibling, 1 reply; 20+ messages in thread
From: Vasiliy Tolstov @ 2015-10-01  7:50 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Olga Krishtal, Michael Roth, Denis V. Lunev, qemu-devel

2015-10-01 10:43 GMT+03:00 Denis V. Lunev <den-lists@parallels.com>:
> new simplified version posted. Can you pls look & review?


Sorry, i cant find it in qemu list

-- 
Vasiliy Tolstov,
e-mail: v.tolstov@selfip.ru

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-10-01  7:50             ` Vasiliy Tolstov
@ 2015-10-01  8:00               ` Denis V. Lunev
  2015-10-01  8:17                 ` Vasiliy Tolstov
  0 siblings, 1 reply; 20+ messages in thread
From: Denis V. Lunev @ 2015-10-01  8:00 UTC (permalink / raw)
  To: Vasiliy Tolstov; +Cc: Olga Krishtal, Michael Roth, Denis V. Lunev, qemu-devel

On 10/01/2015 10:50 AM, Vasiliy Tolstov wrote:
> 2015-10-01 10:43 GMT+03:00 Denis V. Lunev <den-lists@parallels.com>:
>> new simplified version posted. Can you pls look & review?
>
> Sorry, i cant find it in qemu list
>
Subject: [PATCH 0/5] simplified QEMU guest exec
Date: Thu, 1 Oct 2015 10:37:58 +0300
Message-ID: <1443685083-6242-1-git-send-email-den@openvz.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-10-01  8:00               ` Denis V. Lunev
@ 2015-10-01  8:17                 ` Vasiliy Tolstov
  2015-10-01 21:42                   ` Michael Roth
  0 siblings, 1 reply; 20+ messages in thread
From: Vasiliy Tolstov @ 2015-10-01  8:17 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: Olga Krishtal, Michael Roth, Denis V. Lunev, qemu-devel

2015-10-01 11:00 GMT+03:00 Denis V. Lunev <den-lists@parallels.com>:
> Subject: [PATCH 0/5] simplified QEMU guest exec
> Date: Thu, 1 Oct 2015 10:37:58 +0300
> Message-ID: <1443685083-6242-1-git-send-email-den@openvz.org>


hm... i don't see it and google and
http://lists.nongnu.org/archive/html/qemu-devel/2015-10/threads.html
says nothing =(

-- 
Vasiliy Tolstov,
e-mail: v.tolstov@selfip.ru

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-10-01  8:17                 ` Vasiliy Tolstov
@ 2015-10-01 21:42                   ` Michael Roth
  2015-10-02 15:39                     ` Vasiliy Tolstov
  0 siblings, 1 reply; 20+ messages in thread
From: Michael Roth @ 2015-10-01 21:42 UTC (permalink / raw)
  To: Vasiliy Tolstov, Denis V. Lunev; +Cc: Olga Krishtal, qemu-devel, Denis V. Lunev

Quoting Vasiliy Tolstov (2015-10-01 03:17:34)
> 2015-10-01 11:00 GMT+03:00 Denis V. Lunev <den-lists@parallels.com>:
> > Subject: [PATCH 0/5] simplified QEMU guest exec
> > Date: Thu, 1 Oct 2015 10:37:58 +0300
> > Message-ID: <1443685083-6242-1-git-send-email-den@openvz.org>
> 
> 
> hm... i don't see it and google and
> http://lists.nongnu.org/archive/html/qemu-devel/2015-10/threads.html
> says nothing =(

Not sure how regularly that archive is updated, but it's here now if
you haven't gotten it yet:

  http://thread.gmane.org/gmane.comp.emulators.qemu/366140

> 
> -- 
> Vasiliy Tolstov,
> e-mail: v.tolstov@selfip.ru
> 

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command
  2015-10-01 21:42                   ` Michael Roth
@ 2015-10-02 15:39                     ` Vasiliy Tolstov
  0 siblings, 0 replies; 20+ messages in thread
From: Vasiliy Tolstov @ 2015-10-02 15:39 UTC (permalink / raw)
  To: Michael Roth; +Cc: Olga Krishtal, qemu-devel, Denis V. Lunev, Denis V. Lunev

2015-10-02 0:42 GMT+03:00 Michael Roth <mdroth@linux.vnet.ibm.com>:
> Not sure how regularly that archive is updated, but it's here now if
> you haven't gotten it yet:
>
>   http://thread.gmane.org/gmane.comp.emulators.qemu/366140


Thanks!

-- 
Vasiliy Tolstov,
e-mail: v.tolstov@selfip.ru

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2015-10-02 15:40 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-21  5:49 [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
2015-05-21  5:49 ` [Qemu-devel] [PATCH 1/6] util, qga: drop guest_file_toggle_flags Denis V. Lunev
2015-05-21  5:49 ` [Qemu-devel] [PATCH 2/6] qga: implement guest-pipe-open command Denis V. Lunev
2015-05-21  5:49 ` [Qemu-devel] [PATCH 3/6] qga: guest exec functionality for Unix guests Denis V. Lunev
2015-05-21  5:49 ` [Qemu-devel] [PATCH 4/6] qga: handle possible SIGPIPE in guest-file-write Denis V. Lunev
2015-05-21  5:49 ` [Qemu-devel] [PATCH 5/6] qga: guest-pipe-open for Windows guest Denis V. Lunev
2015-05-21  5:49 ` [Qemu-devel] [PATCH 6/6] qga: guest exec functionality for Windows guests Denis V. Lunev
2015-05-27  7:08 ` [Qemu-devel] [PATCH v3 0/6] qemu: guest agent: implement guest-exec command Denis V. Lunev
2015-06-08  6:42 ` Denis V. Lunev
2015-06-15  7:07   ` Denis V. Lunev
2015-09-15  8:02     ` Vasiliy Tolstov
2015-09-15  8:15       ` Denis V. Lunev
2015-09-15  8:27         ` Vasiliy Tolstov
2015-10-01  7:43           ` Denis V. Lunev
2015-10-01  7:47             ` Vasiliy Tolstov
2015-10-01  7:50             ` Vasiliy Tolstov
2015-10-01  8:00               ` Denis V. Lunev
2015-10-01  8:17                 ` Vasiliy Tolstov
2015-10-01 21:42                   ` Michael Roth
2015-10-02 15:39                     ` Vasiliy Tolstov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).