From: Peter Krempa <[email protected]> Extract the common code used to pass FDs from a virCommand to a child process into virCommandMassClose - a new wrapper - and create 'virCommandFDMassClose' which simply takes a bitmap of FDs to be kept and closes everything else.
This will allow reuse of the algorithm in test files where we want to prevent FDs leaked from the environment from breakign the test. Signed-off-by: Peter Krempa <[email protected]> --- src/libvirt_private.syms | 1 + src/util/vircommand.c | 101 +++++++++++++++++++++------------------ src/util/vircommand.h | 3 ++ 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f22b5895db..744932acd8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2182,6 +2182,7 @@ virCommandDoAsyncIO; virCommandDryRunTokenFree; virCommandDryRunTokenNew; virCommandExec; +virCommandFDMassClose; virCommandFree; virCommandGetArgList; virCommandGetBinaryPath; diff --git a/src/util/vircommand.c b/src/util/vircommand.c index e871d572a6..07e7040ef8 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -520,16 +520,12 @@ virCommandMassCloseGetFDs(virBitmap *fds) } static int -virCommandMassCloseFrom(virCommand *cmd, - int childin, - int childout, - int childerr) +virCommandMassCloseFrom(virBitmap *keep) { g_autoptr(virBitmap) fds = NULL; int openmax = sysconf(_SC_OPEN_MAX); - int lastfd = -1; + int lastfd = virBitmapLastSetBit(keep); int fd = -1; - size_t i; /* In general, it is not safe to call malloc() between fork() and exec() * because the child might have forked at the worst possible time, i.e. @@ -551,24 +547,14 @@ virCommandMassCloseFrom(virCommand *cmd, if (virCommandMassCloseGetFDs(fds) < 0) return -1; - lastfd = MAX(lastfd, childin); - lastfd = MAX(lastfd, childout); - lastfd = MAX(lastfd, childerr); - - for (i = 0; i < cmd->npassfd; i++) - lastfd = MAX(lastfd, cmd->passfd[i].fd); - fd = virBitmapNextSetBit(fds, 2); for (; fd >= 0 && fd <= lastfd; fd = virBitmapNextSetBit(fds, fd)) { - if (fd == childin || fd == childout || fd == childerr) + int tmpfd = fd; + + if (virBitmapIsBitSet(keep, fd)) continue; - if (!virCommandFDIsSet(cmd, fd)) { - int tmpfd = fd; - VIR_MASS_CLOSE(tmpfd); - } else if (virSetInherit(fd, true) < 0) { - virReportSystemError(errno, _("failed to preserve fd %1$d"), fd); - return -1; - } + + VIR_MASS_CLOSE(tmpfd); } if (virCloseFrom(lastfd + 1) < 0) { @@ -588,33 +574,13 @@ virCommandMassCloseFrom(virCommand *cmd, static int -virCommandMassCloseRange(virCommand *cmd, - int childin, - int childout, - int childerr) +virCommandMassCloseRange(virBitmap *keep) { - g_autoptr(virBitmap) fds = virBitmapNew(0); ssize_t first; ssize_t last; - size_t i; - - virBitmapSetBitExpand(fds, childin); - virBitmapSetBitExpand(fds, childout); - virBitmapSetBitExpand(fds, childerr); - - for (i = 0; i < cmd->npassfd; i++) { - int fd = cmd->passfd[i].fd; - - virBitmapSetBitExpand(fds, fd); - - if (virSetInherit(fd, true) < 0) { - virReportSystemError(errno, _("failed to preserve fd %1$d"), fd); - return -1; - } - } first = 2; - while ((last = virBitmapNextSetBit(fds, first)) >= 0) { + while ((last = virBitmapNextSetBit(keep, first)) >= 0) { if (first + 1 == last) { first = last; continue; @@ -642,17 +608,60 @@ virCommandMassCloseRange(virCommand *cmd, } +/** + * virCommandFDMassClose: + * @keep: bitmap of FDs to be kept open in the child process + * + * Closes all open FDs (in the current process) except those represented by + * set bits in @keep. + * + * Returns 0 on success, -1 on error and reports libvirt errors. + */ +int +virCommandFDMassClose(virBitmap *keep) +{ + if (virCloseRangeIsSupported()) + return virCommandMassCloseRange(keep); + + return virCommandMassCloseFrom(keep); +} + +/** + * virCommandMassClose: + * @cmd: command structure + * @childin: fd passed to child as stdin + * @childout: fd passed to child as stdout + * @childerr: fd passed to child as stderr + * + * Prepares FDs to be passed to the child process spawned by @cmd and closes + * every other FD. + */ static int virCommandMassClose(virCommand *cmd, int childin, int childout, int childerr) { - if (virCloseRangeIsSupported()) - return virCommandMassCloseRange(cmd, childin, childout, childerr); + g_autoptr(virBitmap) fds = virBitmapNew(0); + size_t i; + + virBitmapSetBitExpand(fds, childin); + virBitmapSetBitExpand(fds, childout); + virBitmapSetBitExpand(fds, childerr); + + for (i = 0; i < cmd->npassfd; i++) { + int fd = cmd->passfd[i].fd; + + virBitmapSetBitExpand(fds, fd); + + if (virSetInherit(fd, true) < 0) { + virReportSystemError(errno, _("failed to preserve fd %1$d"), fd); + return -1; + } + } - return virCommandMassCloseFrom(cmd, childin, childout, childerr); + return virCommandFDMassClose(fds); } diff --git a/src/util/vircommand.h b/src/util/vircommand.h index a6e9a9a165..523ad1297d 100644 --- a/src/util/vircommand.h +++ b/src/util/vircommand.h @@ -23,6 +23,7 @@ #include "internal.h" #include "virbuffer.h" +#include "virbitmap.h" typedef struct _virCommandSendBuffer virCommandSendBuffer; struct _virCommandSendBuffer { @@ -32,6 +33,8 @@ struct _virCommandSendBuffer { off_t offset; }; +int virCommandFDMassClose(virBitmap *keep); + typedef struct _virCommand virCommand; /* This will execute in the context of the first child -- 2.54.0
