aboutsummaryrefslogtreecommitdiff
path: root/io/channel-command.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2022-10-06 15:36:55 +0400
committerMarc-André Lureau <marcandre.lureau@redhat.com>2022-10-12 19:22:01 +0400
commita95570e3e4d61a7c8e527e512246665c51caa6f4 (patch)
tree335c5e60b5908261038044db448fb4660b3abbb9 /io/channel-command.c
parentbb06b0143b492203ab3d17640be1d819cfc33de7 (diff)
io/command: use glib GSpawn, instead of open-coding fork/exec
Simplify qio_channel_command_new_spawn() with GSpawn API. This will allow to build for WIN32 in the following patches. As pointed out by Daniel Berrangé: there is a change in semantics here too. The current code only touches stdin/stdout/stderr. Any other FDs which do NOT have O_CLOEXEC set will be inherited. With the new code, all FDs except stdin/out/err will be explicitly closed, because we don't set the flag G_SPAWN_LEAVE_DESCRIPTORS_OPEN. The only place we use QIOChannelCommand today is the migration exec: protocol, and that is only declared to use stdin/stdout. Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20221006113657.2656108-5-marcandre.lureau@redhat.com>
Diffstat (limited to 'io/channel-command.c')
-rw-r--r--io/channel-command.c105
1 files changed, 18 insertions, 87 deletions
diff --git a/io/channel-command.c b/io/channel-command.c
index 9f2f4a1793..f84d1f03a0 100644
--- a/io/channel-command.c
+++ b/io/channel-command.c
@@ -31,7 +31,7 @@
* qio_channel_command_new_pid:
* @writefd: the FD connected to the command's stdin
* @readfd: the FD connected to the command's stdout
- * @pid: the PID of the running child command
+ * @pid: the PID/HANDLE of the running child command
* @errp: pointer to a NULL-initialized error object
*
* Create a channel for performing I/O with the
@@ -50,7 +50,7 @@
static QIOChannelCommand *
qio_channel_command_new_pid(int writefd,
int readfd,
- pid_t pid)
+ GPid pid)
{
QIOChannelCommand *ioc;
@@ -69,94 +69,24 @@ qio_channel_command_new_spawn(const char *const argv[],
int flags,
Error **errp)
{
- pid_t pid = -1;
- int stdinfd[2] = { -1, -1 };
- int stdoutfd[2] = { -1, -1 };
- int devnull = -1;
- bool stdinnull = false, stdoutnull = false;
- QIOChannelCommand *ioc;
+ g_autoptr(GError) err = NULL;
+ GPid pid = 0;
+ GSpawnFlags gflags = G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD;
+ int stdinfd = -1, stdoutfd = -1;
flags = flags & O_ACCMODE;
-
- if (flags == O_RDONLY) {
- stdinnull = true;
- }
- if (flags == O_WRONLY) {
- stdoutnull = true;
- }
-
- if (stdinnull || stdoutnull) {
- devnull = open("/dev/null", O_RDWR);
- if (devnull < 0) {
- error_setg_errno(errp, errno,
- "Unable to open /dev/null");
- goto error;
- }
- }
-
- if ((!stdinnull && !g_unix_open_pipe(stdinfd, FD_CLOEXEC, NULL)) ||
- (!stdoutnull && !g_unix_open_pipe(stdoutfd, FD_CLOEXEC, NULL))) {
- error_setg_errno(errp, errno,
- "Unable to open pipe");
- goto error;
- }
-
- pid = qemu_fork(errp);
- if (pid < 0) {
- goto error;
- }
-
- if (pid == 0) { /* child */
- dup2(stdinnull ? devnull : stdinfd[0], STDIN_FILENO);
- dup2(stdoutnull ? devnull : stdoutfd[1], STDOUT_FILENO);
- /* Leave stderr connected to qemu's stderr */
-
- if (!stdinnull) {
- close(stdinfd[0]);
- close(stdinfd[1]);
- }
- if (!stdoutnull) {
- close(stdoutfd[0]);
- close(stdoutfd[1]);
- }
- if (devnull != -1) {
- close(devnull);
- }
-
- execv(argv[0], (char * const *)argv);
- _exit(1);
+ gflags |= flags == O_WRONLY ? G_SPAWN_STDOUT_TO_DEV_NULL : 0;
+
+ if (!g_spawn_async_with_pipes(NULL, (char **)argv, NULL, gflags, NULL, NULL,
+ &pid,
+ flags == O_RDONLY ? NULL : &stdinfd,
+ flags == O_WRONLY ? NULL : &stdoutfd,
+ NULL, &err)) {
+ error_setg(errp, "%s", err->message);
+ return NULL;
}
- if (!stdinnull) {
- close(stdinfd[0]);
- }
- if (!stdoutnull) {
- close(stdoutfd[1]);
- }
-
- ioc = qio_channel_command_new_pid(stdinnull ? devnull : stdinfd[1],
- stdoutnull ? devnull : stdoutfd[0],
- pid);
- trace_qio_channel_command_new_spawn(ioc, argv[0], flags);
- return ioc;
-
- error:
- if (devnull != -1) {
- close(devnull);
- }
- if (stdinfd[0] != -1) {
- close(stdinfd[0]);
- }
- if (stdinfd[1] != -1) {
- close(stdinfd[1]);
- }
- if (stdoutfd[0] != -1) {
- close(stdoutfd[0]);
- }
- if (stdoutfd[1] != -1) {
- close(stdoutfd[1]);
- }
- return NULL;
+ return qio_channel_command_new_pid(stdinfd, stdoutfd, pid);
}
#else /* WIN32 */
@@ -221,7 +151,7 @@ static void qio_channel_command_init(Object *obj)
QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj);
ioc->readfd = -1;
ioc->writefd = -1;
- ioc->pid = -1;
+ ioc->pid = 0;
}
static void qio_channel_command_finalize(Object *obj)
@@ -239,6 +169,7 @@ static void qio_channel_command_finalize(Object *obj)
#ifndef WIN32
qio_channel_command_abort(ioc, NULL);
#endif
+ g_spawn_close_pid(ioc->pid);
}
}