mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 16:52:14 +00:00
Compare commits
18 Commits
freebsd
...
cmd-empty-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
743f0cca35 | ||
|
|
81ad643b00 | ||
|
|
6fd1200ab7 | ||
|
|
c7bdccd57e | ||
|
|
d6bcb0014a | ||
|
|
e5f0f245bd | ||
|
|
a4a3770501 | ||
|
|
1e5892b8fb | ||
|
|
85b29d6442 | ||
|
|
b9ee759365 | ||
|
|
f3b163a933 | ||
|
|
be2ae2c3cf | ||
|
|
b2f5ebc760 | ||
|
|
e34557faa0 | ||
|
|
a9f083f45c | ||
|
|
b5ab94c932 | ||
|
|
9ceda79fa2 | ||
|
|
68cbeae491 |
10
.drone.star
10
.drone.star
@@ -16,16 +16,16 @@ def main(ctx):
|
||||
return [
|
||||
freebsd_cxx("gcc 11 freebsd", "g++-11", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '17,20', 'B2_LINKFLAGS': '-Wl,-rpath=/usr/local/lib/gcc11'}, globalenv=globalenv),
|
||||
freebsd_cxx("clang 14 freebsd", "clang++-14", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'clang-14', 'B2_CXXSTD': '17,20'}, globalenv=globalenv),
|
||||
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync mlocate", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
|
||||
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
|
||||
linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True),
|
||||
linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
|
||||
linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={ 'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '17ba079169m'}, arch="arm64", globalenv=globalenv),
|
||||
linux_cxx("GCC 10, Debug + Coverage", "g++-10", packages="g++-10 libssl-dev libffi-dev binutils-gold gdb mlocate",
|
||||
linux_cxx("GCC 10, Debug + Coverage", "g++-10", packages="g++-10 libssl-dev libffi-dev binutils-gold gdb",
|
||||
image="cppalliance/droneubuntu2004:1", buildtype="boost", buildscript="drone", environment={"GCOV": "gcov-10", "LCOV_VERSION": "1.15", "VARIANT": "process_coverage", "TOOLSET": "gcc", "COMPILER": "g++-10", "CXXSTD": "11", "DRONE_BEFORE_INSTALL" : "process_coverage", "CODECOV_TOKEN": {"from_secret": "codecov_token"}}, globalenv=globalenv, privileged=True),
|
||||
# A set of jobs based on the earlier .travis.yml configuration:
|
||||
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev mlocate", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
|
||||
linux_cxx("Default g++", "g++", packages="mlocate", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
|
||||
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev mlocate", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
|
||||
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
|
||||
linux_cxx("Default g++", "g++", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
|
||||
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
|
||||
linux_cxx("gcc 6", "g++-6", packages="g++-6", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'B2_TOOLSET': 'gcc-6', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
|
||||
linux_cxx("clang 3.8", "clang++-3.8", packages="clang-3.8", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'B2_TOOLSET': 'clang', 'COMPILER': 'clang++-3.8', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '7b52009b64'}, globalenv=globalenv),
|
||||
osx_cxx("clang", "g++", packages="", buildtype="boost", buildscript="drone", environment={'B2_TOOLSET': 'clang', 'B2_CXXSTD': '11,17', 'DRONE_JOB_UUID': '91032ad7bb'}, globalenv=globalenv),
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,4 +31,5 @@
|
||||
/notes.cpp
|
||||
/notes_p.txt
|
||||
.settings
|
||||
.DS_Store
|
||||
|
||||
|
||||
@@ -8,4 +8,6 @@ A special thank you goes to [@http://www.intra2net.com/ Intra2net AG] (especiall
|
||||
|
||||
Great thanks also goes to Boris Schaeling, who despite having boost.process rejected, went on to work on it and maintained it up until this day and participated in the development of the current version.
|
||||
|
||||
Many Thanks, to [@https://github.com/time-killer-games Samuel Venable] for contributing the v2::ext functionality and all the research that went into it.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[section:quickstart Quickstrat]
|
||||
[section:quickstart Quickstart]
|
||||
|
||||
A process needs four things to be launched:
|
||||
|
||||
|
||||
@@ -125,7 +125,10 @@ public:
|
||||
boost::process::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
@@ -135,6 +138,7 @@ public:
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
std::error_code ec;
|
||||
@@ -142,6 +146,7 @@ public:
|
||||
boost::process::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool running(std::error_code & ec) noexcept
|
||||
{
|
||||
@@ -178,13 +183,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
if (!_exited())
|
||||
@@ -197,7 +205,7 @@ public:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
|
||||
@@ -114,6 +114,8 @@ template<typename Char> constexpr Char space_sign();
|
||||
template<> constexpr char space_sign<char> () {return ' '; }
|
||||
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}}
|
||||
#endif
|
||||
|
||||
@@ -155,13 +155,15 @@ private:
|
||||
|
||||
std::vector<char*> exe_cmd_init<char>::make_cmd()
|
||||
{
|
||||
// any string must be writable.
|
||||
static char empty_string[1] = "";
|
||||
std::vector<char*> vec;
|
||||
if (!exe.empty())
|
||||
vec.push_back(&exe.front());
|
||||
vec.push_back(exe.empty() ? empty_string : &exe.front());
|
||||
|
||||
if (!args.empty()) {
|
||||
for (auto & v : args)
|
||||
vec.push_back(&v.front());
|
||||
vec.push_back(v.empty() ? empty_string : &v.front());
|
||||
}
|
||||
|
||||
vec.push_back(nullptr);
|
||||
|
||||
@@ -27,7 +27,11 @@ inline boost::process::filesystem::path search_path(
|
||||
for (const boost::process::filesystem::path & pp : path)
|
||||
{
|
||||
auto p = pp / filename;
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
std::error_code ec;
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
#endif
|
||||
bool file = boost::process::filesystem::is_regular_file(p, ec);
|
||||
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
|
||||
return p;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <signal.h>
|
||||
#include <functional>
|
||||
#include <sys/wait.h>
|
||||
#include <list>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -23,7 +24,7 @@ class sigchld_service : public boost::asio::detail::service_base<sigchld_service
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
|
||||
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
|
||||
|
||||
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||
inline void _handle_signal(const boost::system::error_code & ec);
|
||||
public:
|
||||
sigchld_service(boost::asio::io_context & io_context)
|
||||
|
||||
@@ -90,12 +90,12 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
|
||||
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
|
||||
else
|
||||
return std::basic_string<Char>(
|
||||
buf.data(), buf.data()+ size + 1);
|
||||
buf.data(), buf.data()+ size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return std::basic_string<Char>(buf, buf+size+1);
|
||||
return std::basic_string<Char>(buf, buf+size);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
|
||||
@@ -35,7 +35,9 @@ inline boost::process::filesystem::path search_path(
|
||||
[&](const value_type & e)
|
||||
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
|
||||
|
||||
auto extensions_in = itr->to_vector();
|
||||
std::vector<std::wstring> extensions_in;
|
||||
if (itr != ne.cend())
|
||||
extensions_in = itr->to_vector();
|
||||
|
||||
std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1);
|
||||
|
||||
@@ -61,7 +63,11 @@ inline boost::process::filesystem::path search_path(
|
||||
{
|
||||
boost::process::filesystem::path pp_ext = p;
|
||||
pp_ext += ext;
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
std::error_code ec;
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
#endif
|
||||
bool file = boost::process::filesystem::is_regular_file(pp_ext, ec);
|
||||
if (!ec && file &&
|
||||
::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
|
||||
|
||||
@@ -263,7 +263,7 @@ public:
|
||||
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
const auto len = std::char_traits<Char>::length(*p);
|
||||
const int len = std::char_traits<Char>::length(*p);
|
||||
if ((std::distance(st1.begin(), st1.end()) < len)
|
||||
&& std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
|
||||
@@ -122,9 +122,11 @@ public:
|
||||
{
|
||||
boost::process::detail::api::wait(_group_handle, ec);
|
||||
}
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
/** Wait for the process group to exit for period of time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time);
|
||||
@@ -132,6 +134,7 @@ public:
|
||||
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
|
||||
@@ -140,17 +143,19 @@ public:
|
||||
/** Wait for the process group to exit until a point in time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time);
|
||||
}
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
|
||||
}
|
||||
|
||||
#endif
|
||||
///Check if the group has a valid handle.
|
||||
bool valid() const
|
||||
{
|
||||
|
||||
@@ -106,7 +106,7 @@ struct basic_cstring_ref
|
||||
BOOST_CXX14_CONSTEXPR const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= size())
|
||||
throw std::out_of_range("cstring-view out of range");
|
||||
throw_exception(std::out_of_range("cstring-view out of range"));
|
||||
return view_[pos];
|
||||
}
|
||||
BOOST_CONSTEXPR const_reference front() const {return *view_;}
|
||||
|
||||
@@ -97,6 +97,14 @@ namespace filesystem = std::filesystem;
|
||||
using std::quoted;
|
||||
using std::optional;
|
||||
|
||||
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
|
||||
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category()); \
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) ec.assign(__VA_ARGS__);
|
||||
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
|
||||
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error()); \
|
||||
|
||||
|
||||
#else
|
||||
|
||||
using boost::system::error_code ;
|
||||
@@ -112,6 +120,25 @@ namespace filesystem = std::filesystem;
|
||||
namespace filesystem = boost::filesystem;
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category(), &loc##__LINE__); \
|
||||
}
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
ec.assign(__VA_ARGS__, &loc##__LINE__); \
|
||||
}
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(), &loc##__LINE__); \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
@@ -150,6 +177,4 @@ BOOST_PROCESS_V2_END_NAMESPACE
|
||||
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_CONFIG_HPP
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
|
||||
#if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
|
||||
extern "C" { extern char **environ; }
|
||||
#endif
|
||||
|
||||
@@ -77,4 +77,4 @@ BOOST_PROCESS_V2_DECL bool is_executable(const filesystem::path & pth, error_cod
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -34,7 +34,7 @@ basic_cstring_ref<char_type, value_char_traits<char>> get(
|
||||
auto res = ::getenv(key.c_str());
|
||||
if (res == nullptr)
|
||||
{
|
||||
ec.assign(ENOENT, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOENT, system_category())
|
||||
return {};
|
||||
}
|
||||
return res;
|
||||
@@ -45,13 +45,13 @@ void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (::setenv(key.c_str(), value.c_str(), true))
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec)
|
||||
{
|
||||
if (::unsetenv(key.c_str()))
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ std::basic_string<char_type, value_char_traits<char_type>> get(
|
||||
buf.resize(size);
|
||||
|
||||
if (buf.size() == 0)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -60,14 +60,14 @@ void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableW(key.c_str(), value.c_str()))
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableW(key.c_str(), nullptr))
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ std::basic_string<char, value_char_traits<char>> get(
|
||||
buf.resize(size);
|
||||
|
||||
if (buf.size() == 0)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -98,14 +98,14 @@ void set(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableA(key.c_str(), value.c_str()))
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableA(key.c_str(), nullptr))
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,20 +28,6 @@ error_code get_last_error()
|
||||
|
||||
}
|
||||
|
||||
void throw_last_error()
|
||||
{
|
||||
throw system_error(get_last_error());
|
||||
}
|
||||
void throw_last_error(const char * msg)
|
||||
{
|
||||
throw system_error(get_last_error(), msg);
|
||||
}
|
||||
void throw_last_error(const std::string & msg)
|
||||
{
|
||||
throw system_error(get_last_error(), msg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
@@ -9,9 +9,20 @@
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/detail/process_handle_windows.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
|
||||
extern "C"
|
||||
{
|
||||
|
||||
LONG WINAPI NtResumeProcess(HANDLE ProcessHandle);
|
||||
LONG WINAPI NtSuspendProcess(HANDLE ProcessHandle);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
@@ -23,7 +34,7 @@ void get_exit_code_(
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::GetExitCodeProcess(handle, &exit_code))
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +42,12 @@ HANDLE open_process_(DWORD pid)
|
||||
{
|
||||
auto proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
|
||||
if (proc == nullptr)
|
||||
detail::throw_last_error("open_process()");
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
throw system_error(ec, "open_process()");
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
@@ -40,17 +56,17 @@ void terminate_if_running_(HANDLE handle)
|
||||
{
|
||||
DWORD exit_code = 0u;
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return ;
|
||||
return ;
|
||||
if (::GetExitCodeProcess(handle, &exit_code))
|
||||
if (exit_code == STILL_ACTIVE)
|
||||
::TerminateProcess(handle, 260);
|
||||
if (exit_code == STILL_ACTIVE)
|
||||
::TerminateProcess(handle, 260);
|
||||
}
|
||||
|
||||
bool check_handle_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -60,8 +76,8 @@ bool check_pid_(pid_type pid_, error_code & ec)
|
||||
{
|
||||
if (pid_ == 0)
|
||||
{
|
||||
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
|
||||
return false;
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -73,46 +89,73 @@ struct enum_windows_data_t
|
||||
};
|
||||
|
||||
static BOOL CALLBACK enum_window(HWND hwnd, LPARAM param)
|
||||
{
|
||||
{
|
||||
auto data = reinterpret_cast<enum_windows_data_t*>(param);
|
||||
DWORD pid{0u};
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
if (pid != data->pid)
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
|
||||
LRESULT res = ::SendMessageW(hwnd, WM_CLOSE, 0, 0);
|
||||
|
||||
if (res)
|
||||
data->ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(data->ec)
|
||||
return res == 0;
|
||||
}
|
||||
}
|
||||
|
||||
void request_exit_(pid_type pid_, error_code & ec)
|
||||
{
|
||||
enum_windows_data_t data{ec, pid_};
|
||||
|
||||
if (!::EnumWindows(enum_window, reinterpret_cast<LONG_PTR>(&data)))
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void interrupt_(pid_type pid_, error_code & ec)
|
||||
{
|
||||
if (!::GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid_))
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void terminate_(HANDLE handle, error_code & ec, DWORD & exit_status)
|
||||
{
|
||||
if (!::TerminateProcess(handle, 260))
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void check_running_(HANDLE handle, error_code & ec, DWORD & exit_status)
|
||||
{
|
||||
if (!::GetExitCodeProcess(handle, &exit_status))
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
|
||||
void suspend_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
auto nt_err = NtSuspendProcess(handle);
|
||||
ULONG dos_err = RtlNtStatusToDosError(nt_err);
|
||||
if (dos_err)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void resume_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
auto nt_err = NtResumeProcess(handle);
|
||||
ULONG dos_err = RtlNtStatusToDosError(nt_err);
|
||||
if (dos_err)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
#else
|
||||
void suspend_(HANDLE, error_code & ec)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
|
||||
}
|
||||
|
||||
void resume_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
template struct basic_process_handle_win<>;
|
||||
|
||||
@@ -27,13 +27,13 @@ inline void handle_error(error_code & ec)
|
||||
switch (err)
|
||||
{
|
||||
case ERROR_INSUFFICIENT_BUFFER:
|
||||
ec.assign(error::insufficient_buffer, error::utf8_category);
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::utf8_category)
|
||||
break;
|
||||
case ERROR_NO_UNICODE_TRANSLATION:
|
||||
ec.assign(error::invalid_character, error::utf8_category);
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::utf8_category)
|
||||
break;
|
||||
default:
|
||||
ec.assign(err, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
|
||||
if (*from > max_wchar) {
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
ec.assign(error::invalid_character, error::get_utf8_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
|
||||
return 0u;
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
|
||||
if (to == to_end && i != cont_octet_count) {
|
||||
from_next = from;
|
||||
to_next = to - (i + 1);
|
||||
ec.assign(error::insufficient_buffer, error::get_utf8_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
|
||||
return 0u;
|
||||
}
|
||||
++from;
|
||||
@@ -280,7 +280,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
|
||||
|
||||
// Were we done or did we run out of destination space
|
||||
if (from != from_end)
|
||||
ec.assign(error::insufficient_buffer, error::get_utf8_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
|
||||
|
||||
return to_next - out;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
if (invalid_leading_octet(*from)) {
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
ec.assign(error::invalid_character, error::get_utf8_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
|
||||
return 0u;
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
if (invalid_continuing_octet(*from)) {
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
ec.assign(error::invalid_character, error::get_utf8_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
|
||||
return 0u;
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
// rewind "from" to before the current character translation
|
||||
from_next = from - (i + 1);
|
||||
to_next = to;
|
||||
ec.assign(error::insufficient_buffer, error::get_utf8_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
|
||||
return 0u;
|
||||
}
|
||||
*to++ = ucs_result;
|
||||
@@ -365,7 +365,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
to_next = to;
|
||||
|
||||
if (from != from_end)
|
||||
ec.assign(error::insufficient_buffer, error::get_utf8_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
|
||||
|
||||
return to_next - out;
|
||||
}
|
||||
|
||||
@@ -9,14 +9,13 @@
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL error_code get_last_error();
|
||||
BOOST_PROCESS_V2_DECL void throw_last_error();
|
||||
BOOST_PROCESS_V2_DECL void throw_last_error(const char * msg);
|
||||
BOOST_PROCESS_V2_DECL void throw_last_error(const std::string & msg);
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
@@ -101,6 +101,8 @@ struct basic_process_handle_fd
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
|
||||
native_handle_type native_handle() {return pid_;}
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
@@ -182,7 +184,42 @@ struct basic_process_handle_fd
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGSTOP) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
|
||||
@@ -128,6 +128,7 @@ struct basic_process_handle_fd_or_signal
|
||||
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
native_handle_type native_handle() {return pid_;}
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
@@ -211,6 +212,42 @@ struct basic_process_handle_fd_or_signal
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGSTOP) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ struct basic_process_handle_signal
|
||||
{
|
||||
native_handle_type() = delete;
|
||||
native_handle_type(const native_handle_type & ) = delete;
|
||||
~native_handle_type() = delete;
|
||||
~native_handle_type() = default;
|
||||
};
|
||||
|
||||
typedef Executor executor_type;
|
||||
@@ -101,8 +101,8 @@ struct basic_process_handle_signal
|
||||
handle.pid_ = -1;
|
||||
}
|
||||
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
pid_type id() const { return pid_; }
|
||||
native_handle_type native_handle() {return {};}
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
@@ -112,7 +112,7 @@ struct basic_process_handle_signal
|
||||
void terminate_if_running()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
|
||||
{
|
||||
::kill(pid_, SIGKILL);
|
||||
@@ -123,7 +123,7 @@ struct basic_process_handle_signal
|
||||
void wait(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
while (::waitpid(pid_, &exit_status, 0) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
@@ -137,7 +137,7 @@ struct basic_process_handle_signal
|
||||
void wait(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
error_code ec;
|
||||
wait(exit_status, ec);
|
||||
if (ec)
|
||||
@@ -147,7 +147,7 @@ struct basic_process_handle_signal
|
||||
void interrupt(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
@@ -155,7 +155,7 @@ struct basic_process_handle_signal
|
||||
void interrupt()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
error_code ec;
|
||||
interrupt(ec);
|
||||
if (ec)
|
||||
@@ -165,7 +165,7 @@ struct basic_process_handle_signal
|
||||
void request_exit(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
@@ -173,17 +173,53 @@ struct basic_process_handle_signal
|
||||
void request_exit()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
error_code ec;
|
||||
request_exit(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
if (::kill(pid_, SIGKILL) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
@@ -191,7 +227,7 @@ struct basic_process_handle_signal
|
||||
void terminate(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
return;
|
||||
error_code ec;
|
||||
terminate(exit_status, ec);
|
||||
if (ec)
|
||||
@@ -284,7 +320,7 @@ struct basic_process_handle_signal
|
||||
if (!ec && (wait_res == 0))
|
||||
{
|
||||
handle.async_wait(std::move(self));
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
struct completer
|
||||
|
||||
@@ -32,6 +32,8 @@ BOOST_PROCESS_V2_DECL void terminate_if_running_(void * handle);
|
||||
BOOST_PROCESS_V2_DECL bool check_handle_(void* handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL bool check_pid_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void interrupt_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void suspend_(void * handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void resume_(void * handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void terminate_(void * handle, error_code & ec, native_exit_code_type & exit_code);
|
||||
BOOST_PROCESS_V2_DECL void request_exit_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void check_running_(void* handle, error_code & ec, native_exit_code_type & exit_status);
|
||||
@@ -176,6 +178,32 @@ struct basic_process_handle_win
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
detail::suspend_(handle_.native_handle(), ec);
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
detail::resume_(handle_.native_handle(), ec);
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (!detail::check_handle_(handle_.native_handle(), ec))
|
||||
|
||||
@@ -524,7 +524,7 @@ struct key
|
||||
~key() = default;
|
||||
|
||||
key& operator=( const key& p ) = default;
|
||||
key& operator=( key&& p ) noexcept = default;
|
||||
key& operator=( key&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
|
||||
key& operator=( string_type&& source )
|
||||
{
|
||||
value_ = std::move(source);
|
||||
@@ -742,7 +742,7 @@ struct value
|
||||
~value() = default;
|
||||
|
||||
value& operator=( const value& p ) = default;
|
||||
value& operator=( value&& p ) noexcept = default;
|
||||
value& operator=( value&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
|
||||
value& operator=( string_type&& source )
|
||||
{
|
||||
value_ = std::move(source);
|
||||
@@ -999,7 +999,7 @@ struct key_value_pair
|
||||
~key_value_pair() = default;
|
||||
|
||||
key_value_pair& operator=( const key_value_pair& p ) = default;
|
||||
key_value_pair& operator=( key_value_pair&& p ) noexcept = default;
|
||||
key_value_pair& operator=( key_value_pair&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
|
||||
key_value_pair& operator=( string_type&& source )
|
||||
{
|
||||
value_ = std::move(source);
|
||||
|
||||
@@ -148,7 +148,7 @@ struct code_as_error_handler
|
||||
void operator()(error_code ec, native_exit_code_type code)
|
||||
{
|
||||
if (!ec)
|
||||
ec.assign(code, category);
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, code, category)
|
||||
std::move(handler_)(ec);
|
||||
}
|
||||
|
||||
|
||||
16
include/boost/process/v2/ext.hpp
Normal file
16
include/boost/process/v2/ext.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.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_EXT_HPP
|
||||
#define BOOST_PROCESS_V2_EXT_HPP
|
||||
|
||||
#include <boost/process/v2/ext/cmd.hpp>
|
||||
#include <boost/process/v2/ext/cwd.hpp>
|
||||
#include <boost/process/v2/ext/env.hpp>
|
||||
#include <boost/process/v2/ext/exe.hpp>
|
||||
|
||||
#endif //BOOST_PROCESS_V2_EXT_HPP
|
||||
66
include/boost/process/v2/ext/cmd.hpp
Normal file
66
include/boost/process/v2/ext/cmd.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_CMD_HPP
|
||||
#define BOOST_PROCESS_V2_CMD_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#include <boost/process/v2/shell.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
/// @{
|
||||
/// Get the argument vector of another process
|
||||
BOOST_PROCESS_V2_DECL shell cmd(pid_type pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL shell cmd(pid_type pid);
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
BOOST_PROCESS_V2_DECL shell cmd(HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL shell cmd(HANDLE handle);
|
||||
#endif
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL shell cmd(basic_process_handle<Executor> & handle, error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return cmd(handle.native_handle(), ec);
|
||||
#else
|
||||
return cmd(handle.id(), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL shell cmd(basic_process_handle<Executor> & handle)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return cmd(handle.native_handle());
|
||||
#else
|
||||
return cmd(handle.id());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
#include <boost/process/v2/ext/impl/cmd.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BOOST_PROCESS_V2_CMD_HPP
|
||||
59
include/boost/process/v2/ext/cwd.hpp
Normal file
59
include/boost/process/v2/ext/cwd.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_CWD_HPP
|
||||
#define BOOST_PROCESS_V2_CWD_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
/// @{
|
||||
/// Obtain the current path of another process
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(pid_type pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(pid_type pid);
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(basic_process_handle<Executor> & handle, error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return cwd(handle.native_handle(), ec);
|
||||
#else
|
||||
return cwd(handle.id(), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(basic_process_handle<Executor> & handle)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return cwd(handle.native_handle());
|
||||
#else
|
||||
return cwd(handle.id());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(HANDLE handle);
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
#include <boost/process/v2/ext/impl/cwd.ipp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PROCESS_V2_CWD_HPP
|
||||
127
include/boost/process/v2/ext/detail/impl/proc_info.ipp
Normal file
127
include/boost/process/v2/ext/detail/impl/proc_info.ipp
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_IMPL_DETAIL_PROC_INFO_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_DETAIL_PROC_INFO_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <cstdlib>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
namespace ext
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
// type of process memory to read?
|
||||
enum MEMTYP {MEMCMD, MEMCWD};
|
||||
std::wstring cwd_cmd_from_proc(HANDLE proc, int type, boost::system::error_code & ec)
|
||||
{
|
||||
std::wstring buffer;
|
||||
PEB peb;
|
||||
SIZE_T nRead = 0;
|
||||
ULONG len = 0;
|
||||
PROCESS_BASIC_INFORMATION pbi;
|
||||
RTL_USER_PROCESS_PARAMETERS_EXTENDED upp;
|
||||
|
||||
NTSTATUS status = 0;
|
||||
PVOID buf = nullptr;
|
||||
status = NtQueryInformationProcess(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
|
||||
ULONG error = RtlNtStatusToDosError(status);
|
||||
|
||||
if (error)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error, boost::system::system_category())
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(proc, pbi.PebBaseAddress, &peb, sizeof(peb), &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(proc, peb.ProcessParameters, &upp, sizeof(upp), &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (type == MEMCWD)
|
||||
{
|
||||
buf = upp.CurrentDirectory.DosPath.Buffer;
|
||||
len = upp.CurrentDirectory.DosPath.Length;
|
||||
}
|
||||
else if (type == MEMCMD)
|
||||
{
|
||||
buf = upp.CommandLine.Buffer;
|
||||
len = upp.CommandLine.Length;
|
||||
}
|
||||
|
||||
buffer.resize(len / 2 + 1);
|
||||
|
||||
if (!ReadProcessMemory(proc, buf, &buffer[0], len, &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
buffer.pop_back();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// with debug_privilege enabled allows reading info from more processes
|
||||
// this includes stuff such as exe path, cwd path, cmdline, and environ
|
||||
HANDLE open_process_with_debug_privilege(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
HANDLE proc = nullptr;
|
||||
HANDLE hToken = nullptr;
|
||||
LUID luid;
|
||||
TOKEN_PRIVILEGES tkp;
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
{
|
||||
if (LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &luid))
|
||||
{
|
||||
tkp.PrivilegeCount = 1;
|
||||
tkp.Privileges[0].Luid = luid;
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
if (AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), nullptr, nullptr))
|
||||
{
|
||||
proc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
|
||||
}
|
||||
}
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
if (!proc)
|
||||
proc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
|
||||
if (!proc)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return proc;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace ext
|
||||
|
||||
} // namespace detail
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_DETAIL_PROC_INFO_IPP
|
||||
|
||||
125
include/boost/process/v2/ext/detail/proc_info.hpp
Normal file
125
include/boost/process/v2/ext/detail/proc_info.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_DETAIL_PROC_INFO_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_PROC_INFO_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
extern "C" ULONG NTAPI RtlNtStatusToDosError(NTSTATUS Status);
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
namespace ext
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#if !defined(_MSC_VER)
|
||||
#pragma pack(push, 8)
|
||||
#else
|
||||
#include <pshpack8.h>
|
||||
#endif
|
||||
|
||||
/* CURDIR struct from:
|
||||
https://github.com/processhacker/phnt/
|
||||
CC BY 4.0 licence */
|
||||
|
||||
typedef struct {
|
||||
UNICODE_STRING DosPath;
|
||||
HANDLE Handle;
|
||||
} CURDIR;
|
||||
|
||||
/* RTL_DRIVE_LETTER_CURDIR struct from:
|
||||
https://github.com/processhacker/phnt/
|
||||
CC BY 4.0 licence */
|
||||
|
||||
typedef struct {
|
||||
USHORT Flags;
|
||||
USHORT Length;
|
||||
ULONG TimeStamp;
|
||||
STRING DosPath;
|
||||
} RTL_DRIVE_LETTER_CURDIR;
|
||||
|
||||
/* RTL_USER_PROCESS_PARAMETERS struct from:
|
||||
https://github.com/processhacker/phnt/
|
||||
CC BY 4.0 licence */
|
||||
|
||||
typedef struct {
|
||||
ULONG MaximumLength;
|
||||
ULONG Length;
|
||||
ULONG Flags;
|
||||
ULONG DebugFlags;
|
||||
HANDLE ConsoleHandle;
|
||||
ULONG ConsoleFlags;
|
||||
HANDLE StandardInput;
|
||||
HANDLE StandardOutput;
|
||||
HANDLE StandardError;
|
||||
CURDIR CurrentDirectory;
|
||||
UNICODE_STRING DllPath;
|
||||
UNICODE_STRING ImagePathName;
|
||||
UNICODE_STRING CommandLine;
|
||||
PVOID Environment;
|
||||
ULONG StartingX;
|
||||
ULONG StartingY;
|
||||
ULONG CountX;
|
||||
ULONG CountY;
|
||||
ULONG CountCharsX;
|
||||
ULONG CountCharsY;
|
||||
ULONG FillAttribute;
|
||||
ULONG WindowFlags;
|
||||
ULONG ShowWindowFlags;
|
||||
UNICODE_STRING WindowTitle;
|
||||
UNICODE_STRING DesktopInfo;
|
||||
UNICODE_STRING ShellInfo;
|
||||
UNICODE_STRING RuntimeData;
|
||||
RTL_DRIVE_LETTER_CURDIR CurrentDirectories[32];
|
||||
ULONG_PTR EnvironmentSize;
|
||||
ULONG_PTR EnvironmentVersion;
|
||||
PVOID PackageDependencyData;
|
||||
ULONG ProcessGroupId;
|
||||
ULONG LoaderThreads;
|
||||
UNICODE_STRING RedirectionDllName;
|
||||
UNICODE_STRING HeapPartitionName;
|
||||
ULONG_PTR DefaultThreadpoolCpuSetMasks;
|
||||
ULONG DefaultThreadpoolCpuSetMaskCount;
|
||||
} RTL_USER_PROCESS_PARAMETERS_EXTENDED;
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#pragma pack(pop)
|
||||
#else
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
BOOST_PROCESS_V2_DECL std::wstring cwd_cmd_from_proc(HANDLE proc, int type, boost::system::error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL HANDLE open_process_with_debug_privilege(boost::process::v2::pid_type pid, boost::system::error_code & ec);
|
||||
#endif
|
||||
|
||||
} // namespace ext
|
||||
|
||||
} // namespace detail
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
#include <boost/process/v2/ext/detail/impl/proc_info.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PROCESS_V2_DETAIL_PROC_INFO_HPP
|
||||
|
||||
154
include/boost/process/v2/ext/env.hpp
Normal file
154
include/boost/process/v2/ext/env.hpp
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_ENV_HPP
|
||||
#define BOOST_PROCESS_V2_ENV_HPP
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#include <boost/process/v2/environment.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace ext
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
using native_env_handle_type = wchar_t *;
|
||||
using native_env_iterator = wchar_t *;
|
||||
#elif defined(__FreeBSD__)
|
||||
using native_env_handle_type = char **;
|
||||
using native_env_iterator = char **;
|
||||
#else
|
||||
using native_env_handle_type = char *;
|
||||
using native_env_iterator = char *;
|
||||
#endif
|
||||
|
||||
struct native_env_handle_deleter
|
||||
{
|
||||
BOOST_PROCESS_V2_DECL void operator()(native_env_handle_type) const;
|
||||
};
|
||||
|
||||
BOOST_PROCESS_V2_DECL native_env_iterator next(native_env_iterator nh);
|
||||
BOOST_PROCESS_V2_DECL native_env_iterator find_end(native_env_iterator nh);
|
||||
BOOST_PROCESS_V2_DECL const environment::char_type * dereference(native_env_iterator iterator);
|
||||
|
||||
} // namespace ext
|
||||
} // namespace detail
|
||||
|
||||
namespace ext {
|
||||
|
||||
/// The view of an environment
|
||||
struct env_view
|
||||
{
|
||||
using native_handle_type = detail::ext::native_env_handle_type;
|
||||
using value_type = environment::key_value_pair_view;
|
||||
|
||||
env_view() = default;
|
||||
env_view(env_view && nt) = default;
|
||||
|
||||
native_handle_type native_handle() { return handle_.get(); }
|
||||
|
||||
|
||||
struct iterator
|
||||
{
|
||||
using value_type = environment::key_value_pair_view;
|
||||
using difference_type = int;
|
||||
using reference = environment::key_value_pair_view;
|
||||
using pointer = environment::key_value_pair_view;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
iterator() = default;
|
||||
iterator(const iterator & ) = default;
|
||||
iterator(const detail::ext::native_env_iterator &native_handle) : iterator_(native_handle) {}
|
||||
|
||||
iterator & operator++()
|
||||
{
|
||||
iterator_ = detail::ext::next(iterator_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
auto last = *this;
|
||||
iterator_ = detail::ext::next(iterator_);
|
||||
return last;
|
||||
}
|
||||
environment::key_value_pair_view operator*() const
|
||||
{
|
||||
return detail::ext::dereference(iterator_);
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator & l, const iterator & r) {return l.iterator_ == r.iterator_;}
|
||||
friend bool operator!=(const iterator & l, const iterator & r) {return l.iterator_ != r.iterator_;}
|
||||
|
||||
private:
|
||||
detail::ext::native_env_iterator iterator_;
|
||||
};
|
||||
|
||||
iterator begin() const {return iterator(handle_.get());}
|
||||
iterator end() const {return iterator(detail::ext::find_end(handle_.get()));}
|
||||
|
||||
private:
|
||||
friend BOOST_PROCESS_V2_DECL env_view env(pid_type pid, error_code & ec);
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
friend BOOST_PROCESS_V2_DECL env_view env(HANDLE handle, error_code & ec);
|
||||
#endif
|
||||
|
||||
std::unique_ptr<typename remove_pointer<detail::ext::native_env_handle_type>::type,
|
||||
detail::ext::native_env_handle_deleter> handle_;
|
||||
};
|
||||
|
||||
/// @{
|
||||
/// Get the environment of another process.
|
||||
BOOST_PROCESS_V2_DECL env_view env(pid_type pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL env_view env(pid_type pid);
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL env_view env(basic_process_handle<Executor> & handle, error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return env(handle.native_handle(), ec);
|
||||
#else
|
||||
return env(handle.id(), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL env_view env(basic_process_handle<Executor> & handle)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return env(handle.native_handle());
|
||||
#else
|
||||
return env(handle.id());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
BOOST_PROCESS_V2_DECL env_view env(HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL env_view env(HANDLE handle);
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
#include <boost/process/v2/ext/impl/env.ipp>
|
||||
|
||||
#endif
|
||||
#endif // BOOST_PROCESS_V2_ENV_HPP
|
||||
62
include/boost/process/v2/ext/exe.hpp
Normal file
62
include/boost/process/v2/ext/exe.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_EXE_HPP
|
||||
#define BOOST_PROCESS_V2_EXE_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
/// @{
|
||||
/// Return the executable of another process by pid or handle.
|
||||
BOOST_PROCESS_V2_DECL filesystem::path exe(pid_type pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL filesystem::path exe(pid_type pid);
|
||||
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
filesystem::path exe(basic_process_handle<Executor> & handle, error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return exe(handle.native_handle(), ec);
|
||||
#else
|
||||
return exe(handle.id(), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
filesystem::path exe(basic_process_handle<Executor> & handle)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return exe(handle.native_handle());
|
||||
#else
|
||||
return exe(handle.id());
|
||||
#endif
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
BOOST_PROCESS_V2_DECL filesystem::path exe(HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL filesystem::path exe(HANDLE handle);
|
||||
#endif
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
#include <boost/process/v2/ext/impl/exe.ipp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PROCESS_V2_EXE_HPP
|
||||
|
||||
460
include/boost/process/v2/ext/impl/cmd.ipp
Normal file
460
include/boost/process/v2/ext/impl/cmd.ipp
Normal file
@@ -0,0 +1,460 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_IMPL_CMD_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_CMD_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
#include <boost/process/v2/ext/cmd.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__ANDROID__))
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/user.h>
|
||||
#include <libprocstat.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__DragonFly__) || defined(__OpenBSD__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#include <kvm.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun)
|
||||
#include <sys/types.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
struct make_cmd_shell_
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
static shell make(std::wstring data)
|
||||
{
|
||||
shell res;
|
||||
res.input_ = res.buffer_ = std::move(data);
|
||||
res.parse_();
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
static shell make(std::string data,
|
||||
int argc, char ** argv,
|
||||
void(*free_func)(int, char**))
|
||||
{
|
||||
shell res;
|
||||
res.argc_ = argc;
|
||||
res.input_ = res.buffer_ = std::move(data);
|
||||
res.argv_ = argv;
|
||||
res.free_argv_ = free_func;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static shell clone(char ** cmd)
|
||||
{
|
||||
shell res;
|
||||
res.argc_ = 0;
|
||||
std::size_t str_lengths = 0;
|
||||
for (auto c = cmd; *c != nullptr; c++)
|
||||
{
|
||||
res.argc_++;
|
||||
str_lengths += (std::strlen(*c) + 1);
|
||||
}
|
||||
// yes, not the greatest solution.
|
||||
res.buffer_.resize(str_lengths);
|
||||
|
||||
res.argv_ = new char*[res.argc_ + 1];
|
||||
res.free_argv_ = +[](int argc, char ** argv) {delete[] argv;};
|
||||
res.argv_[res.argc_] = nullptr;
|
||||
auto p = &*res.buffer_.begin();
|
||||
|
||||
for (int i = 0; i < res.argc_; i++)
|
||||
{
|
||||
const auto ln = std::strlen(cmd[i]);
|
||||
res.argv_[i] = std::strcpy(p, cmd[i]);
|
||||
p += (ln + 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace ext {
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
shell cmd(HANDLE proc, error_code & ec)
|
||||
{
|
||||
std::wstring buffer = boost::process::v2::detail::ext::cwd_cmd_from_proc(proc, 0/*=MEMCMD*/, ec);
|
||||
|
||||
if (!ec)
|
||||
return make_cmd_shell_::make(std::move(buffer));
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
shell cmd(HANDLE proc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = cmd(proc, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "cmd");
|
||||
return res;
|
||||
}
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
::CloseHandle(h);
|
||||
};
|
||||
};
|
||||
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
|
||||
if (proc == nullptr)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
else
|
||||
return cmd(proc.get(), ec);
|
||||
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
int mib[3] = {CTL_KERN, KERN_ARGMAX, 0};
|
||||
int argmax = 0;
|
||||
auto size = sizeof(argmax);
|
||||
if (sysctl(mib, 2, &argmax, &size, nullptr, 0) == -1)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string procargs;
|
||||
procargs.resize(argmax - 1);
|
||||
mib[1] = KERN_PROCARGS;
|
||||
mib[2] = pid;
|
||||
|
||||
size = argmax;
|
||||
|
||||
if (sysctl(mib, 3, &*procargs.begin(), &size, nullptr, 0) != 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
int argc = *reinterpret_cast<const int*>(procargs.data());
|
||||
auto itr = procargs.begin() + sizeof(argc);
|
||||
|
||||
std::unique_ptr<char*[]> argv{new char*[argc + 1]};
|
||||
const auto end = procargs.end();
|
||||
|
||||
argv[argc] = nullptr; //args is a null-terminated list
|
||||
|
||||
for (auto n = 0u; n <= argc; n++)
|
||||
{
|
||||
auto e = std::find(itr, end, '\0');
|
||||
if (e == end && n < argc) // something off
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, EINVAL, system_category())
|
||||
return {};
|
||||
}
|
||||
argv[n] = &*itr;
|
||||
itr = e + 1; // start searching start
|
||||
}
|
||||
|
||||
auto fr_func = +[](int argc, char ** argv) {delete [] argv;};
|
||||
|
||||
return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func);
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__))
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::string procargs;
|
||||
procargs.resize(4096);
|
||||
int f = ::open(("/proc/" + std::to_string(pid) + "/cmdline").c_str(), O_RDONLY);
|
||||
|
||||
while (procargs.back() != EOF)
|
||||
{
|
||||
auto r = ::read(f, &*(procargs.end() - 4096), 4096);
|
||||
if (r < 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
::close(f);
|
||||
return {};
|
||||
}
|
||||
if (r < 4096) // done!
|
||||
{
|
||||
procargs.resize(procargs.size() - 4096 + r);
|
||||
break;
|
||||
}
|
||||
procargs.resize(procargs.size() + 4096);
|
||||
}
|
||||
::close(f);
|
||||
|
||||
if (procargs.back() == EOF)
|
||||
procargs.pop_back();
|
||||
|
||||
auto argc = std::count(procargs.begin(), procargs.end(), '\0');
|
||||
|
||||
auto itr = procargs.begin();
|
||||
|
||||
std::unique_ptr<char*[]> argv{new char*[argc + 1]};
|
||||
const auto end = procargs.end();
|
||||
|
||||
argv[argc] = nullptr; //args is a null-terminated list
|
||||
|
||||
|
||||
for (auto n = 0u; n <= argc; n++)
|
||||
{
|
||||
auto e = std::find(itr, end, '\0');
|
||||
if (e == end && n < argc) // something off
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, EINVAL, system_category())
|
||||
return {};
|
||||
}
|
||||
argv[n] = &*itr;
|
||||
itr = e + 1; // start searching start
|
||||
}
|
||||
|
||||
auto fr_func = +[](int argc, char ** argv) {delete [] argv;};
|
||||
|
||||
return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func);
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
struct cl_proc_stat
|
||||
{
|
||||
void operator()(struct procstat *proc_stat)
|
||||
{
|
||||
procstat_close(proc_stat);
|
||||
}
|
||||
};
|
||||
std::unique_ptr<struct procstat, cl_proc_stat> proc_stat{procstat_open_sysctl()};
|
||||
if (!proc_stat)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
struct proc_info_close
|
||||
{
|
||||
struct procstat * proc_stat;
|
||||
|
||||
void operator()(struct kinfo_proc * proc_info)
|
||||
{
|
||||
procstat_freeprocs(proc_stat, proc_info);
|
||||
}
|
||||
};
|
||||
|
||||
unsigned cntp;
|
||||
std::unique_ptr<struct kinfo_proc, proc_info_close> proc_info{
|
||||
procstat_getprocs(proc_stat.get(), KERN_PROC_PID, pid, &cntp),
|
||||
proc_info_close{proc_stat.get()}};
|
||||
|
||||
if (!proc_info)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
char **cmd = procstat_getargv(proc_stat.get(), proc_info.get(), 0);
|
||||
if (!cmd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
auto res = make_cmd_shell_::clone(cmd);
|
||||
procstat_freeargv(proc_stat.get());
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif defined(__DragonFly__)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return {};}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, &cntp)))
|
||||
{
|
||||
char **cmd = kvm_getargv(kd.get(), proc_info, 0);
|
||||
if (cmd)
|
||||
return make_cmd_shell_::clone(cmd);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
|
||||
std::vector<std::string> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
|
||||
if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return vec;}
|
||||
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
char **cmd = kvm_getargv2(kd.get(), proc_info, 0);
|
||||
if (cmd)
|
||||
return make_cmd_shell_::clone(cmd);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<std::string> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return vec;}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
char **cmd = kvm_getargv(kd.get(), proc_info, 0);
|
||||
if (cmd)
|
||||
return make_cmd_shell_::clone(cmd);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
kvm_close(kd);
|
||||
return {};
|
||||
}
|
||||
|
||||
#elif defined(__sun)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
char **cmd = nullptr;
|
||||
proc *proc_info = nullptr;
|
||||
user *proc_user = nullptr;
|
||||
kd = kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr);
|
||||
if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return {};}
|
||||
if ((proc_info = kvm_getproc(kd, pid)))
|
||||
{
|
||||
if ((proc_user = kvm_getu(kd, proc_info)))
|
||||
{
|
||||
if (!kvm_getcmd(kd, proc_info, proc_user, &cmd, nullptr))
|
||||
{
|
||||
int argc = 0;
|
||||
for (int i = 0; cmd[i] != nullptr; i++)
|
||||
argc ++;
|
||||
return make_cmd_shell_::make(
|
||||
{}, argc, cmd,
|
||||
+[](int, char ** argv) {::free(argv);})
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
kvm_close(kd);
|
||||
return {};
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = cmd(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "cmd");
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_CMD_IPP
|
||||
|
||||
234
include/boost/process/v2/ext/impl/cwd.ipp
Normal file
234
include/boost/process/v2/ext/impl/cwd.ipp
Normal file
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_IMPL_CWD_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_CWD_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
#include <boost/process/v2/ext/cwd.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <climits>
|
||||
#endif
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
#if (defined(BOOST_PROCESS_V2_WINDOWS) || defined(__linux__) || defined(__ANDROID__) || defined(__sun))
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/user.h>
|
||||
#include <libprocstat.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__NetBSD__) || defined(__OpenBSD__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__DragonFly__)
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
namespace filesystem = std::filesystem;
|
||||
#else
|
||||
namespace filesystem = boost::filesystem;
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
filesystem::path cwd(HANDLE proc, boost::system::error_code & ec)
|
||||
{
|
||||
auto buffer = boost::process::v2::detail::ext::cwd_cmd_from_proc(proc, 1/*=MEMCWD*/, ec);
|
||||
if (!buffer.empty())
|
||||
return filesystem::canonical(buffer, ec);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return "";
|
||||
}
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
::CloseHandle(h);
|
||||
};
|
||||
};
|
||||
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
|
||||
if (proc == nullptr)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
else
|
||||
return cwd(proc.get(), ec);
|
||||
return {};
|
||||
}
|
||||
|
||||
filesystem::path cwd(HANDLE proc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = cwd(proc, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "cwd");
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
proc_vnodepathinfo vpi;
|
||||
if (proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi)) > 0)
|
||||
return filesystem::canonical(vpi.pvi_cdir.vip_path, ec);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return "";
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__) || defined(__sun))
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
return filesystem::canonical(
|
||||
filesystem::path("/proc") / std::to_string(pid) / "cwd", ec);
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
// FIXME: Add error handling.
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
filesystem::path path;
|
||||
unsigned cntp = 0;
|
||||
procstat *proc_stat = procstat_open_sysctl();
|
||||
if (proc_stat) {
|
||||
kinfo_proc *proc_info = procstat_getprocs(proc_stat, KERN_PROC_PID, pid, &cntp);
|
||||
if (proc_info) {
|
||||
filestat_list *head = procstat_getfiles(proc_stat, proc_info, 0);
|
||||
if (head) {
|
||||
filestat *fst = nullptr;
|
||||
STAILQ_FOREACH(fst, head, next) {
|
||||
if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
|
||||
{
|
||||
path = filesystem::canonical(fst->fs_path, ec);
|
||||
}
|
||||
}
|
||||
procstat_freefiles(proc_stat, head);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
procstat_freeprocs(proc_stat, proc_info);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
procstat_close(proc_stat);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return path;
|
||||
}
|
||||
|
||||
#elif defined(__DragonFly__)
|
||||
|
||||
// FIXME: Add error handling.
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
filesystem::path path;
|
||||
/* Probably the hackiest thing ever we are doing here, because the "official" API is broken OS-level. */
|
||||
FILE *fp = popen(("pos=`ans=\\`/usr/bin/fstat -w -p " + std::to_string(pid) + " | /usr/bin/sed -n 1p\\`; " +
|
||||
"/usr/bin/awk -v ans=\"$ans\" 'BEGIN{print index(ans, \"INUM\")}'`; str=`/usr/bin/fstat -w -p " +
|
||||
std::to_string(pid) + " | /usr/bin/sed -n 3p`; /usr/bin/awk -v str=\"$str\" -v pos=\"$pos\" " +
|
||||
"'BEGIN{print substr(str, 0, pos + 4)}' | /usr/bin/awk 'NF{NF--};1 {$1=$2=$3=$4=\"\"; print" +
|
||||
" substr($0, 5)'}").c_str(), "r");
|
||||
if (fp)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
if (fgets(buffer, sizeof(buffer), fp))
|
||||
{
|
||||
std::string str = buffer;
|
||||
std::size_t pos = str.find("\n", strlen(buffer) - 1);
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
str.replace(pos, 1, "");
|
||||
}
|
||||
path = filesystem::canonical(str.c_str(), ec);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
pclose(fp);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return path;
|
||||
}
|
||||
|
||||
#elif (defined(__NetBSD__) || defined(__OpenBSD__))
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::string path;
|
||||
#if defined(__NetBSD__)
|
||||
int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_CWD};
|
||||
const std::size_t sz = 4;
|
||||
#elif defined(__OpenBSD__)
|
||||
int mib[3] = {CTL_KERN, KERN_PROC_CWD, pid};
|
||||
const std::size_t sz = 3;
|
||||
#endif
|
||||
std::size_t len = 0;
|
||||
if (sysctl(mib, sz, nullptr, &len, nullptr, 0) == 0)
|
||||
{
|
||||
std::string strbuff;
|
||||
strbuff.resize(len);
|
||||
if (sysctl(mib, 4, &strbuff[0], &len, nullptr, 0) == 0)
|
||||
{
|
||||
filesystem::canonical(strbuff, ec);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = cwd(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "cwd");
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_CWD_IPP
|
||||
|
||||
389
include/boost/process/v2/ext/impl/env.ipp
Normal file
389
include/boost/process/v2/ext/impl/env.ipp
Normal file
@@ -0,0 +1,389 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
//
|
||||
// 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_EXT_IMPL_ENV_IPP
|
||||
#define BOOST_PROCESS_V2_EXT_IMPL_ENV_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
#include <boost/process/v2/ext/env.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <shellapi.h>
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__ANDROID__))
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
namespace ext {
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
void native_env_handle_deleter::operator()(native_env_handle_type h) const
|
||||
{
|
||||
delete [] h;
|
||||
}
|
||||
|
||||
native_env_iterator next(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != L'\0')
|
||||
nh ++;
|
||||
return ++nh ;
|
||||
}
|
||||
native_env_iterator find_end(native_env_iterator nh)
|
||||
{
|
||||
while (*nh - 1 != L'\0' && *nh != L'\0')
|
||||
nh ++;
|
||||
return nh ;
|
||||
}
|
||||
|
||||
const environment::char_type * dereference(native_env_iterator iterator)
|
||||
{
|
||||
return iterator;
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__))
|
||||
//linux stores this as a blob with an EOF at the end
|
||||
|
||||
void native_env_handle_deleter::operator()(native_env_handle_type h) const
|
||||
{
|
||||
delete [] h;
|
||||
}
|
||||
|
||||
native_env_iterator next(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != '\0')
|
||||
nh ++;
|
||||
return ++nh ;
|
||||
}
|
||||
native_env_iterator find_end(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != EOF)
|
||||
nh ++;
|
||||
return nh ;
|
||||
}
|
||||
|
||||
const environment::char_type * dereference(native_env_iterator iterator)
|
||||
{
|
||||
return iterator;
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE___) || defined(__MACH__))
|
||||
|
||||
void native_env_handle_deleter::operator()(native_env_handle_type h) const
|
||||
{
|
||||
delete [] h;
|
||||
}
|
||||
|
||||
native_env_iterator next(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != '\0')
|
||||
nh ++;
|
||||
return ++nh ;
|
||||
}
|
||||
native_env_iterator find_end(native_env_iterator nh)
|
||||
{
|
||||
while (*nh - 1 != '\0' && *nh != '\0')
|
||||
nh ++;
|
||||
return nh ;
|
||||
}
|
||||
|
||||
const environment::char_type * dereference(native_env_iterator iterator)
|
||||
{
|
||||
return iterator;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
void native_env_handle_deleter::operator()(native_env_handle_type h) const
|
||||
{
|
||||
delete [] h;
|
||||
}
|
||||
|
||||
native_env_iterator next(native_env_iterator nh)
|
||||
{
|
||||
return ++nh ;
|
||||
}
|
||||
native_env_iterator find_end(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != nullptr)
|
||||
nh++;
|
||||
|
||||
return nh ;
|
||||
}
|
||||
|
||||
const environment::char_type * dereference(native_env_iterator iterator)
|
||||
{
|
||||
return *iterator;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace ext
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
env_view env(HANDLE proc, boost::system::error_code & ec)
|
||||
{
|
||||
wchar_t *buffer = nullptr;
|
||||
PEB peb;
|
||||
SIZE_T nRead = 0;
|
||||
ULONG len = 0;
|
||||
PROCESS_BASIC_INFORMATION pbi;
|
||||
detail::ext::RTL_USER_PROCESS_PARAMETERS_EXTENDED upp;
|
||||
|
||||
NTSTATUS status = 0;
|
||||
PVOID buf = nullptr;
|
||||
status = NtQueryInformationProcess(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
|
||||
ULONG error = RtlNtStatusToDosError(status);
|
||||
|
||||
if (error)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error, boost::system::system_category())
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(proc, pbi.PebBaseAddress, &peb, sizeof(peb), &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(proc, peb.ProcessParameters, &upp, sizeof(upp), &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
env_view ev;
|
||||
buf = upp.Environment;
|
||||
len = (ULONG)upp.EnvironmentSize;
|
||||
ev.handle_.reset(new wchar_t[len / 2 + 1]());
|
||||
|
||||
if (!ReadProcessMemory(proc, buf, ev.handle_.get(), len, &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
ev.handle_.get()[len / 2] = L'\0';
|
||||
return ev;
|
||||
}
|
||||
|
||||
env_view env(HANDLE handle)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = env(handle, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "env");
|
||||
return res;
|
||||
}
|
||||
|
||||
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
::CloseHandle(h);
|
||||
};
|
||||
};
|
||||
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
|
||||
if (proc == nullptr)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
else
|
||||
return env(proc.get(), ec);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE___) || defined(__MACH__))
|
||||
|
||||
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
int mib[3] = {CTL_KERN, KERN_ARGMAX, 0};
|
||||
int argmax = 0;
|
||||
auto size = sizeof(argmax);
|
||||
if (sysctl(mib, 2, &argmax, &size, nullptr, 0) == -1)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string procargs;
|
||||
procargs.resize(argmax - 1);
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = pid;
|
||||
|
||||
size = argmax;
|
||||
|
||||
if (sysctl(mib, 3, &*procargs.begin(), &size, nullptr, 0) != 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
std::uint32_t nargs;
|
||||
memcpy(&nargs, &*procargs.begin(), sizeof(nargs));
|
||||
char *cp = &*procargs.begin() + sizeof(nargs);
|
||||
|
||||
for (; cp < &*procargs.end(); cp++)
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
|
||||
|
||||
if (cp == &procargs[size])
|
||||
return {};
|
||||
|
||||
|
||||
for (; cp < &*procargs.end(); cp++)
|
||||
if (*cp != '\0') break;
|
||||
|
||||
|
||||
if (cp == &*procargs.end())
|
||||
return {};
|
||||
|
||||
|
||||
int i = 0;
|
||||
char *sp = cp;
|
||||
std::vector<char> vec;
|
||||
|
||||
while ((*sp != '\0' || i < nargs) && sp < &*procargs.end()) {
|
||||
if (i >= nargs)
|
||||
vec.push_back(*sp);
|
||||
|
||||
sp += 1;
|
||||
}
|
||||
|
||||
env_view ev;
|
||||
ev.handle_.reset(new char[vec.size()]());
|
||||
std::copy(vec.begin(), vec.end(), ev.handle_.get());
|
||||
return ev;
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__))
|
||||
|
||||
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
std::unique_ptr<char, detail::ext::native_env_handle_deleter> procargs{};
|
||||
|
||||
int f = ::open(("/proc/" + std::to_string(pid) + "/environ").c_str(), O_RDONLY);
|
||||
|
||||
while (!procargs || procargs.get()[size - 1] != EOF)
|
||||
{
|
||||
std::unique_ptr<char, detail::ext::native_env_handle_deleter> buf{new char[size + 4096]};
|
||||
if (size > 0)
|
||||
std::memmove(buf.get(), procargs.get(), size);
|
||||
auto r = ::read(f, buf.get() + size, 4096);
|
||||
if (r < 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
::close(f);
|
||||
return {};
|
||||
}
|
||||
procargs = std::move(buf);
|
||||
size += r;
|
||||
if (r < 4096) // done!
|
||||
{
|
||||
procargs.get()[size] = EOF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
::close(f);
|
||||
|
||||
env_view ev;
|
||||
ev.handle_ = std::move(procargs);
|
||||
return ev;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
env_view ev;
|
||||
|
||||
unsigned cntp = 0;
|
||||
procstat *proc_stat = procstat_open_sysctl();
|
||||
if (proc_stat != nullptr)
|
||||
{
|
||||
kinfo_proc *proc_info = procstat_getprocs(proc_stat, KERN_PROC_PID, pid, &cntp);
|
||||
if (proc_info != nullptr)
|
||||
{
|
||||
char **env = procstat_getenvv(proc_stat, proc_info, 0);
|
||||
if (env != nullptr)
|
||||
{
|
||||
auto e = env;
|
||||
std::size_t n = 0u, len = 0u;
|
||||
while (e && *e != nullptr)
|
||||
{
|
||||
n ++;
|
||||
len += std::strlen(*e);
|
||||
e++;
|
||||
}
|
||||
std::size_t mem_needed =
|
||||
// environ - nullptr - strlen + null terminators
|
||||
(n * sizeof(char*)) + sizeof(char*) + len + n;
|
||||
|
||||
char * out = new (std::nothrow) char[mem_needed];
|
||||
if (out != nullptr)
|
||||
{
|
||||
auto eno = reinterpret_cast<char**>(out);
|
||||
auto eeo = eno;
|
||||
auto str = out + (n * sizeof(char*)) + sizeof(char*);
|
||||
e = env;
|
||||
while (*e != nullptr)
|
||||
{
|
||||
auto len = std::strlen(*e) + 1u;
|
||||
std::memcpy(str, *e, len);
|
||||
*eno = str;
|
||||
str += len;
|
||||
eno ++;
|
||||
e++;
|
||||
}
|
||||
*eno = nullptr;
|
||||
|
||||
ev.handle_.reset(eeo);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
}
|
||||
procstat_freeprocs(proc_stat, proc_info);
|
||||
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
procstat_close(proc_stat);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ev;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
env_view env(boost::process::v2::pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = env(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "env");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_EXT_IMPL_ENV_IPP
|
||||
193
include/boost/process/v2/ext/impl/exe.ipp
Normal file
193
include/boost/process/v2/ext/impl/exe.ipp
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_IMPL_EXE_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_EXE_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
#include <boost/process/v2/ext/exe.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <climits>
|
||||
#endif
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
#if (defined(BOOST_PROCESS_V2_WINDOWS) || defined(__linux__) || defined(__ANDROID__) || defined(__sun))
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#if !defined(__FreeBSD__)
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
#include <boost/process/v2/ext/cwd.hpp>
|
||||
#include <boost/process/v2/ext/cmd.hpp>
|
||||
#include <boost/process/v2/ext/env.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <kvm.h>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
filesystem::path exe(HANDLE process_handle)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = exe(process_handle, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "exe");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
filesystem::path exe(HANDLE proc, boost::system::error_code & ec)
|
||||
{
|
||||
wchar_t buffer[MAX_PATH];
|
||||
// On input, specifies the size of the lpExeName buffer, in characters.
|
||||
DWORD size = MAX_PATH;
|
||||
if (QueryFullProcessImageNameW(proc, 0, buffer, &size))
|
||||
{
|
||||
return filesystem::canonical(buffer, ec);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
if (pid == GetCurrentProcessId())
|
||||
{
|
||||
wchar_t buffer[MAX_PATH];
|
||||
if (GetModuleFileNameW(nullptr, buffer, sizeof(buffer)))
|
||||
{
|
||||
return filesystem::canonical(buffer, ec);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
::CloseHandle(h);
|
||||
};
|
||||
};
|
||||
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
|
||||
if (proc == nullptr)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
else
|
||||
return exe(proc.get(), ec);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
char buffer[PROC_PIDPATHINFO_MAXSIZE];
|
||||
if (proc_pidpath(pid, buffer, sizeof(buffer)) > 0)
|
||||
{
|
||||
return filesystem::canonical(buffer, ec);
|
||||
}
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return "";
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__) || defined(__sun))
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
#if (defined(__linux__) || defined(__ANDROID__))
|
||||
return filesystem::canonical(
|
||||
filesystem::path("/proc") / std::to_string(pid) / "exe", ec
|
||||
);
|
||||
#elif defined(__sun)
|
||||
return fileystem::canonical(
|
||||
filesystem::path("/proc") / std::to_string(pid) / "path/a.out"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__))
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
#if (defined(__FreeBSD__) || defined(__DragonFly__))
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid};
|
||||
#elif defined(__NetBSD__)
|
||||
int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_PATHNAME};
|
||||
#endif
|
||||
std::size_t len = 0;
|
||||
if (sysctl(mib, 4, nullptr, &len, nullptr, 0) == 0)
|
||||
{
|
||||
std::string strbuff;
|
||||
strbuff.resize(len);
|
||||
if (sysctl(mib, 4, &strbuff[0], &len, nullptr, 0) == 0)
|
||||
{
|
||||
strbuff.resize(len - 1);
|
||||
return filesystem::canonical(strbuff, ec);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return "";
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, boost::system::system_category())
|
||||
return "";
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = exe(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "exe");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_EXE_IPP
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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)
|
||||
@@ -6,14 +7,56 @@
|
||||
#define BOOST_PROCESS_V2_IMPL_PID_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__ANDROID__))
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <libutil.h>
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if (defined(__DragonFly__) || defined(__OpenBSD__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#include <kvm.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun)
|
||||
#include <sys/types.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
@@ -22,6 +65,700 @@ pid_type current_pid() {return ::GetCurrentProcessId();}
|
||||
pid_type current_pid() {return ::getpid();}
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (!hp)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
PROCESSENTRY32 pe;
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
if (Process32First(hp, &pe))
|
||||
{
|
||||
do
|
||||
{
|
||||
vec.push_back(pe.th32ProcessID);
|
||||
} while (Process32Next(hp, &pe));
|
||||
}
|
||||
CloseHandle(hp);
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (!hp)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
PROCESSENTRY32 pe;
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
if (Process32First(hp, &pe))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (pe.th32ProcessID == pid)
|
||||
{
|
||||
ppid = pe.th32ParentProcessID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (Process32Next(hp, &pe));
|
||||
}
|
||||
CloseHandle(hp);
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (!hp)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
PROCESSENTRY32 pe;
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
if (Process32First(hp, &pe))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (pe.th32ParentProcessID == pid)
|
||||
{
|
||||
vec.push_back(pe.th32ProcessID);
|
||||
}
|
||||
}
|
||||
while (Process32Next(hp, &pe));
|
||||
}
|
||||
CloseHandle(hp);
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
vec.reserve(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0));
|
||||
if (proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(pid_type) * vec.size()))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
auto itr = std::partition(vec.begin(), vec.end(), [](pid_type pt) {return pt != 0;});
|
||||
vec.erase(itr, vec.end());
|
||||
std::reverse(vec.begin(), vec.end());
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
proc_bsdinfo proc_info;
|
||||
if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &proc_info, sizeof(proc_info)) <= 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
else
|
||||
ppid = proc_info.pbi_ppid;
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
vec.reserve(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0));
|
||||
if (proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size()))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
auto itr = std::partition(vec.begin(), vec.end(), [](pid_type pt) {return pt != 0;});
|
||||
vec.erase(itr, vec.end());
|
||||
std::reverse(vec.begin(), vec.end());
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__))
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
DIR *proc = opendir("/proc");
|
||||
if (!proc)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
struct dirent *ent = nullptr;
|
||||
while ((ent = readdir(proc)))
|
||||
{
|
||||
if (!isdigit(*ent->d_name))
|
||||
continue;
|
||||
vec.push_back(atoi(ent->d_name));
|
||||
}
|
||||
closedir(proc);
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
char buffer[BUFSIZ];
|
||||
sprintf(buffer, "/proc/%d/stat", pid);
|
||||
FILE *stat = fopen(buffer, "r");
|
||||
if (!stat)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t size = fread(buffer, sizeof(char), sizeof(buffer), stat);
|
||||
if (size > 0)
|
||||
{
|
||||
char *token = nullptr;
|
||||
if ((token = strtok(buffer, " ")))
|
||||
{
|
||||
if ((token = strtok(nullptr, " ")))
|
||||
{
|
||||
if ((token = strtok(nullptr, " ")))
|
||||
{
|
||||
if ((token = strtok(nullptr, " ")))
|
||||
{
|
||||
ppid = (pid_type)strtoul(token, nullptr, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!token)
|
||||
{
|
||||
fclose(stat);
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
}
|
||||
fclose(stat);
|
||||
}
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
std::vector<pid_type> pids = all_pids(ec);
|
||||
if (!pids.empty())
|
||||
vec.reserve(pids.size());
|
||||
for (std::size_t i = 0; i < pids.size(); i++)
|
||||
{
|
||||
pid_type ppid = parent_pid(pids[i], ec);
|
||||
if (ppid != -1 && ppid == pid)
|
||||
{
|
||||
vec.push_back(pids[i]);
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = kinfo_getallproc(&cntp);
|
||||
if (proc_info)
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
vec.push_back(proc_info[i].ki_pid);
|
||||
free(proc_info);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
kinfo_proc *proc_info = kinfo_getproc(pid);
|
||||
if (proc_info)
|
||||
{
|
||||
ppid = proc_info->ki_ppid;
|
||||
free(proc_info);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = kinfo_getallproc(&cntp);
|
||||
if (proc_info)
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
{
|
||||
if (proc_info[i].ki_ppid == pid)
|
||||
{
|
||||
vec.push_back(proc_info[i].ki_pid);
|
||||
}
|
||||
}
|
||||
free(proc_info);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__DragonFly__)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
if (proc_info[i].kp_pid >= 0)
|
||||
vec.push_back(proc_info[i].kp_pid);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, &cntp)))
|
||||
{
|
||||
if (proc_info->kp_ppid >= 0)
|
||||
{
|
||||
ppid = proc_info->kp_ppid;
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
{
|
||||
if (proc_info[i].kp_pid >= 0 && proc_info[i].kp_ppid >= 0 && proc_info[i].kp_ppid == pid)
|
||||
{
|
||||
vec.push_back(proc_info[i].kp_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--)
|
||||
{
|
||||
vec.push_back(proc_info[i].p_pid);
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
ppid = proc_info->p_ppid;
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--)
|
||||
{
|
||||
if (proc_info[i].p_ppid == pid)
|
||||
{
|
||||
vec.push_back(proc_info[i].p_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--)
|
||||
{
|
||||
if (proc_info[i].kp_pid >= 0)
|
||||
{
|
||||
vec.push_back(proc_info[i].kp_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
ppid = proc_info->p_ppid;
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--)
|
||||
{
|
||||
if (proc_info[i].p_ppid == pid)
|
||||
{
|
||||
vec.push_back(proc_info[i].p_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__sun)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
struct pid cur_pid;
|
||||
proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
while ((proc_info = kvm_nextproc(kd)))
|
||||
{
|
||||
if (kvm_kread(kd, (std::uintptr_t)proc_info->p_pidp, &cur_pid, sizeof(cur_pid)) != -1)
|
||||
{
|
||||
vec.insert(vec.begin(), cur_pid.pid_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
if ((proc_info = kvm_getproc(kd, pid)))
|
||||
{
|
||||
ppid = proc_info->p_ppid;
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
struct pid cur_pid;
|
||||
proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr);
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
while ((proc_info = kvm_nextproc(kd)))
|
||||
{
|
||||
if (proc_info->p_ppid == pid)
|
||||
{
|
||||
if (kvm_kread(kd, (std::uintptr_t)proc_info->p_pidp, &cur_pid, sizeof(cur_pid)) != -1)
|
||||
{
|
||||
vec.insert(vec.begin(), cur_pid.pid_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
|
||||
std::vector<pid_type> all_pids()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = all_pids(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "all_pids");
|
||||
return res;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = parent_pid(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "parent_pid");
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = child_pids(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "child_pids");
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_IMPL_PID_IPP
|
||||
#endif // BOOST_PROCESS_V2_IMPL_PID_IPP
|
||||
|
||||
|
||||
@@ -69,7 +69,11 @@ void shell::parse_()
|
||||
{
|
||||
argv_ = ::CommandLineToArgvW(input_.c_str(), &argc_);
|
||||
if (argv_ == nullptr)
|
||||
detail::throw_last_error();
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
|
||||
throw system_error(ec, "shell::parse");
|
||||
}
|
||||
}
|
||||
|
||||
shell::~shell()
|
||||
@@ -96,21 +100,23 @@ void shell::parse_()
|
||||
{
|
||||
argc_ = static_cast<int>(we.we_wordc);
|
||||
argv_ = we.we_wordv;
|
||||
reserved_ = static_cast<int>(we.we_offs);
|
||||
}
|
||||
|
||||
free_argv_ = +[](int argc, char ** argv)
|
||||
{
|
||||
wordexp_t we{
|
||||
.we_wordc = static_cast<std::size_t>(argc),
|
||||
.we_wordv = argv,
|
||||
.we_offs = 0
|
||||
};
|
||||
wordfree(&we);
|
||||
};
|
||||
}
|
||||
|
||||
shell::~shell()
|
||||
{
|
||||
if (argv_ != nullptr)
|
||||
{
|
||||
wordexp_t we{
|
||||
.we_wordc = static_cast<std::size_t>(argc_),
|
||||
.we_wordv = argv_,
|
||||
.we_offs = static_cast<std::size_t>(reserved_)
|
||||
};
|
||||
wordfree(&we);
|
||||
}
|
||||
if (argv_ != nullptr && free_argv_ != nullptr)
|
||||
free_argv_(argc_, argv_);
|
||||
}
|
||||
|
||||
auto shell::args() const -> args_type
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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)
|
||||
@@ -6,6 +7,7 @@
|
||||
#define BOOST_PROCESS_V2_PID_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
@@ -14,7 +16,6 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
//An integral type representing a process id.
|
||||
typedef implementation_defined pid_type;
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
@@ -28,14 +29,38 @@ typedef int pid_type;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(BOOST_PROCESS_V2_WINDOWS) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__sun))
|
||||
constexpr static pid_type root_pid = 0;
|
||||
#elif (defined(__APPLE__) && defined(__MACH__) || defined(__linux__) || defined(__ANDROID__) || defined(__OpenBSD__))
|
||||
constexpr static pid_type root_pid = 1;
|
||||
#endif
|
||||
|
||||
/// Get the process id of the current process.
|
||||
BOOST_PROCESS_V2_DECL pid_type current_pid();
|
||||
|
||||
/// List all available pids.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> all_pids(boost::system::error_code & ec);
|
||||
|
||||
/// List all available pids.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> all_pids();
|
||||
|
||||
// return parent pid of pid.
|
||||
BOOST_PROCESS_V2_DECL pid_type parent_pid(pid_type pid, boost::system::error_code & ec);
|
||||
|
||||
// return parent pid of pid.
|
||||
BOOST_PROCESS_V2_DECL pid_type parent_pid(pid_type pid);
|
||||
|
||||
// return child pids of pid.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec);
|
||||
|
||||
// return child pids of pid.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> child_pids(pid_type pid);
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
#include <boost/process/v2/impl/pid.ipp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PROCESS_V2_PID_HPP
|
||||
|
||||
#endif //BOOST_PROCESS_V2_PID_HPP
|
||||
|
||||
@@ -364,12 +364,12 @@ struct default_launcher
|
||||
pipe_guard pg;
|
||||
if (::pipe(pg.p))
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
ec = detail::on_setup(*this, executable, argv, inits ...);
|
||||
@@ -390,7 +390,7 @@ struct default_launcher
|
||||
detail::on_fork_error(*this, executable, argv, ec, inits...);
|
||||
detail::on_error(*this, executable, argv, ec, inits...);
|
||||
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
else if (pid == 0)
|
||||
@@ -406,7 +406,7 @@ struct default_launcher
|
||||
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
|
||||
|
||||
ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
detail::on_exec_error(*this, executable, argv, ec, inits...);
|
||||
::exit(EXIT_FAILURE);
|
||||
return basic_process<Executor>{exec};
|
||||
@@ -422,12 +422,12 @@ struct default_launcher
|
||||
int err = errno;
|
||||
if ((err != EAGAIN) && (err != EINTR))
|
||||
{
|
||||
ec.assign(err, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count != 0)
|
||||
ec.assign(child_error, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
|
||||
|
||||
if (ec)
|
||||
{
|
||||
|
||||
@@ -94,7 +94,7 @@ struct fork_and_forget_launcher : default_launcher
|
||||
detail::on_fork_error(*this, executable, argv, ec, inits...);
|
||||
detail::on_error(*this, executable, argv, ec, inits...);
|
||||
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
else if (pid == 0)
|
||||
@@ -107,7 +107,7 @@ struct fork_and_forget_launcher : default_launcher
|
||||
if (!ec)
|
||||
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
|
||||
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
detail::on_exec_error(*this, executable, argv, ec, inits...);
|
||||
::exit(EXIT_FAILURE);
|
||||
return basic_process<Executor>{exec};
|
||||
|
||||
@@ -85,12 +85,12 @@ struct pdfork_launcher : default_launcher
|
||||
pipe_guard pg;
|
||||
if (::pipe(pg.p))
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
|
||||
{
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
ec = detail::on_setup(*this, executable, argv, inits ...);
|
||||
@@ -111,7 +111,7 @@ struct pdfork_launcher : default_launcher
|
||||
detail::on_fork_error(*this, executable, argv, ec, inits...);
|
||||
detail::on_error(*this, executable, argv, ec, inits...);
|
||||
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
else if (pid == 0)
|
||||
@@ -128,7 +128,7 @@ struct pdfork_launcher : default_launcher
|
||||
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
|
||||
|
||||
default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
detail::on_exec_error(*this, executable, argv, ec, inits...);
|
||||
::exit(EXIT_FAILURE);
|
||||
return basic_process<Executor>{exec};
|
||||
@@ -143,12 +143,12 @@ struct pdfork_launcher : default_launcher
|
||||
int err = errno;
|
||||
if ((err != EAGAIN) && (err != EINTR))
|
||||
{
|
||||
ec.assign(err, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count != 0)
|
||||
ec.assign(child_error, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
|
||||
|
||||
if (ec)
|
||||
{
|
||||
|
||||
@@ -96,7 +96,7 @@ struct vfork_launcher : default_launcher
|
||||
detail::on_fork_error(*this, executable, argv, ec, inits...);
|
||||
detail::on_error(*this, executable, argv, ec, inits...);
|
||||
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
else if (pid == 0)
|
||||
@@ -108,7 +108,7 @@ struct vfork_launcher : default_launcher
|
||||
if (!ec)
|
||||
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
|
||||
|
||||
ec.assign(errno, system_category());
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
detail::on_exec_error(*this, executable, argv, ec, inits...);
|
||||
::exit(EXIT_FAILURE);
|
||||
return basic_process<Executor>{exec};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <boost/process/v2/default_launcher.hpp>
|
||||
#include <boost/process/v2/exit_code.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
#include <boost/process/v2/ext/exe.hpp>
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
@@ -214,6 +215,37 @@ struct basic_process
|
||||
process_handle_.request_exit(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to stop. This may rely on undocumented functions.
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
process_handle_.suspend(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to stop. This may rely on undocumented functions.
|
||||
void suspend()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
|
||||
/// Send the process a signal requesting it to resume. This may rely on undocumented functions.
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
process_handle_.resume(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to resume. This may rely on undocumented functions.
|
||||
void resume()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
/// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec)
|
||||
void terminate()
|
||||
{
|
||||
@@ -368,4 +400,4 @@ typedef basic_process<> process;
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_PROCESS_HPP
|
||||
#endif //BOOST_PROCESS_V2_PROCESS_HPP
|
||||
|
||||
@@ -79,8 +79,10 @@ struct shell
|
||||
: buffer_(std::move(lhs.buffer_)),
|
||||
input_(std::move(lhs.input_)),
|
||||
argc_(boost::exchange(lhs.argc_, 0)),
|
||||
argv_(boost::exchange(lhs.argv_, nullptr)),
|
||||
reserved_(boost::exchange(lhs.reserved_, 0))
|
||||
argv_(boost::exchange(lhs.argv_, nullptr))
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
, free_argv_(boost::exchange(lhs.free_argv_, nullptr))
|
||||
#endif
|
||||
{
|
||||
}
|
||||
shell& operator=(shell && lhs) noexcept
|
||||
@@ -90,7 +92,9 @@ struct shell
|
||||
input_ = std::move(lhs.input_);
|
||||
argc_ = boost::exchange(lhs.argc_, 0);
|
||||
argv_ = boost::exchange(lhs.argv_, nullptr);
|
||||
reserved_ = boost::exchange(lhs.reserved_, 0);
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
free_argv_ = boost::exchange(lhs.free_argv_, nullptr);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -116,6 +120,9 @@ struct shell
|
||||
BOOST_PROCESS_V2_DECL ~shell();
|
||||
|
||||
private:
|
||||
|
||||
friend struct make_cmd_shell_;
|
||||
|
||||
BOOST_PROCESS_V2_DECL void parse_();
|
||||
|
||||
// storage in case we need a conversion
|
||||
@@ -124,7 +131,10 @@ struct shell
|
||||
// impl details
|
||||
int argc_ = 0;
|
||||
char_type ** argv_ = nullptr;
|
||||
int reserved_ = 0;
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
void(*free_argv_)(int, char **);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -10,11 +10,16 @@
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
# error Do not compile Beast library source with BOOST_BEAST_HEADER_ONLY defined
|
||||
# error Do not compile Process V2 library source with BOOST_PROCESS_V2_HEADER_ONLY defined. You should probably define BOOST_PROCESS_V2_SEPARATE_COMPILATION
|
||||
#endif
|
||||
|
||||
#include <boost/process/v2/impl/error.ipp>
|
||||
#include <boost/process/v2/impl/pid.ipp>
|
||||
#include <boost/process/v2/ext/impl/exe.ipp>
|
||||
#include <boost/process/v2/ext/impl/cwd.ipp>
|
||||
#include <boost/process/v2/ext/impl/cmd.ipp>
|
||||
#include <boost/process/v2/ext/impl/env.ipp>
|
||||
#include <boost/process/v2/ext/detail/impl/proc_info.ipp>
|
||||
#include <boost/process/v2/detail/impl/environment.ipp>
|
||||
#include <boost/process/v2/detail/impl/last_error.ipp>
|
||||
#include <boost/process/v2/detail/impl/throw_error.ipp>
|
||||
|
||||
@@ -69,7 +69,11 @@ struct process_io_binding
|
||||
{
|
||||
DWORD res;
|
||||
if (!::GetHandleInformation(h, &res))
|
||||
detail::throw_last_error("get_flags");
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
|
||||
throw system_error(ec, "get_flags");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -176,7 +180,7 @@ struct process_io_binding
|
||||
fd = p[1];
|
||||
if (::fcntl(p[0], F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ;
|
||||
}
|
||||
fd_needs_closing = true;
|
||||
@@ -195,7 +199,7 @@ struct process_io_binding
|
||||
fd = p[0];
|
||||
if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ;
|
||||
}
|
||||
fd_needs_closing = true;
|
||||
|
||||
@@ -107,7 +107,7 @@ struct as_user_launcher : default_launcher
|
||||
|
||||
if (ok == 0)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
detail::on_error(*this, executable, command_line, ec, inits...);
|
||||
|
||||
if (process_information.hProcess != INVALID_HANDLE_VALUE)
|
||||
|
||||
@@ -314,7 +314,7 @@ struct default_launcher
|
||||
auto ec__ = detail::get_last_error();
|
||||
if (ok == 0)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
detail::on_error(*this, executable, command_line, ec, inits...);
|
||||
|
||||
if (process_information.hProcess != INVALID_HANDLE_VALUE)
|
||||
|
||||
@@ -111,7 +111,7 @@ struct with_logon_launcher : default_launcher
|
||||
|
||||
if (ok == 0)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
detail::on_error(*this, executable, command_line, ec, inits...);
|
||||
|
||||
if (process_information.hProcess != INVALID_HANDLE_VALUE)
|
||||
|
||||
@@ -106,7 +106,7 @@ struct with_token_launcher : default_launcher
|
||||
|
||||
if (ok == 0)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
detail::on_error(*this, executable, command_line, ec, inits...);
|
||||
|
||||
if (process_information.hProcess != INVALID_HANDLE_VALUE)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"key": "process",
|
||||
"name": "process",
|
||||
"name": "Process",
|
||||
"authors": [
|
||||
"Merino Vidal", "Ilya Sokolov", "Felipe Tanus",
|
||||
"Jeff Flinn", "Thomas Jarosch", "Boris Schaeling", "Klemens D. Morgenstern"
|
||||
|
||||
@@ -100,7 +100,7 @@ test-suite with-valgrind :
|
||||
[ run env.cpp program_options system filesystem : [ test-options env ] : sparring_partner ]
|
||||
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch ]
|
||||
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch : <build>no <target-os>windows:<build>yes <define>BOOST_USE_WINDOWS_H=1 : group-windows-h ]
|
||||
[ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner : <target-os>darwin:<build>no ]
|
||||
[ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner : <target-os>darwin:<build>no <target-os>freebsd:<build>no ]
|
||||
[ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner : <target-os>freebsd:<build>no ]
|
||||
[ run run_exe.cpp filesystem : : sparring_partner ]
|
||||
[ run run_exe_path.cpp filesystem : [ test-options run_exe_path ] : sparring_partner ]
|
||||
@@ -111,7 +111,7 @@ test-suite with-valgrind :
|
||||
[ run system_test2.cpp filesystem system : [ test-options system_test2 ] : sparring_partner ]
|
||||
[ run spawn.cpp filesystem system : [ test-options spawn ] : sparring_partner ]
|
||||
[ run start_dir.cpp filesystem system : [ test-options start_dir ] : sparring_partner ]
|
||||
[ run terminate.cpp system filesystem : [ test-options terminate ] : sparring_partner ]
|
||||
[ run terminate.cpp system filesystem : [ test-options terminate ] : sparring_partner : <target-os>freebsd:<build>no ]
|
||||
[ run throw_on_error.cpp system filesystem : [ test-options throw_on_error ] : sparring_partner ]
|
||||
[ run wait.cpp system filesystem : [ test-options wait ] : sparring_partner ]
|
||||
[ run wait_for.cpp system filesystem : [ test-options wait_for ] : sparring_partner ]
|
||||
|
||||
@@ -83,3 +83,24 @@ BOOST_AUTO_TEST_CASE(implicit)
|
||||
BOOST_TEST_MESSAGE(ec.message());
|
||||
BOOST_CHECK_EQUAL(ret, 21);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_cmd)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::path pth = master_test_suite().argv[1];
|
||||
auto env = boost::this_process::environment();
|
||||
|
||||
auto itr = std::find_if(env.begin(), env.end(),
|
||||
[](const bp::native_environment::entry_type & e){return boost::to_upper_copy(e.get_name()) == "PATH";});
|
||||
|
||||
BOOST_REQUIRE(itr != env.end());
|
||||
|
||||
(*itr) += fs::canonical(fs::absolute(pth.parent_path())).string();
|
||||
BOOST_REQUIRE(itr != env.end());
|
||||
|
||||
bp::system("sparring_partner \"\" ", ec);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/extend.hpp>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
enable_testing()
|
||||
|
||||
add_library(boost_process_v2_test_impl test_impl.cpp)
|
||||
target_link_libraries(boost_process_v2_test_impl Boost::process Boost::unit_test_framework Boost::process)
|
||||
target_compile_definitions(boost_process_v2_test_impl PUBLIC -DBOOST_PROCESS_V2_SEPARATE_COMPILATION=1)
|
||||
|
||||
if (WIN32)
|
||||
target_compile_definitions(boost_process_v2_test_impl PUBLIC WIN32_LEAN_AND_MEAN=1)
|
||||
target_link_libraries(boost_process_v2_test_impl Boost::process Boost::unit_test_framework Boost::process Ntdll)
|
||||
else()
|
||||
target_link_libraries(boost_process_v2_test_impl Boost::process Boost::unit_test_framework Boost::process)
|
||||
endif()
|
||||
|
||||
function(boost_process_v2_standalone_test name)
|
||||
@@ -31,6 +33,9 @@ function(boost_process_v2_test_with_target name)
|
||||
add_dependencies(boost_process_v2_${name} boost_process_v2_test_target)
|
||||
add_test(NAME boost_process_v2_${name} COMMAND $<TARGET_FILE:boost_process_v2_${name}>
|
||||
-- $<TARGET_FILE:boost_process_v2_test_target>)
|
||||
|
||||
|
||||
endfunction()
|
||||
|
||||
boost_process_v2_test_with_target(process)
|
||||
boost_process_v2_test_with_target(process)
|
||||
boost_process_v2_test_with_target(ext)
|
||||
@@ -21,7 +21,12 @@ project : requirements
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
|
||||
<toolset>msvc:<cxxflags>/bigobj
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<target-os>windows:<define>_WIN32_WINNT=0x0601
|
||||
<target-os>linux:<linkflags>-lpthread
|
||||
<target-os>freebsd:<linkflags>-lutil
|
||||
<target-os>freebsd:<linkflags>-lkvm
|
||||
<target-os>freebsd:<linkflags>-lprocstat
|
||||
<target-os>bsd:<linkflags>-lkvm
|
||||
<os>NT,<toolset>cw:<library>ws2_32
|
||||
<os>NT,<toolset>gcc:<library>ws2_32
|
||||
<define>BOOST_PROCESS_V2_SEPARATE_COMPILATION=1
|
||||
@@ -46,18 +51,21 @@ lib test_impl : test_impl.cpp filesystem :
|
||||
<link>static
|
||||
<target-os>windows:<source>shell32
|
||||
<target-os>windows:<source>user32
|
||||
<target-os>windows:<source>Ntdll
|
||||
<target-os>windows:<source>Advapi32
|
||||
;
|
||||
|
||||
test-suite standalone :
|
||||
[ run utf8.cpp test_impl ]
|
||||
[ run cstring_ref.cpp test_impl ]
|
||||
[ run environment.cpp test_impl ]
|
||||
[ run pid.cpp test_impl ]
|
||||
[ run pid.cpp test_impl : : : <target-os>darwin:<build>no ]
|
||||
[ run shell.cpp test_impl ]
|
||||
;
|
||||
|
||||
test-suite with_target :
|
||||
[ run process.cpp test_impl : --log_level=all --catch_system_errors=no -- : target ]
|
||||
[ run windows.cpp test_impl : --log_level=all --catch_system_errors=no -- : target : <build>no <target-os>windows:<build>yes <target-os>windows:<source>Advapi32 ]
|
||||
[ run ext.cpp test_impl : --log_level=all --catch_system_errors=no -- : target : <target-os>darwin:<build>no ]
|
||||
;
|
||||
|
||||
|
||||
180
test/v2/ext.cpp
Normal file
180
test/v2/ext.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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)
|
||||
|
||||
#include <boost/process/v2/ext/cmd.hpp>
|
||||
#include <boost/process/v2/ext/cwd.hpp>
|
||||
#include <boost/process/v2/ext/env.hpp>
|
||||
#include <boost/process/v2/ext/exe.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
#include <boost/process/v2/process.hpp>
|
||||
#include <boost/process/v2/start_dir.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(ext)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_exe)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
namespace bp2 = boost::process::v2;
|
||||
auto pth = bp2::ext::exe(bp2::current_pid());
|
||||
BOOST_CHECK(!pth.empty());
|
||||
BOOST_CHECK_EQUAL(bp2::filesystem::canonical(master_test_suite().argv[0]).string(),
|
||||
bp2::filesystem::canonical(pth).string());
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_child_exe)
|
||||
{
|
||||
namespace bp2 = boost::process::v2;
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = bp2::filesystem::canonical(master_test_suite().argv[0]);
|
||||
|
||||
boost::asio::io_context ctx;
|
||||
bp2::process proc(ctx, pth, {"sleep", "10000"});
|
||||
BOOST_CHECK_EQUAL(bp2::ext::exe(proc.handle()), pth);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cmd)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
namespace bp2 = boost::process::v2;
|
||||
auto cmd = bp2::ext::cmd(bp2::current_pid());
|
||||
|
||||
// the test framework drops a bunch of args.
|
||||
bp2::basic_cstring_ref<typename bp2::shell::char_type> ref(cmd.argv()[0]);
|
||||
BOOST_CHECK_EQUAL(
|
||||
bp2::detail::conv_string<char>(
|
||||
ref.data(), ref.size()
|
||||
), master_test_suite().argv[0]);
|
||||
|
||||
auto cm = cmd.argv() + (cmd.argc() - master_test_suite().argc);
|
||||
for (auto i = 1; i < master_test_suite().argc; i++)
|
||||
{
|
||||
bp2::basic_cstring_ref<typename bp2::shell::char_type> ref(cm[i]);
|
||||
|
||||
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()),
|
||||
master_test_suite().argv[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cmd_exe)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = master_test_suite().argv[0];
|
||||
|
||||
namespace bp2 = boost::process::v2;
|
||||
|
||||
boost::asio::io_context ctx;
|
||||
std::vector<std::string> args = {"sleep", "10000", "moar", "args", " to test "};
|
||||
bp2::process proc(ctx, pth, args);
|
||||
auto cm = bp2::ext::cmd(proc.handle());
|
||||
|
||||
bp2::basic_cstring_ref<typename bp2::shell::char_type> ref(cm.argv()[0]);
|
||||
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()), pth);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(cm.argc(), args.size() + 1);
|
||||
for (auto i = 0; i < args.size(); i++)
|
||||
{
|
||||
ref = cm.argv()[i + 1];
|
||||
|
||||
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()), args[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_cwd)
|
||||
{
|
||||
namespace bp2 = boost::process::v2;
|
||||
auto pth = bp2::ext::cwd(bp2::current_pid()).string();
|
||||
if (pth.back() == '\\')
|
||||
pth.pop_back();
|
||||
BOOST_CHECK_EQUAL(pth, bp2::filesystem::current_path());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_cwd_exe)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
namespace bp2 = boost::process::v2;
|
||||
const auto pth = bp2::filesystem::absolute(master_test_suite().argv[0]);
|
||||
|
||||
auto tmp = bp2::filesystem::temp_directory_path();
|
||||
|
||||
boost::asio::io_context ctx;
|
||||
bp2::process proc(ctx, pth, {"sleep", "10000"},
|
||||
bp2::process_start_dir{tmp});
|
||||
auto tt = bp2::ext::cwd(proc.handle()).string();
|
||||
if (tt.back() == '\\')
|
||||
tt.pop_back();
|
||||
BOOST_CHECK_EQUAL(tt, tmp);
|
||||
bp2::error_code ec;
|
||||
bp2::filesystem::remove(tmp, ec);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_env)
|
||||
{
|
||||
namespace bp2 = boost::process::v2;
|
||||
auto env = bp2::ext::env(bp2::current_pid());
|
||||
|
||||
std::size_t e = 0;
|
||||
|
||||
for (const auto & kp : bp2::environment::current())
|
||||
{
|
||||
auto itr = std::find_if(env.begin(), env.end(),
|
||||
[&](bp2::environment::key_value_pair_view kp_)
|
||||
{
|
||||
return kp.key() == kp_.key();
|
||||
});
|
||||
if (itr != env.end())
|
||||
{
|
||||
BOOST_CHECK_EQUAL(kp.value(), (*itr).value());
|
||||
e++;
|
||||
}
|
||||
|
||||
}
|
||||
BOOST_CHECK_GT(e, 0u);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_env_exe)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = master_test_suite().argv[0];
|
||||
namespace bp2 = boost::process::v2;
|
||||
|
||||
auto tmp = bp2::filesystem::temp_directory_path();
|
||||
|
||||
boost::asio::io_context ctx;
|
||||
|
||||
std::vector<bp2::environment::key_value_pair> new_env;
|
||||
{
|
||||
auto cr = bp2::environment::current();
|
||||
new_env.assign(cr.begin(), cr.end());
|
||||
}
|
||||
|
||||
new_env.push_back("FOO=42");
|
||||
new_env.push_back("BAR=FOO");
|
||||
|
||||
bp2::process proc(ctx, pth, {"sleep", "10000"},
|
||||
bp2::process_environment(new_env));
|
||||
|
||||
auto env = bp2::ext::env(proc.handle());
|
||||
for (const auto & kp : new_env)
|
||||
{
|
||||
auto itr = std::find_if(env.begin(), env.end(),
|
||||
[&](bp2::environment::key_value_pair_view kp_)
|
||||
{
|
||||
return kp.key() == kp_.key();
|
||||
});
|
||||
BOOST_REQUIRE(itr != env.end());
|
||||
BOOST_CHECK_EQUAL(kp.value(), (*itr).value());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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)
|
||||
@@ -7,9 +8,35 @@
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_pid)
|
||||
{
|
||||
namespace bp2 = boost::process::v2;
|
||||
BOOST_CHECK_NE(bp2::current_pid(), static_cast<bp2::pid_type>(0));
|
||||
}
|
||||
|
||||
auto all = bp2::all_pids();
|
||||
auto itr = std::find(all.begin(), all.end(), bp2::current_pid());
|
||||
|
||||
BOOST_CHECK_GT(all.size(), 0u);
|
||||
BOOST_CHECK(itr != all.end());
|
||||
|
||||
std::vector<bp2::pid_type> children, grand_children;
|
||||
auto grand_child_pids = [](bp2::pid_type pid,
|
||||
std::vector<bp2::pid_type> & children,
|
||||
std::vector<bp2::pid_type> & grand_children)
|
||||
{
|
||||
children = bp2::child_pids(pid);
|
||||
for (unsigned i = 0; i < children.size(); i++)
|
||||
{
|
||||
std::vector<bp2::pid_type> tmp1;
|
||||
std::vector<bp2::pid_type> tmp2 = bp2::child_pids(children[i]);
|
||||
tmp1.insert(std::end(tmp1), std::begin(tmp2), std::end(tmp2));
|
||||
grand_children = tmp1;
|
||||
}
|
||||
return (!children.empty() || !grand_children.empty());
|
||||
};
|
||||
BOOST_CHECK_NE(grand_child_pids(bp2::root_pid, children, grand_children), false);
|
||||
|
||||
}
|
||||
|
||||
@@ -150,6 +150,8 @@ BOOST_AUTO_TEST_CASE(terminate)
|
||||
|
||||
BOOST_CHECK_MESSAGE(!sh.empty(), sh);
|
||||
bpv::process proc(ctx, sh, {});
|
||||
proc.suspend();
|
||||
proc.resume();
|
||||
proc.terminate();
|
||||
proc.wait();
|
||||
}
|
||||
@@ -219,6 +221,8 @@ BOOST_AUTO_TEST_CASE(print_args_out)
|
||||
bpv::error_code ec;
|
||||
|
||||
auto sz = asio::read(rp, st, ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, st, ec);
|
||||
|
||||
BOOST_CHECK_NE(sz, 0u);
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
@@ -265,6 +269,8 @@ BOOST_AUTO_TEST_CASE(print_args_err)
|
||||
bpv::error_code ec;
|
||||
|
||||
auto sz = asio::read(rp, st, ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, st, ec);
|
||||
|
||||
BOOST_CHECK_NE(sz , 0u);
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
@@ -318,6 +324,9 @@ BOOST_AUTO_TEST_CASE(echo_file)
|
||||
bpv::error_code ec;
|
||||
|
||||
auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
|
||||
BOOST_CHECK(sz != 0);
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
BOOST_CHECK_MESSAGE(out == test_data, out);
|
||||
@@ -342,6 +351,9 @@ BOOST_AUTO_TEST_CASE(print_same_cwd)
|
||||
bpv::error_code ec;
|
||||
|
||||
auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
|
||||
BOOST_CHECK(sz != 0);
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
BOOST_CHECK_MESSAGE(bpv::filesystem::path(out) == bpv::filesystem::current_path(),
|
||||
@@ -371,6 +383,9 @@ BOOST_AUTO_TEST_CASE(popen)
|
||||
std::string res;
|
||||
boost::system::error_code ec;
|
||||
std::size_t n = asio::read(proc, asio::dynamic_buffer(res), ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
n += asio::read(rp, asio::dynamic_buffer(res), ec);
|
||||
|
||||
BOOST_CHECK_MESSAGE(ec == asio::error::eof || ec == asio::error::broken_pipe, ec.message());
|
||||
BOOST_REQUIRE_GE(n, 1u);
|
||||
// remove EOF
|
||||
@@ -404,6 +419,9 @@ BOOST_AUTO_TEST_CASE(print_other_cwd)
|
||||
bpv::error_code ec;
|
||||
|
||||
auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
|
||||
BOOST_CHECK(sz != 0);
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
BOOST_CHECK_MESSAGE(bpv::filesystem::path(out) == target,
|
||||
@@ -434,7 +452,10 @@ std::string read_env(const char * name, Inits && ... inits)
|
||||
std::string out;
|
||||
bpv::error_code ec;
|
||||
|
||||
const auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
out.resize(sz);
|
||||
trim_end(out);
|
||||
@@ -527,6 +548,9 @@ BOOST_AUTO_TEST_CASE(bind_launcher)
|
||||
bpv::error_code ec;
|
||||
|
||||
auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
while (ec == asio::error::interrupted)
|
||||
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
|
||||
|
||||
BOOST_CHECK(sz != 0);
|
||||
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
|
||||
BOOST_CHECK_MESSAGE(bpv::filesystem::path(out) == target,
|
||||
|
||||
Reference in New Issue
Block a user