2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-20 04:42:24 +00:00

Compare commits

..

7 Commits

Author SHA1 Message Date
Klemens
7832cb6af3 Shell(posix) fixes. 2022-09-02 18:43:35 +08:00
Klemens Morgenstern
68f4c50be9 Exeuction support for shell. 2022-09-02 18:25:40 +08:00
Klemens Morgenstern
cd226a7616 Implemented shell on windows. 2022-09-02 17:05:49 +08:00
Klemens Morgenstern
4243ce72f8 Windows bugfixes. 2022-09-02 16:46:45 +08:00
Klemens
9065833e61 Added shell class. 2022-08-31 23:54:22 +08:00
Klemens
df33c1ad7b Fixed unsafe post-fork allocs for fd_whitelist. 2022-08-31 15:35:41 +08:00
Klemens
bbabea30dd Added reaping child for execve error, closes #265. 2022-08-31 15:35:41 +08:00
97 changed files with 432 additions and 4109 deletions

View File

@@ -14,18 +14,17 @@ windowsglobalimage="cppalliance/dronevs2019"
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", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
#freebsd_cxx("FreeBSD", "g++10", packages="g++10", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, 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("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",
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",
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", 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("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("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),

View File

@@ -17,6 +17,10 @@ jobs:
fail-fast: false
matrix:
include:
- toolset: gcc-4.8
cxxstd: "11"
os: ubuntu-18.04
install: g++-4.8
- toolset: gcc-5
cxxstd: "11,14,1z"
os: ubuntu-18.04
@@ -28,10 +32,21 @@ jobs:
- toolset: gcc-7
cxxstd: "11,14,17"
os: ubuntu-18.04
- toolset: gcc-8
cxxstd: "11,14,17,2a"
os: ubuntu-18.04
install: g++-8
- toolset: gcc-9
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
- toolset: gcc-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-10
- toolset: gcc-11
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-11
- toolset: gcc-12
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
@@ -247,4 +262,114 @@ jobs:
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
- name: Install
run: |
cd ../boost-root/__build__
cmake --build . --target install
- name: Use the installed library
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
- name: Build tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
- name: Run tests
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error

1
.gitignore vendored
View File

@@ -31,5 +31,4 @@
/notes.cpp
/notes_p.txt
.settings
.DS_Store

View File

@@ -8,6 +8,4 @@ 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]

View File

@@ -41,7 +41,7 @@ which means, that the named pipe behaves like a file.
Windows does provide a facility called [@https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx named pipes],
which also have file-like names, but are in a different scope than the actual file system.
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchronous communication on windows.]
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchrounous communication on windows.]
[endsect]

View File

@@ -31,7 +31,7 @@ else if (pid == 0) //child process
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
<emphasis>unspecified();</emphasis>//here the error is sent to the father process internally
<emphasis>unspecified();</emphasis>//here the error is send to the father process interally
<ulink url="http://en.cppreference.com/w/cpp/utility/program/exit">std::exit</ulink>(<ulink url="http://en.cppreference.com/w/c/program/EXIT_status">EXIT_FAILURE</ulink>);
return <classname alt="boost::process::child">child</classname>(); //for C++ compliance
@@ -39,7 +39,7 @@ else if (pid == 0) //child process
<classname alt="boost::process::child">child</classname> c(pid, exit_code);
<emphasis>unspecified();</emphasis>//here, we read the error from the child process
<emphasis>unspecified();</emphasis>//here, we read the the error from the child process
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
for (auto &amp; s : seq)
@@ -48,7 +48,7 @@ else
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
//now we check again, because an on_success handler might've errored.
//now we check again, because a on_success handler might've errored.
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
{
for (auto &amp; s : seq)

View File

@@ -9,7 +9,7 @@ Additionally, environment can be lists separated by `:` or `;`; `environment::va
`environment::value_view` can be used to iterate those.
Beyond that, the requirements on an environment are a low as possible;
an environment is either a list of strings or a list of string-pairs. It is however recommended to use the environment types,
an environment is either a list of strings or a list of string-pairs. It is however recommented to use the environment types,
as to have the right value comparisons.
To note is the `find_executable` functions, which searches in an environment for an executable.

View File

@@ -27,7 +27,7 @@ For process v2, the interfaces is simple:
extern asio::io_context ctx;
process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env));
Every initializer addresses one logical component (e.g. stdio) instead of multiple ones accumulating.
Every initializer adresses one logical compoent (e.g. stdio) instead of multiple ones accumulating.
Furthermore, every process has a path and arguments, instead of a confusing mixture of cmd-style and
exe-args that can be randomly spread out.

View File

@@ -21,7 +21,7 @@ A launcher is invoked through the call operator.
```
auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF);
asio::io_context ctx;
boost::system::error_code ec;
boost::system::eror_code ec;
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
```
@@ -38,7 +38,7 @@ Alternatively, the `vfork_launcher` can report errors directly back to the paren
Thus some calls to the initializers occur after forking from the child process.
```
struct custom_initializer
struct custom_initalizer
{
// functions called from the parent process:
@@ -47,7 +47,7 @@ Thus some calls to the initializers occur after forking from the child process.
template<typename Launcher>
error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called for every initializer if an error occurred during setup or process creation
// called for every initializer if an error occured during setup or process creation
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
@@ -56,7 +56,7 @@ Thus some calls to the initializers occur after forking from the child process.
template<typename Launcher>
void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called for every initializer if an error occurred when forking, in addition to on_error.
// called for every initializer if an error occured when forking, in addtion to on_error.
template<typename Launcher>
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
@@ -94,7 +94,7 @@ The launcher will close all non-whitelisted file descriptors after `on_exec_setu
[section:windows Windows Launchers]
Windows launchers are pretty straight forward, they will call the following functions on the initializer if present.
Windows launchers are pretty streight forward, they will call the following functions on the initializer if present.
```
struct custom_initializer
@@ -103,7 +103,7 @@ Windows launchers are pretty straight forward, they will call the following func
template<typename Launcher>
error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
// called for every initializer if an error occurred during setup or process creation
// called for every initializer if an error occured during setup or process creation
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
const error_code & ec);

View File

@@ -1,4 +1,4 @@
[section:quickstart Quickstart]
[section:quickstart Quickstrat]
A process needs four things to be launched:
@@ -32,7 +32,7 @@ also returned from `.wait()`.
```
The normal exit-code is what the subprocess returned from `main`;
posix will however add additional information about the process.
posix will however add addtional information about the process.
This is called the `native_exit_code`.
@@ -42,7 +42,7 @@ The `.running()` function can be used to detect if the process is still active.
[section:signal Signalling the subprocess]
The parent process can signal the subprocess demanding certain actions.
The parent process can signal the subprocess demaning certain actions.
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
This is the only reliable & portable way to end a subprocess.
@@ -76,7 +76,7 @@ interpret as a signal to shutdown.
[section:execute Execute functions]
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
Process v2 provides `execute` and `async_execute` functons that can be used for managed executions.
```
assert(execute(process("/bin/ls", {}) == 0));
@@ -90,7 +90,7 @@ The async version supports cancellation and will forward cancellation types as f
```
asio::io_context ctx;
asio::steady_timer timeout{ctx, std::chrono::seconds(10)};
asio::steady_timer timout{ctx, std::chrono::seconds(10)};
asio::cancellation_signal sig;
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),

View File

@@ -23,7 +23,7 @@ automatically connected and the other side will get assigned to the child proces
proc.wait();
```
readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`.
readable pipes can be assigned to `out` an `err``, while writable_pipes can be assigned to `in`.
[endsect]

View File

@@ -29,7 +29,7 @@ else
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
//now we check again, because an on_success handler might've errored.
//now we check again, because a on_success handler might've errored.
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
{
for (auto &amp; s : seq)

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2022 Klemens Morgenstern
// Copyright (c) 2022Klemens Morgernstern
//
// 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)

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2022Klemens Morgenstern
// Copyright (c) 2022Klemens Morgernstern
//
// 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)

View File

@@ -5,7 +5,7 @@
/** \file boost/process/async.hpp
The header which provides the basic asynchronous features.
The header which provides the basic asynchrounous features.
It provides the on_exit property, which allows callbacks when the process exits.
It also implements the necessary traits for passing an boost::asio::io_context,
which is needed for asynchronous communication.

View File

@@ -11,7 +11,7 @@
/**
* \file boost/process/async_system.hpp
*
* Defines the asynchronous version of the system function.
* Defines the asynchrounous version of the system function.
*/
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
@@ -38,11 +38,12 @@ namespace process {
namespace detail
{
template<typename Handler>
template<typename ExitHandler>
struct async_system_handler : ::boost::process::detail::api::async_handler
{
boost::asio::io_context & ios;
Handler handler;
boost::asio::async_completion<
ExitHandler, void(boost::system::error_code, int)> init;
#if defined(BOOST_POSIX_API)
bool errored = false;
@@ -51,8 +52,9 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
template<typename ExitHandler_>
async_system_handler(
boost::asio::io_context & ios,
ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
{
}
@@ -62,15 +64,21 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
#if defined(BOOST_POSIX_API)
errored = true;
#endif
auto h = std::make_shared<Handler>(std::move(handler));
auto & h = init.completion_handler;
boost::asio::post(
ios.get_executor(),
[h, ec]() mutable
{
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
});
}
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
get_result()
{
return init.result.get();
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
@@ -78,10 +86,10 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
if (errored)
return [](int , const std::error_code &){};
#endif
auto h = std::make_shared<Handler>(std::move(handler));
auto & h = init.completion_handler;
return [h](int exit_code, const std::error_code & ec) mutable
{
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
};
}
};
@@ -112,36 +120,21 @@ inline boost::process::detail::dummy
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
#endif
namespace detail
{
struct async_system_init_op
{
template<typename Handler, typename ... Args>
void operator()(Handler && handler, asio::io_context & ios, Args && ... args)
{
detail::async_system_handler<typename std::decay<Handler>::type> async_h{ios, std::forward<Handler>(handler)};
child(ios, std::forward<Args>(args)..., async_h ).detach();
}
};
}
template<typename ExitHandler, typename ...Args>
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
{
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
has_err_handling;
static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
);
child(ios, std::forward<Args>(args)..., async_h ).detach();
return async_h.get_result();
}

View File

@@ -125,10 +125,7 @@ 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;
@@ -138,7 +135,6 @@ 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;
@@ -146,7 +142,6 @@ public:
boost::process::detail::throw_error(ec, "wait_until error");
return b;
}
#endif
bool running(std::error_code & ec) noexcept
{
@@ -183,16 +178,13 @@ 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())
@@ -205,7 +197,7 @@ public:
}
return true;
}
#endif
bool valid() const
{

View File

@@ -114,8 +114,6 @@ 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

View File

@@ -39,10 +39,10 @@ inline std::string build_cmd_shell(const std::string & exe, std::vector<std::str
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), '"' );
arg += '"'; //that is the post one.
arg += '"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceding space
if (!st.empty())//first one does not need a preceeding space
st += ' ';
st += arg;
@@ -139,7 +139,7 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
}
static exe_cmd_init cmd_shell(std::string&& cmd)
{
std::vector<std::string> args = {"-c", cmd};
std::vector<std::string> args = {"-c", "\"" + cmd + "\""};
std::string sh = shell().string();
return exe_cmd_init(
@@ -155,15 +155,13 @@ 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.empty() ? empty_string : &exe.front());
vec.push_back(&exe.front());
if (!args.empty()) {
for (auto & v : args)
vec.push_back(v.empty() ? empty_string : &v.front());
vec.push_back(&v.front());
}
vec.push_back(nullptr);

View File

@@ -155,8 +155,8 @@ class executor
void write_error(const std::error_code & ec, const char * msg)
{
//I am the child
const auto len = static_cast<int>(std::strlen(msg));
int data[2] = {ec.value(), len + 1};
const auto len = std::strlen(msg);
int data[2] = {ec.value(), static_cast<int>(len + 1)};
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
boost::ignore_unused(::write(_pipe_sink, msg, len));
@@ -444,7 +444,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
}
if (_ec)
{
//if an error occurred we need to reap the child process
//if an error occured we need to reap the child process
::waitpid(this->pid, nullptr, WNOHANG);
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();

View File

@@ -80,7 +80,7 @@ struct io_context_ref : handler_base_ext
void on_success(Executor& exec)
{
ios.notify_fork(boost::asio::io_context::fork_parent);
//must be on the heap, so I can move it into the lambda.
//must be on the heap so I can move it into the lambda.
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type

View File

@@ -34,7 +34,7 @@ inline bool is_running(const child_handle &p, int & exit_code, std::error_code &
if (ret == -1)
{
if (errno != ECHILD) //because it no child is running, then this one isn't either, obviously.
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
ec = ::boost::process::detail::get_last_error();
return false;
}

View File

@@ -27,11 +27,7 @@ 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;

View File

@@ -7,18 +7,14 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/consign.hpp>
#include <boost/asio/append.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/strand.hpp>
#include <boost/optional.hpp>
#include <signal.h>
#include <functional>
#include <sys/wait.h>
#include <list>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -27,45 +23,8 @@ 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::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
inline void _handle_signal(const boost::system::error_code & ec);
struct initiate_async_wait_op
{
sigchld_service * self;
template<typename Initiation>
void operator()(Initiation && init, ::pid_t pid)
{
// check if the child actually is running first
int status;
auto pid_res = ::waitpid(pid, &status, WNOHANG);
if (pid_res < 0)
{
auto ec = get_last_error();
boost::asio::post(
self->_strand,
asio::append(std::forward<Initiation>(init), pid_res, ec));
}
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
boost::asio::post(
self->_strand,
boost::asio::append(std::forward<Initiation>(init), status, std::error_code{}));
else //still running
{
sigchld_service * self_ = self;
if (self->_receivers.empty())
self->_signal_set.async_wait(
boost::asio::bind_executor(
self->_strand,
[self_](const boost::system::error_code &ec, int)
{
self_->_handle_signal(ec);
}));
self->_receivers.emplace_back(pid, init);
}
}
};
public:
sigchld_service(boost::asio::io_context & io_context)
: boost::asio::detail::service_base<sigchld_service>(io_context)
@@ -77,10 +36,47 @@ public:
void (int, std::error_code))
async_wait(::pid_t pid, SignalHandler && handler)
{
return boost::asio::async_initiate<
SignalHandler,
void(int, std::error_code)>(
initiate_async_wait_op{this}, handler, pid);
boost::asio::async_completion<
SignalHandler, void(boost::system::error_code)> init{handler};
auto & h = init.completion_handler;
boost::asio::dispatch(
_strand,
[this, pid, h]
{
//check if the child actually is running first
int status;
auto pid_res = ::waitpid(pid, &status, WNOHANG);
if (pid_res < 0)
{
auto ec = get_last_error();
boost::asio::post(
_strand,
[pid_res, ec, h]
{
h(pid_res, ec);
});
}
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
boost::asio::post(
_strand,
[status, h]
{
h(status, {}); //successfully exited already
});
else //still running
{
if (_receivers.empty())
_signal_set.async_wait(
[this](const boost::system::error_code &ec, int)
{
boost::asio::dispatch(_strand, [this, ec]{this->_handle_signal(ec);});
});
_receivers.emplace_back(pid, h);
}
});
return init.result.get();
}
void shutdown() override
{

View File

@@ -62,7 +62,7 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
}
}
if (!st.empty())//first one does not need a preceding space
if (!st.empty())//first one does not need a preceeding space
st += ' ';
st += arg;
@@ -106,7 +106,7 @@ inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstrin
}
}
if (!st.empty())//first one does not need a preceding space
if (!st.empty())//first one does not need a preceeding space
st += L' ';
st += arg;

View File

@@ -81,7 +81,7 @@ struct child_handle
{
::boost::winapi::BOOL_ value;
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
throw_last_error("IsProcessInJob Failed");
throw_last_error("IsProcessinJob Failed");
return value!=0;
}
bool in_group(std::error_code &ec) const noexcept

View File

@@ -73,8 +73,8 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
{
/* limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
* but I used 32768, so it is a multiple of 4096.
/*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
* but I used 32768 so it is a multiple of 4096.
*/
constexpr static std::size_t max_size = 32768;
//Handle variables longer then buf.
@@ -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);
buf.data(), buf.data()+ size + 1);
}
}
return std::basic_string<Char>(buf, buf+size);
return std::basic_string<Char>(buf, buf+size+1);
}
template<typename Char>
@@ -232,7 +232,7 @@ basic_environment_impl<Char>::basic_environment_impl(const native_environment_im
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return string_type(_data.data());
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
@@ -273,7 +273,7 @@ template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
//ok, we need to check the size of data first
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return;
//check if it's the first one, spares us the search.

View File

@@ -12,7 +12,6 @@
#include <boost/process/detail/windows/handler.hpp>
#include <boost/winapi/get_current_process_id.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
namespace boost { namespace process { namespace detail {
@@ -164,7 +163,7 @@ struct limit_handles_ : handler_base_ext
}
template<typename Executor>
void on_success(Executor & exec) const
void on_sucess(Executor & exec) const
{
for (auto handle : handles_with_inherit_flag)
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);

View File

@@ -35,9 +35,7 @@ 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());});
std::vector<std::wstring> extensions_in;
if (itr != ne.cend())
extensions_in = itr->to_vector();
auto extensions_in = itr->to_vector();
std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1);
@@ -63,11 +61,7 @@ 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_))

View File

@@ -437,7 +437,7 @@ for both `id` and `value`.
\subsubsection env_reset Reset variables
Resetting single variables can be done in the following way:
Reseting signle variables can be done in the following way:
\code{.cpp}
env[id] = boost::none;

View File

@@ -70,7 +70,7 @@ using ::boost::process::detail::get_used_handles;
///This handler is invoked before the process in launched, to setup parameters. The required signature is `void(Exec &)`, where `Exec` is a template parameter.
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_setup_> on_setup;
///This handler is invoked if an error occurred. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter.
///This handler is invoked if an error occured. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter.
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_error_> on_error;
///This handler is invoked if launching the process has succeeded. The required signature is `void(auto & exec)`, where `Exec` is a template parameter.
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_success_> on_success;

View File

@@ -122,11 +122,9 @@ 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);
@@ -134,7 +132,6 @@ 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);
@@ -143,19 +140,17 @@ 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
{

View File

@@ -82,7 +82,7 @@ using limit_handles_ = ::boost::process::detail::api::limit_handles_;
}
/**
* The limit_handles property sets all properties to be inherited only explicitly. It closes all unused file-descriptors on posix after the fork and
* The limit_handles property sets all properties to be inherited only expcitly. It closes all unused file-descriptors on posix after the fork and
* removes the inherit flags on windows.
*
* \note This is executed after the fork on posix.

View File

@@ -35,7 +35,7 @@ namespace boost {
namespace boost { namespace process {
///Namespace containing the posix extensions.
///Namespace containing the posix exensions.
namespace posix {
/** This property lets you modify file-descriptors other than the standard ones (0,1,2).

View File

@@ -1,240 +0,0 @@
//
// boost/process/v2/bind_launcher.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
#define BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/default_launcher.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
template<std::size_t ... Idx>
struct index_sequence { };
template<std::size_t Size, typename T>
struct make_index_sequence_impl;
template<std::size_t Size, std::size_t ... Idx>
struct make_index_sequence_impl<Size, index_sequence<Idx...>>
{
constexpr make_index_sequence_impl() {}
using type = typename make_index_sequence_impl<Size - 1u, index_sequence<Size - 1u, Idx...>>::type;
};
template<std::size_t ... Idx>
struct make_index_sequence_impl<0u, index_sequence<Idx...>>
{
constexpr make_index_sequence_impl() {}
using type = index_sequence<Idx...>;
};
template<std::size_t Cnt>
struct make_index_sequence
{
using type = typename make_index_sequence_impl<Cnt, index_sequence<>>::type;
};
template<std::size_t Cnt>
using make_index_sequence_t = typename make_index_sequence<Cnt>::type;
}
/** @brief Utility class to bind initializers to a launcher
* @tparam Launcher The inner launcher to be used
* @tparam ...Init The initializers to be prepended.
*
* This can be used when multiple processes shared some settings,
* e.g.
*
*/
template<typename Launcher, typename ... Init>
struct bound_launcher
{
template<typename Launcher_, typename ... Init_>
bound_launcher(Launcher_ && l, Init_ && ... init) :
launcher_(std::forward<Launcher_>(l)), init_(std::forward<Init_>(init)...)
{
}
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
context,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
error_code & ec,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
context, ec,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
std::move(exec),
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
error_code & ec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
std::move(exec), ec,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
private:
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
ExecutionContext & context,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
{
return launcher_(context,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
ExecutionContext & context,
error_code & ec,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
return launcher_(context, ec,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
Executor exec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return launcher_(std::move(exec),
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
Executor exec,
error_code & ec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return launcher_(std::move(exec), ec,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
Launcher launcher_;
std::tuple<Init...> init_;
};
template<typename Launcher, typename ... Init>
auto bind_launcher(Launcher && launcher, Init && ... init)
-> bound_launcher<typename std::decay<Launcher>::type,
typename std::decay<Init>::type...>
{
return bound_launcher<typename std::decay<Launcher>::type,
typename std::decay<Init>::type...>(
std::forward<Launcher>(launcher),
std::forward<Init>(init)...);
}
/// @brief @overload bind_launcher(Launcher && launcher, Init && init)
/// @tparam ...Init The initializer types to bind to the default_launcher.
/// @param ...init The initializers types to bind to the default_launcher.
/// @return The new default_launcher.
template<typename ... Init>
auto bind_default_launcher(Init && ... init)
-> bound_launcher<default_process_launcher,
typename std::decay<Init>::type...>
{
return bound_launcher<default_process_launcher,
typename std::decay<Init>::type...>(
default_process_launcher(),
std::forward<Init>(init)...);
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif // BOOST_PROCESS_V2_BIND_LAUNCHER_HPP

View File

@@ -106,7 +106,7 @@ struct basic_cstring_ref
BOOST_CXX14_CONSTEXPR const_reference at(size_type pos) const
{
if (pos >= size())
throw_exception(std::out_of_range("cstring-view out of range"));
throw std::out_of_range("cstring-view out of range");
return view_[pos];
}
BOOST_CONSTEXPR const_reference front() const {return *view_;}

View File

@@ -7,19 +7,18 @@
#if defined(BOOST_PROCESS_V2_STANDALONE)
#define BOOST_PROCESS_V2_ASIO_NAMESPACE asio
#define BOOST_PROCESS_V2_ASIO_NAMESPACE ::asio
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) ASIO_COMPLETION_TOKEN_FOR(Sig)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
#include <asio/detail/config.hpp>
#include <system_error>
#include <filesystem>
#include <string_view>
#include <iomanip>
#include <optional>
#if defined(ASIO_WINDOWS)
#define BOOST_PROCESS_V2_WINDOWS 1
@@ -40,19 +39,18 @@
#else
#define BOOST_PROCESS_V2_ASIO_NAMESPACE boost::asio
#define BOOST_PROCESS_V2_ASIO_NAMESPACE ::boost::asio
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) BOOST_ASIO_COMPLETION_TOKEN_FOR(Sig)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
#include <boost/config.hpp>
#include <boost/io/quoted.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_category.hpp>
#include <boost/system/system_error.hpp>
#include <boost/optional.hpp>
#if defined(BOOST_WINDOWS_API)
#define BOOST_PROCESS_V2_WINDOWS 1
@@ -74,9 +72,11 @@
#if defined(BOOST_PROCESS_USE_STD_FS)
#include <filesystem>
#include <optional>
#else
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/optional.hpp>
#endif
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 {
@@ -97,14 +97,6 @@ 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 ;
@@ -120,25 +112,6 @@ 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
@@ -169,7 +142,7 @@ BOOST_PROCESS_V2_END_NAMESPACE
#endif
#endif
#if defined(__FreeBSD__) && defined(BOOST_PROCESS_V2_ENABLE_PDFORK)
#if defined(__FreeBSD__) && !defined(BOOST_PROCESS_V2_DISABLE_PDFORK)
#define BOOST_PROCESS_V2_PDFORK 1
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif
@@ -177,4 +150,6 @@ BOOST_PROCESS_V2_END_NAMESPACE
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif
#endif //BOOST_PROCESS_V2_DETAIL_CONFIG_HPP

View File

@@ -14,7 +14,7 @@
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
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

View File

@@ -34,7 +34,7 @@ basic_cstring_ref<char_type, value_char_traits<char>> get(
auto res = ::getenv(key.c_str());
if (res == nullptr)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOENT, system_category())
ec.assign(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))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec)
{
if (::unsetenv(key.c_str()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}

View File

@@ -50,7 +50,7 @@ std::basic_string<char_type, value_char_traits<char_type>> get(
buf.resize(size);
if (buf.size() == 0)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
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()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
if (!::SetEnvironmentVariableW(key.c_str(), nullptr))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
@@ -88,7 +88,7 @@ std::basic_string<char, value_char_traits<char>> get(
buf.resize(size);
if (buf.size() == 0)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
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()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
error_code & ec)
{
if (!::SetEnvironmentVariableA(key.c_str(), nullptr))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}

View File

@@ -28,6 +28,20 @@ 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

View File

@@ -9,20 +9,9 @@
#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
@@ -34,7 +23,7 @@ void get_exit_code_(
error_code & ec)
{
if (!::GetExitCodeProcess(handle, &exit_code))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
}
@@ -42,12 +31,7 @@ HANDLE open_process_(DWORD pid)
{
auto proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
if (proc == nullptr)
{
error_code ec;
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
throw system_error(ec, "open_process()");
}
detail::throw_last_error("open_process()");
return proc;
}
@@ -56,17 +40,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)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
return false;
}
return true;
@@ -76,8 +60,8 @@ bool check_pid_(pid_type pid_, error_code & ec)
{
if (pid_ == 0)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
return false;
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
return false;
}
return true;
}
@@ -89,73 +73,46 @@ 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)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(data->ec)
data->ec = detail::get_last_error();
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)))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
}
void interrupt_(pid_type pid_, error_code & ec)
{
if (!::GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid_))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
}
void terminate_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::TerminateProcess(handle, 260))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
}
void check_running_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::GetExitCodeProcess(handle, &exit_status))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
}
#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<>;

View File

@@ -27,13 +27,13 @@ inline void handle_error(error_code & ec)
switch (err)
{
case ERROR_INSUFFICIENT_BUFFER:
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::utf8_category)
ec.assign(error::insufficient_buffer, error::utf8_category);
break;
case ERROR_NO_UNICODE_TRANSLATION:
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::utf8_category)
ec.assign(error::invalid_character, error::utf8_category);
break;
default:
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
ec.assign(err, system_category());
}
}
@@ -128,7 +128,7 @@ inline int get_cont_octet_out_count_impl<4>(wchar_t word) {
// Note that the following code will generate warnings on some platforms
// where wchar_t is defined as UCS2. The warnings are superfluous as the
// specialization is never instantiated with such compilers, but this
// specialization is never instantitiated with such compilers, but this
// can cause problems if warnings are being treated as errors, so we guard
// against that. Including <boost/detail/utf8_codecvt_facet.hpp> as we do
// should be enough to get WCHAR_MAX defined.
@@ -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;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
ec.assign(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);
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
ec.assign(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)
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
ec.assign(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;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
ec.assign(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;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
ec.assign(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;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
ec.assign(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)
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
ec.assign(error::insufficient_buffer, error::get_utf8_category());
return to_next - out;
}

View File

@@ -9,13 +9,14 @@
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)

View File

@@ -101,8 +101,6 @@ 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)
@@ -184,42 +182,7 @@ 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)

View File

@@ -128,7 +128,6 @@ 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 &)
{
@@ -212,42 +211,6 @@ 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)
{

View File

@@ -41,7 +41,7 @@ struct basic_process_handle_signal
{
native_handle_type() = delete;
native_handle_type(const native_handle_type & ) = delete;
~native_handle_type() = default;
~native_handle_type() = delete;
};
typedef Executor executor_type;
@@ -101,8 +101,8 @@ struct basic_process_handle_signal
handle.pid_ = -1;
}
pid_type id() const { return pid_; }
native_handle_type native_handle() {return {};}
pid_type id() const
{ return pid_; }
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,53 +173,17 @@ 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();
}
@@ -227,7 +191,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)
@@ -320,7 +284,7 @@ struct basic_process_handle_signal
if (!ec && (wait_res == 0))
{
handle.async_wait(std::move(self));
return;
return ;
}
struct completer

View File

@@ -32,8 +32,6 @@ 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);
@@ -178,32 +176,6 @@ 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))

View File

@@ -488,7 +488,7 @@ struct key
using string_type = std::basic_string<char_type, traits_type>;
using string_view_type = basic_string_view<char_type, traits_type>;
key() {}
key() noexcept = default;
key( const key& p ) = default;
key( key&& p ) noexcept = default;
key( const string_type& source ) : value_(source) {}
@@ -524,11 +524,7 @@ struct key
~key() = default;
key& operator=( const key& p ) = default;
key& operator=( key&& p )
{
value_ = std::move(p.value_);
return *this;
}
key& operator=( key&& p ) noexcept = default;
key& operator=( string_type&& source )
{
value_ = std::move(source);
@@ -712,7 +708,7 @@ struct value
using string_type = std::basic_string<char_type, traits_type>;
using string_view_type = basic_cstring_ref<char_type, traits_type>;
value() {}
value() noexcept = default;
value( const value& p ) = default;
value( const string_type& source ) : value_(source) {}
@@ -746,11 +742,7 @@ struct value
~value() = default;
value& operator=( const value& p ) = default;
value& operator=( value&& p )
{
value_ = std::move(p.value_);
return *this;
}
value& operator=( value&& p ) noexcept = default;
value& operator=( string_type&& source )
{
value_ = std::move(source);
@@ -943,7 +935,7 @@ struct key_value_pair
using string_type = std::basic_string<char_type>;
using string_view_type = basic_cstring_ref<char_type>;
key_value_pair() {}
key_value_pair() noexcept = default;
key_value_pair( const key_value_pair& p ) = default;
key_value_pair( key_value_pair&& p ) noexcept = default;
key_value_pair(key_view key, value_view value) : value_(key.basic_string<char_type, traits_type>() + equality_sign +
@@ -1007,11 +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 )
{
value_ = std::move(p.value_);
return *this;
}
key_value_pair& operator=( key_value_pair&& p ) noexcept = default;
key_value_pair& operator=( string_type&& source )
{
value_ = std::move(source);

View File

@@ -22,7 +22,7 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
* @tparam Executor The asio executor of the process handle
* @param proc The process to be run.
* @return int The exit code of the process
* @exception system_error An error that might have occurred during the wait.
* @exception system_error An error that might have occured during the wait.
*/
template<typename Executor>
inline int execute(basic_process<Executor> proc)
@@ -92,13 +92,13 @@ struct execute_op
/** This function asynchronously for a process to complete.
*
* Cancelling the execution will signal the child process to exit
* with the following interpretations:
* with the following intepretations:
*
* - cancellation_type::total -> interrupt
* - cancellation_type::partial -> request_exit
* - cancellation_type::terminal -> terminate
*
* It is to note that `async_execute` will us the lowest selected cancellation
* It is to note that `async_execute` will us the lowest seelected cancellation
* type. A subprocess might ignore anything not terminal.
*/
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor,

View File

@@ -12,15 +12,6 @@
#define BOOST_PROCESS_V2_EXIT_CODE_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/error.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/associator.hpp>
#include <asio/async_result.hpp>
#else
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#endif
#if defined(BOOST_PROCESS_V2_POSIX)
#include <sys/wait.h>
@@ -94,157 +85,6 @@ inline int evaluate_exit_code(int code)
#endif
/** Convert the exit-code in a completion into an error if the actual error isn't set.
* @code {.cpp}
* process proc{ctx, "exit", {"1"}};
*
* proc.async_wait(code_as_error(
* [](error_code ec)
* {
* assert(ec.value() == 10);
* assert(ec.category() == error::get_exit_code_category());
* }));
*
* @endcode
*/
template<typename CompletionToken>
struct code_as_error_t
{
CompletionToken token_;
const error_category & category;
template<typename Token_>
code_as_error_t(Token_ && token, const error_category & category)
: token_(std::forward<Token_>(token)), category(category)
{
}
};
/// Deduction function for code_as_error_t.
template<typename CompletionToken>
code_as_error_t<CompletionToken> code_as_error(
CompletionToken && token,
const error_category & category = error::get_exit_code_category())
{
return code_as_error_t<typename std::decay<CompletionToken>::type>(
std::forward<CompletionToken>(token), category);
};
namespace detail
{
template<typename Handler>
struct code_as_error_handler
{
typedef void result_type;
template<typename H>
code_as_error_handler(H && h, const error_category & category)
: handler_(std::forward<H>(h)), category(category)
{
}
void operator()(error_code ec, native_exit_code_type code)
{
if (!ec)
BOOST_PROCESS_V2_ASSIGN_EC(ec, code, category)
std::move(handler_)(ec);
}
Handler handler_;
const error_category & category;
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#if !defined(BOOST_PROCESS_V2_STANDALONE)
namespace boost
{
#endif
namespace asio
{
template <typename CompletionToken>
struct async_result<
BOOST_PROCESS_V2_NAMESPACE::code_as_error_t<CompletionToken>,
void(BOOST_PROCESS_V2_NAMESPACE::error_code,
BOOST_PROCESS_V2_NAMESPACE::native_exit_code_type)>
{
using signature = void(BOOST_PROCESS_V2_NAMESPACE::error_code);
using return_type = typename async_result<CompletionToken, void(BOOST_PROCESS_V2_NAMESPACE::error_code)>::return_type;
template <typename Initiation>
struct init_wrapper
{
init_wrapper(Initiation init)
: initiation_(std::move(init))
{
}
template <typename Handler, typename... Args>
void operator()(
Handler && handler,
const BOOST_PROCESS_V2_NAMESPACE::error_category & cat,
Args && ... args)
{
std::move(initiation_)(
BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<typename decay<Handler>::type>(
std::forward<Handler>(handler), cat),
std::forward<Args>(args)...);
}
Initiation initiation_;
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, signature,
(async_initiate<CompletionToken, signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<CompletionToken&>(),
declval<BOOST_ASIO_MOVE_ARG(Args)>()...)))
initiate(
Initiation && initiation,
RawCompletionToken && token,
Args &&... args)
{
return async_initiate<CompletionToken, signature>(
init_wrapper<typename decay<Initiation>::type>(
std::forward<Initiation>(initiation)),
token.token_,
token.category,
std::forward<Args>(args)...);
}
};
template<template <typename, typename> class Associator, typename Handler, typename DefaultCandidate>
struct associator<Associator,
BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<Handler>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<Handler> & h,
const DefaultCandidate& c = DefaultCandidate()) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
}
#if !defined(BOOST_PROCESS_V2_STANDALONE)
} // boost
#endif
#endif //BOOST_PROCESS_V2_EXIT_CODE_HPP

View File

@@ -1,16 +0,0 @@
//
// 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

View File

@@ -1,66 +0,0 @@
// 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

View File

@@ -1,59 +0,0 @@
// 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

View File

@@ -1,127 +0,0 @@
// 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

View File

@@ -1,125 +0,0 @@
// 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

View File

@@ -1,154 +0,0 @@
// 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

View File

@@ -1,62 +0,0 @@
// 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

View File

@@ -1,460 +0,0 @@
// 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

View File

@@ -1,234 +0,0 @@
// 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

View File

@@ -1,389 +0,0 @@
// 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

View File

@@ -1,193 +0,0 @@
// 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

View File

@@ -1,5 +1,4 @@
// 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,56 +6,14 @@
#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)
@@ -65,698 +22,6 @@ 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.resize(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0) / sizeof(pid_type));
const auto sz = proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(pid_type) * vec.size());
if (sz < 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
vec.resize(sz);
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.resize(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0) / sizeof(pid_type));
const auto sz = proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size());
if (sz < 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
vec.resize(sz);
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

View File

@@ -69,11 +69,7 @@ void shell::parse_()
{
argv_ = ::CommandLineToArgvW(input_.c_str(), &argc_);
if (argv_ == nullptr)
{
error_code ec;
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
throw system_error(ec, "shell::parse");
}
detail::throw_last_error();
}
shell::~shell()
@@ -100,23 +96,21 @@ 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 && free_argv_ != nullptr)
free_argv_(argc_, argv_);
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);
}
}
auto shell::args() const -> args_type

View File

@@ -1,5 +1,4 @@
// 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,7 +6,6 @@
#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
@@ -16,6 +14,7 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
//An integral type representing a process id.
typedef implementation_defined pid_type;
#else
#if defined(BOOST_PROCESS_V2_WINDOWS)
@@ -29,38 +28,14 @@ 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

View File

@@ -74,6 +74,8 @@ struct basic_popen : basic_process<Executor>
{
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename ... Inits>
explicit basic_popen(
@@ -83,66 +85,30 @@ struct basic_popen : basic_process<Executor>
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
*static_cast<basic_process<Executor>*>(this) =
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
);
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename ... Inits>
explicit basic_popen(
executor_type executor,
const filesystem::path& exe,
const filesystem::path& exe,
std::initializer_list<wstring_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
*static_cast<basic_process<Executor>*>(this) =
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
std::initializer_list<wstring_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
);
}
/// Construct a child from a property list and launch it using the default process launcher.
@@ -153,112 +119,53 @@ struct basic_popen : basic_process<Executor>
Args&& args, Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
*static_cast<basic_process<Executor>*>(this) =
default_process_launcher()(
std::move(executor), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename Args, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
std::move(executor), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
);
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename ExecutionContext, typename ... Inits>
explicit basic_popen(
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
std::initializer_list<string_view> args,
Inits&&... inits)
Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
*static_cast<basic_process<Executor>*>(this) =
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ExecutionContext, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
);
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename ExecutionContext, typename Args, typename ... Inits>
explicit basic_popen(
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
*static_cast<basic_process<Executor>*>(this) =
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
);
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ExecutionContext, typename Args, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// The type used for stdin on the parent process side.
using stdin_type = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor>;
/// The type used for stdout on the parent process side.

View File

@@ -61,7 +61,7 @@ struct bind_fd
*/
bind_fd(int target, FILE * f) : bind_fd(target, fileno(f)) {}
/// Inherit a file descriptor with as a different value.
/// Inherit a file descriptor with as a differnet value.
/**
* This will pass 24 as 42 to the child process:
* @code
@@ -79,7 +79,7 @@ struct bind_fd
*/
bind_fd(int target, std::nullptr_t) : bind_fd(target, filesystem::path("/dev/null")) {}
/// Inherit a newly opened-file as a set descriptor.
/// Inherit a newly openedfile as a set descriptor.
/**
* This will pass 24 as 42 to the child process:
* @code
@@ -94,7 +94,6 @@ struct bind_fd
error_code on_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
{
launcher.fd_whitelist.push_back(target);
return {};
}
/// Implementation of the initialization function.

View File

@@ -364,12 +364,12 @@ struct default_launcher
pipe_guard pg;
if (::pipe(pg.p))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(errno, system_category());
return basic_process<Executor>{exec};
}
if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(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...);
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(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)));
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(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))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
ec.assign(err, system_category());
break;
}
}
if (count != 0)
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
ec.assign(child_error, system_category());
if (ec)
{

View File

@@ -1,5 +1,5 @@
//
// boost/process/v2/posix/detail/close_handles.hpp
// boost/process/v2/poxix/detail/close_handles.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)

View File

@@ -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...);
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(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));
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(errno, system_category());
detail::on_exec_error(*this, executable, argv, ec, inits...);
::exit(EXIT_FAILURE);
return basic_process<Executor>{exec};

View File

@@ -85,12 +85,12 @@ struct pdfork_launcher : default_launcher
pipe_guard pg;
if (::pipe(pg.p))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(errno, system_category());
return basic_process<Executor>{exec};
}
if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(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...);
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(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)));
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(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))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
ec.assign(err, system_category());
break;
}
}
if (count != 0)
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
ec.assign(child_error, system_category());
if (ec)
{

View File

@@ -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...);
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(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));
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
ec.assign(errno, system_category());
detail::on_exec_error(*this, executable, argv, ec, inits...);
::exit(EXIT_FAILURE);
return basic_process<Executor>{exec};

View File

@@ -15,7 +15,6 @@
#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)
@@ -215,37 +214,6 @@ 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()
{
@@ -270,7 +238,7 @@ struct basic_process
detail::throw_error(ec, "wait failed");
return exit_code();
}
/// Waits for the process to exit, store the exit code internally and return it.
/// Waits for the process to exit, store the exit code internall and return it.
int wait(error_code & ec)
{
if (running(ec))
@@ -400,4 +368,4 @@ typedef basic_process<> process;
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_PROCESS_HPP
#endif //BOOST_PROCESS_V2_PROCESS_HPP

View File

@@ -27,8 +27,8 @@ static const error_category& shell_category = get_shell_category();
* In v1, this was possible directly when starting a process,
* but has been removed based on the security risks associated with this.
*
* By making the shell parsing explicitly, it encourages
* a user to run a sanity check on the executable before launching it.
* By making the shell parsing explicity, it is encouraged
* that a user runs a sanity check on the executable before launching it.
*
* @par Example
* @code {.cpp}
@@ -79,10 +79,8 @@ struct shell
: buffer_(std::move(lhs.buffer_)),
input_(std::move(lhs.input_)),
argc_(boost::exchange(lhs.argc_, 0)),
argv_(boost::exchange(lhs.argv_, nullptr))
#if defined(BOOST_PROCESS_V2_POSIX)
, free_argv_(boost::exchange(lhs.free_argv_, nullptr))
#endif
argv_(boost::exchange(lhs.argv_, nullptr)),
reserved_(boost::exchange(lhs.reserved_, 0))
{
}
shell& operator=(shell && lhs) noexcept
@@ -92,9 +90,7 @@ struct shell
input_ = std::move(lhs.input_);
argc_ = boost::exchange(lhs.argc_, 0);
argv_ = boost::exchange(lhs.argv_, nullptr);
#if defined(BOOST_PROCESS_V2_POSIX)
free_argv_ = boost::exchange(lhs.free_argv_, nullptr);
#endif
reserved_ = boost::exchange(lhs.reserved_, 0);
return *this;
}
@@ -120,9 +116,6 @@ 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
@@ -131,10 +124,7 @@ struct shell
// impl details
int argc_ = 0;
char_type ** argv_ = nullptr;
#if defined(BOOST_PROCESS_V2_POSIX)
void(*free_argv_)(int, char **);
#endif
int reserved_ = 0;
};

View File

@@ -10,16 +10,11 @@
#include <boost/process/v2/detail/config.hpp>
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
# error Do not compile Process V2 library source with BOOST_PROCESS_V2_HEADER_ONLY defined. You should probably define BOOST_PROCESS_V2_SEPARATE_COMPILATION
# error Do not compile Beast library source with BOOST_BEAST_HEADER_ONLY defined
#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>

View File

@@ -11,7 +11,6 @@
#define BOOST_PROCESS_v2_START_DIR_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/default_launcher.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE

View File

@@ -11,7 +11,6 @@
#define BOOST_PROCESS_V2_STDIO_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/default_launcher.hpp>
#include <cstddef>
#if defined(BOOST_PROCESS_V2_STANDALONE)
@@ -69,11 +68,7 @@ struct process_io_binding
{
DWORD res;
if (!::GetHandleInformation(h, &res))
{
error_code ec;
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
throw system_error(ec, "get_flags");
}
detail::throw_last_error("get_flags");
return res;
}
@@ -180,7 +175,7 @@ struct process_io_binding
fd = p[1];
if (::fcntl(p[0], F_SETFD, FD_CLOEXEC) == -1)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
return ;
}
fd_needs_closing = true;
@@ -199,7 +194,7 @@ struct process_io_binding
fd = p[0];
if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
return ;
}
fd_needs_closing = true;
@@ -265,7 +260,7 @@ typedef process_io_binding<STDERR_FILENO> process_error_binding;
* - `FILE*` any open file, including `stdin`, `stdout` and `stderr`
* - a filesystem::path, which will open a readable or writable depending on the direction of the stream
* - `native_handle` any native file handle (`HANDLE` on windows) or file descriptor (`int` on posix)
* - any io-object with a .native_handle() function that is compatible with the above. E.g. a asio::ip::tcp::socket
* - any io-object with a .native_handle() function that is comptaiblie with the above. E.g. a asio::ip::tcp::socket
* - an asio::basic_writeable_pipe for stdin or asio::basic_readable_pipe for stderr/stdout.
*
*

View File

@@ -107,7 +107,7 @@ struct as_user_launcher : default_launcher
if (ok == 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
detail::on_error(*this, executable, command_line, ec, inits...);
if (process_information.hProcess != INVALID_HANDLE_VALUE)

View File

@@ -36,7 +36,7 @@ struct process_creation_flags
};
};
/// A flag to create a new process group. Necessary to allow interrupts for the subprocess.
/// A flag to create a new process group. Necessary to allow interupts for the subproces.
constexpr static process_creation_flags<CREATE_NEW_PROCESS_GROUP> create_new_process_group;
}

View File

@@ -314,7 +314,7 @@ struct default_launcher
auto ec__ = detail::get_last_error();
if (ok == 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
detail::on_error(*this, executable, command_line, ec, inits...);
if (process_information.hProcess != INVALID_HANDLE_VALUE)

View File

@@ -111,7 +111,7 @@ struct with_logon_launcher : default_launcher
if (ok == 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
detail::on_error(*this, executable, command_line, ec, inits...);
if (process_information.hProcess != INVALID_HANDLE_VALUE)

View File

@@ -106,7 +106,7 @@ struct with_token_launcher : default_launcher
if (ok == 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
ec = detail::get_last_error();
detail::on_error(*this, executable, command_line, ec, inits...);
if (process_information.hProcess != INVALID_HANDLE_VALUE)

View File

@@ -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"

View File

@@ -100,8 +100,8 @@ 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 <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 group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner : <target-os>darwin:<build>no ]
[ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner ]
[ run run_exe.cpp filesystem : : sparring_partner ]
[ run run_exe_path.cpp filesystem : [ test-options run_exe_path ] : sparring_partner ]
[ run search_path.cpp filesystem system : [ test-options search_path ] : : <target-os>windows:<source>shell32 ]
@@ -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 : <target-os>freebsd:<build>no ]
[ run terminate.cpp system filesystem : [ test-options terminate ] : sparring_partner ]
[ 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 ]

View File

@@ -1,6 +1,6 @@
//
// 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)
// Created by kleme on 26.02.2018.
//
#define BOOST_ASIO_NO_DEPRECATED 1
#include <boost/process.hpp>

View File

@@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(multithreaded_async_pipe)
asio::io_context ioc;
std::vector<std::thread> threads;
for (auto i = 0u; i < std::thread::hardware_concurrency(); i++)
for (int i = 0; i < std::thread::hardware_concurrency(); i++)
{
threads.emplace_back([&ioc]
{
@@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(move_pipe)
}
/*
{
//copy a closed pipe
//copy an a closed pipe
BOOST_TEST_CHECKPOINT("Copy assign");
BOOST_TEST_CHECKPOINT("Fourth move, from closed");
bp::async_pipe ap_inv{ios};
@@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(move_pipe)
}
{
//copy a closed pipe
//copy an a closed pipe
BOOST_TEST_CHECKPOINT("Copy assign");
BOOST_TEST_CHECKPOINT("Fourth move, from closed");
bp::async_pipe ap_inv{ios};

View File

@@ -30,7 +30,7 @@ namespace bp = boost::process;
namespace fs = boost::process::filesystem;
BOOST_AUTO_TEST_CASE(explicit_)
BOOST_AUTO_TEST_CASE(excplicit)
{
using boost::unit_test::framework::master_test_suite;
@@ -83,24 +83,3 @@ 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);
}

View File

@@ -12,6 +12,7 @@
#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>

View File

@@ -16,7 +16,7 @@
#include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/scope_exit.hpp>
#include <boost/process/error.hpp>
#include <boost/process/io.hpp>
#include <boost/process/args.hpp>
@@ -45,10 +45,6 @@ BOOST_AUTO_TEST_CASE(wait_group_test, *boost::unit_test::timeout(5))
BOOST_REQUIRE(done.load());
}};
BOOST_SCOPE_EXIT_ALL(&) {
done.store(true);
thr.join();
};
using boost::unit_test::framework::master_test_suite;
@@ -78,10 +74,13 @@ BOOST_AUTO_TEST_CASE(wait_group_test, *boost::unit_test::timeout(5))
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_REQUIRE(c2.in_group(ec));
BOOST_CHECK_MESSAGE(!ec, ec.message());
g.wait(ec);
g.wait();
BOOST_CHECK(!c1.running());
BOOST_CHECK(!c2.running());
done.store(true);
thr.join();
}

View File

@@ -40,19 +40,12 @@ BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
#if defined(BOOST_WINDOWS_API)
const auto get_handle = [](FILE * f) {return reinterpret_cast<bt::native_handle_type>(_get_osfhandle(_fileno(f)));};
const auto socket_to_handle = [](::boost::winapi::UINT_PTR_ sock){return reinterpret_cast<::boost::winapi::HANDLE_>(sock);};
#else
const auto get_handle = [](FILE * f) {return fileno(f);};
const auto socket_to_handle = [](int i){ return i;};
#if !defined(__linux__)
return ;
#endif
#endif
std::error_code ec;

View File

@@ -1,14 +1,9 @@
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)
add_executable(boost_process_v2_${name} ${name}.cpp)
@@ -33,9 +28,6 @@ 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(ext)
boost_process_v2_test_with_target(process)

View File

@@ -21,12 +21,7 @@ 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
@@ -51,21 +46,18 @@ 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 shell.cpp test_impl ]
;
test-suite with_target :
[ run pid.cpp test_impl : --log_level=all --catch_system_errors=no -- : 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 ]
;

View File

@@ -1,180 +0,0 @@
// 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 = 0u; 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()

View File

@@ -1,53 +1,15 @@
// 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/pid.hpp>
#include <boost/process/v2/process.hpp>
#include <boost/test/unit_test.hpp>
#include <algorithm>
#include <thread>
#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());
}
BOOST_AUTO_TEST_CASE(child_pid)
{
namespace bp2 = boost::process::v2;
using boost::unit_test::framework::master_test_suite;
const auto pth = bp2::filesystem::absolute(master_test_suite().argv[1]);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
auto cs = bp2::child_pids(bp2::current_pid());
boost::asio::io_context ctx;
bp2::process proc(ctx, pth, {"sleep", "50000"});
std::this_thread::sleep_for(std::chrono::milliseconds(20));
auto c2 = bp2::child_pids(bp2::current_pid());
BOOST_CHECK_LT(cs.size(), c2.size());
BOOST_CHECK(std::find(cs.begin(), cs.end(), proc.id()) == cs.end());
BOOST_CHECK(std::find(c2.begin(), c2.end(), proc.id()) != c2.end());
proc.terminate();
proc.wait();
auto c3 = bp2::child_pids(bp2::current_pid());
BOOST_CHECK(std::find(c3.begin(), c3.end(), proc.id()) == c3.end());
BOOST_CHECK_LT(c3.size(), c2.size());
}

View File

@@ -24,7 +24,6 @@
#include <boost/process/v2/start_dir.hpp>
#include <boost/process/v2/execute.hpp>
#include <boost/process/v2/stdio.hpp>
#include <boost/process/v2/bind_launcher.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/asio/io_context.hpp>
@@ -150,8 +149,6 @@ BOOST_AUTO_TEST_CASE(terminate)
BOOST_CHECK_MESSAGE(!sh.empty(), sh);
bpv::process proc(ctx, sh, {});
proc.suspend();
proc.resume();
proc.terminate();
proc.wait();
}
@@ -162,12 +159,7 @@ BOOST_AUTO_TEST_CASE(request_exit)
auto sh = closable();
BOOST_CHECK_MESSAGE(!sh.empty(), sh);
asio::readable_pipe rp{ctx};
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);
bpv::process proc(ctx, sh, {}, bpv::process_stdio{wp}
bpv::process proc(ctx, sh, {}
#if defined(ASIO_WINDOWS)
, asio::windows::show_window_minimized_not_active
#endif
@@ -221,8 +213,6 @@ 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());
@@ -269,8 +259,6 @@ 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());
@@ -324,9 +312,6 @@ 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);
@@ -351,9 +336,6 @@ 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(),
@@ -375,19 +357,16 @@ BOOST_AUTO_TEST_CASE(popen)
// default CWD
bpv::popen proc(/*bpv::default_process_launcher(), */ctx, pth, {"echo"});
bpv::popen proc(ctx, pth, {"echo"});
asio::write(proc, asio::buffer("FOOBAR"));
auto written = asio::write(proc, asio::buffer("FOOBAR"));
proc.get_stdin().close();
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);
BOOST_CHECK(ec == asio::error::eof || ec == asio::error::broken_pipe);
BOOST_REQUIRE_GE(n, 1);
// remove EOF
res.pop_back();
BOOST_CHECK_EQUAL(res, "FOOBAR");
@@ -419,16 +398,8 @@ 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());
if (out.back() != '/' && target.string().back() == '/')
out += '/';
BOOST_CHECK_MESSAGE(bpv::filesystem::path(out) == target,
bpv::filesystem::path(out) << " != " << target);
@@ -457,10 +428,7 @@ std::string read_env(const char * name, Inits && ... inits)
std::string out;
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);
const auto 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);
@@ -505,69 +473,5 @@ BOOST_AUTO_TEST_CASE(environment)
BOOST_CHECK_EQUAL(read_env("PATH", bpv::process_environment(bpv::environment::current())), ::getenv("PATH"));
}
BOOST_AUTO_TEST_CASE(exit_code_as_error)
{
using boost::unit_test::framework::master_test_suite;
const auto pth = bpv::filesystem::absolute(master_test_suite().argv[1]);
asio::io_context ctx;
bpv::process proc1(ctx, pth, {"exit-code", "0"});
bpv::process proc2(ctx, pth, {"exit-code", "2"});
bpv::process proc3(ctx, pth, {"sleep", "2000"});
int called = 0;
proc3.terminate();
proc1.async_wait(bpv::code_as_error([&](bpv::error_code ec){called ++; BOOST_CHECK(!ec);}));
proc2.async_wait(bpv::code_as_error([&](bpv::error_code ec){called ++; BOOST_CHECK_MESSAGE(ec, ec.message());}));
proc3.async_wait(bpv::code_as_error([&](bpv::error_code ec){called ++; BOOST_CHECK_MESSAGE(ec, ec.message());}));
ctx.run();
BOOST_CHECK_EQUAL(called, 3);
}
BOOST_AUTO_TEST_CASE(bind_launcher)
{
using boost::unit_test::framework::master_test_suite;
const auto pth = bpv::filesystem::absolute(master_test_suite().argv[1]);
asio::io_context ctx;
asio::readable_pipe rp{ctx};
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);
auto target = bpv::filesystem::canonical(bpv::filesystem::temp_directory_path());
auto l = bpv::bind_default_launcher(bpv::process_start_dir(target));
std::vector<std::string> args = {"print-cwd"};
// default CWD
bpv::process proc = l(ctx, pth, args, bpv::process_stdio{/*.in=*/{}, /*.out=*/wp});
wp.close();
std::string out;
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());
if (out.back() != '/' && target.string().back() == '/')
out += '/';
BOOST_CHECK_MESSAGE(bpv::filesystem::path(out) == target,
bpv::filesystem::path(out) << " != " << target);
proc.wait();
BOOST_CHECK_MESSAGE(proc.exit_code() == 0, proc.exit_code() << " from " << proc.native_exit_code());
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -39,9 +39,9 @@ BOOST_AUTO_TEST_CASE(test_shell_parser)
BOOST_CHECK(sh.argv()[2] == STR_VIEW("foo bar"));
#if defined(BOOST_PROCESS_V2_POSIX)
auto raw_shell = "sh -c true";
auto raw_shell = "sh -c false";
#else
auto raw_shell = "cmd /c exit 0";
auto raw_shell = "cmd /c exit 1";
#endif
sh = shell(raw_shell);
@@ -52,5 +52,5 @@ BOOST_AUTO_TEST_CASE(test_shell_parser)
bpv::process proc{ctx, exe, sh.args()};
proc.wait();
BOOST_CHECK_EQUAL(proc.exit_code(), 0);
BOOST_CHECK_EQUAL(proc.exit_code(), 1);
}

View File

@@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(wait_for)
BOOST_CHECK(!c.wait_for(std::chrono::milliseconds(200)));
BOOST_CHECK( c.wait_for(std::chrono::milliseconds(2000)));
BOOST_CHECK( c.wait_for(std::chrono::milliseconds(1000)));
auto timeout_t = std::chrono::system_clock::now();