194 lines
5.0 KiB
Plaintext
194 lines
5.0 KiB
Plaintext
|
//
|
||
|
// boost/process/v2/poxix/detail/close_handles.hpp
|
||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
//
|
||
|
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||
|
//
|
||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||
|
//
|
||
|
|
||
|
#ifndef BOOST_PROCESS_V2_POSIX_DETAIL_CLOSE_HANDLES_IPP
|
||
|
#define BOOST_PROCESS_V2_POSIX_DETAIL_CLOSE_HANDLES_IPP
|
||
|
|
||
|
#include <boost/process/v2/detail/config.hpp>
|
||
|
#include <boost/process/v2/detail/last_error.hpp>
|
||
|
#include <boost/process/v2/posix/detail/close_handles.hpp>
|
||
|
// linux has close_range since 5.19
|
||
|
|
||
|
|
||
|
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||
|
|
||
|
// https://www.freebsd.org/cgi/man.cgi?query=close_range&apropos=0&sektion=0&manpath=FreeBSD+13.1-RELEASE+and+Ports&arch=default&format=html
|
||
|
// https://man.netbsd.org/closefrom.3
|
||
|
// __FreeBSD__
|
||
|
//
|
||
|
// gives us
|
||
|
//
|
||
|
// int closefrom(int fd);
|
||
|
// int close_range(u_int lowfd, u_int highfd, int flags);
|
||
|
|
||
|
#include <unistd.h>
|
||
|
#define BOOST_PROCESS_V2_HAS_CLOSE_RANGE_AND_CLOSEFROM 1
|
||
|
|
||
|
#elif defined(__sun)
|
||
|
|
||
|
/*https://docs.oracle.com/cd/E36784_01/html/E36874/closefrom-3c.html
|
||
|
|
||
|
int fdwalk(int (*func)(void *, int), void *cd);
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#define BOOST_PROCESS_V2_HAS_PDFORK 1
|
||
|
|
||
|
#elif defined(__linux__)
|
||
|
|
||
|
#include <linux/version.h>
|
||
|
|
||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,11,0)
|
||
|
|
||
|
// https://man7.org/linux/man-pages/man2/close_range.2.html
|
||
|
#include <linux/close_range.h>
|
||
|
#define BOOST_PROCESS_V2_HAS_CLOSE_RANGE 1
|
||
|
#else
|
||
|
|
||
|
#include <dirent.h>
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#else
|
||
|
|
||
|
#include <dirent.h>
|
||
|
|
||
|
#endif
|
||
|
|
||
|
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||
|
|
||
|
namespace posix
|
||
|
{
|
||
|
|
||
|
namespace detail
|
||
|
{
|
||
|
|
||
|
#if defined(BOOST_PROCESS_V2_HAS_PDFORK)
|
||
|
|
||
|
void close_all(const std::vector<int> & whitelist, error_code & ec)
|
||
|
{
|
||
|
fdwalk(+[](void * p, int fd)
|
||
|
{
|
||
|
const auto & wl = *static_cast<const std::vector<int>*>(p);
|
||
|
if (std::find(wl.begin(), wl.end(), fd) == wl.end())
|
||
|
return ::close(fd);
|
||
|
else
|
||
|
return 0;
|
||
|
}, const_cast<void*>(static_cast<const void*>(&whitelist)) );
|
||
|
ec = BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||
|
}
|
||
|
|
||
|
#elif defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE_AND_CLOSEFROM)
|
||
|
|
||
|
// freeBSD impl - whitelist must be ordered
|
||
|
void close_all(const std::vector<int> & whitelist, error_code & ec)
|
||
|
{
|
||
|
//the most common scenario is whitelist = {0,1,2}
|
||
|
if (!whitelist.empty())
|
||
|
{
|
||
|
if (whitelist.front() != 0)
|
||
|
::close_range(0, whitelist.front() - 1, 0);
|
||
|
|
||
|
for (std::size_t idx = 0u;
|
||
|
idx < (whitelist.size() - 1u);
|
||
|
idx++)
|
||
|
{
|
||
|
const auto mine = whitelist[idx];
|
||
|
const auto next = whitelist[idx];
|
||
|
if ((mine + 1) != next && (mine != next))
|
||
|
{
|
||
|
::close_range(mine + 1, next - 1, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
::closefrom(whitelist.back() + 1);
|
||
|
}
|
||
|
else
|
||
|
::closefrom(0);
|
||
|
}
|
||
|
|
||
|
#elif defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE)
|
||
|
|
||
|
|
||
|
// linux impl - whitelist must be ordered
|
||
|
void close_all(const std::vector<int> & whitelist, error_code & ec)
|
||
|
{
|
||
|
// https://patchwork.kernel.org/project/linux-fsdevel/cover/20200602204219.186620-1-christian.brauner@ubuntu.com/
|
||
|
//the most common scenario is whitelist = {0,1,2}
|
||
|
if (!whitelist.empty())
|
||
|
{
|
||
|
if (whitelist.front() != 0)
|
||
|
::close_range(0, whitelist.front() - 1, CLOSE_RANGE_UNSHARE);
|
||
|
|
||
|
for (std::size_t idx = 0u;
|
||
|
idx < (whitelist.size() - 1u);
|
||
|
idx++)
|
||
|
{
|
||
|
const auto mine = whitelist[idx];
|
||
|
const auto next = whitelist[idx];
|
||
|
if ((mine + 1) != next && (mine != next))
|
||
|
{
|
||
|
::close_range(mine + 1, next - 1, CLOSE_RANGE_UNSHARE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
::close_range(whitelist.back() + 1, std::numeric_limits<int>::max(), CLOSE_RANGE_UNSHARE);
|
||
|
}
|
||
|
else
|
||
|
::close_range(0, std::numeric_limits<int>::max(), CLOSE_RANGE_UNSHARE);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
// default one
|
||
|
void close_all(const std::vector<int> & whitelist, error_code & ec)
|
||
|
{
|
||
|
std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}};
|
||
|
if (dir.get() == nullptr)
|
||
|
{
|
||
|
ec = BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
auto dir_fd = ::dirfd(dir.get());
|
||
|
if (dir_fd == -1)
|
||
|
{
|
||
|
ec = BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
struct ::dirent * ent_p;
|
||
|
|
||
|
while ((ent_p = ::readdir(dir.get())) != nullptr)
|
||
|
{
|
||
|
if (ent_p->d_name[0] == '.')
|
||
|
continue;
|
||
|
|
||
|
const auto conv = std::atoi(ent_p->d_name);
|
||
|
if (conv == 0 && (ent_p->d_name[0] != '0' && ent_p->d_name[1] != '\0'))
|
||
|
continue;
|
||
|
|
||
|
if (conv == dir_fd
|
||
|
|| (std::find(whitelist.begin(), whitelist.end(), conv) != whitelist.end()))
|
||
|
continue;
|
||
|
|
||
|
::close(conv);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOST_PROCESS_V2_END_NAMESPACE
|
||
|
|
||
|
#endif //BOOST_PROCESS_V2_POSIX_DETAIL_CLOSE_HANDLES_IPP
|