mirror of
git://git.yoctoproject.org/poky
synced 2026-10-02 17:25:46 +00:00
The patch chardev-connect-socket-to-a-spawned-command.patch calls "socketpair". This function is missing in mingw, so the patch needs to be modified accordingly, otherwise we end up with a broken mingw build. While it is possible to simply remove the patch on a recipe level for mingw platform, it makes more sense to modify the patch itself. (From OE-Core rev: fd978a5ddf6938404f2043c9f9ede47dcdb47180) Signed-off-by: Juro Bystricky <juro.bystricky@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
249 lines
8.3 KiB
Diff
249 lines
8.3 KiB
Diff
From aa3aef4cf5f4dd98f9133df085e825ff5da7dcbd Mon Sep 17 00:00:00 2001
|
|
From: Patrick Ohly <patrick.ohly@intel.com>
|
|
Date: Fri, 27 Oct 2017 15:23:35 +0200
|
|
Subject: [PATCH] chardev: connect socket to a spawned command
|
|
|
|
The command is started in a shell (sh -c) with stdin connect to QEMU
|
|
via a Unix domain stream socket. QEMU then exchanges data via its own
|
|
end of the socket, just like it normally does.
|
|
|
|
"-chardev socket" supports some ways of connecting via protocols like
|
|
telnet, but that is only a subset of the functionality supported by
|
|
tools socat. To use socat instead, for example to connect via a socks
|
|
proxy, use:
|
|
|
|
-chardev 'socket,id=socat,cmd=exec socat FD:0 SOCKS4A:socks-proxy.localdomain:example.com:9999,,socksuser=nobody' \
|
|
-device usb-serial,chardev=socat
|
|
|
|
Beware that commas in the command must be escaped as double commas.
|
|
|
|
Or interactively in the console:
|
|
(qemu) chardev-add socket,id=cat,cmd=cat
|
|
(qemu) device_add usb-serial,chardev=cat
|
|
^ac
|
|
# cat >/dev/ttyUSB0
|
|
hello
|
|
hello
|
|
|
|
Another usage is starting swtpm from inside QEMU. swtpm will
|
|
automatically shut down once it looses the connection to the parent
|
|
QEMU, so there is no risk of lingering processes:
|
|
|
|
-chardev 'socket,id=chrtpm0,cmd=exec swtpm socket --terminate --ctrl type=unixio,,clientfd=0 --tpmstate dir=... --log file=swtpm.log' \
|
|
-tpmdev emulator,id=tpm0,chardev=chrtpm0 \
|
|
-device tpm-tis,tpmdev=tpm0
|
|
|
|
The patch was discussed upstream, but QEMU developers believe that the
|
|
code calling QEMU should be responsible for managing additional
|
|
processes. In OE-core, that would imply enhancing runqemu and
|
|
oeqa. This patch is a simpler solution.
|
|
|
|
Because it is not going upstream, the patch was written so that it is
|
|
as simple as possible.
|
|
|
|
Upstream-Status: Inappropriate [embedded specific]
|
|
|
|
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
|
|
|
|
---
|
|
chardev/char-socket.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++---
|
|
chardev/char.c | 3 ++
|
|
qapi-schema.json | 5 +++
|
|
3 files changed, 90 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
|
|
index 1ae730a4..c366a02a 100644
|
|
--- a/chardev/char-socket.c
|
|
+++ b/chardev/char-socket.c
|
|
@@ -854,6 +854,68 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
|
|
return false;
|
|
}
|
|
|
|
+#ifndef _WIN32
|
|
+static void chardev_open_socket_cmd(Chardev *chr,
|
|
+ const char *cmd,
|
|
+ Error **errp)
|
|
+{
|
|
+ int fds[2] = { -1, -1 };
|
|
+ QIOChannelSocket *sioc = NULL;
|
|
+ pid_t pid = -1;
|
|
+ const char *argv[] = { "/bin/sh", "-c", cmd, NULL };
|
|
+
|
|
+ /*
|
|
+ * We need a Unix domain socket for commands like swtpm and a single
|
|
+ * connection, therefore we cannot use qio_channel_command_new_spawn()
|
|
+ * without patching it first. Duplicating the functionality is easier.
|
|
+ */
|
|
+ if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds)) {
|
|
+ error_setg_errno(errp, errno, "Error creating socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC)");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ pid = qemu_fork(errp);
|
|
+ if (pid < 0) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (!pid) {
|
|
+ /* child */
|
|
+ dup2(fds[1], STDIN_FILENO);
|
|
+ execv(argv[0], (char * const *)argv);
|
|
+ _exit(1);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Hand over our end of the socket pair to the qio channel.
|
|
+ *
|
|
+ * We don't reap the child because it is expected to keep
|
|
+ * running. We also don't support the "reconnect" option for the
|
|
+ * same reason.
|
|
+ */
|
|
+ sioc = qio_channel_socket_new_fd(fds[0], errp);
|
|
+ if (!sioc) {
|
|
+ goto error;
|
|
+ }
|
|
+ fds[0] = -1;
|
|
+
|
|
+ g_free(chr->filename);
|
|
+ chr->filename = g_strdup_printf("cmd:%s", cmd);
|
|
+ tcp_chr_new_client(chr, sioc);
|
|
+
|
|
+ error:
|
|
+ if (fds[0] >= 0) {
|
|
+ close(fds[0]);
|
|
+ }
|
|
+ if (fds[1] >= 0) {
|
|
+ close(fds[1]);
|
|
+ }
|
|
+ if (sioc) {
|
|
+ object_unref(OBJECT(sioc));
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
static void qmp_chardev_open_socket(Chardev *chr,
|
|
ChardevBackend *backend,
|
|
bool *be_opened,
|
|
@@ -861,6 +923,9 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
|
{
|
|
SocketChardev *s = SOCKET_CHARDEV(chr);
|
|
ChardevSocket *sock = backend->u.socket.data;
|
|
+#ifndef _WIN32
|
|
+ const char *cmd = sock->cmd;
|
|
+#endif
|
|
bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
|
|
bool is_listen = sock->has_server ? sock->server : true;
|
|
bool is_telnet = sock->has_telnet ? sock->telnet : false;
|
|
@@ -928,7 +993,15 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
|
s->reconnect_time = reconnect;
|
|
}
|
|
|
|
- if (s->reconnect_time) {
|
|
+#ifndef _WIN32
|
|
+ if (cmd) {
|
|
+ chardev_open_socket_cmd(chr, cmd, errp);
|
|
+
|
|
+ /* everything ready (or failed permanently) before we return */
|
|
+ *be_opened = true;
|
|
+ } else
|
|
+#endif
|
|
+ if (s->reconnect_time) {
|
|
sioc = qio_channel_socket_new();
|
|
tcp_chr_set_client_ioc_name(chr, sioc);
|
|
qio_channel_socket_connect_async(sioc, s->addr,
|
|
@@ -987,11 +1060,27 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
|
|
const char *host = qemu_opt_get(opts, "host");
|
|
const char *port = qemu_opt_get(opts, "port");
|
|
const char *tls_creds = qemu_opt_get(opts, "tls-creds");
|
|
+#ifndef _WIN32
|
|
+ const char *cmd = qemu_opt_get(opts, "cmd");
|
|
+#endif
|
|
SocketAddressLegacy *addr;
|
|
ChardevSocket *sock;
|
|
|
|
backend->type = CHARDEV_BACKEND_KIND_SOCKET;
|
|
- if (!path) {
|
|
+#ifndef _WIN32
|
|
+ if (cmd) {
|
|
+ /*
|
|
+ * Here we have to ensure that no options are set which are incompatible with
|
|
+ * spawning a command, otherwise unmodified code that doesn't know about
|
|
+ * command spawning (like socket_reconnect_timeout()) might get called.
|
|
+ */
|
|
+ if (path || is_listen || is_telnet || is_tn3270 || reconnect || host || port || tls_creds) {
|
|
+ error_setg(errp, "chardev: socket: cmd does not support any additional options");
|
|
+ return;
|
|
+ }
|
|
+ } else
|
|
+#endif
|
|
+ if (!path) {
|
|
if (!host) {
|
|
error_setg(errp, "chardev: socket: no host given");
|
|
return;
|
|
@@ -1023,13 +1112,24 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
|
|
sock->has_reconnect = true;
|
|
sock->reconnect = reconnect;
|
|
sock->tls_creds = g_strdup(tls_creds);
|
|
+#ifndef _WIN32
|
|
+ sock->cmd = g_strdup(cmd);
|
|
+#endif
|
|
|
|
addr = g_new0(SocketAddressLegacy, 1);
|
|
+#ifndef _WIN32
|
|
+ if (path || cmd) {
|
|
+#else
|
|
if (path) {
|
|
+#endif
|
|
UnixSocketAddress *q_unix;
|
|
addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX;
|
|
q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
|
- q_unix->path = g_strdup(path);
|
|
+#ifndef _WIN32
|
|
+ q_unix->path = cmd ? g_strdup_printf("cmd:%s", cmd) : g_strdup(path);
|
|
+#else
|
|
+ q_unix->path = g_strdup(path);
|
|
+#endif
|
|
} else {
|
|
addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
|
|
addr->u.inet.data = g_new(InetSocketAddress, 1);
|
|
diff --git a/chardev/char.c b/chardev/char.c
|
|
index 5d283b90..ccb329d4 100644
|
|
--- a/chardev/char.c
|
|
+++ b/chardev/char.c
|
|
@@ -782,6 +782,9 @@ QemuOptsList qemu_chardev_opts = {
|
|
.name = "path",
|
|
.type = QEMU_OPT_STRING,
|
|
},{
|
|
+ .name = "cmd",
|
|
+ .type = QEMU_OPT_STRING,
|
|
+ },{
|
|
.name = "host",
|
|
.type = QEMU_OPT_STRING,
|
|
},{
|
|
diff --git a/qapi-schema.json b/qapi-schema.json
|
|
index 78a00bc8..790b026d 100644
|
|
--- a/qapi-schema.json
|
|
+++ b/qapi-schema.json
|
|
@@ -5004,6 +5004,10 @@
|
|
#
|
|
# @addr: socket address to listen on (server=true)
|
|
# or connect to (server=false)
|
|
+# @cmd: command to run via "sh -c" with stdin as one end of
|
|
+# a AF_UNIX SOCK_DSTREAM socket pair. The other end
|
|
+# is used by the chardev. Either an addr or a cmd can
|
|
+# be specified, but not both.
|
|
# @tls-creds: the ID of the TLS credentials object (since 2.6)
|
|
# @server: create server socket (default: true)
|
|
# @wait: wait for incoming connection on server
|
|
@@ -5021,6 +5025,7 @@
|
|
# Since: 1.4
|
|
##
|
|
{ 'struct': 'ChardevSocket', 'data': { 'addr' : 'SocketAddressLegacy',
|
|
+ '*cmd' : 'str',
|
|
'*tls-creds' : 'str',
|
|
'*server' : 'bool',
|
|
'*wait' : 'bool',
|
|
--
|
|
2.11.0
|
|
|