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

Compare commits

...

127 Commits

Author SHA1 Message Date
Samuel Venable
1873f34435 Fix V2::EXT::CWD [SunOS] (#310)
* Fix V2::EXT::CWD [SunOS]

filesystem::canonical is basically the same thing as realpath on Unix-likes, which only resolves one symbolic link. If one symbolic link points to yet another symbolic link and so on and so forth, it will not resolve all symbolic links. It will only do one link for each call to canonical. On SunOS, unlike Linux, /proc/${pid}/cwd does not directly point to the literal current working directory of the given ${pid}. Instead, it will point to yet another symlink - /proc/${pid}/path/cwd which once you have followed that second link only then will you have the literal cwd path for the process id.
2023-10-12 21:43:59 +08:00
Ilia
5f795d9e62 Fix compilation for macOS 14 SDK
Fixes #342
2023-10-09 10:46:25 +08:00
Daniel Richard G
f17be678f2 fix group_wait test in cmake build. 2023-10-09 10:46:03 +08:00
AJIOB
b9fc531507 Code typos fix 2023-10-05 09:36:50 +08:00
Klemens Morgenstern
69c2c25729 added SIGTERM bit mask for freeBSD. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
8ab2332327 v2/env win test fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
ea69cda6d8 added can_interrupt check on windows to win tests. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
6b75b4039f increased timeout & added diagnostics. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
3c1beb40f6 windows move handle fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
e51970e3bb fixed windows interrupt & request_exit test. 2023-10-05 06:52:20 +08:00
Klemens
f3f8548dea allowing for SIGTERM in exit code on posix interrupts. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
4b7a00d4cf target: global timer workaround helper. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
c11f31d77e drone windows update. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
3769ec01f4 process native-exit code test. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
af47f4677c creation-flags fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
cf14d54343 pid no-access workarounds. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
b81cac8042 moved interrupt & request_exit into target. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
c92cce3652 cmd.ipp return fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
d270712fba link error fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
7b6b93691f fixed executor reset_cancellation_state.
Closes #338.
2023-10-05 06:52:20 +08:00
Shauren
507768e230 Fixed compile warning on msvc 2023-09-14 08:09:35 +08:00
SilverPlate3
502dc48753 Pass empty argument
closes #256
2023-08-14 17:47:17 +08:00
Ed Tanous
402acc151a Use boost::throw_exception
Using boost::throw_exception allows for modifications to these
exceptions on a per-application basis, including overriding with custom
implementations.

This also has the benefit of allowing compilation with -fno-exceptions
set, which should make this code more portable.
2023-08-14 17:41:37 +08:00
Roberto Rodriguez
0503b0997c Fix compilation with -Wall and -Werror 2023-08-14 17:41:00 +08:00
Klemens Morgenstern
8d372cb510 v2::environment link fixes 2023-08-14 17:28:54 +08:00
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
117 changed files with 4744 additions and 766 deletions

View File

@@ -14,17 +14,18 @@ windowsglobalimage="cppalliance/dronevs2019"
def main(ctx):
return [
#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),
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),
linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True),
linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={ 'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '17ba079169m'}, arch="arm64", globalenv=globalenv),
linux_cxx("GCC 10, Debug + Coverage", "g++-10", packages="g++-10 libssl-dev libffi-dev binutils-gold gdb mlocate",
#linux_cxx("gcc 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:
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev mlocate", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
linux_cxx("Default g++", "g++", packages="mlocate", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev mlocate", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
linux_cxx("Default g++", "g++", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
linux_cxx("gcc 6", "g++-6", packages="g++-6", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'B2_TOOLSET': 'gcc-6', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
linux_cxx("clang 3.8", "clang++-3.8", packages="clang-3.8", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'B2_TOOLSET': 'clang', 'COMPILER': 'clang++-3.8', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '7b52009b64'}, globalenv=globalenv),
osx_cxx("clang", "g++", packages="", buildtype="boost", buildscript="drone", environment={'B2_TOOLSET': 'clang', 'B2_CXXSTD': '11,17', 'DRONE_JOB_UUID': '91032ad7bb'}, globalenv=globalenv),

View File

@@ -26,9 +26,7 @@ set B2_TARGETS=libs/!SELF!/test
cd !BOOST_ROOT!
call bootstrap.bat
b2 headers
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test -j3
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/example -j3
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test libs/!SELF!/example -j3
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
REM not used

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

1
.gitignore vendored
View File

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

View File

@@ -8,4 +8,6 @@ A special thank you goes to [@http://www.intra2net.com/ Intra2net AG] (especiall
Great thanks also goes to Boris Schaeling, who despite having boost.process rejected, went on to work on it and maintained it up until this day and participated in the development of the current version.
Many Thanks, to [@https://github.com/time-killer-games Samuel Venable] for contributing the v2::ext functionality and all the research that went into it.
[endsect]

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

@@ -83,7 +83,7 @@ will be called on the respective events on process launching. The names are:
As an example:
```
child c("ls", on_setup([](){cout << "On Setup" << endl;});
child c("ls", on_setup([](){cout << "On Setup" << endl;}));
```

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

@@ -348,7 +348,7 @@ and use the following code, the `gcc` process will still run afterwards:
```
bp::child c("make");
if (!c.child_wait_for(std::chrono::seconds(10)) //give it 10 seconds
if (!c.child_wait_for(std::chrono::seconds(10))) //give it 10 seconds
c.child_terminate(); //then terminate
```
@@ -357,7 +357,7 @@ So in order to also terminate `gcc` we can use a group.
```
bp::group g;
bp::child c("make", g);
if (!g.group_wait_for(std::chrono::seconds(10))
if (!g.group_wait_for(std::chrono::seconds(10)))
g.group_terminate();
c.child_wait(); //to avoid a zombie process & get the exit code

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.
@@ -20,8 +20,8 @@ To note is the `find_executable` functions, which searches in an environment for
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"}
{"PATH", {"/bin", "/usr/bin"}
{"SECRET", "THIS_IS_A_TEST"},
{"PATH", {"/bin", "/usr/bin"}}
};
auto other_exe = environment::find_executable("g++", my_env);
@@ -35,10 +35,10 @@ The subprocess environment assignment follows the same constraints:
asio::io_context ctx;
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"}
{"PATH", {"/bin", "/usr/bin"}
{"SECRET", "THIS_IS_A_TEST"},
{"PATH", {"/bin", "/usr/bin"}}
};
auto exe = find_executable("g++"), my_env);
auto exe = find_executable("g++");
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
```

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

@@ -1,4 +1,4 @@
[section:quickstart Quickstrat]
[section:quickstart Quickstart]
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 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"}),
@@ -114,7 +114,6 @@ The async version supports cancellation and will forward cancellation types as f
if (!ec)
sig.emit(asio::cancellation_type::terminal);
});
);
});
```

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
@@ -38,12 +38,11 @@ namespace process {
namespace detail
{
template<typename ExitHandler>
template<typename Handler>
struct async_system_handler : ::boost::process::detail::api::async_handler
{
boost::asio::io_context & ios;
boost::asio::async_completion<
ExitHandler, void(boost::system::error_code, int)> init;
Handler handler;
#if defined(BOOST_POSIX_API)
bool errored = false;
@@ -52,9 +51,8 @@ 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), init(exit_handler)
ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
{
}
@@ -64,21 +62,15 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
#if defined(BOOST_POSIX_API)
errored = true;
#endif
auto & h = init.completion_handler;
auto h = std::make_shared<Handler>(std::move(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&)
{
@@ -86,10 +78,10 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
if (errored)
return [](int , const std::error_code &){};
#endif
auto & h = init.completion_handler;
auto h = std::make_shared<Handler>(std::move(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);
};
}
};
@@ -120,21 +112,36 @@ 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");
child(ios, std::forward<Args>(args)..., async_h ).detach();
return async_h.get_result();
return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
);
}

View File

@@ -125,7 +125,10 @@ public:
boost::process::detail::throw_error(ec, "wait error");
}
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
template< class Rep, class Period >
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
{
std::error_code ec;
@@ -135,6 +138,7 @@ public:
}
template< class Clock, class Duration >
BOOST_DEPRECATED("wait_until is unreliable")
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
{
std::error_code ec;
@@ -142,6 +146,7 @@ public:
boost::process::detail::throw_error(ec, "wait_until error");
return b;
}
#endif
bool running(std::error_code & ec) noexcept
{
@@ -178,13 +183,16 @@ public:
}
}
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
template< class Rep, class Period >
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
{
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Clock, class Duration >
BOOST_DEPRECATED("wait_until is unreliable")
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
{
if (!_exited())
@@ -197,7 +205,7 @@ public:
}
return true;
}
#endif
bool valid() const
{

View File

@@ -21,7 +21,9 @@
#include <system_error>
#include <boost/system/api_config.hpp>
#include <boost/throw_exception.hpp>
#include <boost/process/exception.hpp>
#include <boost/assert/source_location.hpp>
#if defined(BOOST_POSIX_API)
#include <errno.h>
@@ -71,31 +73,33 @@ inline std::error_code get_last_error() noexcept
}
#endif
inline void throw_last_error(const std::string & msg)
inline void throw_last_error(const std::string & msg, boost::source_location const & loc = boost::source_location())
{
throw process_error(get_last_error(), msg);
boost::throw_exception(process_error(get_last_error(), msg), loc);
}
inline void throw_last_error(const char * msg)
inline void throw_last_error(const char * msg, boost::source_location const & loc = boost::source_location())
{
throw process_error(get_last_error(), msg);
boost::throw_exception(process_error(get_last_error(), msg), loc);
}
inline void throw_last_error()
inline void throw_last_error(boost::source_location const & loc = boost::source_location())
{
throw process_error(get_last_error());
boost::throw_exception(process_error(get_last_error()), loc);
}
inline void throw_error(const std::error_code& ec)
inline void throw_error(const std::error_code& ec,
boost::source_location const & loc = boost::source_location())
{
if (ec)
throw process_error(ec);
boost::throw_exception(process_error(ec), loc);
}
inline void throw_error(const std::error_code& ec, const char* msg)
inline void throw_error(const std::error_code& ec, const char* msg,
boost::source_location const & loc = boost::source_location())
{
if (ec)
throw process_error(ec, msg);
boost::throw_exception(process_error(ec, msg), loc);
}
template<typename Char> constexpr Char null_char();
@@ -114,6 +118,8 @@ template<typename Char> constexpr Char space_sign();
template<> constexpr char space_sign<char> () {return ' '; }
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
}
}
}
}}}
#endif

View File

@@ -71,7 +71,7 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
}
template <typename Executor>
inline void on_success(Executor &exec)
inline void on_success(Executor &)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,

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
@@ -139,7 +142,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,13 +158,15 @@ private:
std::vector<char*> exe_cmd_init<char>::make_cmd()
{
// any string must be writable.
static char empty_string[1] = "";
std::vector<char*> vec;
if (!exe.empty())
vec.push_back(&exe.front());
vec.push_back(exe.empty() ? empty_string : &exe.front());
if (!args.empty()) {
for (auto & v : args)
vec.push_back(&v.front());
vec.push_back(v.empty() ? empty_string : &v.front());
}
vec.push_back(nullptr);

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

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

View File

@@ -33,7 +33,7 @@ inline std::vector<native_handle_type> get_handles(std::error_code & ec)
else
ec.clear();
auto my_fd = ::dirfd(dir.get());
auto my_fd = dirfd(dir.get());
struct ::dirent * ent_p;
@@ -117,7 +117,7 @@ struct limit_handles_ : handler_base_ext
return;
}
auto my_fd = ::dirfd(dir);
auto my_fd = dirfd(dir);
struct ::dirent * ent_p;
while ((ent_p = readdir(dir)) != nullptr)

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

@@ -27,7 +27,11 @@ inline boost::process::filesystem::path search_path(
for (const boost::process::filesystem::path & pp : path)
{
auto p = pp / filename;
#if defined(BOOST_PROCESS_USE_STD_FS)
std::error_code ec;
#else
boost::system::error_code ec;
#endif
bool file = boost::process::filesystem::is_regular_file(p, ec);
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
return p;

View File

@@ -7,14 +7,18 @@
#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 {
@@ -23,8 +27,45 @@ class sigchld_service : public boost::asio::detail::service_base<sigchld_service
boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
inline void _handle_signal(const boost::system::error_code & ec);
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)
@@ -36,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

@@ -61,8 +61,12 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
arg += '"';
}
}
else
{
arg = "\"\"";
}
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;
@@ -105,8 +109,12 @@ inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstrin
arg += '"';
}
}
else
{
arg = L"\"\"";
}
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.
@@ -90,12 +90,12 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
else
return std::basic_string<Char>(
buf.data(), buf.data()+ size + 1);
buf.data(), buf.data()+ size);
}
}
return std::basic_string<Char>(buf, buf+size+1);
return std::basic_string<Char>(buf, buf+size);
}
template<typename Char>
@@ -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

@@ -35,7 +35,9 @@ inline boost::process::filesystem::path search_path(
[&](const value_type & e)
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
auto extensions_in = itr->to_vector();
std::vector<std::wstring> extensions_in;
if (itr != ne.cend())
extensions_in = itr->to_vector();
std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1);
@@ -61,7 +63,11 @@ inline boost::process::filesystem::path search_path(
{
boost::process::filesystem::path pp_ext = p;
pp_ext += ext;
#if defined(BOOST_PROCESS_USE_STD_FS)
std::error_code ec;
#else
boost::system::error_code ec;
#endif
bool file = boost::process::filesystem::is_regular_file(pp_ext, ec);
if (!ec && file &&
::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))

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

@@ -122,9 +122,11 @@ public:
{
boost::process::detail::api::wait(_group_handle, ec);
}
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
/** Wait for the process group to exit for period of time.
* \return True if all child processes exited while waiting.*/
template< class Rep, class Period >
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
{
return boost::process::detail::api::wait_for(_group_handle, rel_time);
@@ -132,6 +134,7 @@ public:
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
template< class Rep, class Period >
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
{
return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
@@ -140,17 +143,19 @@ public:
/** Wait for the process group to exit until a point in time.
* \return True if all child processes exited while waiting.*/
template< class Clock, class Duration >
BOOST_DEPRECATED("wait_until is unreliable")
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
{
return boost::process::detail::api::wait_until(_group_handle, timeout_time);
}
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
template< class Clock, class Duration >
BOOST_DEPRECATED("wait_until is unreliable")
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
{
return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
}
#endif
///Check if the group has a valid handle.
bool valid() const
{

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

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

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

@@ -0,0 +1,240 @@
//
// 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 std::out_of_range("cstring-view out of range");
throw_exception(std::out_of_range("cstring-view out of range"));
return view_[pos];
}
BOOST_CONSTEXPR const_reference front() const {return *view_;}

View File

@@ -7,18 +7,19 @@
#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
@@ -39,18 +40,19 @@
#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
@@ -72,11 +74,9 @@
#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,6 +97,14 @@ namespace filesystem = std::filesystem;
using std::quoted;
using std::optional;
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category()); \
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) ec.assign(__VA_ARGS__);
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error()); \
#else
using boost::system::error_code ;
@@ -112,6 +120,25 @@ namespace filesystem = std::filesystem;
namespace filesystem = boost::filesystem;
#endif
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category(), &loc##__LINE__); \
}
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
ec.assign(__VA_ARGS__, &loc##__LINE__); \
}
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(), &loc##__LINE__); \
}
#endif
BOOST_PROCESS_V2_END_NAMESPACE
@@ -142,7 +169,7 @@ BOOST_PROCESS_V2_END_NAMESPACE
#endif
#endif
#if defined(__FreeBSD__) && !defined(BOOST_PROCESS_V2_DISABLE_PDFORK)
#if defined(__FreeBSD__) && defined(BOOST_PROCESS_V2_ENABLE_PDFORK)
#define BOOST_PROCESS_V2_PDFORK 1
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif
@@ -150,6 +177,4 @@ BOOST_PROCESS_V2_END_NAMESPACE
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif
#endif //BOOST_PROCESS_V2_DETAIL_CONFIG_HPP

View File

@@ -14,7 +14,7 @@
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
#if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
extern "C" { extern char **environ; }
#endif
@@ -77,4 +77,4 @@ BOOST_PROCESS_V2_DECL bool is_executable(const filesystem::path & pth, error_cod
BOOST_PROCESS_V2_END_NAMESPACE
#endif
#endif

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)
{
ec.assign(ENOENT, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOENT, system_category())
return {};
}
return res;
@@ -45,13 +45,13 @@ void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
if (::setenv(key.c_str(), value.c_str(), true))
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec)
{
if (::unsetenv(key.c_str()))
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}

View File

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

View File

@@ -28,20 +28,6 @@ error_code get_last_error()
}
void throw_last_error()
{
throw system_error(get_last_error());
}
void throw_last_error(const char * msg)
{
throw system_error(get_last_error(), msg);
}
void throw_last_error(const std::string & msg)
{
throw system_error(get_last_error(), msg);
}
}
BOOST_PROCESS_V2_END_NAMESPACE

View File

@@ -9,9 +9,20 @@
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/detail/process_handle_windows.hpp>
#include <boost/process/v2/ext/detail/proc_info.hpp>
#include <windows.h>
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
extern "C"
{
LONG WINAPI NtResumeProcess(HANDLE ProcessHandle);
LONG WINAPI NtSuspendProcess(HANDLE ProcessHandle);
}
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
@@ -23,7 +34,7 @@ void get_exit_code_(
error_code & ec)
{
if (!::GetExitCodeProcess(handle, &exit_code))
ec = detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
@@ -31,7 +42,12 @@ HANDLE open_process_(DWORD pid)
{
auto proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
if (proc == nullptr)
detail::throw_last_error("open_process()");
{
error_code ec;
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
throw system_error(ec, "open_process()");
}
return proc;
}
@@ -40,17 +56,17 @@ void terminate_if_running_(HANDLE handle)
{
DWORD exit_code = 0u;
if (handle == INVALID_HANDLE_VALUE)
return ;
return ;
if (::GetExitCodeProcess(handle, &exit_code))
if (exit_code == STILL_ACTIVE)
::TerminateProcess(handle, 260);
if (exit_code == STILL_ACTIVE)
::TerminateProcess(handle, 260);
}
bool check_handle_(HANDLE handle, error_code & ec)
{
if (handle == INVALID_HANDLE_VALUE)
{
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
return false;
}
return true;
@@ -60,8 +76,8 @@ bool check_pid_(pid_type pid_, error_code & ec)
{
if (pid_ == 0)
{
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
return false;
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
return false;
}
return true;
}
@@ -73,46 +89,73 @@ struct enum_windows_data_t
};
static BOOL CALLBACK enum_window(HWND hwnd, LPARAM param)
{
{
auto data = reinterpret_cast<enum_windows_data_t*>(param);
DWORD pid{0u};
GetWindowThreadProcessId(hwnd, &pid);
if (pid != data->pid)
return TRUE;
return TRUE;
LRESULT res = ::SendMessageW(hwnd, WM_CLOSE, 0, 0);
if (!res)
data->ec = detail::get_last_error();
return res != 0;
}
if (res)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(data->ec)
return res == 0;
}
void request_exit_(pid_type pid_, error_code & ec)
{
enum_windows_data_t data{ec, pid_};
if (!::EnumWindows(enum_window, reinterpret_cast<LONG_PTR>(&data)))
ec = detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void interrupt_(pid_type pid_, error_code & ec)
{
if (!::GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid_))
ec = detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void terminate_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::TerminateProcess(handle, 260))
ec = detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void check_running_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::GetExitCodeProcess(handle, &exit_status))
ec = detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
void suspend_(HANDLE handle, error_code & ec)
{
auto nt_err = NtSuspendProcess(handle);
ULONG dos_err = RtlNtStatusToDosError(nt_err);
if (dos_err)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void resume_(HANDLE handle, error_code & ec)
{
auto nt_err = NtResumeProcess(handle);
ULONG dos_err = RtlNtStatusToDosError(nt_err);
if (dos_err)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
#else
void suspend_(HANDLE, error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
}
void resume_(HANDLE handle, error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
}
#endif
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
template struct basic_process_handle_win<>;

View File

@@ -27,13 +27,13 @@ inline void handle_error(error_code & ec)
switch (err)
{
case ERROR_INSUFFICIENT_BUFFER:
ec.assign(error::insufficient_buffer, error::utf8_category);
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::utf8_category)
break;
case ERROR_NO_UNICODE_TRANSLATION:
ec.assign(error::invalid_character, error::utf8_category);
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::utf8_category)
break;
default:
ec.assign(err, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
}
}
@@ -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.
@@ -242,7 +242,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
if (*from > max_wchar) {
from_next = from;
to_next = to;
ec.assign(error::invalid_character, error::get_utf8_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
@@ -270,7 +270,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
if (to == to_end && i != cont_octet_count) {
from_next = from;
to_next = to - (i + 1);
ec.assign(error::insufficient_buffer, error::get_utf8_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return 0u;
}
++from;
@@ -280,7 +280,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
// Were we done or did we run out of destination space
if (from != from_end)
ec.assign(error::insufficient_buffer, error::get_utf8_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return to_next - out;
}
@@ -315,7 +315,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
if (invalid_leading_octet(*from)) {
from_next = from;
to_next = to;
ec.assign(error::invalid_character, error::get_utf8_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
@@ -339,7 +339,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
if (invalid_continuing_octet(*from)) {
from_next = from;
to_next = to;
ec.assign(error::invalid_character, error::get_utf8_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
@@ -356,7 +356,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
// rewind "from" to before the current character translation
from_next = from - (i + 1);
to_next = to;
ec.assign(error::insufficient_buffer, error::get_utf8_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return 0u;
}
*to++ = ucs_result;
@@ -365,7 +365,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
to_next = to;
if (from != from_end)
ec.assign(error::insufficient_buffer, error::get_utf8_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return to_next - out;
}

View File

@@ -9,14 +9,13 @@
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail {
namespace detail
{
BOOST_PROCESS_V2_DECL error_code get_last_error();
BOOST_PROCESS_V2_DECL void throw_last_error();
BOOST_PROCESS_V2_DECL void throw_last_error(const char * msg);
BOOST_PROCESS_V2_DECL void throw_last_error(const std::string & msg);
}
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)

View File

@@ -101,6 +101,8 @@ struct basic_process_handle_fd
pid_type id() const
{ return pid_; }
native_handle_type native_handle() {return pid_;}
void terminate_if_running(error_code &)
{
if (pid_ <= 0)
@@ -182,7 +184,42 @@ struct basic_process_handle_fd
if (ec)
detail::throw_error(ec, "request_exit");
}
void suspend()
{
if (pid_ <= 0)
return ;
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
void suspend(error_code &ec)
{
if (pid_ <= 0)
return ;
if (::kill(pid_, SIGSTOP) == -1)
ec = get_last_error();
}
void resume()
{
if (pid_ <= 0)
return ;
error_code ec;
resume(ec);
if (ec)
detail::throw_error(ec, "resume");
}
void resume(error_code &ec)
{
if (pid_ <= 0)
return ;
if (::kill(pid_, SIGCONT) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)

View File

@@ -128,6 +128,7 @@ struct basic_process_handle_fd_or_signal
pid_type id() const
{ return pid_; }
native_handle_type native_handle() {return pid_;}
void terminate_if_running(error_code &)
{
@@ -211,6 +212,42 @@ struct basic_process_handle_fd_or_signal
if (ec)
detail::throw_error(ec, "request_exit");
}
void suspend()
{
if (pid_ <= 0)
return ;
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
void suspend(error_code &ec)
{
if (pid_ <= 0)
return ;
if (::kill(pid_, SIGSTOP) == -1)
ec = get_last_error();
}
void resume()
{
if (pid_ <= 0)
return ;
error_code ec;
resume(ec);
if (ec)
detail::throw_error(ec, "resume");
}
void resume(error_code &ec)
{
if (pid_ <= 0)
return ;
if (::kill(pid_, SIGCONT) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status, error_code &ec)
{

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() = delete;
~native_handle_type() = default;
};
typedef Executor executor_type;
@@ -101,8 +101,8 @@ struct basic_process_handle_signal
handle.pid_ = -1;
}
pid_type id() const
{ return pid_; }
pid_type id() const { return pid_; }
native_handle_type native_handle() {return {};}
void terminate_if_running(error_code &)
{
@@ -112,7 +112,7 @@ struct basic_process_handle_signal
void terminate_if_running()
{
if (pid_ <= 0)
return ;
return;
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
{
::kill(pid_, SIGKILL);
@@ -123,7 +123,7 @@ struct basic_process_handle_signal
void wait(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)
return ;
return;
while (::waitpid(pid_, &exit_status, 0) < 0)
{
if (errno != EINTR)
@@ -137,7 +137,7 @@ struct basic_process_handle_signal
void wait(native_exit_code_type &exit_status)
{
if (pid_ <= 0)
return ;
return;
error_code ec;
wait(exit_status, ec);
if (ec)
@@ -147,7 +147,7 @@ struct basic_process_handle_signal
void interrupt(error_code &ec)
{
if (pid_ <= 0)
return ;
return;
if (::kill(pid_, SIGTERM) == -1)
ec = get_last_error();
}
@@ -155,7 +155,7 @@ struct basic_process_handle_signal
void interrupt()
{
if (pid_ <= 0)
return ;
return;
error_code ec;
interrupt(ec);
if (ec)
@@ -165,7 +165,7 @@ struct basic_process_handle_signal
void request_exit(error_code &ec)
{
if (pid_ <= 0)
return ;
return;
if (::kill(pid_, SIGTERM) == -1)
ec = get_last_error();
}
@@ -173,17 +173,53 @@ struct basic_process_handle_signal
void request_exit()
{
if (pid_ <= 0)
return ;
return;
error_code ec;
request_exit(ec);
if (ec)
detail::throw_error(ec, "request_exit");
}
void suspend()
{
if (pid_ <= 0)
return;
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
void suspend(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGCONT) == -1)
ec = get_last_error();
}
void resume()
{
if (pid_ <= 0)
return;
error_code ec;
resume(ec);
if (ec)
detail::throw_error(ec, "resume");
}
void resume(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGTERM) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)
return ;
return;
if (::kill(pid_, SIGKILL) == -1)
ec = get_last_error();
}
@@ -191,7 +227,7 @@ struct basic_process_handle_signal
void terminate(native_exit_code_type &exit_status)
{
if (pid_ <= 0)
return ;
return;
error_code ec;
terminate(exit_status, ec);
if (ec)
@@ -284,7 +320,7 @@ struct basic_process_handle_signal
if (!ec && (wait_res == 0))
{
handle.async_wait(std::move(self));
return ;
return;
}
struct completer

View File

@@ -32,6 +32,8 @@ BOOST_PROCESS_V2_DECL void terminate_if_running_(void * handle);
BOOST_PROCESS_V2_DECL bool check_handle_(void* handle, error_code & ec);
BOOST_PROCESS_V2_DECL bool check_pid_(pid_type pid_, error_code & ec);
BOOST_PROCESS_V2_DECL void interrupt_(pid_type pid_, error_code & ec);
BOOST_PROCESS_V2_DECL void suspend_(void * handle, error_code & ec);
BOOST_PROCESS_V2_DECL void resume_(void * handle, error_code & ec);
BOOST_PROCESS_V2_DECL void terminate_(void * handle, error_code & ec, native_exit_code_type & exit_code);
BOOST_PROCESS_V2_DECL void request_exit_(pid_type pid_, error_code & ec);
BOOST_PROCESS_V2_DECL void check_running_(void* handle, error_code & ec, native_exit_code_type & exit_status);
@@ -83,21 +85,20 @@ struct basic_process_handle_win
template<typename Executor1>
basic_process_handle_win(basic_process_handle_win<Executor1> && handle)
: pid_(handle.pid_), handle_(handle.handle_.get_executor())
: pid_(handle.pid_), handle_(std::move(handle.handle_))
{
}
basic_process_handle_win(basic_process_handle_win && handle)
basic_process_handle_win(basic_process_handle_win && handle)
: pid_(handle.id()), handle_(std::move(handle.handle_))
{
pid_ = handle.id();
handle_ = std::move(handle.handle_);
handle.pid_ = static_cast<DWORD>(-1);
}
basic_process_handle_win& operator=(basic_process_handle_win && handle)
{
pid_ = handle.pid_;
handle_ = std::mopve(handle_))
handle_ = std::move(handle.handle_);
handle.pid_ = static_cast<DWORD>(-1);
return *this;
}
@@ -166,7 +167,6 @@ struct basic_process_handle_win
{
if (!detail::check_pid_(pid_, ec))
return;
detail::request_exit_(pid_, ec);
}
@@ -178,6 +178,32 @@ struct basic_process_handle_win
detail::throw_error(ec, "request_exit");
}
void suspend(error_code &ec)
{
detail::suspend_(handle_.native_handle(), ec);
}
void suspend()
{
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
void resume(error_code &ec)
{
detail::resume_(handle_.native_handle(), ec);
}
void resume()
{
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "resume");
}
void terminate(native_exit_code_type &exit_status, error_code &ec)
{
if (!detail::check_handle_(handle_.native_handle(), ec))

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 = 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 = 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()))
{
@@ -979,7 +988,8 @@ struct key_value_pair
const std::pair<Key, Value> & kv/*,
typename std::enable_if<std::is_constructible<struct key, Key >::value &&
std::is_constructible<struct value, Value>::value
>::type = 0*/) : value_(((struct key)(kv.first)).string() + equality_sign + ((struct value)(kv.second)).string())
>::type = 0*/) : value_(((struct key)(kv.first)).basic_string<char_type, traits_type>() + equality_sign
+ ((struct value)(kv.second)).basic_string<char_type, traits_type>())
{}
key_value_pair(const typename conditional<is_same<value_type, char>::value, wchar_t, char>::type * raw)
@@ -998,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 = 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);
@@ -1045,6 +1059,7 @@ struct key_value_pair
operator string_type() const {return native();}
operator string_view_type() const {return native_view();}
operator typename string_view_type::string_view_type() const {return native_view();}
operator key_value_pair_view() const {return native_view();}
int compare( const key_value_pair& p ) const noexcept
@@ -1432,8 +1447,9 @@ auto find_key(Environment & env, key_view ky)
template<typename Environment = current_view>
inline filesystem::path home(Environment && env = current())
{
#if defined(ASIO_WINDOWS)
return detail::find_key(env, L"HOMEDRIVE") + detail::find_key(env, L"HOMEPATH").native_string();
#if defined(BOOST_PROCESS_V2_WINDOWS)
return detail::find_key(env, L"HOMEDRIVE").native_string()
+ detail::find_key(env, L"HOMEPATH").native_string();
#else
return detail::find_key(env, "HOME").native_string();
#endif
@@ -1468,7 +1484,7 @@ inline BOOST_PROCESS_V2_NAMESPACE::filesystem::path find_executable(
// first check if it has the extension already
BOOST_PROCESS_V2_NAMESPACE::filesystem::path full_nm(name);
BOOST_PROCESS_V2_NAMESPACE::filesystem::path pp(pp_view.begin(), pp_view.end());
auto p = pp / nm;
auto p = pp / full_nm;
error_code ec;
if (detail::is_executable(p, ec) && !ec)
@@ -1695,67 +1711,53 @@ struct process_environment
template<typename Args>
void build_env(Args && args, string_view rs)
static
std::vector<wchar_t> build_env(Args && args,
typename std::enable_if<
std::is_convertible<
decltype(*std::begin(std::declval<Args>())),
wcstring_ref>::value>::type * = nullptr)
{
std::size_t length = 0u;
for (string_view v : args)
length += detail::size_as_wide(v.data(), v.size(), ec) + 1u;
std::vector<wchar_t> res;
std::size_t sz = 1;
for (wcstring_ref cs : std::forward<Args>(args))
sz =+ cs.size() + 1;
res.reserve(sz);
for (wcstring_ref cs : std::forward<Args>(args))
res.insert(res.end(), cs.begin(), std::next(cs.end()));
if (ec)
return;
length ++ ;
unicode_env.resize(length);
auto itr = &unicode_env.front();
for (string_view v : args)
{
itr += detail::convert_to_wide(
v.data(), v.size(),
itr, &unicode_env.back() - itr,
ec);
if (ec)
break;
*(itr++) = '\0';
}
unicode_env.back() = '\0';
}
template<typename Args>
void build_env(Args && args, wstring_view rs)
{
std::size_t length = 0u;
for (const auto & v : std::forward<Args>(args))
length += v.size() + 1u;
length ++ ;
unicode_env.resize(length);
auto itr = unicode_env.begin();
for (wstring_view v : args )
{
itr = std::copy(v.begin(), v.end(), itr);
*(itr++) = L'\0';
}
unicode_env.back() = L'\0';
res.push_back(L'\0');
return res;
}
template<typename Args>
std::vector<wchar_t> build_env(Args && args,
typename std::enable_if<
!std::is_convertible<
decltype(*std::begin(std::declval<Args>())),
wcstring_ref>::value>::type * = nullptr)
{
for (auto && arg: std::forward<Args>(args))
env_buffer.emplace_back(arg);
return build_env(env_buffer);
}
process_environment(std::initializer_list<string_view> sv) { build_env(sv, ""); }
process_environment(std::initializer_list<wstring_view> sv) { 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)
process_environment(Args && args) : unicode_env{build_env(std::forward<Args>(args))}
{
if (std::begin(args) != std::end(args))
build_env(std::forward<Args>(args), *std::begin(args));
}
error_code error() {return ec;}
error_code ec;
std::vector<environment::key_value_pair> env_buffer;
std::vector<wchar_t> unicode_env;
BOOST_PROCESS_V2_DECL
error_code on_setup(windows::default_launcher & launcher,
const filesystem::path &, const std::wstring &);
@@ -1804,6 +1806,7 @@ struct process_environment
}
BOOST_PROCESS_V2_DECL
error_code on_setup(posix::default_launcher & launcher,
const filesystem::path &, const char * const *);
@@ -1885,6 +1888,7 @@ struct hash<BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair>
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/impl/environment.ipp>
#include <boost/process/v2/detail/impl/environment.ipp>
#endif

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)
@@ -66,7 +66,7 @@ struct execute_op
template<typename Self>
void operator()(Self && self)
{
self.reset_cancellation_state();
self.reset_cancellation_state(BOOST_PROCESS_V2_ASIO_NAMESPACE::enable_total_cancellation());
BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_slot s = self.get_cancellation_state().slot();
if (s.is_connected())
s.emplace<cancel>(proc.get());
@@ -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

@@ -12,6 +12,15 @@
#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>
@@ -85,6 +94,39 @@ inline int evaluate_exit_code(int code)
#endif
/// @{
/** 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(
* 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);
* assert(ec.category() == error::get_exit_code_category());
* }));
*
* @endcode
*/
inline error_code check_exit_code(
error_code &ec, native_exit_code_type native_code,
const error_category & category = error::get_exit_code_category())
{
if (!ec)
BOOST_PROCESS_V2_ASSIGN_EC(ec, native_code, category);
return ec;
}
/// @}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_EXIT_CODE_HPP

View File

@@ -0,0 +1,16 @@
//
// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_EXT_HPP
#define BOOST_PROCESS_V2_EXT_HPP
#include <boost/process/v2/ext/cmd.hpp>
#include <boost/process/v2/ext/cwd.hpp>
#include <boost/process/v2/ext/env.hpp>
#include <boost/process/v2/ext/exe.hpp>
#endif //BOOST_PROCESS_V2_EXT_HPP

View File

@@ -0,0 +1,71 @@
// 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 {
#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);
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

@@ -0,0 +1,58 @@
// 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 {
#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);
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
}
/// @}
} // 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

@@ -0,0 +1,127 @@
// Copyright (c) 2022 Klemens D. Morgenstern
// Copyright (c) 2022 Samuel Venable
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_IMPL_DETAIL_PROC_INFO_IPP
#define BOOST_PROCESS_V2_IMPL_DETAIL_PROC_INFO_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/ext/detail/proc_info.hpp>
#include <string>
#if (defined(__APPLE__) && defined(__MACH__))
#include <cstdlib>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/proc_info.h>
#include <libproc.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
namespace ext
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
// type of process memory to read?
enum MEMTYP {MEMCMD, MEMCWD};
std::wstring cwd_cmd_from_proc(HANDLE proc, int type, boost::system::error_code & ec)
{
std::wstring buffer;
PEB peb;
SIZE_T nRead = 0;
ULONG len = 0;
PROCESS_BASIC_INFORMATION pbi;
RTL_USER_PROCESS_PARAMETERS_EXTENDED upp;
NTSTATUS status = 0;
PVOID buf = nullptr;
status = NtQueryInformationProcess(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
ULONG error = RtlNtStatusToDosError(status);
if (error)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, error, boost::system::system_category())
return {};
}
if (!ReadProcessMemory(proc, pbi.PebBaseAddress, &peb, sizeof(peb), &nRead))
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
if (!ReadProcessMemory(proc, peb.ProcessParameters, &upp, sizeof(upp), &nRead))
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
if (type == MEMCWD)
{
buf = upp.CurrentDirectory.DosPath.Buffer;
len = upp.CurrentDirectory.DosPath.Length;
}
else if (type == MEMCMD)
{
buf = upp.CommandLine.Buffer;
len = upp.CommandLine.Length;
}
buffer.resize(len / 2 + 1);
if (!ReadProcessMemory(proc, buf, &buffer[0], len, &nRead))
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
buffer.pop_back();
return buffer;
}
// with debug_privilege enabled allows reading info from more processes
// this includes stuff such as exe path, cwd path, cmdline, and environ
HANDLE open_process_with_debug_privilege(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
HANDLE proc = nullptr;
HANDLE hToken = nullptr;
LUID luid;
TOKEN_PRIVILEGES tkp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
if (LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &luid))
{
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), nullptr, nullptr))
{
proc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
}
}
CloseHandle(hToken);
}
if (!proc)
proc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
if (!proc)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return proc;
}
#endif
} // namespace ext
} // namespace detail
BOOST_PROCESS_V2_END_NAMESPACE
#endif // BOOST_PROCESS_V2_IMPL_DETAIL_PROC_INFO_IPP

View File

@@ -0,0 +1,125 @@
// Copyright (c) 2022 Klemens D. Morgenstern
// Copyright (c) 2022 Samuel Venable
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_PROC_INFO_HPP
#define BOOST_PROCESS_V2_DETAIL_PROC_INFO_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/pid.hpp>
#include <string>
#include <vector>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <iterator>
#include <algorithm>
#include <windows.h>
#include <winternl.h>
extern "C" ULONG NTAPI RtlNtStatusToDosError(NTSTATUS Status);
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
namespace ext
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
#if !defined(_MSC_VER)
#pragma pack(push, 8)
#else
#include <pshpack8.h>
#endif
/* CURDIR struct from:
https://github.com/processhacker/phnt/
CC BY 4.0 licence */
typedef struct {
UNICODE_STRING DosPath;
HANDLE Handle;
} CURDIR;
/* RTL_DRIVE_LETTER_CURDIR struct from:
https://github.com/processhacker/phnt/
CC BY 4.0 licence */
typedef struct {
USHORT Flags;
USHORT Length;
ULONG TimeStamp;
STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR;
/* RTL_USER_PROCESS_PARAMETERS struct from:
https://github.com/processhacker/phnt/
CC BY 4.0 licence */
typedef struct {
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
HANDLE ConsoleHandle;
ULONG ConsoleFlags;
HANDLE StandardInput;
HANDLE StandardOutput;
HANDLE StandardError;
CURDIR CurrentDirectory;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PVOID Environment;
ULONG StartingX;
ULONG StartingY;
ULONG CountX;
ULONG CountY;
ULONG CountCharsX;
ULONG CountCharsY;
ULONG FillAttribute;
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
RTL_DRIVE_LETTER_CURDIR CurrentDirectories[32];
ULONG_PTR EnvironmentSize;
ULONG_PTR EnvironmentVersion;
PVOID PackageDependencyData;
ULONG ProcessGroupId;
ULONG LoaderThreads;
UNICODE_STRING RedirectionDllName;
UNICODE_STRING HeapPartitionName;
ULONG_PTR DefaultThreadpoolCpuSetMasks;
ULONG DefaultThreadpoolCpuSetMaskCount;
} RTL_USER_PROCESS_PARAMETERS_EXTENDED;
#if !defined(_MSC_VER)
#pragma pack(pop)
#else
#include <poppack.h>
#endif
BOOST_PROCESS_V2_DECL std::wstring cwd_cmd_from_proc(HANDLE proc, int type, boost::system::error_code & ec);
BOOST_PROCESS_V2_DECL HANDLE open_process_with_debug_privilege(boost::process::v2::pid_type pid, boost::system::error_code & ec);
#endif
} // namespace ext
} // namespace detail
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/ext/detail/impl/proc_info.ipp>
#endif
#endif // BOOST_PROCESS_V2_DETAIL_PROC_INFO_HPP

View File

@@ -0,0 +1,155 @@
// 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_;
};
#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);
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
}
/// @}
} // 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

@@ -0,0 +1,62 @@
// Copyright (c) 2022 Klemens D. Morgenstern
// Copyright (c) 2022 Samuel Venable
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_EXE_HPP
#define BOOST_PROCESS_V2_EXE_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/process_handle.hpp>
#include <boost/process/v2/pid.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace ext {
#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);
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
}
///@}
} // 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

@@ -0,0 +1,463 @@
// 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);
return shell{};
}
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

@@ -0,0 +1,241 @@
// 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)
{
#if (defined(__linux__) || defined(__ANDROID__))
return filesystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "cwd", ec
);
#elif defined(__sun)
return fileystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "path/cwd", ec
);
#endif
}
#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

@@ -0,0 +1,389 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_EXT_IMPL_ENV_IPP
#define BOOST_PROCESS_V2_EXT_IMPL_ENV_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/ext/detail/proc_info.hpp>
#include <boost/process/v2/ext/env.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <shellapi.h>
#else
#include <cstdlib>
#endif
#if (defined(__linux__) || defined(__ANDROID__))
#include <cstdio>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail {
namespace ext {
#if defined(BOOST_PROCESS_V2_WINDOWS)
void native_env_handle_deleter::operator()(native_env_handle_type h) const
{
delete [] h;
}
native_env_iterator next(native_env_iterator nh)
{
while (*nh != L'\0')
nh ++;
return ++nh ;
}
native_env_iterator find_end(native_env_iterator nh)
{
while (*nh - 1 != L'\0' && *nh != L'\0')
nh ++;
return nh ;
}
const environment::char_type * dereference(native_env_iterator iterator)
{
return iterator;
}
#elif (defined(__linux__) || defined(__ANDROID__))
//linux stores this as a blob with an EOF at the end
void native_env_handle_deleter::operator()(native_env_handle_type h) const
{
delete [] h;
}
native_env_iterator next(native_env_iterator nh)
{
while (*nh != '\0')
nh ++;
return ++nh ;
}
native_env_iterator find_end(native_env_iterator nh)
{
while (*nh != EOF)
nh ++;
return nh ;
}
const environment::char_type * dereference(native_env_iterator iterator)
{
return iterator;
}
#elif (defined(__APPLE___) || defined(__MACH__))
void native_env_handle_deleter::operator()(native_env_handle_type h) const
{
delete [] h;
}
native_env_iterator next(native_env_iterator nh)
{
while (*nh != '\0')
nh ++;
return ++nh ;
}
native_env_iterator find_end(native_env_iterator nh)
{
while (*nh - 1 != '\0' && *nh != '\0')
nh ++;
return nh ;
}
const environment::char_type * dereference(native_env_iterator iterator)
{
return iterator;
}
#elif defined(__FreeBSD__)
void native_env_handle_deleter::operator()(native_env_handle_type h) const
{
delete [] h;
}
native_env_iterator next(native_env_iterator nh)
{
return ++nh ;
}
native_env_iterator find_end(native_env_iterator nh)
{
while (*nh != nullptr)
nh++;
return nh ;
}
const environment::char_type * dereference(native_env_iterator iterator)
{
return *iterator;
}
#endif
}
}
namespace ext
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
env_view env(HANDLE proc, boost::system::error_code & ec)
{
wchar_t *buffer = nullptr;
PEB peb;
SIZE_T nRead = 0;
ULONG len = 0;
PROCESS_BASIC_INFORMATION pbi;
detail::ext::RTL_USER_PROCESS_PARAMETERS_EXTENDED upp;
NTSTATUS status = 0;
PVOID buf = nullptr;
status = NtQueryInformationProcess(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
ULONG error = RtlNtStatusToDosError(status);
if (error)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, error, boost::system::system_category())
return {};
}
if (!ReadProcessMemory(proc, pbi.PebBaseAddress, &peb, sizeof(peb), &nRead))
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
if (!ReadProcessMemory(proc, peb.ProcessParameters, &upp, sizeof(upp), &nRead))
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
env_view ev;
buf = upp.Environment;
len = (ULONG)upp.EnvironmentSize;
ev.handle_.reset(new wchar_t[len / 2 + 1]());
if (!ReadProcessMemory(proc, buf, ev.handle_.get(), len, &nRead))
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
ev.handle_.get()[len / 2] = L'\0';
return ev;
}
env_view env(HANDLE handle)
{
boost::system::error_code ec;
auto res = env(handle, ec);
if (ec)
detail::throw_error(ec, "env");
return res;
}
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
struct del
{
void operator()(HANDLE h)
{
::CloseHandle(h);
};
};
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
if (proc == nullptr)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
else
return env(proc.get(), ec);
return {};
}
#elif (defined(__APPLE___) || defined(__MACH__))
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
int mib[3] = {CTL_KERN, KERN_ARGMAX, 0};
int argmax = 0;
auto size = sizeof(argmax);
if (sysctl(mib, 2, &argmax, &size, nullptr, 0) == -1)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
std::string procargs;
procargs.resize(argmax - 1);
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
size = argmax;
if (sysctl(mib, 3, &*procargs.begin(), &size, nullptr, 0) != 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return {};
}
std::uint32_t nargs;
memcpy(&nargs, &*procargs.begin(), sizeof(nargs));
char *cp = &*procargs.begin() + sizeof(nargs);
for (; cp < &*procargs.end(); cp++)
if (*cp == '\0')
break;
if (cp == &procargs[size])
return {};
for (; cp < &*procargs.end(); cp++)
if (*cp != '\0') break;
if (cp == &*procargs.end())
return {};
int i = 0;
char *sp = cp;
std::vector<char> vec;
while ((*sp != '\0' || i < nargs) && sp < &*procargs.end()) {
if (i >= nargs)
vec.push_back(*sp);
sp += 1;
}
env_view ev;
ev.handle_.reset(new char[vec.size()]());
std::copy(vec.begin(), vec.end(), ev.handle_.get());
return ev;
}
#elif (defined(__linux__) || defined(__ANDROID__))
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
std::size_t size = 0;
std::unique_ptr<char, detail::ext::native_env_handle_deleter> procargs{};
int f = ::open(("/proc/" + std::to_string(pid) + "/environ").c_str(), O_RDONLY);
while (!procargs || procargs.get()[size - 1] != EOF)
{
std::unique_ptr<char, detail::ext::native_env_handle_deleter> buf{new char[size + 4096]};
if (size > 0)
std::memmove(buf.get(), procargs.get(), size);
auto r = ::read(f, buf.get() + size, 4096);
if (r < 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
::close(f);
return {};
}
procargs = std::move(buf);
size += r;
if (r < 4096) // done!
{
procargs.get()[size] = EOF;
break;
}
}
::close(f);
env_view ev;
ev.handle_ = std::move(procargs);
return ev;
}
#elif defined(__FreeBSD__)
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
env_view ev;
unsigned cntp = 0;
procstat *proc_stat = procstat_open_sysctl();
if (proc_stat != nullptr)
{
kinfo_proc *proc_info = procstat_getprocs(proc_stat, KERN_PROC_PID, pid, &cntp);
if (proc_info != nullptr)
{
char **env = procstat_getenvv(proc_stat, proc_info, 0);
if (env != nullptr)
{
auto e = env;
std::size_t n = 0u, len = 0u;
while (e && *e != nullptr)
{
n ++;
len += std::strlen(*e);
e++;
}
std::size_t mem_needed =
// environ - nullptr - strlen + null terminators
(n * sizeof(char*)) + sizeof(char*) + len + n;
char * out = new (std::nothrow) char[mem_needed];
if (out != nullptr)
{
auto eno = reinterpret_cast<char**>(out);
auto eeo = eno;
auto str = out + (n * sizeof(char*)) + sizeof(char*);
e = env;
while (*e != nullptr)
{
auto len = std::strlen(*e) + 1u;
std::memcpy(str, *e, len);
*eno = str;
str += len;
eno ++;
e++;
}
*eno = nullptr;
ev.handle_.reset(eeo);
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
procstat_freeprocs(proc_stat, proc_info);
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
procstat_close(proc_stat);
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return ev;
}
#endif
env_view env(boost::process::v2::pid_type pid)
{
boost::system::error_code ec;
auto res = env(pid, ec);
if (ec)
detail::throw_error(ec, "env");
return res;
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_EXT_IMPL_ENV_IPP

View File

@@ -0,0 +1,193 @@
// Copyright (c) 2022 Klemens D. Morgenstern
// Copyright (c) 2022 Samuel Venable
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_IMPL_EXE_IPP
#define BOOST_PROCESS_V2_IMPL_EXE_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/ext/detail/proc_info.hpp>
#include <boost/process/v2/ext/exe.hpp>
#include <string>
#include <vector>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <windows.h>
#else
#include <climits>
#endif
#if (defined(__APPLE__) && defined(__MACH__))
#include <sys/proc_info.h>
#include <libproc.h>
#endif
#if (defined(BOOST_PROCESS_V2_WINDOWS) || defined(__linux__) || defined(__ANDROID__) || defined(__sun))
#include <cstdlib>
#endif
#if (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__))
#include <sys/types.h>
#include <sys/sysctl.h>
#if !defined(__FreeBSD__)
#include <alloca.h>
#endif
#endif
#if defined(__OpenBSD__)
#include <boost/process/v2/ext/cwd.hpp>
#include <boost/process/v2/ext/cmd.hpp>
#include <boost/process/v2/ext/env.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <kvm.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace ext {
#if defined(BOOST_PROCESS_V2_WINDOWS)
filesystem::path exe(HANDLE process_handle)
{
boost::system::error_code ec;
auto res = exe(process_handle, ec);
if (ec)
detail::throw_error(ec, "exe");
return res;
}
filesystem::path exe(HANDLE proc, boost::system::error_code & ec)
{
wchar_t buffer[MAX_PATH];
// On input, specifies the size of the lpExeName buffer, in characters.
DWORD size = MAX_PATH;
if (QueryFullProcessImageNameW(proc, 0, buffer, &size))
{
return filesystem::canonical(buffer, ec);
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return "";
}
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
if (pid == GetCurrentProcessId())
{
wchar_t buffer[MAX_PATH];
if (GetModuleFileNameW(nullptr, buffer, sizeof(buffer)))
{
return filesystem::canonical(buffer, ec);
}
}
else
{
struct del
{
void operator()(HANDLE h)
{
::CloseHandle(h);
};
};
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
if (proc == nullptr)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
else
return exe(proc.get(), ec);
}
return "";
}
#elif (defined(__APPLE__) && defined(__MACH__))
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
char buffer[PROC_PIDPATHINFO_MAXSIZE];
if (proc_pidpath(pid, buffer, sizeof(buffer)) > 0)
{
return filesystem::canonical(buffer, ec);
}
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return "";
}
#elif (defined(__linux__) || defined(__ANDROID__) || defined(__sun))
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
{
#if (defined(__linux__) || defined(__ANDROID__))
return filesystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "exe", ec
);
#elif defined(__sun)
return fileystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "path/a.out", ec
);
#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

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

@@ -1,4 +1,5 @@
// Copyright (c) 2022 Klemens D. Morgenstern
// Copyright (c) 2022 Samuel Venable
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -6,14 +7,56 @@
#define BOOST_PROCESS_V2_IMPL_PID_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/pid.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <windows.h>
#include <tlhelp32.h>
#else
#include <unistd.h>
#endif
#if (defined(__APPLE__) && defined(__MACH__))
#include <sys/proc_info.h>
#include <libproc.h>
#endif
#if (defined(__linux__) || defined(__ANDROID__))
#include <dirent.h>
#endif
#if defined(__FreeBSD__)
#include <sys/types.h>
#include <sys/user.h>
#include <libutil.h>
#include <cstdlib>
#endif
#if (defined(__DragonFly__) || defined(__OpenBSD__))
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <kvm.h>
#endif
#if defined(__NetBSD__)
#include <sys/types.h>
#include <kvm.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#if defined(__sun)
#include <sys/types.h>
#include <kvm.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/proc.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(BOOST_PROCESS_V2_WINDOWS)
@@ -22,6 +65,698 @@ 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

@@ -0,0 +1,137 @@
// 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_IMPL_SHELL_IPP
#define BOOST_PROCESS_V2_IMPL_SHELL_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/detail/config.hpp>
#include <boost/process/v2/error.hpp>
#include <boost/process/v2/shell.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <shellapi.h>
#else
#include <wordexp.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(BOOST_PROCESS_V2_WINDOWS)
BOOST_PROCESS_V2_DECL const error_category& get_shell_category()
{
return system_category();
}
#else
struct shell_category_t final : public error_category
{
shell_category_t() : error_category(0xDAF1u) {}
const char* name() const noexcept
{
return "process.v2.utf8";
}
std::string message(int value) const
{
switch (value)
{
case WRDE_BADCHAR:
return "Illegal occurrence of newline or one of |, &, ;, <, >, (, ), {, }.";
case WRDE_BADVAL:
return "An undefined shell variable was referenced, and the WRDE_UNDEF flag told us to consider this an error.";
case WRDE_CMDSUB:
return "Command substitution occurred, and the WRDE_NOCMD flag told us to consider this an error.";
case WRDE_NOSPACE:
return "Out of memory.";
case WRDE_SYNTAX:
return "Shell syntax error, such as unbalanced parentheses or unmatched quotes.";
default:
return "process.v2.wordexp error";
}
}
};
BOOST_PROCESS_V2_DECL const error_category& get_shell_category()
{
static shell_category_t instance;
return instance;
}
#endif
#if defined (BOOST_PROCESS_V2_WINDOWS)
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");
}
}
shell::~shell()
{
if (argv_ != nullptr)
LocalFree(argv_);
}
auto shell::args() const-> args_type
{
return input_.c_str();
}
#else
void shell::parse_()
{
wordexp_t we{};
auto cd = wordexp(input_.c_str(), &we, WRDE_NOCMD);
if (cd != 0)
detail::throw_error(error_code(cd, get_shell_category()), "shell::parse");
else
{
argc_ = static_cast<int>(we.we_wordc);
argv_ = we.we_wordv;
}
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_);
}
auto shell::args() const -> args_type
{
if (argc() == 0)
{
static const char * helper = nullptr;
return &helper;
}
else
return const_cast<const char**>(argv());
}
#endif
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_IMPL_SHELL_IPP

View File

@@ -1,4 +1,5 @@
// Copyright (c) 2022 Klemens D. Morgenstern
// Copyright (c) 2022 Samuel Venable
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -6,6 +7,7 @@
#define BOOST_PROCESS_V2_PID_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
@@ -14,7 +16,6 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
//An integral type representing a process id.
typedef implementation_defined pid_type;
#else
#if defined(BOOST_PROCESS_V2_WINDOWS)
@@ -28,14 +29,38 @@ typedef int pid_type;
#endif
#endif
#if (defined(BOOST_PROCESS_V2_WINDOWS) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__sun))
constexpr static pid_type root_pid = 0;
#elif (defined(__APPLE__) && defined(__MACH__) || defined(__linux__) || defined(__ANDROID__) || defined(__OpenBSD__))
constexpr static pid_type root_pid = 1;
#endif
/// Get the process id of the current process.
BOOST_PROCESS_V2_DECL pid_type current_pid();
/// List all available pids.
BOOST_PROCESS_V2_DECL std::vector<pid_type> all_pids(boost::system::error_code & ec);
/// List all available pids.
BOOST_PROCESS_V2_DECL std::vector<pid_type> all_pids();
// return parent pid of pid.
BOOST_PROCESS_V2_DECL pid_type parent_pid(pid_type pid, boost::system::error_code & ec);
// return parent pid of pid.
BOOST_PROCESS_V2_DECL pid_type parent_pid(pid_type pid);
// return child pids of pid.
BOOST_PROCESS_V2_DECL std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec);
// return child pids of pid.
BOOST_PROCESS_V2_DECL std::vector<pid_type> child_pids(pid_type pid);
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/impl/pid.ipp>
#endif
#endif // BOOST_PROCESS_V2_PID_HPP
#endif //BOOST_PROCESS_V2_PID_HPP

View File

@@ -74,8 +74,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(
@@ -85,30 +83,30 @@ struct basic_popen : basic_process<Executor>
Inits&&... inits)
: basic_process<Executor>(executor)
{
*static_cast<basic_process<Executor>*>(this) =
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 ... Inits>
template<typename Launcher, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
std::initializer_list<wstring_view> args,
const filesystem::path& exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
*static_cast<basic_process<Executor>*>(this) =
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
);
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.
@@ -119,53 +117,112 @@ struct basic_popen : basic_process<Executor>
Args&& args, Inits&&... inits)
: basic_process<Executor>(executor)
{
*static_cast<basic_process<Executor>*>(this) =
this->basic_process<Executor>::operator=(
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)
{
*static_cast<basic_process<Executor>*>(this) =
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 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)
{
*static_cast<basic_process<Executor>*>(this) =
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 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 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
@@ -91,13 +91,17 @@ 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.
error_code on_exec_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
{
if (::dup2(fd, target) == -1)
return error_code(errno, system_category());
launcher.fd_whitelist.push_back(target);
return error_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;
}
@@ -364,12 +365,12 @@ struct default_launcher
pipe_guard pg;
if (::pipe(pg.p))
{
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
return basic_process<Executor>{exec};
}
if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
{
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
return basic_process<Executor>{exec};
}
ec = detail::on_setup(*this, executable, argv, inits ...);
@@ -378,6 +379,7 @@ struct default_launcher
detail::on_error(*this, executable, argv, ec, inits...);
return basic_process<Executor>(exec);
}
fd_whitelist.push_back(pg.p[1]);
auto & ctx = BOOST_PROCESS_V2_ASIO_NAMESPACE::query(
exec, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::context);
@@ -389,7 +391,7 @@ struct default_launcher
detail::on_fork_error(*this, executable, argv, ec, inits...);
detail::on_error(*this, executable, argv, ec, inits...);
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
return basic_process<Executor>{exec};
}
else if (pid == 0)
@@ -399,14 +401,13 @@ struct default_launcher
ec = detail::on_exec_setup(*this, executable, argv, inits...);
if (!ec)
{
fd_whitelist.push_back(pg.p[1]);
close_all_fds(ec);
}
if (!ec)
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
detail::on_exec_error(*this, executable, argv, ec, inits...);
::exit(EXIT_FAILURE);
return basic_process<Executor>{exec};
@@ -422,12 +423,12 @@ struct default_launcher
int err = errno;
if ((err != EAGAIN) && (err != EINTR))
{
ec.assign(err, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
break;
}
}
if (count != 0)
ec.assign(child_error, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
if (ec)
{
@@ -485,6 +486,11 @@ struct default_launcher
return argv_.data();
}
const char * const * build_argv_(const filesystem::path &, const char ** argv)
{
return argv;
}
template<typename Args>
const char * const * build_argv_(const filesystem::path & pt, const Args & args,
typename std::enable_if<

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;
}
@@ -94,7 +94,7 @@ struct fork_and_forget_launcher : default_launcher
detail::on_fork_error(*this, executable, argv, ec, inits...);
detail::on_error(*this, executable, argv, ec, inits...);
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
return basic_process<Executor>{exec};
}
else if (pid == 0)
@@ -107,7 +107,7 @@ struct fork_and_forget_launcher : default_launcher
if (!ec)
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
detail::on_exec_error(*this, executable, argv, ec, inits...);
::exit(EXIT_FAILURE);
return basic_process<Executor>{exec};

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;
}
@@ -85,12 +85,12 @@ struct pdfork_launcher : default_launcher
pipe_guard pg;
if (::pipe(pg.p))
{
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
return basic_process<Executor>{exec};
}
if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
{
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
return basic_process<Executor>{exec};
}
ec = detail::on_setup(*this, executable, argv, inits ...);
@@ -99,6 +99,7 @@ struct pdfork_launcher : default_launcher
detail::on_error(*this, executable, argv, ec, inits...);
return basic_process<Executor>(exec);
}
fd_whitelist.push_back(pg.p[1]);
auto & ctx = BOOST_PROCESS_V2_ASIO_NAMESPACE::query(
exec, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::context);
@@ -110,7 +111,7 @@ struct pdfork_launcher : default_launcher
detail::on_fork_error(*this, executable, argv, ec, inits...);
detail::on_error(*this, executable, argv, ec, inits...);
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
return basic_process<Executor>{exec};
}
else if (pid == 0)
@@ -121,14 +122,13 @@ struct pdfork_launcher : default_launcher
ec = detail::on_exec_setup(*this, executable, argv, inits...);
if (!ec)
{
fd_whitelist.push_back(pg.p[1]);
close_all_fds(ec);
}
if (!ec)
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
detail::on_exec_error(*this, executable, argv, ec, inits...);
::exit(EXIT_FAILURE);
return basic_process<Executor>{exec};
@@ -143,12 +143,12 @@ struct pdfork_launcher : default_launcher
int err = errno;
if ((err != EAGAIN) && (err != EINTR))
{
ec.assign(err, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
break;
}
}
if (count != 0)
ec.assign(child_error, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
if (ec)
{

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;
}
@@ -96,21 +96,20 @@ struct vfork_launcher : default_launcher
detail::on_fork_error(*this, executable, argv, ec, inits...);
detail::on_error(*this, executable, argv, ec, inits...);
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
return basic_process<Executor>{exec};
}
else if (pid == 0)
{
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);
if (!ec)
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
ec.assign(errno, system_category());
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
detail::on_exec_error(*this, executable, argv, ec, inits...);
::exit(EXIT_FAILURE);
::_exit(EXIT_FAILURE);
return basic_process<Executor>{exec};
}
ctx.notify_fork(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context::fork_parent);

View File

@@ -15,13 +15,16 @@
#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)
#include <asio/any_io_executor.hpp>
#include <asio/post.hpp>
#include <utility>
#else
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/post.hpp>
#include <boost/core/exchange.hpp>
#endif
@@ -90,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(
@@ -164,7 +157,7 @@ struct basic_process
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value, void *>::type = nullptr)
: process_handle_(context, pid, native_handle) {}
: process_handle_(context.get_executor(), pid, native_handle) {}
/// Create an invalid handle
template <typename ExecutionContext>
@@ -172,7 +165,7 @@ struct basic_process
typename std::enable_if<
is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value, void *>::type = nullptr)
: process_handle_(context) {}
: process_handle_(context.get_executor()) {}
@@ -212,6 +205,37 @@ struct basic_process
process_handle_.request_exit(ec);
}
/// Send the process a signal requesting it to stop. This may rely on undocumented functions.
void suspend(error_code &ec)
{
process_handle_.suspend(ec);
}
/// Send the process a signal requesting it to stop. This may rely on undocumented functions.
void suspend()
{
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
/// Send the process a signal requesting it to resume. This may rely on undocumented functions.
void resume(error_code &ec)
{
process_handle_.resume(ec);
}
/// Send the process a signal requesting it to resume. This may rely on undocumented functions.
void resume()
{
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "resume");
}
/// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec)
void terminate()
{
@@ -231,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))
@@ -253,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_);
@@ -300,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))
@@ -339,7 +364,7 @@ private:
};
BOOST_PROCESS_V2_ASIO_NAMESPACE::post(handle.get_executor(),
completer{res, std::move(self)});
completer{static_cast<int>(res), std::move(self)});
}
else
handle.async_wait(std::move(self));
@@ -366,4 +391,4 @@ typedef basic_process<> process;
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_PROCESS_HPP
#endif //BOOST_PROCESS_V2_PROCESS_HPP

View File

@@ -0,0 +1,149 @@
// 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_SHELL_HPP
#define BOOST_PROCESS_V2_SHELL_HPP
#include <boost/core/exchange.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/utf8.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/environment.hpp>
#include <memory>
#include <string>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
/// Error category used by the shell parser.
extern BOOST_PROCESS_V2_DECL const error_category& get_shell_category();
static const error_category& shell_category = get_shell_category();
/// Utility to parse commands
/** This utility class parses command lines into tokens
* and allows users to executed based on textual inputs.
*
* 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.
*
* @par Example
* @code {.cpp}
* asio::io_context ctx;
*
* auto cmd = shell("my-app --help");
* auto exe = cmd.exe();
* check_if_malicious(exe);
*
* process proc{ctx, exe, cmd.args()};
*
* @endcode
*
*
*/
struct shell
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
using char_type = wchar_t;
using args_type = const wchar_t *;
#else
using char_type = char;
using args_type = const char **;
#endif
shell() = default;
template<typename Char, typename Traits>
shell(basic_string_view<Char, Traits> input)
: buffer_(detail::conv_string<char_type>(input.data(), input.size()))
{
parse_();
}
shell(basic_cstring_ref<char_type> input) : input_(input) {parse_();}
shell(basic_string_view<
typename std::conditional<
std::is_same<char_type, char>::value,
wchar_t, char>::type> input) : buffer_(detail::conv_string<char_type>(input.data(), input.size()))
{
parse_();
}
shell(const shell &) = delete;
shell& operator=(const shell &) = delete;
shell(shell && lhs) noexcept
: 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
{
}
shell& operator=(shell && lhs) noexcept
{
shell tmp(std::move(*this));
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
return *this;
}
// the length of the parsed shell, including the executable
int argc() const { return argc_; }
char_type** argv() const { return argv_; }
char_type** begin() const {return argv();}
char_type** end() const {return argv() + argc();}
bool empty() const {return argc() == 0;}
std::size_t size() const {return static_cast<std::size_t>(argc()); }
/// Native representation of the arguments to be used - excluding the executable
BOOST_PROCESS_V2_DECL args_type args() const;
template<typename Environment = environment::current_view>
filesystem::path exe(Environment && env = environment::current()) const
{
if (argc() == 0)
return "";
else
return environment::find_executable(0[argv()], std::forward<Environment>(env));
}
BOOST_PROCESS_V2_DECL ~shell();
private:
friend struct make_cmd_shell_;
BOOST_PROCESS_V2_DECL void parse_();
// storage in case we need a conversion
std::basic_string<char_type> buffer_;
basic_cstring_ref<char_type> input_{buffer_};
// impl details
int argc_ = 0;
char_type ** argv_ = nullptr;
#if defined(BOOST_PROCESS_V2_POSIX)
void(*free_argv_)(int, char **);
#endif
};
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/impl/shell.ipp>
#endif
#endif //BOOST_PROCESS_V2_ERROR_HPP

View File

@@ -10,11 +10,16 @@
#include <boost/process/v2/detail/config.hpp>
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
# error Do not compile Beast library source with BOOST_BEAST_HEADER_ONLY defined
# error Do not compile Process V2 library source with BOOST_PROCESS_V2_HEADER_ONLY defined. You should probably define BOOST_PROCESS_V2_SEPARATE_COMPILATION
#endif
#include <boost/process/v2/impl/error.ipp>
#include <boost/process/v2/impl/pid.ipp>
#include <boost/process/v2/ext/impl/exe.ipp>
#include <boost/process/v2/ext/impl/cwd.ipp>
#include <boost/process/v2/ext/impl/cmd.ipp>
#include <boost/process/v2/ext/impl/env.ipp>
#include <boost/process/v2/ext/detail/impl/proc_info.ipp>
#include <boost/process/v2/detail/impl/environment.ipp>
#include <boost/process/v2/detail/impl/last_error.ipp>
#include <boost/process/v2/detail/impl/throw_error.ipp>
@@ -22,5 +27,6 @@
#include <boost/process/v2/impl/default_launcher.ipp>
#include <boost/process/v2/impl/environment.ipp>
#include <boost/process/v2/impl/process_handle.ipp>
#include <boost/process/v2/impl/shell.ipp>
#endif //BOOST_PROCESS_V2_SRC_HPP

View File

@@ -11,6 +11,7 @@
#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,8 +11,9 @@
#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)
#include <asio/connect_pipe.hpp>
#else
@@ -52,7 +53,7 @@ struct handle_closer
DWORD flags{0xFFFFFFFFu};
};
template<DWORD Io>
template<DWORD Target>
struct process_io_binding
{
HANDLE prepare()
@@ -62,13 +63,17 @@ struct process_io_binding
return hh;
}
std::unique_ptr<void, handle_closer> h{::GetStdHandle(Io), false};
std::unique_ptr<void, handle_closer> h{::GetStdHandle(Target), false};
static DWORD get_flags(HANDLE h)
{
DWORD res;
if (!::GetHandleInformation(h, &res))
detail::throw_last_error("get_flags");
{
error_code ec;
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
throw system_error(ec, "get_flags");
}
return res;
}
@@ -82,10 +87,11 @@ struct process_io_binding
process_io_binding(FILE * f) : process_io_binding(_get_osfhandle(_fileno(f))) {}
process_io_binding(HANDLE h) : h{h, get_flags(h)} {}
process_io_binding(std::nullptr_t) : process_io_binding(filesystem::path("NUL")) {}
process_io_binding(const filesystem::path & pth)
template<typename T, typename = typename std::enable_if<std::is_same<T, filesystem::path>::value>::type>
process_io_binding(const T & pth)
: h(::CreateFileW(
pth.c_str(),
Io == STD_INPUT_HANDLE ? GENERIC_READ : GENERIC_WRITE,
Target == STD_INPUT_HANDLE ? GENERIC_READ : GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_ALWAYS,
@@ -97,28 +103,43 @@ 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);
if (ec)
return ;
detail::throw_error(ec, "create_pipe");
h = std::unique_ptr<void, handle_closer>{p[1], true};
readable_pipe.assign(p[0], ec);
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);
if (ec)
return ;
detail::throw_error(ec, "create_pipe");
h = std::unique_ptr<void, handle_closer>{p[0], true};
writable_pipe.assign(p[1], ec);
pipe.assign(p[1]);
}
};
@@ -160,17 +181,23 @@ 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)
{
ec = detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return ;
}
fd_needs_closing = true;
@@ -179,17 +206,24 @@ 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)
{
ec = detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return ;
}
fd_needs_closing = true;
@@ -255,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.
*
*
@@ -289,11 +323,6 @@ struct process_stdio
if (::dup2(err.fd, err.target) == -1)
return error_code(errno, system_category());
launcher.fd_whitelist.push_back(STDIN_FILENO);
launcher.fd_whitelist.push_back(STDOUT_FILENO);
launcher.fd_whitelist.push_back(STDERR_FILENO);
return error_code {};
};
#endif

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

View File

@@ -31,14 +31,19 @@ struct process_creation_flags
const filesystem::path &,
const std::wstring &) const
{
launcher.startup_info.StartupInfo.dwFlags |= Flags;
launcher.creation_flags |= Flags;
return error_code {};
};
};
/// 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;
constexpr static process_creation_flags<CREATE_BREAKAWAY_FROM_JOB> create_breakaway_from_job;
constexpr static process_creation_flags<CREATE_NEW_CONSOLE> create_new_console;
}
BOOST_PROCESS_V2_END_NAMESPACE

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,10 +312,9 @@ struct default_launcher
&startup_info.StartupInfo,
&process_information);
auto ec__ = detail::get_last_error();
if (ok == 0)
{
ec = detail::get_last_error();
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
detail::on_error(*this, executable, command_line, ec, inits...);
if (process_information.hProcess != INVALID_HANDLE_VALUE)
@@ -398,6 +398,11 @@ struct default_launcher
return build_command_line_impl(pt, args, *std::begin(args));
}
static std::wstring build_command_line(const filesystem::path & pt, const wchar_t * args)
{
return args;
}
};

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

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

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

@@ -21,7 +21,7 @@ process_standalone_test(pipe)
function(process_sub_launch_test name )
add_executable(boost_process_${name} ${name}.cpp)
target_link_libraries(boost_process_${name} Boost::process Boost::system Boost::filesystem Boost::thread Boost::unit_test_framework)
target_link_libraries(boost_process_${name} Boost::process Boost::system Boost::filesystem Boost::scope_exit Boost::thread Boost::unit_test_framework)
add_test(NAME boost_process_${name} COMMAND $<TARGET_FILE:boost_process_${name}> $<TARGET_FILE:boost_process_sub_launch> )
endfunction()

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 ]
[ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner ]
[ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner : <target-os>darwin:<build>no <target-os>freebsd:<build>no ]
[ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner : <target-os>freebsd:<build>no ]
[ run run_exe.cpp filesystem : : sparring_partner ]
[ run run_exe_path.cpp filesystem : [ test-options run_exe_path ] : sparring_partner ]
[ 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 ]
[ run terminate.cpp system filesystem : [ test-options terminate ] : sparring_partner : <target-os>freebsd:<build>no ]
[ run throw_on_error.cpp system filesystem : [ test-options throw_on_error ] : sparring_partner ]
[ run wait.cpp system filesystem : [ test-options wait ] : sparring_partner ]
[ run wait_for.cpp system filesystem : [ test-options wait_for ] : sparring_partner ]

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};

Some files were not shown because too many files have changed in this diff Show More