blob: 540eba0fbdd16603d8c0ca64f00b1c6f1bf8dd56 (
plain) (
tree)
|
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifndef TEST
#ifdef __linux__
# include <sys/syscall.h>
#endif
static int
uintpcmp(const void *av, const void *bv)
{
const unsigned int *ap = av;
const unsigned int *bp = bv;
const unsigned int a = *ap;
const unsigned int b = *bp;
return a < b ? -1 : a > b;
}
static unsigned int *
list_fds(unsigned int min, unsigned int max, size_t *count)
{
DIR *dir;
int ignore_fd;
unsigned int *ret = NULL, *new;
size_t size = 0;
struct dirent *f;
unsigned long int fd;
char *end;
*count = 0;
dir = opendir("/dev/fd");
if (!dir)
return NULL;
ignore_fd = dirfd(dir);
errno = 0;
while ((f = readdir(dir))) {
if (!isdigit(f->d_name[0]))
continue;
fd = strtoul(f->d_name, &end, 10);
if ((int)fd == ignore_fd || (unsigned int)fd < min || (unsigned int)fd > max)
continue;
if (*end || fd > INT_MAX || (!fd && errno))
continue;
if (*count == size) {
size += 16;
new = realloc(ret, size * sizeof(*ret));
if (!new)
goto fail;
ret = new;
}
ret[(*count)++] = (unsigned int)fd;
}
if (errno) {
fail:
closedir(dir);
fail_closed:
free(ret);
return NULL;
}
if (closedir(dir))
goto fail_closed;
return ret;
}
int
libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next) /* TODO test */
{
int saved_errno;
*next = first;
if (first > last) {
errno = EINVAL;
return -1;
}
if (first > INT_MAX)
return 0;
if (last > INT_MAX)
last = INT_MAX;
saved_errno = errno;
#if defined(__linux__) && defined(__NR_close_range)
if (!syscall(__NR_close_range, first, last, 0))
return 0;
else if (errno != ENOSYS)
return -1;
#endif
if (last - first > 100) { /* TODO best limit should be researched */
unsigned int *fds;
size_t n, i;
fds = list_fds(first, last, &n);
if (!fds)
goto fallback;
qsort(fds, n, sizeof(*fds), uintpcmp);
for (i = 0; i < n; i++) {
if (close((int)fds[i]) && errno != EBADF) {
if (i + 1 < n)
*next = fds[i + 1];
else
*next = fds[i] + (fds[i] < LIBSIMPLE_CLOSE_RANGE_MAX);
free(fds);
return -1;
}
}
free(fds);
goto out;
}
fallback:
do {
if (close((int)first) && errno != EBADF) {
*next = first + (first < LIBSIMPLE_CLOSE_RANGE_MAX);
return -1;
}
} while (first++ < last);
out:
*next = last + (last < LIBSIMPLE_CLOSE_RANGE_MAX);
errno = saved_errno;
return 0;
}
#else
#include "test.h"
int
main(void)
{
return 0;
}
#endif
|