]>
Commit | Line | Data |
---|---|---|
195e14d0 DB |
1 | /* |
2 | * QEMU I/O channels external command driver | |
3 | * | |
4 | * Copyright (c) 2015 Red Hat, Inc. | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
c8198bd5 | 9 | * version 2.1 of the License, or (at your option) any later version. |
195e14d0 DB |
10 | * |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | * | |
19 | */ | |
20 | ||
cae9fc56 | 21 | #include "qemu/osdep.h" |
195e14d0 DB |
22 | #include "io/channel-command.h" |
23 | #include "io/channel-watch.h" | |
da34e65c | 24 | #include "qapi/error.h" |
0b8fa32f | 25 | #include "qemu/module.h" |
195e14d0 DB |
26 | #include "qemu/sockets.h" |
27 | #include "trace.h" | |
28 | ||
05e50e8f MAL |
29 | #ifndef WIN32 |
30 | /** | |
31 | * qio_channel_command_new_pid: | |
32 | * @writefd: the FD connected to the command's stdin | |
33 | * @readfd: the FD connected to the command's stdout | |
34 | * @pid: the PID of the running child command | |
35 | * @errp: pointer to a NULL-initialized error object | |
36 | * | |
37 | * Create a channel for performing I/O with the | |
38 | * previously spawned command identified by @pid. | |
39 | * The two file descriptors provide the connection | |
40 | * to command's stdio streams, either one or which | |
41 | * may be -1 to indicate that stream is not open. | |
42 | * | |
43 | * The channel will take ownership of the process | |
44 | * @pid and will kill it when closing the channel. | |
45 | * Similarly it will take responsibility for | |
46 | * closing the file descriptors @writefd and @readfd. | |
47 | * | |
48 | * Returns: the command channel object, or NULL on error | |
49 | */ | |
50 | static QIOChannelCommand * | |
195e14d0 DB |
51 | qio_channel_command_new_pid(int writefd, |
52 | int readfd, | |
53 | pid_t pid) | |
54 | { | |
55 | QIOChannelCommand *ioc; | |
56 | ||
57 | ioc = QIO_CHANNEL_COMMAND(object_new(TYPE_QIO_CHANNEL_COMMAND)); | |
58 | ||
59 | ioc->readfd = readfd; | |
60 | ioc->writefd = writefd; | |
61 | ioc->pid = pid; | |
62 | ||
63 | trace_qio_channel_command_new_pid(ioc, writefd, readfd, pid); | |
64 | return ioc; | |
65 | } | |
66 | ||
195e14d0 DB |
67 | QIOChannelCommand * |
68 | qio_channel_command_new_spawn(const char *const argv[], | |
69 | int flags, | |
70 | Error **errp) | |
71 | { | |
72 | pid_t pid = -1; | |
73 | int stdinfd[2] = { -1, -1 }; | |
74 | int stdoutfd[2] = { -1, -1 }; | |
75 | int devnull = -1; | |
76 | bool stdinnull = false, stdoutnull = false; | |
77 | QIOChannelCommand *ioc; | |
78 | ||
79 | flags = flags & O_ACCMODE; | |
80 | ||
81 | if (flags == O_RDONLY) { | |
82 | stdinnull = true; | |
83 | } | |
84 | if (flags == O_WRONLY) { | |
85 | stdoutnull = true; | |
86 | } | |
87 | ||
88 | if (stdinnull || stdoutnull) { | |
89 | devnull = open("/dev/null", O_RDWR); | |
e155494c | 90 | if (devnull < 0) { |
195e14d0 DB |
91 | error_setg_errno(errp, errno, |
92 | "Unable to open /dev/null"); | |
93 | goto error; | |
94 | } | |
95 | } | |
96 | ||
d640b59e MAL |
97 | if ((!stdinnull && !g_unix_open_pipe(stdinfd, FD_CLOEXEC, NULL)) || |
98 | (!stdoutnull && !g_unix_open_pipe(stdoutfd, FD_CLOEXEC, NULL))) { | |
195e14d0 DB |
99 | error_setg_errno(errp, errno, |
100 | "Unable to open pipe"); | |
101 | goto error; | |
102 | } | |
103 | ||
104 | pid = qemu_fork(errp); | |
105 | if (pid < 0) { | |
106 | goto error; | |
107 | } | |
108 | ||
109 | if (pid == 0) { /* child */ | |
110 | dup2(stdinnull ? devnull : stdinfd[0], STDIN_FILENO); | |
111 | dup2(stdoutnull ? devnull : stdoutfd[1], STDOUT_FILENO); | |
112 | /* Leave stderr connected to qemu's stderr */ | |
113 | ||
114 | if (!stdinnull) { | |
115 | close(stdinfd[0]); | |
116 | close(stdinfd[1]); | |
117 | } | |
118 | if (!stdoutnull) { | |
119 | close(stdoutfd[0]); | |
120 | close(stdoutfd[1]); | |
121 | } | |
e155494c DB |
122 | if (devnull != -1) { |
123 | close(devnull); | |
124 | } | |
195e14d0 DB |
125 | |
126 | execv(argv[0], (char * const *)argv); | |
127 | _exit(1); | |
128 | } | |
129 | ||
130 | if (!stdinnull) { | |
131 | close(stdinfd[0]); | |
132 | } | |
133 | if (!stdoutnull) { | |
134 | close(stdoutfd[1]); | |
135 | } | |
136 | ||
137 | ioc = qio_channel_command_new_pid(stdinnull ? devnull : stdinfd[1], | |
138 | stdoutnull ? devnull : stdoutfd[0], | |
139 | pid); | |
140 | trace_qio_channel_command_new_spawn(ioc, argv[0], flags); | |
141 | return ioc; | |
142 | ||
143 | error: | |
e155494c DB |
144 | if (devnull != -1) { |
145 | close(devnull); | |
146 | } | |
195e14d0 DB |
147 | if (stdinfd[0] != -1) { |
148 | close(stdinfd[0]); | |
149 | } | |
150 | if (stdinfd[1] != -1) { | |
151 | close(stdinfd[1]); | |
152 | } | |
153 | if (stdoutfd[0] != -1) { | |
154 | close(stdoutfd[0]); | |
155 | } | |
156 | if (stdoutfd[1] != -1) { | |
157 | close(stdoutfd[1]); | |
158 | } | |
159 | return NULL; | |
160 | } | |
161 | ||
162 | #else /* WIN32 */ | |
163 | QIOChannelCommand * | |
164 | qio_channel_command_new_spawn(const char *const argv[], | |
165 | int flags, | |
166 | Error **errp) | |
167 | { | |
168 | error_setg_errno(errp, ENOSYS, | |
169 | "Command spawn not supported on this platform"); | |
170 | return NULL; | |
171 | } | |
172 | #endif /* WIN32 */ | |
173 | ||
174 | #ifndef WIN32 | |
175 | static int qio_channel_command_abort(QIOChannelCommand *ioc, | |
176 | Error **errp) | |
177 | { | |
178 | pid_t ret; | |
179 | int status; | |
180 | int step = 0; | |
181 | ||
182 | /* See if intermediate process has exited; if not, try a nice | |
183 | * SIGTERM followed by a more severe SIGKILL. | |
184 | */ | |
185 | rewait: | |
186 | trace_qio_channel_command_abort(ioc, ioc->pid); | |
187 | ret = waitpid(ioc->pid, &status, WNOHANG); | |
188 | trace_qio_channel_command_wait(ioc, ioc->pid, ret, status); | |
189 | if (ret == (pid_t)-1) { | |
190 | if (errno == EINTR) { | |
191 | goto rewait; | |
192 | } else { | |
193 | error_setg_errno(errp, errno, | |
194 | "Cannot wait on pid %llu", | |
195 | (unsigned long long)ioc->pid); | |
196 | return -1; | |
197 | } | |
198 | } else if (ret == 0) { | |
199 | if (step == 0) { | |
200 | kill(ioc->pid, SIGTERM); | |
201 | } else if (step == 1) { | |
202 | kill(ioc->pid, SIGKILL); | |
203 | } else { | |
204 | error_setg(errp, | |
205 | "Process %llu refused to die", | |
206 | (unsigned long long)ioc->pid); | |
207 | return -1; | |
208 | } | |
0c0a55b2 | 209 | step++; |
195e14d0 DB |
210 | usleep(10 * 1000); |
211 | goto rewait; | |
212 | } | |
213 | ||
214 | return 0; | |
215 | } | |
216 | #endif /* ! WIN32 */ | |
217 | ||
218 | ||
219 | static void qio_channel_command_init(Object *obj) | |
220 | { | |
221 | QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj); | |
222 | ioc->readfd = -1; | |
223 | ioc->writefd = -1; | |
224 | ioc->pid = -1; | |
225 | } | |
226 | ||
227 | static void qio_channel_command_finalize(Object *obj) | |
228 | { | |
229 | QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj); | |
230 | if (ioc->readfd != -1) { | |
231 | close(ioc->readfd); | |
195e14d0 | 232 | } |
e155494c DB |
233 | if (ioc->writefd != -1 && |
234 | ioc->writefd != ioc->readfd) { | |
195e14d0 | 235 | close(ioc->writefd); |
195e14d0 | 236 | } |
e155494c | 237 | ioc->writefd = ioc->readfd = -1; |
195e14d0 DB |
238 | if (ioc->pid > 0) { |
239 | #ifndef WIN32 | |
240 | qio_channel_command_abort(ioc, NULL); | |
241 | #endif | |
242 | } | |
243 | } | |
244 | ||
245 | ||
246 | static ssize_t qio_channel_command_readv(QIOChannel *ioc, | |
247 | const struct iovec *iov, | |
248 | size_t niov, | |
249 | int **fds, | |
250 | size_t *nfds, | |
251 | Error **errp) | |
252 | { | |
253 | QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); | |
254 | ssize_t ret; | |
255 | ||
256 | retry: | |
257 | ret = readv(cioc->readfd, iov, niov); | |
258 | if (ret < 0) { | |
30fd3e27 | 259 | if (errno == EAGAIN) { |
195e14d0 DB |
260 | return QIO_CHANNEL_ERR_BLOCK; |
261 | } | |
262 | if (errno == EINTR) { | |
263 | goto retry; | |
264 | } | |
265 | ||
266 | error_setg_errno(errp, errno, | |
267 | "Unable to read from command"); | |
268 | return -1; | |
269 | } | |
270 | ||
271 | return ret; | |
272 | } | |
273 | ||
274 | static ssize_t qio_channel_command_writev(QIOChannel *ioc, | |
275 | const struct iovec *iov, | |
276 | size_t niov, | |
277 | int *fds, | |
278 | size_t nfds, | |
279 | Error **errp) | |
280 | { | |
281 | QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); | |
282 | ssize_t ret; | |
283 | ||
284 | retry: | |
285 | ret = writev(cioc->writefd, iov, niov); | |
286 | if (ret <= 0) { | |
30fd3e27 | 287 | if (errno == EAGAIN) { |
195e14d0 DB |
288 | return QIO_CHANNEL_ERR_BLOCK; |
289 | } | |
290 | if (errno == EINTR) { | |
291 | goto retry; | |
292 | } | |
293 | error_setg_errno(errp, errno, "%s", | |
294 | "Unable to write to command"); | |
295 | return -1; | |
296 | } | |
297 | return ret; | |
298 | } | |
299 | ||
300 | static int qio_channel_command_set_blocking(QIOChannel *ioc, | |
301 | bool enabled, | |
302 | Error **errp) | |
303 | { | |
17fc1245 MAL |
304 | #ifdef WIN32 |
305 | /* command spawn is not supported on win32 */ | |
306 | g_assert_not_reached(); | |
307 | #else | |
195e14d0 DB |
308 | QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); |
309 | ||
17fc1245 MAL |
310 | if (!g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL) || |
311 | !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL)) { | |
312 | error_setg_errno(errp, errno, "Failed to set FD nonblocking"); | |
313 | return -1; | |
195e14d0 | 314 | } |
17fc1245 | 315 | #endif |
195e14d0 DB |
316 | return 0; |
317 | } | |
318 | ||
319 | ||
320 | static int qio_channel_command_close(QIOChannel *ioc, | |
321 | Error **errp) | |
322 | { | |
323 | QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); | |
324 | int rv = 0; | |
fe823b6f TH |
325 | #ifndef WIN32 |
326 | pid_t wp; | |
327 | #endif | |
195e14d0 DB |
328 | |
329 | /* We close FDs before killing, because that | |
330 | * gives a better chance of clean shutdown | |
331 | */ | |
e155494c DB |
332 | if (cioc->readfd != -1 && |
333 | close(cioc->readfd) < 0) { | |
195e14d0 DB |
334 | rv = -1; |
335 | } | |
e155494c DB |
336 | if (cioc->writefd != -1 && |
337 | cioc->writefd != cioc->readfd && | |
338 | close(cioc->writefd) < 0) { | |
195e14d0 DB |
339 | rv = -1; |
340 | } | |
e155494c | 341 | cioc->writefd = cioc->readfd = -1; |
fe823b6f | 342 | |
195e14d0 | 343 | #ifndef WIN32 |
fe823b6f TH |
344 | do { |
345 | wp = waitpid(cioc->pid, NULL, 0); | |
346 | } while (wp == (pid_t)-1 && errno == EINTR); | |
347 | if (wp == (pid_t)-1) { | |
348 | error_setg_errno(errp, errno, "Failed to wait for pid %llu", | |
349 | (unsigned long long)cioc->pid); | |
195e14d0 DB |
350 | return -1; |
351 | } | |
352 | #endif | |
fe823b6f | 353 | |
195e14d0 DB |
354 | if (rv < 0) { |
355 | error_setg_errno(errp, errno, "%s", | |
356 | "Unable to close command"); | |
357 | } | |
358 | return rv; | |
359 | } | |
360 | ||
361 | ||
bf88c124 PB |
362 | static void qio_channel_command_set_aio_fd_handler(QIOChannel *ioc, |
363 | AioContext *ctx, | |
364 | IOHandler *io_read, | |
365 | IOHandler *io_write, | |
366 | void *opaque) | |
367 | { | |
368 | QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); | |
826cc324 SH |
369 | aio_set_fd_handler(ctx, cioc->readfd, false, |
370 | io_read, NULL, NULL, NULL, opaque); | |
371 | aio_set_fd_handler(ctx, cioc->writefd, false, | |
372 | NULL, io_write, NULL, NULL, opaque); | |
bf88c124 PB |
373 | } |
374 | ||
375 | ||
195e14d0 DB |
376 | static GSource *qio_channel_command_create_watch(QIOChannel *ioc, |
377 | GIOCondition condition) | |
378 | { | |
379 | QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc); | |
380 | return qio_channel_create_fd_pair_watch(ioc, | |
381 | cioc->readfd, | |
382 | cioc->writefd, | |
383 | condition); | |
384 | } | |
385 | ||
386 | ||
387 | static void qio_channel_command_class_init(ObjectClass *klass, | |
388 | void *class_data G_GNUC_UNUSED) | |
389 | { | |
390 | QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); | |
391 | ||
392 | ioc_klass->io_writev = qio_channel_command_writev; | |
393 | ioc_klass->io_readv = qio_channel_command_readv; | |
394 | ioc_klass->io_set_blocking = qio_channel_command_set_blocking; | |
395 | ioc_klass->io_close = qio_channel_command_close; | |
396 | ioc_klass->io_create_watch = qio_channel_command_create_watch; | |
bf88c124 | 397 | ioc_klass->io_set_aio_fd_handler = qio_channel_command_set_aio_fd_handler; |
195e14d0 DB |
398 | } |
399 | ||
400 | static const TypeInfo qio_channel_command_info = { | |
401 | .parent = TYPE_QIO_CHANNEL, | |
402 | .name = TYPE_QIO_CHANNEL_COMMAND, | |
403 | .instance_size = sizeof(QIOChannelCommand), | |
404 | .instance_init = qio_channel_command_init, | |
405 | .instance_finalize = qio_channel_command_finalize, | |
406 | .class_init = qio_channel_command_class_init, | |
407 | }; | |
408 | ||
409 | static void qio_channel_command_register_types(void) | |
410 | { | |
411 | type_register_static(&qio_channel_command_info); | |
412 | } | |
413 | ||
414 | type_init(qio_channel_command_register_types); |