mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-23 13:05:27 +00:00
command: Discard FD_SETSIZE limit for opened files
Currently, virCommand implementation uses FD_ macros from sys/select.h. However, those cannot handle more opened files than FD_SETSIZE. Therefore switch to generalized implementation based on array of integers.
This commit is contained in:
parent
49d8c8bc0c
commit
db371a217d
@ -75,9 +75,10 @@ struct _virCommand {
|
|||||||
|
|
||||||
char *pwd;
|
char *pwd;
|
||||||
|
|
||||||
/* XXX Use int[] if we ever need to support more than FD_SETSIZE fd's. */
|
int *preserve; /* FDs to pass to child. */
|
||||||
fd_set preserve; /* FDs to pass to child. */
|
int preserve_size;
|
||||||
fd_set transfer; /* FDs to close in parent. */
|
int *transfer; /* FDs to close in parent. */
|
||||||
|
int transfer_size;
|
||||||
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
||||||
@ -130,6 +131,65 @@ static int virClearCapabilities(void)
|
|||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* virCommandFDIsSet:
|
||||||
|
* @fd: FD to test
|
||||||
|
* @set: the set
|
||||||
|
* @set_size: actual size of @set
|
||||||
|
*
|
||||||
|
* Check if FD is already in @set or not.
|
||||||
|
*
|
||||||
|
* Returns true if @set contains @fd,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
virCommandFDIsSet(int fd,
|
||||||
|
const int *set,
|
||||||
|
int set_size)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < set_size)
|
||||||
|
if (set[i++] == fd)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* virCommandFDSet:
|
||||||
|
* @fd: FD to be put into @set
|
||||||
|
* @set: the set
|
||||||
|
* @set_size: actual size of @set
|
||||||
|
*
|
||||||
|
* This is practically generalized implementation
|
||||||
|
* of FD_SET() as we do not want to be limited
|
||||||
|
* by FD_SETSIZE.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success,
|
||||||
|
* -1 on usage error,
|
||||||
|
* ENOMEM on OOM
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virCommandFDSet(int fd,
|
||||||
|
int **set,
|
||||||
|
int *set_size)
|
||||||
|
{
|
||||||
|
if (fd < 0 || !set || !set_size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (virCommandFDIsSet(fd, *set, *set_size))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (VIR_REALLOC_N(*set, *set_size + 1) < 0) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*set)[*set_size] = fd;
|
||||||
|
(*set_size)++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virFork:
|
* virFork:
|
||||||
@ -303,7 +363,8 @@ prepareStdFd(int fd, int std)
|
|||||||
static int
|
static int
|
||||||
virExecWithHook(const char *const*argv,
|
virExecWithHook(const char *const*argv,
|
||||||
const char *const*envp,
|
const char *const*envp,
|
||||||
const fd_set *keepfd,
|
const int *keepfd,
|
||||||
|
int keepfd_size,
|
||||||
pid_t *retpid,
|
pid_t *retpid,
|
||||||
int infd, int *outfd, int *errfd,
|
int infd, int *outfd, int *errfd,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
@ -430,7 +491,7 @@ virExecWithHook(const char *const*argv,
|
|||||||
for (i = 3; i < openmax; i++) {
|
for (i = 3; i < openmax; i++) {
|
||||||
if (i == infd || i == childout || i == childerr)
|
if (i == infd || i == childout || i == childerr)
|
||||||
continue;
|
continue;
|
||||||
if (!keepfd || i >= FD_SETSIZE || !FD_ISSET(i, keepfd)) {
|
if (!keepfd || !virCommandFDIsSet(i, keepfd, keepfd_size)) {
|
||||||
tmpfd = i;
|
tmpfd = i;
|
||||||
VIR_FORCE_CLOSE(tmpfd);
|
VIR_FORCE_CLOSE(tmpfd);
|
||||||
} else if (virSetInherit(i, true) < 0) {
|
} else if (virSetInherit(i, true) < 0) {
|
||||||
@ -619,7 +680,8 @@ virRun(const char *const *argv ATTRIBUTE_UNUSED,
|
|||||||
static int
|
static int
|
||||||
virExecWithHook(const char *const*argv ATTRIBUTE_UNUSED,
|
virExecWithHook(const char *const*argv ATTRIBUTE_UNUSED,
|
||||||
const char *const*envp ATTRIBUTE_UNUSED,
|
const char *const*envp ATTRIBUTE_UNUSED,
|
||||||
const fd_set *keepfd ATTRIBUTE_UNUSED,
|
const int *keepfd ATTRIBUTE_UNUSED,
|
||||||
|
int keepfd_size ATTRIBUTE_UNUSED,
|
||||||
pid_t *retpid ATTRIBUTE_UNUSED,
|
pid_t *retpid ATTRIBUTE_UNUSED,
|
||||||
int infd ATTRIBUTE_UNUSED,
|
int infd ATTRIBUTE_UNUSED,
|
||||||
int *outfd ATTRIBUTE_UNUSED,
|
int *outfd ATTRIBUTE_UNUSED,
|
||||||
@ -687,8 +749,6 @@ virCommandNewArgs(const char *const*args)
|
|||||||
cmd->handshakeNotify[0] = -1;
|
cmd->handshakeNotify[0] = -1;
|
||||||
cmd->handshakeNotify[1] = -1;
|
cmd->handshakeNotify[1] = -1;
|
||||||
|
|
||||||
FD_ZERO(&cmd->preserve);
|
|
||||||
FD_ZERO(&cmd->transfer);
|
|
||||||
cmd->infd = cmd->outfd = cmd->errfd = -1;
|
cmd->infd = cmd->outfd = cmd->errfd = -1;
|
||||||
cmd->inpipe = -1;
|
cmd->inpipe = -1;
|
||||||
cmd->pid = -1;
|
cmd->pid = -1;
|
||||||
@ -736,19 +796,21 @@ virCommandNewArgList(const char *binary, ...)
|
|||||||
static bool
|
static bool
|
||||||
virCommandKeepFD(virCommandPtr cmd, int fd, bool transfer)
|
virCommandKeepFD(virCommandPtr cmd, int fd, bool transfer)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
return fd > STDERR_FILENO;
|
return fd > STDERR_FILENO;
|
||||||
|
|
||||||
if (fd <= STDERR_FILENO || FD_SETSIZE <= fd) {
|
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)
|
if (!cmd->has_error)
|
||||||
cmd->has_error = -1;
|
cmd->has_error = ret ? ret : -1 ;
|
||||||
VIR_DEBUG("cannot preserve %d", fd);
|
VIR_DEBUG("cannot preserve %d", fd);
|
||||||
return fd > STDERR_FILENO;
|
return fd > STDERR_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
FD_SET(fd, &cmd->preserve);
|
|
||||||
if (transfer)
|
|
||||||
FD_SET(fd, &cmd->transfer);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2082,7 +2144,8 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
|
|||||||
|
|
||||||
ret = virExecWithHook((const char *const *)cmd->args,
|
ret = virExecWithHook((const char *const *)cmd->args,
|
||||||
(const char *const *)cmd->env,
|
(const char *const *)cmd->env,
|
||||||
&cmd->preserve,
|
cmd->preserve,
|
||||||
|
cmd->preserve_size,
|
||||||
&cmd->pid,
|
&cmd->pid,
|
||||||
cmd->infd,
|
cmd->infd,
|
||||||
cmd->outfdptr,
|
cmd->outfdptr,
|
||||||
@ -2095,13 +2158,11 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
|
|||||||
VIR_DEBUG("Command result %d, with PID %d",
|
VIR_DEBUG("Command result %d, with PID %d",
|
||||||
ret, (int)cmd->pid);
|
ret, (int)cmd->pid);
|
||||||
|
|
||||||
for (i = STDERR_FILENO + 1; i < FD_SETSIZE; i++) {
|
for (i = 0; i < cmd->transfer_size; i++) {
|
||||||
if (FD_ISSET(i, &cmd->transfer)) {
|
VIR_FORCE_CLOSE(cmd->transfer[i]);
|
||||||
int tmpfd = i;
|
|
||||||
VIR_FORCE_CLOSE(tmpfd);
|
|
||||||
FD_CLR(i, &cmd->transfer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
cmd->transfer_size = 0;
|
||||||
|
VIR_FREE(cmd->transfer);
|
||||||
|
|
||||||
if (ret == 0 && pid)
|
if (ret == 0 && pid)
|
||||||
*pid = cmd->pid;
|
*pid = cmd->pid;
|
||||||
@ -2466,11 +2527,8 @@ virCommandFree(virCommandPtr cmd)
|
|||||||
if (!cmd)
|
if (!cmd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = STDERR_FILENO + 1; i < FD_SETSIZE; i++) {
|
for (i = 0; i < cmd->transfer_size; i++) {
|
||||||
if (FD_ISSET(i, &cmd->transfer)) {
|
VIR_FORCE_CLOSE(cmd->transfer[i]);
|
||||||
int tmpfd = i;
|
|
||||||
VIR_FORCE_CLOSE(tmpfd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIR_FREE(cmd->inbuf);
|
VIR_FREE(cmd->inbuf);
|
||||||
@ -2500,5 +2558,8 @@ virCommandFree(virCommandPtr cmd)
|
|||||||
if (cmd->reap)
|
if (cmd->reap)
|
||||||
virCommandAbort(cmd);
|
virCommandAbort(cmd);
|
||||||
|
|
||||||
|
VIR_FREE(cmd->transfer);
|
||||||
|
VIR_FREE(cmd->preserve);
|
||||||
|
|
||||||
VIR_FREE(cmd);
|
VIR_FREE(cmd);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user