]> git.ipfire.org Git - thirdparty/openembedded/openembedded-core.git/blob - meta/recipes-devtools/qemu/qemu/chardev-connect-socket-to-a-spawned-command.patch
qemu_2.11.1.bb: support mingw build
[thirdparty/openembedded/openembedded-core.git] / meta / recipes-devtools / qemu / qemu / chardev-connect-socket-to-a-spawned-command.patch
1 From 3bb3100c22eb30146a69656480bdffeef8663575 Mon Sep 17 00:00:00 2001
2 From: Alistair Francis <alistair.francis@xilinx.com>
3 Date: Thu, 21 Dec 2017 11:35:16 -0800
4 Subject: [PATCH] chardev: connect socket to a spawned command
5
6 The command is started in a shell (sh -c) with stdin connect to QEMU
7 via a Unix domain stream socket. QEMU then exchanges data via its own
8 end of the socket, just like it normally does.
9
10 "-chardev socket" supports some ways of connecting via protocols like
11 telnet, but that is only a subset of the functionality supported by
12 tools socat. To use socat instead, for example to connect via a socks
13 proxy, use:
14
15 -chardev 'socket,id=socat,cmd=exec socat FD:0 SOCKS4A:socks-proxy.localdomain:example.com:9999,,socksuser=nobody' \
16 -device usb-serial,chardev=socat
17
18 Beware that commas in the command must be escaped as double commas.
19
20 Or interactively in the console:
21 (qemu) chardev-add socket,id=cat,cmd=cat
22 (qemu) device_add usb-serial,chardev=cat
23 ^ac
24 # cat >/dev/ttyUSB0
25 hello
26 hello
27
28 Another usage is starting swtpm from inside QEMU. swtpm will
29 automatically shut down once it looses the connection to the parent
30 QEMU, so there is no risk of lingering processes:
31
32 -chardev 'socket,id=chrtpm0,cmd=exec swtpm socket --terminate --ctrl type=unixio,,clientfd=0 --tpmstate dir=... --log file=swtpm.log' \
33 -tpmdev emulator,id=tpm0,chardev=chrtpm0 \
34 -device tpm-tis,tpmdev=tpm0
35
36 The patch was discussed upstream, but QEMU developers believe that the
37 code calling QEMU should be responsible for managing additional
38 processes. In OE-core, that would imply enhancing runqemu and
39 oeqa. This patch is a simpler solution.
40
41 Because it is not going upstream, the patch was written so that it is
42 as simple as possible.
43
44 Upstream-Status: Inappropriate [embedded specific]
45
46 Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
47 ---
48 chardev/char-socket.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++---
49 chardev/char.c | 3 ++
50 qapi/char.json | 5 +++
51 3 files changed, 90 insertions(+), 4 deletions(-)
52
53 diff --git a/chardev/char-socket.c b/chardev/char-socket.c
54 index 53eda8ef00..f566107c35 100644
55 --- a/chardev/char-socket.c
56 +++ b/chardev/char-socket.c
57 @@ -852,6 +852,68 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
58 return false;
59 }
60
61 +#ifndef _WIN32
62 +static void chardev_open_socket_cmd(Chardev *chr,
63 + const char *cmd,
64 + Error **errp)
65 +{
66 + int fds[2] = { -1, -1 };
67 + QIOChannelSocket *sioc = NULL;
68 + pid_t pid = -1;
69 + const char *argv[] = { "/bin/sh", "-c", cmd, NULL };
70 +
71 + /*
72 + * We need a Unix domain socket for commands like swtpm and a single
73 + * connection, therefore we cannot use qio_channel_command_new_spawn()
74 + * without patching it first. Duplicating the functionality is easier.
75 + */
76 + if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds)) {
77 + error_setg_errno(errp, errno, "Error creating socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC)");
78 + goto error;
79 + }
80 +
81 + pid = qemu_fork(errp);
82 + if (pid < 0) {
83 + goto error;
84 + }
85 +
86 + if (!pid) {
87 + /* child */
88 + dup2(fds[1], STDIN_FILENO);
89 + execv(argv[0], (char * const *)argv);
90 + _exit(1);
91 + }
92 +
93 + /*
94 + * Hand over our end of the socket pair to the qio channel.
95 + *
96 + * We don't reap the child because it is expected to keep
97 + * running. We also don't support the "reconnect" option for the
98 + * same reason.
99 + */
100 + sioc = qio_channel_socket_new_fd(fds[0], errp);
101 + if (!sioc) {
102 + goto error;
103 + }
104 + fds[0] = -1;
105 +
106 + g_free(chr->filename);
107 + chr->filename = g_strdup_printf("cmd:%s", cmd);
108 + tcp_chr_new_client(chr, sioc);
109 +
110 + error:
111 + if (fds[0] >= 0) {
112 + close(fds[0]);
113 + }
114 + if (fds[1] >= 0) {
115 + close(fds[1]);
116 + }
117 + if (sioc) {
118 + object_unref(OBJECT(sioc));
119 + }
120 +}
121 +#endif
122 +
123 static void qmp_chardev_open_socket(Chardev *chr,
124 ChardevBackend *backend,
125 bool *be_opened,
126 @@ -859,6 +921,9 @@
127 {
128 SocketChardev *s = SOCKET_CHARDEV(chr);
129 ChardevSocket *sock = backend->u.socket.data;
130 +#ifndef _WIN32
131 + const char *cmd = sock->cmd;
132 +#endif
133 bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
134 bool is_listen = sock->has_server ? sock->server : true;
135 bool is_telnet = sock->has_telnet ? sock->telnet : false;
136 @@ -925,7 +990,14 @@
137 } else if (reconnect > 0) {
138 s->reconnect_time = reconnect;
139 }
140 -
141 +#ifndef _WIN32
142 + if (cmd) {
143 + chardev_open_socket_cmd(chr, cmd, errp);
144 +
145 + /* everything ready (or failed permanently) before we return */
146 + *be_opened = true;
147 + } else
148 +#endif
149 if (s->reconnect_time) {
150 sioc = qio_channel_socket_new();
151 tcp_chr_set_client_ioc_name(chr, sioc);
152 @@ -985,10 +1057,26 @@
153 const char *host = qemu_opt_get(opts, "host");
154 const char *port = qemu_opt_get(opts, "port");
155 const char *tls_creds = qemu_opt_get(opts, "tls-creds");
156 +#ifndef _WIN32
157 + const char *cmd = qemu_opt_get(opts, "cmd");
158 +#endif
159 SocketAddressLegacy *addr;
160 ChardevSocket *sock;
161
162 backend->type = CHARDEV_BACKEND_KIND_SOCKET;
163 +#ifndef _WIN32
164 + if (cmd) {
165 + /*
166 + * Here we have to ensure that no options are set which are incompatible with
167 + * spawning a command, otherwise unmodified code that doesn't know about
168 + * command spawning (like socket_reconnect_timeout()) might get called.
169 + */
170 + if (path || is_listen || is_telnet || is_tn3270 || reconnect || host || port || tls_creds) {
171 + error_setg(errp, "chardev: socket: cmd does not support any additional options");
172 + return;
173 + }
174 + } else
175 +#endif
176 if (!path) {
177 if (!host) {
178 error_setg(errp, "chardev: socket: no host given");
179 @@ -1021,13 +1109,24 @@
180 sock->has_reconnect = true;
181 sock->reconnect = reconnect;
182 sock->tls_creds = g_strdup(tls_creds);
183 +#ifndef _WIN32
184 + sock->cmd = g_strdup(cmd);
185 +#endif
186
187 addr = g_new0(SocketAddressLegacy, 1);
188 +#ifndef _WIN32
189 + if (path || cmd) {
190 +#else
191 if (path) {
192 +#endif
193 UnixSocketAddress *q_unix;
194 addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX;
195 q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
196 +#ifndef _WIN32
197 + q_unix->path = cmd ? g_strdup_printf("cmd:%s", cmd) : g_strdup(path);
198 +#else
199 q_unix->path = g_strdup(path);
200 +#endif
201 } else {
202 addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
203 addr->u.inet.data = g_new(InetSocketAddress, 1);
204 diff --git a/chardev/char.c b/chardev/char.c
205 index 2ae4f465ec..5d52cd5de5 100644
206 --- a/chardev/char.c
207 +++ b/chardev/char.c
208 @@ -792,6 +792,9 @@ QemuOptsList qemu_chardev_opts = {
209 },{
210 .name = "path",
211 .type = QEMU_OPT_STRING,
212 + },{
213 + .name = "cmd",
214 + .type = QEMU_OPT_STRING,
215 },{
216 .name = "host",
217 .type = QEMU_OPT_STRING,
218 diff --git a/qapi/char.json b/qapi/char.json
219 index ae19dcd1ed..6de0f29bcd 100644
220 --- a/qapi/char.json
221 +++ b/qapi/char.json
222 @@ -241,6 +241,10 @@
223 #
224 # @addr: socket address to listen on (server=true)
225 # or connect to (server=false)
226 +# @cmd: command to run via "sh -c" with stdin as one end of
227 +# a AF_UNIX SOCK_DSTREAM socket pair. The other end
228 +# is used by the chardev. Either an addr or a cmd can
229 +# be specified, but not both.
230 # @tls-creds: the ID of the TLS credentials object (since 2.6)
231 # @server: create server socket (default: true)
232 # @wait: wait for incoming connection on server
233 @@ -258,6 +262,7 @@
234 # Since: 1.4
235 ##
236 { 'struct': 'ChardevSocket', 'data': { 'addr' : 'SocketAddressLegacy',
237 + '*cmd' : 'str',
238 '*tls-creds' : 'str',
239 '*server' : 'bool',
240 '*wait' : 'bool',
241 --
242 2.14.1