From: "Daniel P. Berrange" <berrange(a)redhat.com>
Merge the virCommandPreserveFD / virCommandTransferFD methods
into a single virCommandPasFD method, and use a new
VIR_COMMAND_PASS_FD_CLOSE_PARENT to indicate their difference
in behaviour
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/fdstream.c | 3 +-
src/libvirt_private.syms | 3 +-
src/lxc/lxc_process.c | 6 +-
src/qemu/qemu_command.c | 16 +++--
src/uml/uml_conf.c | 3 +-
src/util/vircommand.c | 159 ++++++++++++++++++++++-------------------------
src/util/vircommand.h | 13 ++--
tests/commandtest.c | 5 +-
8 files changed, 105 insertions(+), 103 deletions(-)
diff --git a/src/fdstream.c b/src/fdstream.c
index 2ee9bd8..10c7c2a 100644
--- a/src/fdstream.c
+++ b/src/fdstream.c
@@ -648,7 +648,8 @@ virFDStreamOpenFileInternal(virStreamPtr st,
path,
NULL);
virCommandAddArgFormat(cmd, "%llu", length);
- virCommandTransferFD(cmd, fd);
+ virCommandPassFD(cmd, fd,
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
virCommandAddArgFormat(cmd, "%d", fd);
if ((oflags & O_ACCMODE) == O_RDONLY) {
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0ab7632..a9e702c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1228,7 +1228,7 @@ virCommandNew;
virCommandNewArgList;
virCommandNewArgs;
virCommandNonblockingFDs;
-virCommandPreserveFD;
+virCommandPassFD;
virCommandRequireHandshake;
virCommandRun;
virCommandRunAsync;
@@ -1249,7 +1249,6 @@ virCommandSetSELinuxLabel;
virCommandSetUID;
virCommandSetWorkingDirectory;
virCommandToString;
-virCommandTransferFD;
virCommandWait;
virCommandWriteArgLog;
virFork;
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index dd908b8..54eb728 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -853,13 +853,13 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
for (i = 0; i < nttyFDs; i++) {
virCommandAddArg(cmd, "--console");
virCommandAddArgFormat(cmd, "%d", ttyFDs[i]);
- virCommandPreserveFD(cmd, ttyFDs[i]);
+ virCommandPassFD(cmd, ttyFDs[i], 0);
}
for (i = 0; i < nfiles; i++) {
virCommandAddArg(cmd, "--passfd");
virCommandAddArgFormat(cmd, "%d", files[i]);
- virCommandPreserveFD(cmd, files[i], 0);
+ virCommandPassFD(cmd, files[i], 0);
}
virCommandAddArgPair(cmd, "--security",
@@ -873,7 +873,7 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
virCommandAddArgList(cmd, "--veth", veths[i], NULL);
}
- virCommandPreserveFD(cmd, handshakefd);
+ virCommandPassFD(cmd, handshakefd, 0);
return cmd;
cleanup:
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 879aed8..4f126e7 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -245,7 +245,8 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr
cfg,
virCommandAddArgFormat(cmd, "--use-vnet");
virCommandAddArgFormat(cmd, "--br=%s", brname);
virCommandAddArgFormat(cmd, "--fd=%d", pair[1]);
- virCommandTransferFD(cmd, pair[1]);
+ virCommandPassFD(cmd, pair[1],
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
virCommandClearCaps(cmd);
#ifdef CAP_NET_ADMIN
virCommandAllowCap(cmd, CAP_NET_ADMIN);
@@ -6524,13 +6525,15 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
}
for (i = 0; i < tapfdSize; i++) {
- virCommandTransferFD(cmd, tapfd[i]);
+ virCommandPassFD(cmd, tapfd[i],
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
if (virAsprintf(&tapfdName[i], "%d", tapfd[i]) < 0)
goto cleanup;
}
for (i = 0; i < vhostfdSize; i++) {
- virCommandTransferFD(cmd, vhostfd[i]);
+ virCommandPassFD(cmd, vhostfd[i],
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
if (virAsprintf(&vhostfdName[i], "%d", vhostfd[i]) < 0)
goto cleanup;
}
@@ -8301,7 +8304,8 @@ qemuBuildCommandLine(virConnectPtr conn,
goto error;
}
- virCommandTransferFD(cmd, configfd);
+ virCommandPassFD(cmd, configfd,
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
}
}
virCommandAddArg(cmd, "-device");
@@ -8367,7 +8371,7 @@ qemuBuildCommandLine(virConnectPtr conn,
} else if (STREQ(migrateFrom, "stdio")) {
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD)) {
virCommandAddArgFormat(cmd, "fd:%d", migrateFd);
- virCommandPreserveFD(cmd, migrateFd);
+ virCommandPassFD(cmd, migrateFd, 0);
} else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MIGRATE_QEMU_EXEC)) {
virCommandAddArg(cmd, "exec:cat");
virCommandSetInputFD(cmd, migrateFd);
@@ -8396,7 +8400,7 @@ qemuBuildCommandLine(virConnectPtr conn,
goto error;
}
virCommandAddArg(cmd, migrateFrom);
- virCommandPreserveFD(cmd, migrateFd);
+ virCommandPassFD(cmd, migrateFd, 0);
} else if (STRPREFIX(migrateFrom, "unix")) {
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MIGRATE_QEMU_UNIX)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index 18cff50..0f2f38e 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -332,7 +332,8 @@ umlBuildCommandLineChr(virDomainChrDefPtr def,
VIR_FORCE_CLOSE(fd_out);
return NULL;
}
- virCommandTransferFD(cmd, fd_out);
+ virCommandPassFD(cmd, fd_out,
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
}
break;
case VIR_DOMAIN_CHR_TYPE_PIPE:
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 3879504..00ff69a 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -64,6 +64,14 @@ enum {
VIR_EXEC_ASYNC_IO = (1 << 4),
};
+typedef struct _virCommandFD virCommandFD;
+typedef virCommandFD *virCommandFDPtr;
+
+struct _virCommandFD {
+ int fd;
+ unsigned int flags;
+};
+
struct _virCommand {
int has_error; /* ENOMEM on allocation failure, -1 for anything else. */
@@ -77,10 +85,8 @@ struct _virCommand {
char *pwd;
- int *preserve; /* FDs to pass to child. */
- int preserve_size;
- int *transfer; /* FDs to close in parent. */
- int transfer_size;
+ size_t npassfd;
+ virCommandFDPtr passfd;
unsigned int flags;
@@ -135,14 +141,15 @@ struct _virCommand {
* false otherwise.
*/
static bool
-virCommandFDIsSet(int fd,
- const int *set,
- int set_size)
+virCommandFDIsSet(virCommandPtr cmd,
+ int fd)
{
size_t i = 0;
+ if (!cmd)
+ return false;
- while (i < set_size)
- if (set[i++] == fd)
+ while (i < cmd->npassfd)
+ if (cmd->passfd[i++].fd == fd)
return true;
return false;
@@ -163,22 +170,21 @@ virCommandFDIsSet(int fd,
* ENOMEM on OOM
*/
static int
-virCommandFDSet(int fd,
- int **set,
- int *set_size)
+virCommandFDSet(virCommandPtr cmd,
+ int fd,
+ unsigned int flags)
{
- if (fd < 0 || !set || !set_size)
+ if (!cmd || fd < 0)
return -1;
- if (virCommandFDIsSet(fd, *set, *set_size))
+ if (virCommandFDIsSet(cmd, fd))
return 0;
- if (VIR_REALLOC_N(*set, *set_size + 1) < 0) {
+ if (VIR_EXPAND_N(cmd->passfd, cmd->npassfd, 1) < 0)
return ENOMEM;
- }
- (*set)[*set_size] = fd;
- (*set_size)++;
+ cmd->passfd[cmd->npassfd - 1].fd = fd;
+ cmd->passfd[cmd->npassfd - 1].flags = flags;
return 0;
}
@@ -525,8 +531,7 @@ virExec(virCommandPtr cmd)
for (fd = 3; fd < openmax; fd++) {
if (fd == childin || fd == childout || fd == childerr)
continue;
- if (!cmd->preserve ||
- !virCommandFDIsSet(fd, cmd->preserve, cmd->preserve_size)) {
+ if (!virCommandFDIsSet(cmd, fd)) {
tmpfd = fd;
VIR_MASS_CLOSE(tmpfd);
} else if (virSetInherit(fd, true) < 0) {
@@ -882,67 +887,51 @@ virCommandNewVAList(const char *binary, va_list list)
}
-/*
- * Preserve the specified file descriptor in the child, instead of
- * closing it. FD must not be one of the three standard streams. If
- * transfer is true, then fd will be closed in the parent after a call
- * to Run/RunAsync/Free, otherwise caller is still responsible for fd.
- * Returns true if a transferring caller should close FD now, and
- * false if the transfer is successfully recorded.
- */
-static bool
-virCommandKeepFD(virCommandPtr cmd, int fd, bool transfer)
-{
- int ret = 0;
-
- if (!cmd)
- return fd > STDERR_FILENO;
-
- if (fd <= STDERR_FILENO ||
- (ret = virCommandFDSet(fd, &cmd->preserve, &cmd->preserve_size))
||
- (transfer && (ret = virCommandFDSet(fd, &cmd->transfer,
- &cmd->transfer_size)))) {
- if (!cmd->has_error)
- cmd->has_error = ret ? ret : -1;
- VIR_DEBUG("cannot preserve %d", fd);
- return fd > STDERR_FILENO;
- }
-
- return false;
-}
-
-/**
- * virCommandPreserveFD:
- * @cmd: the command to modify
- * @fd: fd to mark for inheritance into child
- *
- * Preserve the specified file descriptor
- * in the child, instead of closing it on exec.
- * The parent is still responsible for managing fd.
- */
-void
-virCommandPreserveFD(virCommandPtr cmd, int fd)
-{
- virCommandKeepFD(cmd, fd, false);
-}
+#define VIR_COMMAND_MAYBE_CLOSE_FD(fd, flags) \
+ if ((fd > STDERR_FILENO) && \
+ (flags & VIR_COMMAND_PASS_FD_CLOSE_PARENT)) \
+ VIR_FORCE_CLOSE(fd)
/**
- * virCommandTransferFD:
+ * virCommandPassFD:
* @cmd: the command to modify
* @fd: fd to reassign to the child
+ * @flags: the flags
*
- * Transfer the specified file descriptor
- * to the child, instead of closing it on exec.
- * The parent should no longer use fd, and the parent's copy will
- * be automatically closed no later than during Run/RunAsync/Free.
+ * Transfer the specified file descriptor to the child, instead
+ * of closing it on exec. @fd must not be one of the three
+ * standard streams.
+ *
+ * If the flag VIR_COMMAND_PASS_FD_CLOSE_PARENT is set then fd will
+ * be closed in the parent no later than Run/RunAsync/Free. The parent
+ * should cease using the @fd when this call completes
*/
void
-virCommandTransferFD(virCommandPtr cmd, int fd)
+virCommandPassFD(virCommandPtr cmd, int fd, unsigned int flags)
{
- if (virCommandKeepFD(cmd, fd, true))
- VIR_FORCE_CLOSE(fd);
-}
+ int ret = 0;
+
+ if (!cmd) {
+ VIR_COMMAND_MAYBE_CLOSE_FD(fd, flags);
+ return;
+ }
+
+ if (fd <= STDERR_FILENO) {
+ VIR_DEBUG("invalid fd %d", fd);
+ VIR_COMMAND_MAYBE_CLOSE_FD(fd, flags);
+ if (!cmd->has_error)
+ cmd->has_error = -1;
+ return;
+ }
+ if ((ret = virCommandFDSet(cmd, fd, flags)) != 0) {
+ if (!cmd->has_error)
+ cmd->has_error = ret;
+ VIR_DEBUG("cannot preserve %d", fd);
+ VIR_COMMAND_MAYBE_CLOSE_FD(fd, flags);
+ return;
+ }
+}
/**
* virCommandSetPidFile:
@@ -2252,11 +2241,12 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
VIR_DEBUG("Command result %d, with PID %d",
ret, (int)cmd->pid);
- for (i = 0; i < cmd->transfer_size; i++) {
- VIR_FORCE_CLOSE(cmd->transfer[i]);
+ for (i = 0; i < cmd->npassfd; i++) {
+ if (cmd->passfd[i].flags & VIR_COMMAND_PASS_FD_CLOSE_PARENT)
+ VIR_FORCE_CLOSE(cmd->passfd[i].fd);
}
- cmd->transfer_size = 0;
- VIR_FREE(cmd->transfer);
+ cmd->npassfd = 0;
+ VIR_FREE(cmd->passfd);
if (ret == 0 && pid)
*pid = cmd->pid;
@@ -2431,8 +2421,10 @@ void virCommandRequireHandshake(virCommandPtr cmd)
"keep handshake wait=%d notify=%d",
cmd->handshakeWait[1], cmd->handshakeNotify[0],
cmd->handshakeWait[0], cmd->handshakeNotify[1]);
- virCommandTransferFD(cmd, cmd->handshakeWait[1]);
- virCommandTransferFD(cmd, cmd->handshakeNotify[0]);
+ virCommandPassFD(cmd, cmd->handshakeWait[1],
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+ virCommandPassFD(cmd, cmd->handshakeNotify[0],
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
cmd->handshake = true;
}
@@ -2555,9 +2547,12 @@ virCommandFree(virCommandPtr cmd)
if (!cmd)
return;
- for (i = 0; i < cmd->transfer_size; i++) {
- VIR_FORCE_CLOSE(cmd->transfer[i]);
+ for (i = 0; i < cmd->npassfd; i++) {
+ if (cmd->passfd[i].flags & VIR_COMMAND_PASS_FD_CLOSE_PARENT)
+ VIR_FORCE_CLOSE(cmd->passfd[i].fd);
}
+ cmd->npassfd = 0;
+ VIR_FREE(cmd->passfd);
if (cmd->asyncioThread) {
virThreadJoin(cmd->asyncioThread);
@@ -2579,7 +2574,7 @@ virCommandFree(virCommandPtr cmd)
if (cmd->handshake) {
/* The other 2 fds in these arrays are closed
- * due to use with virCommandTransferFD
+ * due to use with virCommandPassFD
*/
VIR_FORCE_CLOSE(cmd->handshakeWait[0]);
VIR_FORCE_CLOSE(cmd->handshakeNotify[1]);
@@ -2590,8 +2585,6 @@ virCommandFree(virCommandPtr cmd)
if (cmd->reap)
virCommandAbort(cmd);
- VIR_FREE(cmd->transfer);
- VIR_FREE(cmd->preserve);
#if defined(WITH_SECDRIVER_SELINUX)
VIR_FREE(cmd->seLinuxLabel);
#endif
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index a402139..c619e06 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -51,11 +51,14 @@ virCommandPtr virCommandNewVAList(const char *binary, va_list list)
* delayed until the Run/RunAsync methods
*/
-void virCommandPreserveFD(virCommandPtr cmd,
- int fd);
-
-void virCommandTransferFD(virCommandPtr cmd,
- int fd);
+enum {
+ /* Close the FD in the parent */
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT = (1 << 0),
+};
+
+void virCommandPassFD(virCommandPtr cmd,
+ int fd,
+ unsigned int flags);
void virCommandSetPidFile(virCommandPtr cmd,
const char *pidfile) ATTRIBUTE_NONNULL(2);
diff --git a/tests/commandtest.c b/tests/commandtest.c
index 62f0277..eeb6d1e 100644
--- a/tests/commandtest.c
+++ b/tests/commandtest.c
@@ -194,8 +194,9 @@ static int test3(const void *unused ATTRIBUTE_UNUSED)
int newfd3 = dup(STDERR_FILENO);
int ret = -1;
- virCommandPreserveFD(cmd, newfd1);
- virCommandTransferFD(cmd, newfd3);
+ virCommandPassFD(cmd, newfd1, 0);
+ virCommandPassFD(cmd, newfd3,
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
if (virCommandRun(cmd, NULL) < 0) {
virErrorPtr err = virGetLastError();
--
1.8.1.4