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

Compare commits

..

102 Commits

Author SHA1 Message Date
Klemens Morgenstern
bfb1ebb5bd Merge branch 'master' into develop
# Conflicts:
#	.github/workflows/ci.yml
#	include/boost/process/environment.hpp
#	include/boost/process/v2/exit_code.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
#	test/v2/pid.cpp
#	test/v2/process.cpp
2023-06-28 20:30:30 +08:00
Klemens Morgenstern
c005adc8fc simplified stdio. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
5cab462710 added empty env var check to tests. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
ccd46dc692 added Bcrypt to gcc win builds. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
b3c8c3a8da fixed popen test. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
4dd6f28094 removed code_as_error. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
d73f228469 popen test adjustements. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
ccd1717588 test updates for CI 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
9a4aeab97e simplified terminate test. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
d66dce11bd ext/*.hpp order fix 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
fc38699a4b terminate test logs ec. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
a859c5151c removed posix-cmake-subdir from github actions. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
8c2f403841 posix::basic_cmd handles empty cmd
closes #304.
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
6fb2702a79 fixed unsigned & signed warnings
closes #301
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
6cd4244f05 doc typo fixes 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
0c42a58eac ~pipe_buf catches exceptions from overflow
Closes #111
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
f269236d38 vfork launcher fixes
closes #314
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
4b413d34f4 Remove initializer_list<wstring_view> constructors.
They are causing ambiguity and are not that useful.

Closes #313
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
1403af769b process uses v2::detail::throw_error
closes #318
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
964f6d3f7e pipe_* includes error_code
closes #316
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
bccf42a3ec include fix for v2/environment.hpp. 2023-06-28 20:24:12 +08:00
nikola-sh
70c7ae694f Fix MSVC compile errors 2023-06-13 20:44:03 +08:00
Klemens Morgenstern
1fdd405a3f More typo fixes. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
af2e884352 Typo fixes. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
1fbd8bb5e1 handle_info include fix for handles.hpp. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
09ba5e8d47 Reduced amount of test & fixed path comparisons. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
2c6304b563 pid_test fixes for osx. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
e79c5f5edd Updated pid test. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
7a9ab79162 removed noexcept from env v2 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
0c1c6dfa90 sighchld service & test fixes. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
4f9f4c398a close #296. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
e4a3e305b4 ec use locations. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
9d51e1cd32 xproc fixes 2023-02-22 22:46:07 +08:00
Samuel Venable
f1302430cb extern process management. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
6f0d6a2e24 switched to BOOST_DEPRECATED. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
57b67e0173 added clang 3.8. noexcept deduction. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
bbc7eb82e5 disabled terminate test for freebsd. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
744e9d95b3 [drone] Removed mlocate dep. 2023-02-22 22:46:07 +08:00
Ivan Efimov
bc9a98787e Fix string construction in native_environment_impl::get 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
0fdd448c67 Deprecated wait_for & wait_until. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
5fcf5465ce Switched vector in list of sigclhd_service.
Closes #175
2023-02-22 22:46:07 +08:00
Gary Miguel
1dc9d8689e fix error message 2023-02-22 22:46:07 +08:00
Klemens
dc915be11d ec fix for search_path with std::filesystem.
closes #287.
2023-02-22 22:46:07 +08:00
Orgad Shaneh
d7df60938e Fix crash on search_path on Windows when PATHEXT is not found 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
765650aed3 Update process.cpp 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
f12bc25122 Disabled some tests for freebsd & added interrupt handling to osx test. 2023-02-22 22:46:07 +08:00
sdarwin
32a2c2297c Update metadata 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
3258e3a11c Typo fix. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
ba7e8db9bb Include fixes. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
3211afda4a More typo fixes. 2023-02-22 13:04:13 +08:00
Klemens Morgenstern
d3f006acd4 Typo fixes. 2023-02-22 13:01:46 +08:00
Klemens Morgenstern
99633a6e42 handle_info include fix for handles.hpp. 2023-02-22 12:26:31 +08:00
Klemens Morgenstern
1e614ee43e Reduced amount of test & fixed path comparisons. 2023-02-22 00:54:17 +08:00
Klemens Morgenstern
0e3358705d pid_test fixes for osx. 2023-02-21 16:27:40 +08:00
Klemens Morgenstern
27a35f452d Updated pid test. 2023-02-21 16:27:40 +08:00
Klemens Morgenstern
8fff7283ed removed noexcept from env v2 2023-02-21 16:27:40 +08:00
Klemens Morgenstern
611dac143f sighchld service & test fixes. 2023-02-20 14:09:38 +08:00
Klemens Morgenstern
8d93576b94 close #296. 2023-02-20 14:09:38 +08:00
Klemens Morgenstern
f703845011 ec use locations. 2023-02-20 14:09:38 +08:00
Klemens Morgenstern
abd052e09f xproc fixes 2023-02-20 14:09:38 +08:00
Samuel Venable
a3304564c6 extern process management. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
5865c6b449 switched to BOOST_DEPRECATED. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
4c872c0a0d added clang 3.8. noexcept deduction. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
feabbee098 disabled terminate test for freebsd. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
a5b6e70c39 [drone] Removed mlocate dep. 2023-02-20 14:09:37 +08:00
Ivan Efimov
347fc68476 Fix string construction in native_environment_impl::get 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
61ff12c8da Deprecated wait_for & wait_until. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
bd8e81153c Switched vector in list of sigclhd_service.
Closes #175
2023-02-20 14:09:37 +08:00
Gary Miguel
5fde6bec9f fix error message 2023-02-20 14:09:37 +08:00
Klemens
cf64f7dc6a ec fix for search_path with std::filesystem.
closes #287.
2023-02-20 14:09:37 +08:00
Orgad Shaneh
8355c3e1b6 Fix crash on search_path on Windows when PATHEXT is not found 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
de797e388d Update process.cpp 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
fc33435f8b Disabled some tests for freebsd & added interrupt handling to osx test. 2023-02-20 14:09:37 +08:00
sdarwin
f45ec624db Update metadata 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
9682056278 Typo fix. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
a00115b454 Include fixes. 2023-02-20 14:09:37 +08:00
Sam Darwin
3db86ac69f Drone: update freebsd jobs (#274) 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
5ffb6bf8da using scope-exit limit group_wait. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
2c5a38bfbe Disabled limit_fd for freebsd. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
f28a6406ae group wait test on_scope exit fix. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
7a1820d546 Disabled pdfork by default, bc of asio errors. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
6bc5add9a7 Increased timeout for sporadically failing test. 2022-11-01 19:41:20 +08:00
Alexander Grund
f876ba81e6 Update .drone.star
Remove the `image` param which is superflous, misleading and may become an error. See https://github.com/boostorg/boost-ci/pull/189

[skip ci]
2022-11-01 19:41:20 +08:00
Klemens Morgenstern
e943f8fb9c Improved error message for OSX. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
bc55a93dce passing a pipe into sh test. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
2eee42d5e6 Added return_type to async_result<code_as_error_t> 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
2d2b124647 Minor bugfixes 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
50986cc330 Enabled freebsd build 2022-11-01 19:41:20 +08:00
Klemens
09f0a2c547 Fixed async_system. 2022-11-01 19:41:20 +08:00
Klemens
13af16bfec Added bind_launcher. 2022-11-01 19:41:20 +08:00
Klemens
7745fdc687 Added code_as_error completion handler. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
d36f481392 Added WIN32_LEAN_AND_MEAN to cmake 2022-11-01 19:41:20 +08:00
Klemens
011380c28a Shell(posix) fixes. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
ebd4e723c3 Exeuction support for shell. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
b8108c508f Implemented shell on windows. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
ecf3dde88c Windows bugfixes. 2022-11-01 19:41:20 +08:00
Klemens
4761b375d0 Added shell class. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
ae6a9e6639 Closes #267 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
2c35167d9b Closes #266 2022-11-01 19:41:20 +08:00
Klemens
b68900ca1c Fixed unsafe post-fork allocs for fd_whitelist. 2022-11-01 19:41:20 +08:00
Klemens
ba7fe11193 Added reaping child for execve error, closes #265. 2022-11-01 19:41:20 +08:00
grtowel1510f
b0da4ad10c fix issue #251 - fix simple shell command in posix
see issue #251 for description.
2022-11-01 19:41:20 +08:00
71 changed files with 354 additions and 629 deletions

View File

@@ -19,7 +19,7 @@ def main(ctx):
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True),
linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={ 'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '17ba079169m'}, arch="arm64", globalenv=globalenv),
#linux_cxx("gcc 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",
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:

View File

@@ -17,10 +17,6 @@ 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
@@ -32,21 +28,10 @@ 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
@@ -214,162 +199,3 @@ jobs:
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
posix-cmake-subdir:
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: Use library with add_subdirectory
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
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

View File

@@ -35,13 +35,13 @@ In this library the following functions are used for the creation of unnamed pip
As the name suggests, named pipes have a string identifier. This means that a
handle to them can be obtained with the identifier, too.
The implementation on posix uses [@(http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos],
The implementation on posix uses [@http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos],
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 asynchrounous communication on windows.]
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchronous 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 send to the father process interally
<emphasis>unspecified();</emphasis>//here the error is sent to the father process internally
<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 the error from the child process
<emphasis>unspecified();</emphasis>//here, we read 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 a on_success handler might've errored.
//now we check again, because an 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 recommented to use the environment types,
an environment is either a list of strings or a list of string-pairs. It is however recommended 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 adresses one logical compoent (e.g. stdio) instead of multiple ones accumulating.
Every initializer addresses one logical component (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.
@@ -57,7 +57,7 @@ file-handles for the subprocess.
Certain parts of boost.process were not as reliable as they should've been.
This concerns especially the `wait_for`` and `wait_until` functions on the process.
This concerns especially the `wait_for` and `wait_until` functions on the process.
The latter are easy to do on windows, but posix does not provide an API for this.
Thus the wait_for used signals or fork, which was all but safe.
Since process v2 is based on asio and thus supports cancellation,

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::eror_code ec;
boost::system::error_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_initalizer
struct custom_initializer
{
// 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 occured during setup or process creation
// called for every initializer if an error occurred 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 occured when forking, in addtion to on_error.
// called for every initializer if an error occurred when forking, in addition 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 streight forward, they will call the following functions on the initializer if present.
Windows launchers are pretty straight forward, they will call the following functions on the initializer if present.
```
struct custom_initializer
@@ -103,7 +103,7 @@ Windows launchers are pretty streight 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 occured during setup or process creation
// called for every initializer if an error occurred 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

@@ -32,7 +32,7 @@ also returned from `.wait()`.
```
The normal exit-code is what the subprocess returned from `main`;
posix will however add addtional information about the process.
posix will however add additional 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 demaning certain actions.
The parent process can signal the subprocess demanding 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` functons that can be used for managed executions.
Process v2 provides `execute` and `async_execute` functions 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 timout{ctx, std::chrono::seconds(10)};
asio::steady_timer timeout{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 a on_success handler might've errored.
//now we check again, because an 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) 2022Klemens Morgernstern
// Copyright (c) 2022 Klemens 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)

View File

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

View File

@@ -5,7 +5,7 @@
/** \file boost/process/async.hpp
The header which provides the basic asynchrounous features.
The header which provides the basic asynchronous 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 asynchrounous version of the system function.
* Defines the asynchronous version of the system function.
*/
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP

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 += '"'; //thats the post one.
arg += '"'; //that is the post one.
}
if (!st.empty())//first one does not need a preceeding space
if (!st.empty())//first one does not need a preceding space
st += ' ';
st += arg;
@@ -112,7 +112,10 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
{
if (exe.empty()) //cmd style
{
exec.exe = args.front().c_str();
if (args.empty())
exec.exe = "";
else
exec.exe = args.front().c_str();
exec.cmd_style = true;
}
else

View File

@@ -77,12 +77,9 @@ public:
void assign_source(native_handle_type h) { _source = h;}
void assign_sink (native_handle_type h) { _sink = h;}
int_type write(const char_type * data, int_type count)
{
int_type write_len;
ssize_t write_len;
while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1)
{
//Try again if interrupted
@@ -90,19 +87,19 @@ public:
if (err != EINTR)
::boost::process::detail::throw_last_error();
}
return write_len;
return static_cast<int_type>(write_len);
}
int_type read(char_type * data, int_type count)
{
int_type read_len;
while ((read_len = static_cast<int_type>(::read(_source, data, count * sizeof(char_type)))) == -1)
ssize_t read_len;
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
{
//Try again if interrupted
auto err = errno;
if (err != EINTR)
::boost::process::detail::throw_last_error();
}
return read_len;
return static_cast<int_type>(read_len);
}
bool is_open() const

View File

@@ -444,7 +444,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
}
if (_ec)
{
//if an error occured we need to reap the child process
//if an error occurred 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, than this one isn't either, obviously.
if (errno != ECHILD) //because it no child is running, then this one isn't either, obviously.
ec = ::boost::process::detail::get_last_error();
return false;
}

View File

@@ -7,8 +7,11 @@
#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>
@@ -26,6 +29,43 @@ class sigchld_service : public boost::asio::detail::service_base<sigchld_service
std::list<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)
@@ -37,47 +77,10 @@ public:
void (int, std::error_code))
async_wait(::pid_t pid, SignalHandler && handler)
{
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();
return boost::asio::async_initiate<
SignalHandler,
void(int, std::error_code)>(
initiate_async_wait_op{this}, handler, pid);
}
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 preceeding space
if (!st.empty())//first one does not need a preceding 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 preceeding space
if (!st.empty())//first one does not need a preceding space
st += L' ';
st += arg;

View File

@@ -158,7 +158,7 @@ basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
::boost::process::detail::throw_last_error("create_named_pipe() failed");
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
name.c_str(),
name_.c_str(),
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read

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.
@@ -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's impossible id is in there.
if (id.size() >= _data.size()) //ok, so it is 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's impossible id is in there.
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
return;
//check if it's the first one, spares us the search.

View File

@@ -12,6 +12,7 @@
#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 {
@@ -163,7 +164,7 @@ struct limit_handles_ : handler_base_ext
}
template<typename Executor>
void on_sucess(Executor & exec) const
void on_success(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

@@ -14,6 +14,8 @@
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/system/error_code.hpp>
namespace boost { namespace process { namespace detail { namespace windows {

View File

@@ -15,11 +15,11 @@
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/system/error_code.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct pipe_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{

View File

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

View File

@@ -263,7 +263,7 @@ public:
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
const int len = std::char_traits<Char>::length(*p);
const std::size_t len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len)
&& std::equal(st1.begin(), st1.end(), *p))
break;
@@ -277,7 +277,7 @@ public:
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
const int len = std::char_traits<Char>::length(*p);
const std::size_t len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len)
&& std::equal(st1.begin(), st1.end(), *p))
break;
@@ -292,8 +292,9 @@ public:
auto st1 = st + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
const int len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len)
const std::size_t len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) <
static_cast<typename string_type::iterator::difference_type>(len))
&& std::equal(st1.begin(), st1.end(), *p))
return 1u;
p++;

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 occured. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter.
///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.
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

@@ -82,7 +82,7 @@ using limit_handles_ = ::boost::process::detail::api::limit_handles_;
}
/**
* The limit_handles property sets all properties to be inherited only expcitly. It closes all unused file-descriptors on posix after the fork and
* The limit_handles property sets all properties to be inherited only explicitly. 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

@@ -122,10 +122,14 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
///Destructor -> writes the frest of the data
~basic_pipebuf()
try
{
if (basic_pipebuf::is_open())
basic_pipebuf::overflow(Traits::eof());
}
catch (process_error & )
{
}
///Move construct from a pipe.
basic_pipebuf(pipe_type && p) : _pipe(std::move(p)),

View File

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

View File

@@ -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 instantitiated with such compilers, but this
// specialization is never instantiated 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.

View File

@@ -13,6 +13,7 @@
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#include <boost/process/v2/detail/utf8.hpp>
#include <boost/type_traits.hpp>
#include <functional>
#include <memory>
#include <numeric>
@@ -488,7 +489,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() noexcept = default;
key() {}
key( const key& p ) = default;
key( key&& p ) noexcept = default;
key( const string_type& source ) : value_(source) {}
@@ -501,8 +502,8 @@ struct key
template< class Source >
key( const Source& source,
decltype(source.data()) = nullptr,
decltype(source.size()) = 0u)
decltype(std::declval<Source>().data()) = nullptr,
decltype(std::declval<Source>().size()) = 0u)
: value_(
BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
source.data(), source.size()))
@@ -524,7 +525,11 @@ struct key
~key() = default;
key& operator=( const key& p ) = default;
key& operator=( key&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
key& operator=( key&& p )
{
value_ = std::move(p.value_);
return *this;
}
key& operator=( string_type&& source )
{
value_ = std::move(source);
@@ -708,7 +713,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() noexcept = default;
value() {}
value( const value& p ) = default;
value( const string_type& source ) : value_(source) {}
@@ -720,8 +725,8 @@ struct value
template< class Source >
value( const Source& source,
decltype(source.data()) = nullptr,
decltype(source.size()) = 0u)
decltype(std::declval<Source>().data()) = nullptr,
decltype(std::declval<Source>().size()) = 0u)
: value_(BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
source.data(), source.size()))
{
@@ -742,7 +747,11 @@ struct value
~value() = default;
value& operator=( const value& p ) = default;
value& operator=( value&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
value& operator=( value&& p )
{
value_ = std::move(p.value_);
return *this;
}
value& operator=( string_type&& source )
{
value_ = std::move(source);
@@ -935,7 +944,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() noexcept = default;
key_value_pair() {}
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 +
@@ -966,8 +975,8 @@ struct key_value_pair
template< class Source >
key_value_pair( const Source& source,
decltype(source.data()) = nullptr,
decltype(source.size()) = 0u)
decltype(std::declval<Source>().data()) = nullptr,
decltype(std::declval<Source>().size()) = 0u)
: value_(BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
source.data(), source.size()))
{
@@ -999,7 +1008,11 @@ struct key_value_pair
~key_value_pair() = default;
key_value_pair& operator=( const key_value_pair& p ) = default;
key_value_pair& operator=( key_value_pair&& p ) noexcept(std::is_nothrow_move_constructible<string_type>::value) = default;
key_value_pair& operator=( key_value_pair&& p )
{
value_ = std::move(p.value_);
return *this;
}
key_value_pair& operator=( string_type&& source )
{
value_ = std::move(source);
@@ -1731,8 +1744,8 @@ struct process_environment
return build_env(env_buffer);
}
process_environment(std::initializer_list<string_view> sv) : unicode_env{build_env(sv, "")} {}
process_environment(std::initializer_list<wstring_view> sv) : unicode_env{build_env(sv, L"")} {}
process_environment(std::initializer_list<string_view> sv) : unicode_env{build_env(sv)} {}
process_environment(std::initializer_list<wstring_view> sv) : unicode_env{build_env(sv)} {}
template<typename Args>
process_environment(Args && args) : unicode_env{build_env(std::forward<Args>(args))}

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 occured during the wait.
* @exception system_error An error that might have occurred 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 intepretations:
* with the following interpretations:
*
* - cancellation_type::total -> interrupt
* - cancellation_type::partial -> request_exit
* - cancellation_type::terminal -> terminate
*
* It is to note that `async_execute` will us the lowest seelected cancellation
* It is to note that `async_execute` will us the lowest selected cancellation
* type. A subprocess might ignore anything not terminal.
*/
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor,

View File

@@ -94,12 +94,19 @@ 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.
/// @{
/** Helper to subsume an exit-code into an error_code if there's no actual error isn't set.
* @code {.cpp}
* process proc{ctx, "exit", {"1"}};
*
* proc.async_wait(code_as_error(
* proc.async_wait(
* asio::deferred(
* [&proc](error_code ec, int)
* {
* return asio::deferred.values(
* check_exit_code(ec, proc.native_exit_code())
* );
*
* [](error_code ec)
* {
* assert(ec.value() == 10);
@@ -107,144 +114,19 @@ inline int evaluate_exit_code(int code)
* }));
*
* @endcode
*/
template<typename CompletionToken>
struct code_as_error_t
*/
inline error_code check_exit_code(
error_code &ec, native_exit_code_type native_code,
const error_category & category = error::get_exit_code_category())
{
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;
};
if (!ec)
BOOST_PROCESS_V2_ASSIGN_EC(ec, native_code, category);
return ec;
}
/// @}
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

@@ -20,6 +20,11 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace ext {
#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
/// @{
/// Get the argument vector of another process
BOOST_PROCESS_V2_DECL shell cmd(pid_type pid, error_code & ec);

View File

@@ -15,6 +15,11 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace ext {
#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
/// @{
/// Obtain the current path of another process
BOOST_PROCESS_V2_DECL filesystem::path cwd(pid_type pid, error_code & ec);
@@ -42,12 +47,6 @@ BOOST_PROCESS_V2_DECL filesystem::path cwd(basic_process_handle<Executor> & hand
/// @}
#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

View File

@@ -109,6 +109,11 @@ struct env_view
detail::ext::native_env_handle_deleter> handle_;
};
#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
/// @{
/// Get the environment of another process.
BOOST_PROCESS_V2_DECL env_view env(pid_type pid, error_code & ec);
@@ -136,10 +141,6 @@ BOOST_PROCESS_V2_DECL env_view env(basic_process_handle<Executor> & handle)
/// @}
#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

View File

@@ -16,6 +16,11 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace ext {
#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
/// @{
/// Return the executable of another process by pid or handle.
BOOST_PROCESS_V2_DECL filesystem::path exe(pid_type pid, error_code & ec);
@@ -45,11 +50,6 @@ filesystem::path exe(basic_process_handle<Executor> & handle)
///@}
#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

View File

@@ -55,7 +55,7 @@ struct exit_code_category final : public error_category
}
std::string message(int status) const
{
switch (status)
switch (evaluate_exit_code(status))
{
case v2::detail::still_active:
return "still-active";

View File

@@ -147,15 +147,14 @@ std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
std::vector<pid_type> all_pids(boost::system::error_code & ec)
{
std::vector<pid_type> vec;
vec.reserve(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0));
if (proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(pid_type) * vec.size()))
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 {};
}
auto itr = std::partition(vec.begin(), vec.end(), [](pid_type pt) {return pt != 0;});
vec.erase(itr, vec.end());
std::reverse(vec.begin(), vec.end());
vec.resize(sz);
return vec;
}
@@ -176,15 +175,14 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
{
std::vector<pid_type> vec;
vec.reserve(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0));
if (proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size()))
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 {};
}
auto itr = std::partition(vec.begin(), vec.end(), [](pid_type pt) {return pt != 0;});
vec.erase(itr, vec.end());
std::reverse(vec.begin(), vec.end());
vec.resize(sz);
return vec;
}

View File

@@ -109,42 +109,6 @@ 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(
executor_type executor,
const filesystem::path& exe,
std::initializer_list<wstring_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
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.
template<typename Args, typename ... Inits>
explicit basic_popen(

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 differnet value.
/// Inherit a file descriptor with as a different 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 openedfile as a set descriptor.
/// Inherit a newly opened-file as a set descriptor.
/**
* This will pass 24 as 42 to the child process:
* @code

View File

@@ -8,6 +8,7 @@
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#include <boost/process/v2/posix/detail/close_handles.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/detail/utf8.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
@@ -313,7 +314,7 @@ struct default_launcher
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "default_launcher");
v2::detail::throw_error(ec, "default_launcher");
return proc;
}
@@ -344,7 +345,7 @@ struct default_launcher
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "default_launcher");
v2::detail::throw_error(ec, "default_launcher");
return proc;
}

View File

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

View File

@@ -29,7 +29,7 @@ struct fork_and_forget_launcher : default_launcher
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "fork_and_forget_launcher");
v2::detail::throw_error(ec, "fork_and_forget_launcher");
return proc;
}
@@ -60,7 +60,7 @@ struct fork_and_forget_launcher : default_launcher
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "fork_and_forget_launcher");
v2::detail::throw_error(ec, "fork_and_forget_launcher");
return proc;
}

View File

@@ -34,7 +34,7 @@ struct pdfork_launcher : default_launcher
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "pdfork_launcher");
v2::detail::throw_error(ec, "pdfork_launcher");
return proc;
}
@@ -65,7 +65,7 @@ struct pdfork_launcher : default_launcher
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "pdfork_launcher");
v2::detail::throw_error(ec, "pdfork_launcher");
return proc;
}

View File

@@ -31,7 +31,7 @@ struct vfork_launcher : default_launcher
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "default_launcher");
v2::detail::throw_error(ec, "default_launcher");
return proc;
}
@@ -62,7 +62,7 @@ struct vfork_launcher : default_launcher
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "default_launcher");
v2::detail::throw_error(ec, "default_launcher");
return proc;
}
@@ -101,7 +101,6 @@ struct vfork_launcher : default_launcher
}
else if (pid == 0)
{
ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_child);
ec = detail::on_exec_setup(*this, executable, argv, inits...);
if (!ec)
close_all_fds(ec);
@@ -110,7 +109,7 @@ struct vfork_launcher : default_launcher
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
detail::on_exec_error(*this, executable, argv, ec, inits...);
::exit(EXIT_FAILURE);
::_exit(EXIT_FAILURE);
return basic_process<Executor>{exec};
}
ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent);

View File

@@ -93,17 +93,7 @@ struct basic_process
: basic_process(default_process_launcher()(std::move(executor), exe, args, std::forward<Inits>(inits)...))
{
}
/// Construct a child from a property list and launch it using the default launcher..
template<typename ... Inits>
explicit basic_process(
executor_type executor,
const filesystem::path& exe,
std::initializer_list<wstring_view> args,
Inits&&... inits)
: basic_process(default_process_launcher()(std::move(executor), exe, args, std::forward<Inits>(inits)...))
{
}
/// Construct a child from a property list and launch it using the default launcher..
template<typename Args, typename ... Inits>
explicit basic_process(
@@ -265,12 +255,12 @@ struct basic_process
{
error_code ec;
if (running(ec))
wait(ec);
process_handle_.wait(exit_status_, ec);
if (ec)
detail::throw_error(ec, "wait failed");
return exit_code();
}
/// Waits for the process to exit, store the exit code internall and return it.
/// Waits for the process to exit, store the exit code internally and return it.
int wait(error_code & ec)
{
if (running(ec))
@@ -287,8 +277,9 @@ struct basic_process
return boost::exchange(process_handle_, get_executor());
#endif
}
// Get the native
/// Get the native
native_handle_type native_handle() {return process_handle_.native_handle(); }
/// Return the evaluated exit_code.
int exit_code() const
{
return evaluate_exit_code(exit_status_);
@@ -334,7 +325,7 @@ struct basic_process
/** Note that this might be a process that already exited.*/
bool is_open() const { return process_handle_.is_open(); }
/// Asynchronously wait for the process to exit and deliver the portable exit-code in the completion handler.
/// Asynchronously wait for the process to exit and deliver the native exit-code in the completion handler.
template <BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void (error_code, int))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, int))

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 explicity, it is encouraged
* that a user runs a sanity check on the executable before launching it.
* By making the shell parsing explicitly, it encourages
* a user to run a sanity check on the executable before launching it.
*
* @par Example
* @code {.cpp}

View File

@@ -103,9 +103,15 @@ struct process_io_binding
template<typename Executor>
process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_readable_pipe<Executor> & readable_pipe,
typename std::enable_if<Target != STD_INPUT_HANDLE, Executor*>::type = 0)
process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_readable_pipe<Executor> & pipe)
{
if (Target == STD_INPUT_HANDLE)
{
auto h_ = pipe.native_handle();
h = std::unique_ptr<void, handle_closer>{h_, get_flags(h_)};
return ;
}
BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::native_pipe_handle p[2];
error_code ec;
BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::create_pipe(p, ec);
@@ -113,14 +119,19 @@ struct process_io_binding
detail::throw_error(ec, "create_pipe");
h = std::unique_ptr<void, handle_closer>{p[1], true};
readable_pipe.assign(p[0]);
pipe.assign(p[0]);
}
template<typename Executor>
process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor> & writable_pipe,
typename std::enable_if<Target == STD_INPUT_HANDLE, Executor*>::type = 0)
process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor> & pipe)
{
if (Target != STD_INPUT_HANDLE)
{
auto h_ = pipe.native_handle();
h = std::unique_ptr<void, handle_closer>{h_, get_flags(h_)};
return ;
}
BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::native_pipe_handle p[2];
error_code ec;
BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::create_pipe(p, ec);
@@ -128,7 +139,7 @@ struct process_io_binding
detail::throw_error(ec, "create_pipe");
h = std::unique_ptr<void, handle_closer>{p[0], true};
writable_pipe.assign(p[1]);
pipe.assign(p[1]);
}
};
@@ -170,13 +181,19 @@ struct process_io_binding
}
template<typename Executor>
process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_readable_pipe<Executor> & readable_pipe,
typename std::enable_if<Target != STDIN_FILENO, Executor*>::type = 0)
process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_readable_pipe<Executor> & readable_pipe)
{
if (Target == STDIN_FILENO)
{
fd = readable_pipe.native_handle();
return ;
}
BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::native_pipe_handle p[2];
BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::create_pipe(p, ec);
if (ec)
return ;
detail::throw_error(ec, "create_pipe");
fd = p[1];
if (::fcntl(p[0], F_SETFD, FD_CLOEXEC) == -1)
{
@@ -189,13 +206,20 @@ struct process_io_binding
template<typename Executor>
process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor> & writable_pipe,
typename std::enable_if<Target == STDIN_FILENO, Executor*>::type = 0)
process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor> & writable_pipe)
{
if (Target != STDIN_FILENO)
{
fd = writable_pipe.native_handle();
return ;
}
BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::native_pipe_handle p[2];
error_code ec;
BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::create_pipe(p, ec);
if (ec)
return ;
detail::throw_error(ec, "create_pipe");
fd = p[0];
if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
{
@@ -265,7 +289,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 comptaiblie with the above. E.g. a asio::ip::tcp::socket
* - any io-object with a .native_handle() function that is compatible 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

@@ -37,7 +37,7 @@ struct as_user_launcher : default_launcher
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "as_user_launcher");
v2::detail::throw_error(ec, "as_user_launcher");
return proc;
}
@@ -68,7 +68,7 @@ struct as_user_launcher : default_launcher
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "as_user_launcher");
detail::throw_error(ec, "as_user_launcher");
return proc;
}

View File

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

View File

@@ -14,6 +14,7 @@
#include <boost/process/v2/cstring_ref.hpp>
#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/detail/utf8.hpp>
#include <boost/process/v2/error.hpp>
@@ -244,7 +245,7 @@ struct default_launcher
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "default_launcher");
v2::detail::throw_error(ec, "default_launcher");
return proc;
}
@@ -275,7 +276,7 @@ struct default_launcher
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "default_launcher");
detail::throw_error(ec, "default_launcher");
return proc;
}
@@ -311,7 +312,6 @@ struct default_launcher
&startup_info.StartupInfo,
&process_information);
auto ec__ = detail::get_last_error();
if (ok == 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)

View File

@@ -66,7 +66,7 @@ namespace windows
{
if (wc == L'"')
*(itr++) = L'\\';
*(itr++) = wc;
*(itr++) = wc;
}
*(itr ++) = L'"';

View File

@@ -20,7 +20,7 @@ namespace windows
/// A windows launcher using CreateProcessWithLogon instead of CreateProcess
struct with_logon_launcher : default_launcher
{
std::wstring username, domain, password;
std::wstring username, password, domain;
DWORD logon_flags{0u};
with_logon_launcher(std::wstring username = L"",
@@ -72,7 +72,7 @@ struct with_logon_launcher : default_launcher
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "with_logon_launcher");
v2::detail::throw_error(ec, "with_logon_launcher");
return proc;
}

View File

@@ -38,7 +38,7 @@ struct with_token_launcher : default_launcher
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "with_token_launcher");
v2::detail::throw_error(ec, "with_token_launcher");
return proc;
}
@@ -69,7 +69,7 @@ struct with_token_launcher : default_launcher
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
asio::detail::throw_error(ec, "with_token_launcher");
detail::throw_error(ec, "with_token_launcher");
return proc;
}

View File

@@ -1,6 +1,6 @@
//
// Created by kleme on 26.02.2018.
//
// 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)
#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 (int i = 0; i < std::thread::hardware_concurrency(); i++)
for (auto i = 0u; i < std::thread::hardware_concurrency(); i++)
{
threads.emplace_back([&ioc]
{
@@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(move_pipe)
}
/*
{
//copy an a closed pipe
//copy 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 an a closed pipe
//copy 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(excplicit)
BOOST_AUTO_TEST_CASE(explicit_)
{
using boost::unit_test::framework::master_test_suite;

View File

@@ -78,7 +78,7 @@ 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();
g.wait(ec);
BOOST_CHECK(!c1.running());
BOOST_CHECK(!c2.running());
@@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(wait_group_test_timeout, *boost::unit_test::timeout(15))
bp::child c2(
master_test_suite().argv[1],
"--wait", "4",
"--wait", "5",
g,
ec
);

View File

@@ -97,7 +97,8 @@ BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5))
#if defined( BOOST_WINDOWS_API )
std::thread thr([]{});
BOOST_CHECK(!bt::is_stream_handle(thr.native_handle(), ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_CHECK(!bt::is_stream_handle(::GetCurrentProcess(), ec));
BOOST_CHECK_MESSAGE(!ec, ec.message());
thr.join();
#else
# if defined(TFD_CLOEXEC) //check timer

View File

@@ -23,6 +23,7 @@
#include <iterator>
#include <iostream>
#include <cstdlib>
#include <thread>
#if defined(BOOST_POSIX_API)
# include <boost/lexical_cast.hpp>
# include <boost/iostreams/device/file_descriptor.hpp>
@@ -148,7 +149,8 @@ int main(int argc, char *argv[])
}
else if (vm["loop"].as<bool>())
{
while (true);
while (true)
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
else if (vm["abort"].as<bool>())
{

View File

@@ -24,15 +24,6 @@ namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(terminate_set_on_error, *boost::unit_test::timeout(5))
{
std::atomic<bool> done{false};
std::thread thr{
[&]
{
for (int i = 0; i < 50 && !done.load(); i++)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
BOOST_REQUIRE(done.load());
}};
using boost::unit_test::framework::master_test_suite;
std::error_code ec;
bp::child c(
@@ -44,31 +35,14 @@ BOOST_AUTO_TEST_CASE(terminate_set_on_error, *boost::unit_test::timeout(5))
BOOST_CHECK(c.valid());
BOOST_CHECK(c.running(ec));
BOOST_CHECK(!c.wait_for(std::chrono::milliseconds(100), ec));
BOOST_CHECK(c.running(ec));
BOOST_CHECK(c.valid());
c.terminate(ec);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::milliseconds(25));
BOOST_CHECK(!c.running(ec));
BOOST_CHECK(!ec);
done.store(true);
thr.join();
}
BOOST_AUTO_TEST_CASE(terminate_throw_on_error, *boost::unit_test::timeout(5))
{
std::atomic<bool> done{false};
std::thread thr{
[&]
{
for (int i = 0; i < 50 && !done.load(); i++)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
BOOST_REQUIRE(done.load());
}};
using boost::unit_test::framework::master_test_suite;
std::error_code ec;
@@ -79,17 +53,10 @@ BOOST_AUTO_TEST_CASE(terminate_throw_on_error, *boost::unit_test::timeout(5))
ec
);
BOOST_REQUIRE(!ec);
BOOST_CHECK(c.valid());
BOOST_CHECK(c.running());
BOOST_CHECK(!c.wait_for(std::chrono::milliseconds(100), ec));
BOOST_CHECK(c.running(ec));
BOOST_CHECK(c.valid());
c.terminate();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
std::this_thread::sleep_for(std::chrono::milliseconds(25));
BOOST_CHECK(!c.running());
done.store(true);
thr.join();
}

View File

@@ -13,6 +13,7 @@ if [ os.name ] = NT
lib Advapi32 ;
lib Ntdll ;
lib user32 ;
lib Bcrypt ;
}
project : requirements
@@ -29,6 +30,7 @@ project : requirements
<target-os>bsd:<linkflags>-lkvm
<os>NT,<toolset>cw:<library>ws2_32
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>Bcrypt
<define>BOOST_PROCESS_V2_SEPARATE_COMPILATION=1
;
@@ -59,11 +61,11 @@ test-suite standalone :
[ run utf8.cpp test_impl ]
[ run cstring_ref.cpp test_impl ]
[ run environment.cpp test_impl ]
[ run pid.cpp test_impl : : : <target-os>darwin:<build>no ]
[ 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

@@ -62,7 +62,8 @@ BOOST_AUTO_TEST_CASE(environment)
ec.clear();
for (auto && ke : bpe::current())
BOOST_CHECK_EQUAL(bpe::get(std::get<0>(ke)), std::get<1>(ke));
if (!std::get<1>(ke).empty())
BOOST_CHECK_EQUAL(bpe::get(std::get<0>(ke)), std::get<1>(ke));
#if defined(BOOST_PROCESS_V2_POSIX)
@@ -150,7 +151,11 @@ BOOST_AUTO_TEST_CASE(wenvironment)
BOOST_CHECK(ec);
for (const auto ke : bpe::current())
{
std::string key = std::get<0>(ke).string();
if (!std::get<1>(ke).empty())
BOOST_CHECK_EQUAL(bpe::get(std::get<0>(ke)), std::get<1>(ke));
}
#if defined(BOOST_PROCESS_V2_WINDOWS)
BOOST_CHECK_EQUAL(bpe::key(L"FOO"), bpe::key_view(L"Foo"));

View File

@@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(cmd_exe)
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()), pth);
BOOST_REQUIRE_EQUAL(cm.argc(), args.size() + 1);
for (auto i = 0; i < args.size(); i++)
for (auto i = 0u; i < args.size(); i++)
{
ref = cm.argv()[i + 1];

View File

@@ -5,10 +5,12 @@
// 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)
@@ -22,21 +24,28 @@ BOOST_AUTO_TEST_CASE(test_pid)
BOOST_CHECK_GT(all.size(), 0u);
BOOST_CHECK(itr != all.end());
std::vector<bp2::pid_type> children, grand_children;
auto grand_child_pids = [](bp2::pid_type pid,
std::vector<bp2::pid_type> & children,
std::vector<bp2::pid_type> & grand_children)
{
children = bp2::child_pids(pid);
for (unsigned i = 0; i < children.size(); i++)
{
std::vector<bp2::pid_type> tmp1;
std::vector<bp2::pid_type> tmp2 = bp2::child_pids(children[i]);
tmp1.insert(std::end(tmp1), std::begin(tmp2), std::end(tmp2));
grand_children = tmp1;
}
return (!children.empty() || !grand_children.empty());
};
BOOST_CHECK_NE(grand_child_pids(bp2::root_pid, children, grand_children), false);
}
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(100));
auto cs = bp2::child_pids(bp2::current_pid());
boost::asio::io_context ctx;
bp2::process proc(ctx, pth, {"loop"});
std::this_thread::sleep_for(std::chrono::milliseconds(100));
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

@@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(request_exit)
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);
bpv::process proc(ctx, sh, {}, bpv::process_stdio{wp}
bpv::process proc(ctx, sh, {}, bpv::process_stdio{rp}
#if defined(ASIO_WINDOWS)
, asio::windows::show_window_minimized_not_active
#endif
@@ -371,27 +371,26 @@ BOOST_AUTO_TEST_CASE(popen)
asio::io_context ctx;
asio::readable_pipe rp{ctx};
// default CWD
bpv::popen proc(/*bpv::default_process_launcher(), */ctx, pth, {"echo"});
asio::write(proc, asio::buffer("FOOBAR"));
BOOST_CHECK_EQUAL(asio::write(proc, asio::buffer("FOOBAR", 6)), 6);
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);
n += asio::read(proc, asio::dynamic_buffer(res), ec);
BOOST_CHECK_MESSAGE(ec == asio::error::eof || ec == asio::error::broken_pipe, ec.message());
BOOST_CHECK_MESSAGE(ec == asio::error::eof
|| ec == asio::error::broken_pipe,
ec.message());
BOOST_REQUIRE_GE(n, 1u);
// remove EOF
res.pop_back();
BOOST_CHECK_EQUAL(res, "FOOBAR");
proc.get_stdin().close();
proc.wait();
BOOST_CHECK_MESSAGE(proc.exit_code() == 0, proc.exit_code());
}
@@ -424,6 +423,11 @@ BOOST_AUTO_TEST_CASE(print_other_cwd)
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);
@@ -515,13 +519,34 @@ BOOST_AUTO_TEST_CASE(exit_code_as_error)
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());}));
proc1.async_wait(
[&](bpv::error_code ec, int)
{
called ++;
bpv::check_exit_code(ec, proc1.native_exit_code());
BOOST_CHECK(!ec);
});
proc2.async_wait(
[&](bpv::error_code ec, int)
{
called ++;
bpv::check_exit_code(ec, proc2.native_exit_code());
BOOST_CHECK_MESSAGE(ec, ec.message());
});
proc3.async_wait(
[&](bpv::error_code ec, int)
{
called ++;
bpv::check_exit_code(ec, proc3.native_exit_code());
BOOST_CHECK_MESSAGE(ec, ec.message());
});
ctx.run();
BOOST_CHECK_EQUAL(called, 3);
}
BOOST_AUTO_TEST_CASE(bind_launcher)
@@ -532,17 +557,13 @@ BOOST_AUTO_TEST_CASE(bind_launcher)
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();
bpv::process proc = l(ctx, pth, args, bpv::process_stdio{/*.in=*/{}, /*.out=*/rp});
std::string out;
bpv::error_code ec;
@@ -551,8 +572,12 @@ BOOST_AUTO_TEST_CASE(bind_launcher)
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_REQUIRE(sz != 0);
if (out.back() != '/' && target.string().back() == '/')
out += '/';
BOOST_CHECK_MESSAGE(bpv::filesystem::path(out) == target,
bpv::filesystem::path(out) << " != " << target);