mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-07 06:43:00 +03:00
support: Add support_open_dev_null_range
It returns a range of file descriptor referring to the '/dev/null' pathname. The function takes care of restarting the open range if a file descriptor is found within the specified range and also increases RLIMIT_NOFILE if required. Checked on x86_64-linux-gnu.
This commit is contained in:
134
support/support-open-dev-null-range.c
Normal file
134
support/support-open-dev-null-range.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/* Return a range of open file descriptors.
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <support/support.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
static void
|
||||
increase_nofile (void)
|
||||
{
|
||||
struct rlimit rl;
|
||||
if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
|
||||
FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
|
||||
|
||||
rl.rlim_cur += 128;
|
||||
|
||||
if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
|
||||
FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
|
||||
}
|
||||
|
||||
static int
|
||||
open_dev_null (int flags, mode_t mode)
|
||||
{
|
||||
int fd = open64 ("/dev/null", flags, mode);
|
||||
if (fd > 0)
|
||||
return fd;
|
||||
|
||||
if (fd < 0 && errno != EMFILE)
|
||||
FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode);
|
||||
|
||||
increase_nofile ();
|
||||
|
||||
return xopen ("/dev/null", flags, mode);
|
||||
}
|
||||
|
||||
struct range
|
||||
{
|
||||
int lowfd;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct range_list
|
||||
{
|
||||
size_t total;
|
||||
size_t used;
|
||||
struct range *ranges;
|
||||
};
|
||||
|
||||
static void
|
||||
range_init (struct range_list *r)
|
||||
{
|
||||
r->total = 8;
|
||||
r->used = 0;
|
||||
r->ranges = xmalloc (r->total * sizeof (struct range));
|
||||
}
|
||||
|
||||
static void
|
||||
range_add (struct range_list *r, int lowfd, size_t len)
|
||||
{
|
||||
if (r->used == r->total)
|
||||
{
|
||||
r->total *= 2;
|
||||
r->ranges = xrealloc (r->ranges, r->total * sizeof (struct range));
|
||||
}
|
||||
r->ranges[r->used].lowfd = lowfd;
|
||||
r->ranges[r->used].len = len;
|
||||
r->used++;
|
||||
}
|
||||
|
||||
static void
|
||||
range_close (struct range_list *r)
|
||||
{
|
||||
for (size_t i = 0; i < r->used; i++)
|
||||
{
|
||||
int minfd = r->ranges[i].lowfd;
|
||||
int maxfd = r->ranges[i].lowfd + r->ranges[i].len;
|
||||
for (int fd = minfd; fd < maxfd; fd++)
|
||||
xclose (fd);
|
||||
}
|
||||
free (r->ranges);
|
||||
}
|
||||
|
||||
int
|
||||
support_open_dev_null_range (int num, int flags, mode_t mode)
|
||||
{
|
||||
/* We keep track of the ranges that hit an already opened descriptor, so
|
||||
we close them after we get a working range. */
|
||||
struct range_list rl;
|
||||
range_init (&rl);
|
||||
|
||||
int lowfd = open_dev_null (flags, mode);
|
||||
int prevfd = lowfd;
|
||||
while (true)
|
||||
{
|
||||
int i = 1;
|
||||
for (; i < num; i++)
|
||||
{
|
||||
int fd = open_dev_null (flags, mode);
|
||||
if (fd != lowfd + i)
|
||||
{
|
||||
range_add (&rl, lowfd, prevfd - lowfd + 1);
|
||||
|
||||
prevfd = lowfd = fd;
|
||||
break;
|
||||
}
|
||||
prevfd = fd;
|
||||
}
|
||||
if (i == num)
|
||||
break;
|
||||
}
|
||||
|
||||
range_close (&rl);
|
||||
|
||||
return lowfd;
|
||||
}
|
Reference in New Issue
Block a user