libcarla/include/system/boost/process/v2/posix/detail/close_handles.ipp
2024-10-18 13:19:59 +08:00

194 lines
5.0 KiB
C++

//
// 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