From 662c0b10e3e46bca1c523c36b80511bd9c82d9ef Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 13 Dec 2024 11:58:18 +0800 Subject: [PATCH 01/32] warning fixes Closes #436, #437 --- include/boost/process/v2/popen.hpp | 4 +- include/boost/process/v2/posix/bind_fd.hpp | 2 +- .../process/v2/posix/default_launcher.hpp | 76 +++++++++---------- include/boost/process/v2/start_dir.hpp | 2 +- include/boost/process/v2/stdio.hpp | 2 +- .../process/v2/windows/default_launcher.hpp | 20 ++--- src/detail/utf8.cpp | 9 ++- src/ext/cmd.cpp | 4 +- src/posix/close_handles.cpp | 2 +- test/v2/cstring_ref.cpp | 4 +- test/v2/ext.cpp | 2 +- test/v2/process.cpp | 16 ++-- 12 files changed, 73 insertions(+), 70 deletions(-) diff --git a/include/boost/process/v2/popen.hpp b/include/boost/process/v2/popen.hpp index 4358520a3..31b4e8962 100644 --- a/include/boost/process/v2/popen.hpp +++ b/include/boost/process/v2/popen.hpp @@ -158,7 +158,7 @@ struct basic_popen : basic_process default_process_launcher()( this->get_executor(), exe, args, std::forward(inits)..., - process_stdio{stdin_, stdout_} + process_stdio{stdin_, stdout_, {}} )); } @@ -179,7 +179,7 @@ struct basic_popen : basic_process std::forward(launcher)( this->get_executor(), exe, args, std::forward(inits)..., - process_stdio{stdin_, stdout_} + process_stdio{stdin_, stdout_, {}} )); } diff --git a/include/boost/process/v2/posix/bind_fd.hpp b/include/boost/process/v2/posix/bind_fd.hpp index 0156ed85a..2fbf394b6 100644 --- a/include/boost/process/v2/posix/bind_fd.hpp +++ b/include/boost/process/v2/posix/bind_fd.hpp @@ -98,7 +98,7 @@ struct bind_fd } /// Implementation of the initialization function. - error_code on_exec_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *) + 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()); diff --git a/include/boost/process/v2/posix/default_launcher.hpp b/include/boost/process/v2/posix/default_launcher.hpp index 2d372e0b7..37dc4510a 100644 --- a/include/boost/process/v2/posix/default_launcher.hpp +++ b/include/boost/process/v2/posix/default_launcher.hpp @@ -49,9 +49,9 @@ struct base {}; struct derived : base {}; template -inline error_code invoke_on_setup(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - Init && init, base && ) +inline error_code invoke_on_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + Init && /*init*/, base && ) { return error_code{}; } @@ -66,8 +66,8 @@ inline auto invoke_on_setup(Launcher & launcher, const filesystem::path &executa } template -inline error_code on_setup(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line)) +inline error_code on_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/)) { return error_code{}; } @@ -86,9 +86,9 @@ inline error_code on_setup(Launcher & launcher, const filesystem::path &executab template -inline void invoke_on_error(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - const error_code & ec, Init && init, base && ) +inline void invoke_on_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + const error_code & /*ec*/, Init && /*init*/, base && ) { } @@ -102,9 +102,9 @@ inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executa } template -inline void on_error(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - const error_code & ec) +inline void on_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + const error_code & /*ec*/) { } @@ -119,9 +119,9 @@ inline void on_error(Launcher & launcher, const filesystem::path &executable, } template -inline void invoke_on_success(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - Init && init, base && ) +inline void invoke_on_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + Init && /*init*/, base && ) { } @@ -135,8 +135,8 @@ inline auto invoke_on_success(Launcher & launcher, const filesystem::path &execu } template -inline void on_success(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line)) +inline void on_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/)) { } @@ -150,9 +150,9 @@ inline void on_success(Launcher & launcher, const filesystem::path &executable, } template -inline void invoke_on_fork_error(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - const error_code & ec, Init && init, base && ) +inline void invoke_on_fork_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + const error_code & /*ec*/, Init && /*init*/, base && ) { } @@ -166,9 +166,9 @@ inline auto invoke_on_fork_error(Launcher & launcher, const filesystem::path &ex } template -inline void on_fork_error(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - const error_code & ec) +inline void on_fork_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + const error_code & /*ec*/) { } @@ -185,9 +185,9 @@ inline void on_fork_error(Launcher & launcher, const filesystem::path &executabl template -inline void invoke_on_fork_success(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - Init && init, base && ) +inline void invoke_on_fork_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + Init && /*init*/, base && ) { } @@ -202,8 +202,8 @@ inline auto invoke_on_fork_success(Launcher & launcher, const filesystem::path & } template -inline void on_fork_success(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line)) +inline void on_fork_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/)) { } @@ -218,9 +218,9 @@ inline void on_fork_success(Launcher & launcher, const filesystem::path &executa template -inline error_code invoke_on_exec_setup(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - Init && init, base && ) +inline error_code invoke_on_exec_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + Init && /*init*/, base && ) { return error_code{}; } @@ -235,8 +235,8 @@ inline auto invoke_on_exec_setup(Launcher & launcher, const filesystem::path &ex } template -inline error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line)) +inline error_code on_exec_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/)) { return error_code{}; } @@ -256,9 +256,9 @@ inline error_code on_exec_setup(Launcher & launcher, const filesystem::path &exe template -inline void invoke_on_exec_error(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - const error_code & ec, Init && init, base && ) +inline void invoke_on_exec_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + const error_code & /*ec*/, Init && /*init*/, base && ) { } @@ -272,9 +272,9 @@ inline auto invoke_on_exec_error(Launcher & launcher, const filesystem::path &ex } template -inline void on_exec_error(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - const error_code & ec) +inline void on_exec_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/, + const char * const * (&/*cmd_line*/), + const error_code & /*ec*/) { } diff --git a/include/boost/process/v2/start_dir.hpp b/include/boost/process/v2/start_dir.hpp index c852b6cd0..5b0711bca 100644 --- a/include/boost/process/v2/start_dir.hpp +++ b/include/boost/process/v2/start_dir.hpp @@ -34,7 +34,7 @@ struct process_start_dir }; #else - error_code on_exec_setup(posix::default_launcher & launcher, + error_code on_exec_setup(posix::default_launcher & /*launcher*/, const filesystem::path &, const char * const *) { if (::chdir(start_dir.c_str()) == -1) diff --git a/include/boost/process/v2/stdio.hpp b/include/boost/process/v2/stdio.hpp index fdc348ca2..4deb348dd 100644 --- a/include/boost/process/v2/stdio.hpp +++ b/include/boost/process/v2/stdio.hpp @@ -312,7 +312,7 @@ struct process_stdio return error_code {}; }; #else - error_code on_exec_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *) + error_code on_exec_setup(posix::default_launcher & /*launcher*/, const filesystem::path &, const char * const *) { if (::dup2(in.fd, in.target) == -1) return error_code(errno, system_category()); diff --git a/include/boost/process/v2/windows/default_launcher.hpp b/include/boost/process/v2/windows/default_launcher.hpp index 7ea8c8472..ac615b400 100644 --- a/include/boost/process/v2/windows/default_launcher.hpp +++ b/include/boost/process/v2/windows/default_launcher.hpp @@ -43,8 +43,8 @@ struct base {}; struct derived : base {}; template -inline error_code invoke_on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line, - Init && init, base && ) +inline error_code invoke_on_setup(Launcher & /*launcher*/, const filesystem::path &executable, std::wstring &cmd_line, + Init && /*init*/, base && ) { return error_code{}; } @@ -69,7 +69,7 @@ template using has_on_setup = decltype(probe_on_setup(std::declval(), std::declval(), derived{})); template -inline error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line) +inline error_code on_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/) { return error_code{}; } @@ -87,8 +87,8 @@ inline error_code on_setup(Launcher & launcher, const filesystem::path &executab template -inline void invoke_on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line, - const error_code & ec, Init && init, base && ) +inline void invoke_on_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/, + const error_code & /*ec*/, Init && /*init*/, base && ) { } @@ -114,8 +114,8 @@ using has_on_error = decltype(probe_on_error(std::declval(), std::dec template -inline void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line, - const error_code & ec) +inline void on_error(Launcher & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/, + const error_code & /*ec*/) { } @@ -130,8 +130,8 @@ inline void on_error(Launcher & launcher, const filesystem::path &executable, st } template -inline void invoke_on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line, - Init && init, base && ) +inline void invoke_on_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/, + Init && /*init*/, base && ) { } @@ -155,7 +155,7 @@ template using has_on_success = decltype(probe_on_success(std::declval(), std::declval(), derived{})); template -inline void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line) +inline void on_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, std::wstring &/*cmd_line*/) { } diff --git a/src/detail/utf8.cpp b/src/detail/utf8.cpp index 531683e86..8facb1841 100644 --- a/src/detail/utf8.cpp +++ b/src/detail/utf8.cpp @@ -196,7 +196,7 @@ inline const wchar_t * get_octet1_modifier_table() noexcept } -std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec) +std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code &) { std::size_t res = 0u; const auto from_end = in + size; @@ -205,12 +205,15 @@ std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec) return res; } -std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec) +std::size_t size_as_wide(const char * in, std::size_t size, error_code &) { const auto from = in; const auto from_end = from + size; const char * from_next = from; - for (std::size_t char_count = 0u; from_next < from_end; ++char_count) { + std::size_t char_count = 0u; + while (from_next < from_end) + { + ++char_count; unsigned int octet_count = get_octet_count(*from_next); // The buffer may represent incomplete characters, so terminate early if one is found if (octet_count > static_cast(from_end - from_next)) diff --git a/src/ext/cmd.cpp b/src/ext/cmd.cpp index 14329b4de..34b2668c1 100644 --- a/src/ext/cmd.cpp +++ b/src/ext/cmd.cpp @@ -100,7 +100,7 @@ struct make_cmd_shell_ res.buffer_.resize(str_lengths); res.argv_ = new char*[res.argc_ + 1]; - res.free_argv_ = +[](int argc, char ** argv) {delete[] argv;}; + res.free_argv_ = +[](int /*argc*/, char ** argv) {delete[] argv;}; res.argv_[res.argc_] = nullptr; auto p = &*res.buffer_.begin(); @@ -262,7 +262,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) itr = e + 1; // start searching start } - auto fr_func = +[](int argc, char ** argv) {delete [] argv;}; + auto fr_func = +[](int /*argc*/, char ** argv) {delete [] argv;}; return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func); } diff --git a/src/posix/close_handles.cpp b/src/posix/close_handles.cpp index dc3fbe406..0da2b755e 100644 --- a/src/posix/close_handles.cpp +++ b/src/posix/close_handles.cpp @@ -146,7 +146,7 @@ void close_all(const std::vector & whitelist, error_code & ec) // linux impl - whitelist must be ordered -void close_all(const std::vector & whitelist, error_code & ec) +void close_all(const std::vector & whitelist, error_code & /*ec*/) { // https://patchwork.kernel.org/project/linux-fsdevel/cover/20200602204219.186620-1-christian.brauner@ubuntu.com/ //the most common scenario is whitelist = {0,1,2} diff --git a/test/v2/cstring_ref.cpp b/test/v2/cstring_ref.cpp index f2b82babc..a5aa8c0ff 100644 --- a/test/v2/cstring_ref.cpp +++ b/test/v2/cstring_ref.cpp @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(cstring_view_test) BOOST_CHECK_EQUAL_COLLECTIONS(s.rbegin(), s.rend(), sv.rbegin(), sv.rend()); BOOST_CHECK_EQUAL_COLLECTIONS(s.crbegin(), s.crend(), sv.crbegin(), sv.crend()); - BOOST_CHECK_EQUAL(sv.size(), 6); + BOOST_CHECK_EQUAL(sv.size(), 6u); sv.remove_prefix(1); BOOST_CHECK_EQUAL(sv.at(0), 'a'); BOOST_CHECK_EQUAL(sv.at(4), 'o'); @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(cstring_view_test) BOOST_CHECK_EQUAL(sv.front(), 'a'); BOOST_CHECK_EQUAL(sv.back(), 'o'); - BOOST_CHECK_EQUAL(sv.length(), 5); + BOOST_CHECK_EQUAL(sv.length(), 5u); BOOST_CHECK_EQUAL(sv.c_str(), s.c_str() + 1); BOOST_CHECK_EQUAL(sv.substr(2).c_str(), s.c_str() + 3); diff --git a/test/v2/ext.cpp b/test/v2/ext.cpp index 46cbdc07b..0ed55c9c0 100644 --- a/test/v2/ext.cpp +++ b/test/v2/ext.cpp @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(cmd_exe) bp2::basic_cstring_ref ref(cm.argv()[0]); BOOST_CHECK_EQUAL(bp2::detail::conv_string(ref.data(), ref.size()), pth); - BOOST_REQUIRE_EQUAL(cm.argc(), args.size() + 1u); + BOOST_REQUIRE_EQUAL(cm.argc(), static_cast(args.size() + 1u)); for (auto i = 0u; i < args.size(); i++) { ref = cm.argv()[i + 1]; diff --git a/test/v2/process.cpp b/test/v2/process.cpp index 4daa734c1..b2b71dfd4 100644 --- a/test/v2/process.cpp +++ b/test/v2/process.cpp @@ -73,7 +73,7 @@ BOOST_AUTO_TEST_CASE(exit_code_async) using boost::unit_test::framework::master_test_suite; printf("Running exit_code_async\n"); auto & mm = master_test_suite(); - printf("Running exit_code_async %p\n", &mm); + printf("Running exit_code_async %p\n", static_cast(&mm)); printf("Args: '%d'\n", master_test_suite().argc); printf("Exe '%s'\n", master_test_suite().argv[0]); const auto pth = master_test_suite().argv[1]; @@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE(echo_file) BOOST_CHECK(ofs); } - bpv::process proc(ctx, pth, {"echo"}, bpv::process_stdio{/*.in=*/p, /*.out=*/wp}); + bpv::process proc(ctx, pth, {"echo"}, bpv::process_stdio{/*.in=*/p, /*.out=*/wp, /*.err*/{}}); wp.close(); std::string out; @@ -338,7 +338,7 @@ BOOST_AUTO_TEST_CASE(print_same_cwd) asio::readable_pipe rp{ctx}; // default CWD - bpv::process proc(ctx, pth, {"print-cwd"}, bpv::process_stdio{/*.in=*/{},/*.out=*/rp}); + bpv::process proc(ctx, pth, {"print-cwd"}, bpv::process_stdio{/*.in=*/{},/*.out=*/rp, /*.err*/{}}); std::string out; bpv::error_code ec; @@ -403,7 +403,7 @@ BOOST_AUTO_TEST_CASE(print_other_cwd) // default CWD bpv::process proc(ctx, pth, {"print-cwd"}, - bpv::process_stdio{/*.in=*/{}, /*.out=*/wp}, + bpv::process_stdio{/*.in=*/{}, /*.out=*/wp, /*.err=*/{}}, bpv::process_start_dir(target)); wp.close(); @@ -442,7 +442,7 @@ std::string read_env(const char * name, Inits && ... inits) asio::writable_pipe wp{ctx}; asio::connect_pipe(rp, wp); - bpv::process proc(ctx, pth, {"print-env", name}, bpv::process_stdio{/*.in-*/{}, /*.out*/{wp}}, std::forward(inits)...); + bpv::process proc(ctx, pth, {"print-env", name}, bpv::process_stdio{/*.in-*/{}, /*.out*/{wp}, /*.err*/{}}, std::forward(inits)...); wp.close(); @@ -556,7 +556,7 @@ BOOST_AUTO_TEST_CASE(bind_launcher) auto l = bpv::bind_default_launcher(bpv::process_start_dir(target)); std::vector args = {"print-cwd"}; // default CWD - bpv::process proc = l(ctx, pth, args, bpv::process_stdio{/*.in=*/{}, /*.out=*/rp}); + bpv::process proc = l(ctx, pth, args, bpv::process_stdio{/*.in=*/{}, /*.out=*/rp, /*.err=*/{}}); std::string out; bpv::error_code ec; @@ -607,7 +607,7 @@ BOOST_AUTO_TEST_CASE(async_interrupt) bpv::evaluate_exit_code(res) & ~SIGTERM, 0); })); - tim.async_wait([&](bpv::error_code ec) { sig.emit(asio::cancellation_type::total); }); + tim.async_wait([&](bpv::error_code) { sig.emit(asio::cancellation_type::total); }); ctx.run(); } @@ -636,7 +636,7 @@ BOOST_AUTO_TEST_CASE(async_request_exit) BOOST_CHECK_EQUAL(bpv::evaluate_exit_code(res) & ~SIGTERM, 0); })); - tim.async_wait([&](bpv::error_code ec) { sig.emit(asio::cancellation_type::partial); }); + tim.async_wait([&](bpv::error_code) { sig.emit(asio::cancellation_type::partial); }); ctx.run(); } From 3fe203306272f4309819517b19e3ae1b89a3e846 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 13 Dec 2024 12:26:25 +0800 Subject: [PATCH 02/32] fixes #431 --- include/boost/process/v2/stdio.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/boost/process/v2/stdio.hpp b/include/boost/process/v2/stdio.hpp index 4deb348dd..bb0dbc247 100644 --- a/include/boost/process/v2/stdio.hpp +++ b/include/boost/process/v2/stdio.hpp @@ -26,13 +26,15 @@ #include #endif +#if defined(BOOST_PROCESS_V2_WINDOWS) +#include +#endif + BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace detail { #if defined(BOOST_PROCESS_V2_WINDOWS) -extern "C" intptr_t _get_osfhandle(int fd); - struct handle_closer { handle_closer() = default; @@ -84,7 +86,7 @@ struct process_io_binding : process_io_binding(str.native_handle()) {} - process_io_binding(FILE * f) : process_io_binding(_get_osfhandle(_fileno(f))) {} + 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")) {} template::value>::type> From 0f9dd52f02f69988d9479ade5945e58f145717f0 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 13 Dec 2024 12:26:46 +0800 Subject: [PATCH 03/32] added BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK See #430 --- include/boost/process/v2/posix/default_launcher.hpp | 9 ++++++++- .../process/v2/posix/fork_and_forget_launcher.hpp | 10 +++++++++- include/boost/process/v2/posix/pdfork_launcher.hpp | 8 ++++++++ include/boost/process/v2/posix/vfork_launcher.hpp | 10 +++++++--- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/include/boost/process/v2/posix/default_launcher.hpp b/include/boost/process/v2/posix/default_launcher.hpp index 37dc4510a..0ed0b9211 100644 --- a/include/boost/process/v2/posix/default_launcher.hpp +++ b/include/boost/process/v2/posix/default_launcher.hpp @@ -383,11 +383,15 @@ struct default_launcher auto & ctx = net::query( exec, net::execution::context); +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_prepare); +#endif pid = ::fork(); if (pid == -1) { +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_parent); +#endif detail::on_fork_error(*this, executable, argv, ec, inits...); detail::on_error(*this, executable, argv, ec, inits...); @@ -397,7 +401,9 @@ struct default_launcher else if (pid == 0) { ::close(pg.p[0]); +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_child); +#endif ec = detail::on_exec_setup(*this, executable, argv, inits...); if (!ec) { @@ -412,8 +418,9 @@ struct default_launcher ::exit(EXIT_FAILURE); return basic_process{exec}; } - +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_parent); +#endif ::close(pg.p[1]); pg.p[1] = -1; int child_error{0}; diff --git a/include/boost/process/v2/posix/fork_and_forget_launcher.hpp b/include/boost/process/v2/posix/fork_and_forget_launcher.hpp index ff28eef93..91a622d3b 100644 --- a/include/boost/process/v2/posix/fork_and_forget_launcher.hpp +++ b/include/boost/process/v2/posix/fork_and_forget_launcher.hpp @@ -86,11 +86,16 @@ struct fork_and_forget_launcher : default_launcher auto & ctx = net::query( exec, net::execution::context); +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_prepare); +#endif pid = ::fork(); if (pid == -1) { +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_parent); +#endif + detail::on_fork_error(*this, executable, argv, ec, inits...); detail::on_fork_error(*this, executable, argv, ec, inits...); detail::on_error(*this, executable, argv, ec, inits...); @@ -99,8 +104,9 @@ struct fork_and_forget_launcher : default_launcher } else if (pid == 0) { +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_child); - +#endif ec = detail::on_exec_setup(*this, executable, argv, inits...); if (!ec) close_all_fds(ec); @@ -112,7 +118,9 @@ struct fork_and_forget_launcher : default_launcher ::exit(EXIT_FAILURE); return basic_process{exec}; } +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_parent); +#endif if (ec) { detail::on_error(*this, executable, argv, ec, inits...); diff --git a/include/boost/process/v2/posix/pdfork_launcher.hpp b/include/boost/process/v2/posix/pdfork_launcher.hpp index a00baf4c1..16e5ca821 100644 --- a/include/boost/process/v2/posix/pdfork_launcher.hpp +++ b/include/boost/process/v2/posix/pdfork_launcher.hpp @@ -103,11 +103,15 @@ struct pdfork_launcher : default_launcher auto & ctx = net::query( exec, net::execution::context); +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_prepare); +#endif pid = ::pdfork(&fd, PD_DAEMON | PD_CLOEXEC); if (pid == -1) { +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_parent); +#endif detail::on_fork_error(*this, executable, argv, ec, inits...); detail::on_error(*this, executable, argv, ec, inits...); @@ -116,7 +120,9 @@ struct pdfork_launcher : default_launcher } else if (pid == 0) { +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_child); +#endif ::close(pg.p[0]); ec = detail::on_exec_setup(*this, executable, argv, inits...); @@ -133,7 +139,9 @@ struct pdfork_launcher : default_launcher ::exit(EXIT_FAILURE); return basic_process{exec}; } +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_parent); +#endif ::close(pg.p[1]); pg.p[1] = -1; int child_error{0}; diff --git a/include/boost/process/v2/posix/vfork_launcher.hpp b/include/boost/process/v2/posix/vfork_launcher.hpp index 81c0db832..cec0ca1eb 100644 --- a/include/boost/process/v2/posix/vfork_launcher.hpp +++ b/include/boost/process/v2/posix/vfork_launcher.hpp @@ -86,13 +86,16 @@ struct vfork_launcher : default_launcher return basic_process(exec); } - auto & ctx = net::query( - exec, net::execution::context); + auto & ctx = net::query(exec, net::execution::context); +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_prepare); +#endif pid = ::vfork(); if (pid == -1) { +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_parent); +#endif detail::on_fork_error(*this, executable, argv, ec, inits...); detail::on_error(*this, executable, argv, ec, inits...); @@ -112,8 +115,9 @@ struct vfork_launcher : default_launcher ::_exit(EXIT_FAILURE); return basic_process{exec}; } +#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_parent); - +#endif if (ec) { detail::on_error(*this, executable, argv, ec, inits...); From 64fc05c55dd5b2a4cfc2b453c54b5f83426ad44f Mon Sep 17 00:00:00 2001 From: tomy2105 Date: Thu, 31 Oct 2024 13:27:14 +0100 Subject: [PATCH 04/32] Add ability to auto link process library --- include/boost/process/v2/detail/config.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/process/v2/detail/config.hpp b/include/boost/process/v2/detail/config.hpp index a38c89ed9..17f50c22b 100644 --- a/include/boost/process/v2/detail/config.hpp +++ b/include/boost/process/v2/detail/config.hpp @@ -151,6 +151,14 @@ BOOST_PROCESS_V2_END_NAMESPACE #define BOOST_PROCESS_V2_DECL #endif +#if !defined(BOOST_PROCESS_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_PROCESS_NO_LIB) +#define BOOST_LIB_NAME boost_process +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_PROCESS_DYN_LINK) +#define BOOST_DYN_LINK +#endif +#include +#endif + #if defined(BOOST_PROCESS_V2_POSIX) #if defined(__linux__) && !defined(BOOST_PROCESS_V2_DISABLE_PIDFD_OPEN) From c0a23ae2c3f962c415eeb8420bec5cbbed328169 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Fri, 20 Dec 2024 02:49:30 +0100 Subject: [PATCH 05/32] Fix Github Actions CI (#437) * Fix Github Actions CI Containerize old compiler jobs Fix Node20 Glibc Reformat job list to make it easier to update * Fix install of packages * Remove macos-12 --- .github/workflows/ci.yml | 127 +++++++++++++-------------------------- 1 file changed, 41 insertions(+), 86 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f58158ac2..0c392d825 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,101 +13,56 @@ env: jobs: posix: + defaults: + run: + shell: bash + strategy: fail-fast: false matrix: include: - - toolset: gcc-5 - cxxstd: "11,14,1z" - os: ubuntu-18.04 - install: g++-5 - - toolset: gcc-6 - cxxstd: "11,14,1z" - os: ubuntu-18.04 - install: g++-6 - - toolset: gcc-7 - cxxstd: "11,14,17" - os: ubuntu-18.04 - - toolset: gcc-10 - cxxstd: "11,14,17,2a" - os: ubuntu-20.04 - install: g++-10 - - toolset: gcc-12 - cxxstd: "11,14,17,20,2b" - os: ubuntu-22.04 - install: g++-12 - - toolset: clang - compiler: clang++-3.9 - cxxstd: "11,14" - os: ubuntu-18.04 - install: clang-3.9 - - toolset: clang - compiler: clang++-4.0 - cxxstd: "11,14" - os: ubuntu-18.04 - install: clang-4.0 - - toolset: clang - compiler: clang++-5.0 - cxxstd: "11,14,1z" - os: ubuntu-18.04 - install: clang-5.0 - - toolset: clang - compiler: clang++-6.0 - cxxstd: "11,14,17" - os: ubuntu-18.04 - install: clang-6.0 - - toolset: clang - compiler: clang++-7 - cxxstd: "11,14,17" - os: ubuntu-18.04 - install: clang-7 - - toolset: clang - compiler: clang++-8 - cxxstd: "11,14,17" - os: ubuntu-20.04 - install: clang-8 - - toolset: clang - compiler: clang++-9 - cxxstd: "11,14,17,2a" - os: ubuntu-20.04 - install: clang-9 - - toolset: clang - compiler: clang++-10 - cxxstd: "11,14,17,2a" - os: ubuntu-20.04 - install: clang-10 - - toolset: clang - compiler: clang++-11 - cxxstd: "11,14,17,2a" - os: ubuntu-20.04 - install: clang-11 - - toolset: clang - compiler: clang++-12 - cxxstd: "11,14,17,2a" - os: ubuntu-20.04 - install: clang-12 - - toolset: clang - compiler: clang++-13 - cxxstd: "11,14,17,20,2b" - os: ubuntu-22.04 - install: clang-13 - - toolset: clang - compiler: clang++-14 - cxxstd: "11,14,17,20,2b" - os: ubuntu-22.04 - install: clang-14 - - toolset: clang - cxxstd: "11,14,17,2a" - os: macos-11 + - { toolset: gcc-5, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: g++-5 } + - { toolset: gcc-6, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: g++-6 } + - { toolset: gcc-7, cxxstd: "11,14,17", os: ubuntu-20.04, install: g++-7 } + - { toolset: gcc-10, cxxstd: "11,14,17,2a", os: ubuntu-22.04, install: g++-10 } + - { toolset: gcc-12, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: g++-12 } + - { toolset: clang, compiler: clang++-3.9, cxxstd: "11,14", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-3.9 } + - { toolset: clang, compiler: clang++-4.0, cxxstd: "11,14", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-4.0 } + - { toolset: clang, compiler: clang++-5.0, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-5.0 } + - { toolset: clang, compiler: clang++-6.0, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-6.0 } + - { toolset: clang, compiler: clang++-7, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-7 } + - { toolset: clang, compiler: clang++-8, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-8 } + - { toolset: clang, compiler: clang++-9, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-9 } + - { toolset: clang, compiler: clang++-10, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-10 } + - { toolset: clang, compiler: clang++-11, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-11 } + - { toolset: clang, compiler: clang++-12, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-12 } + - { toolset: clang, compiler: clang++-13, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: clang-13 } + - { toolset: clang, compiler: clang++-14, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: clang-14 } + - { toolset: clang, cxxstd: "11,14,17,2a", os: macos-13 } runs-on: ${{matrix.os}} + container: + image: ${{matrix.container}} + volumes: + - /node20217:/node20217:rw,rshared + - ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }} steps: - - uses: actions/checkout@v2 + - name: Setup container environment + if: matrix.container + run: | + apt-get update + apt-get -y install sudo python3 git g++ curl + if [[ "${{matrix.container}}" == "ubuntu:1"* ]]; then + # Node 20 doesn't work with Ubuntu 16/18 glibc: https://github.com/actions/checkout/issues/1590 + curl -sL https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz | tar -xJ --strip-components 1 -C /node20217 + fi + + - uses: actions/checkout@v4 - name: Install packages if: matrix.install - run: sudo apt install ${{matrix.install}} + run: sudo apt-get -y install ${{matrix.install}} - name: Setup Boost run: | @@ -127,7 +82,7 @@ jobs: 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 + python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY ./bootstrap.sh ./b2 -d0 headers @@ -207,7 +162,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Boost shell: cmd From 5cfdf3ec4c71a761d492fa31232b8ada16af9a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D9=87=D8=AF=D9=8A=20=D8=B4=D9=8A=D9=86=D9=88=D9=86?= =?UTF-8?q?=20=28Mehdi=20Chinoune=29?= <79349457+MehdiChinoune@users.noreply.github.com> Date: Fri, 20 Dec 2024 02:49:55 +0100 Subject: [PATCH 06/32] Fix building with CMake on MinGW-w64. (#439) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be4cba054..a732519c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ else() endif() if (WIN32) - target_link_libraries(boost_process PUBLIC ntdll shell32 advapi32 user32) + target_link_libraries(boost_process PUBLIC ntdll shell32 advapi32 user32 ws2_32) endif() if(BUILD_SHARED_LIBS) From 09a978d8962c37689a42487500e94c865b52085f Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 09:50:51 +0800 Subject: [PATCH 07/32] disabled gcc11 on freebsd --- .drone.star | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.star b/.drone.star index 24fb934bc..8e1104db1 100644 --- a/.drone.star +++ b/.drone.star @@ -14,7 +14,7 @@ windowsglobalimage="cppalliance/dronevs2019" def main(ctx): return [ - freebsd_cxx("gcc 11 freebsd", "g++-11", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '17,20', 'B2_LINKFLAGS': '-Wl,-rpath=/usr/local/lib/gcc11'}, globalenv=globalenv), + #freebsd_cxx("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), From 2275057574cb4bcf8d1db4781198a1c336a63638 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Thu, 7 Nov 2024 22:04:19 +0800 Subject: [PATCH 08/32] v2 uses PROC_THREAD_ATTRIBUTE_HANDLE_LIST for limiting fd thanks @NVCherney for bring this to my attention. --- include/boost/process/v2/stdio.hpp | 6 ++- .../process/v2/windows/as_user_launcher.hpp | 10 ++++- .../process/v2/windows/default_launcher.hpp | 28 +++++++++++-- src/windows/default_launcher.cpp | 39 +++++++++++++++++++ 4 files changed, 77 insertions(+), 6 deletions(-) diff --git a/include/boost/process/v2/stdio.hpp b/include/boost/process/v2/stdio.hpp index bb0dbc247..0568622e0 100644 --- a/include/boost/process/v2/stdio.hpp +++ b/include/boost/process/v2/stdio.hpp @@ -305,12 +305,14 @@ struct process_stdio #if defined(BOOST_PROCESS_V2_WINDOWS) error_code on_setup(windows::default_launcher & launcher, const filesystem::path &, const std::wstring &) { - launcher.startup_info.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; launcher.startup_info.StartupInfo.hStdInput = in.prepare(); launcher.startup_info.StartupInfo.hStdOutput = out.prepare(); launcher.startup_info.StartupInfo.hStdError = err.prepare(); - launcher.inherit_handles = true; + launcher.inherited_handles.reserve(launcher.inherited_handles.size() + 3); + launcher.inherited_handles.push_back(launcher.startup_info.StartupInfo.hStdInput); + launcher.inherited_handles.push_back(launcher.startup_info.StartupInfo.hStdOutput); + launcher.inherited_handles.push_back(launcher.startup_info.StartupInfo.hStdError); return error_code {}; }; #else diff --git a/include/boost/process/v2/windows/as_user_launcher.hpp b/include/boost/process/v2/windows/as_user_launcher.hpp index 3829a120d..053d166e8 100644 --- a/include/boost/process/v2/windows/as_user_launcher.hpp +++ b/include/boost/process/v2/windows/as_user_launcher.hpp @@ -91,13 +91,21 @@ struct as_user_launcher : default_launcher detail::on_error(*this, executable, command_line, ec, inits...); return basic_process(exec); } + + if (!inherited_handles.empty()) + { + set_handle_list(ec); + if (ec) + return basic_process(exec); + } + auto ok = ::CreateProcessAsUserW( token, executable.empty() ? nullptr : executable.c_str(), command_line.empty() ? nullptr : &command_line.front(), process_attributes, thread_attributes, - inherit_handles ? TRUE : FALSE, + inherited_handles.empty() ? FALSE : TRUE, creation_flags, environment, current_directory.empty() ? nullptr : current_directory.c_str(), diff --git a/include/boost/process/v2/windows/default_launcher.hpp b/include/boost/process/v2/windows/default_launcher.hpp index ac615b400..b41f87c49 100644 --- a/include/boost/process/v2/windows/default_launcher.hpp +++ b/include/boost/process/v2/windows/default_launcher.hpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #if defined(BOOST_PROCESS_V2_STANDALONE) @@ -207,8 +209,8 @@ struct default_launcher SECURITY_ATTRIBUTES * process_attributes = nullptr; //// The thread_attributes passed to CreateProcess SECURITY_ATTRIBUTES * thread_attributes = nullptr; - /// The bInheritHandles option. Needs to be set to true by any initializers using handles. - bool inherit_handles = false; + /// The inhreited_handles option. bInheritHandles will be true if not empty.. + std::vector inherited_handles; /// The creation flags of the process. Initializers may add to them; extended startupinfo is assumed. DWORD creation_flags{EXTENDED_STARTUPINFO_PRESENT}; /// A pointer to the subprocess environment. @@ -294,18 +296,26 @@ struct default_launcher auto command_line = this->build_command_line(executable, std::forward(args)); ec = detail::on_setup(*this, executable, command_line, inits...); + if (ec) { detail::on_error(*this, executable, command_line, ec, inits...); return basic_process(exec); } + if (!inherited_handles.empty()) + { + set_handle_list(ec); + if (ec) + return basic_process(exec); + } + auto ok = ::CreateProcessW( executable.empty() ? nullptr : executable.c_str(), command_line.empty() ? nullptr : &command_line.front(), process_attributes, thread_attributes, - inherit_handles ? TRUE : FALSE, + inherited_handles.empty() ? FALSE : TRUE, creation_flags, environment, current_directory.empty() ? nullptr : current_directory.c_str(), @@ -403,6 +413,18 @@ struct default_launcher return args; } + struct lpproc_thread_closer + { + void operator()(::LPPROC_THREAD_ATTRIBUTE_LIST l) + { + ::DeleteProcThreadAttributeList(l); + ::HeapFree(GetProcessHeap(), 0, l); + } + }; + std::unique_ptr::type, lpproc_thread_closer> proc_attribute_list_storage; + + BOOST_PROCESS_V2_DECL LPPROC_THREAD_ATTRIBUTE_LIST get_thread_attribute_list(error_code & ec); + BOOST_PROCESS_V2_DECL void set_handle_list(error_code & ec); }; diff --git a/src/windows/default_launcher.cpp b/src/windows/default_launcher.cpp index 3d7e197cb..f52c86b9e 100644 --- a/src/windows/default_launcher.cpp +++ b/src/windows/default_launcher.cpp @@ -75,6 +75,45 @@ namespace windows return itr - begin; } + LPPROC_THREAD_ATTRIBUTE_LIST default_launcher::get_thread_attribute_list(error_code & ec) + { + if (startup_info.lpAttributeList != nullptr) + return startup_info.lpAttributeList; + SIZE_T size; + if (!(::InitializeProcThreadAttributeList(NULL, 1, 0, &size) || + GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec); + return nullptr; + } + + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = reinterpret_cast(::HeapAlloc(::GetProcessHeap(), 0, size)); + if (lpAttributeList == nullptr) + return nullptr; + + if (!::InitializeProcThreadAttributeList(lpAttributeList, 1, 0, &size)) + { + BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec); + ::HeapFree(GetProcessHeap(), 0, lpAttributeList); + return nullptr; + } + + proc_attribute_list_storage.reset(lpAttributeList); + startup_info.lpAttributeList = proc_attribute_list_storage.get(); + return startup_info.lpAttributeList; + } + + void default_launcher::set_handle_list(error_code & ec) + { + auto tl = get_thread_attribute_list(ec); + if (ec) + return; + if (!::UpdateProcThreadAttribute( + tl, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, + inherited_handles.data(), inherited_handles.size() * sizeof(HANDLE), nullptr, nullptr)) + BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec); + } + } BOOST_PROCESS_V2_END_NAMESPACE From b5eacaca51dff5110a814984914070f628fe46f0 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 10:09:07 +0800 Subject: [PATCH 09/32] disabled shell for android Closes #440. --- src/shell.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shell.cpp b/src/shell.cpp index ec0548d01..bf4bbfd83 100644 --- a/src/shell.cpp +++ b/src/shell.cpp @@ -19,7 +19,7 @@ #if defined(BOOST_PROCESS_V2_WINDOWS) #include #include -#elif !defined(__OpenBSD__) +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) #include #endif @@ -30,7 +30,7 @@ BOOST_PROCESS_V2_DECL const error_category& get_shell_category() { return system_category(); } -#elif !defined(__OpenBSD__) +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) struct shell_category_t final : public error_category { @@ -99,7 +99,7 @@ auto shell::args() const-> args_type return input_.c_str(); } -#elif !defined(__OpenBSD__) +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) void shell::parse_() { From 7874a0495820eb5b536e41266f1d6013cd64e839 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Tue, 19 Nov 2024 08:48:34 +0800 Subject: [PATCH 10/32] switched to asciidoc --- doc/Jamfile.jam | 121 +---- ...owledgements.qbk => acknowledgements.adoc} | 8 +- doc/{v2/env.qbk => env.adoc} | 52 ++- doc/index.adoc | 28 ++ doc/launcher.adoc | 126 ++++++ doc/process.qbk | 18 - doc/quickstart.adoc | 113 +++++ doc/start_dir.adoc | 14 + doc/stdio.adoc | 81 ++++ doc/v1.qbk | 11 - doc/v1/concepts.qbk | 82 ---- doc/v1/design.qbk | 94 ---- doc/v1/extend.qbk | 212 --------- doc/v1/faq.qbk | 87 ---- doc/v1/introduction.qbk | 24 - doc/v1/posix_pseudocode.xml | 60 --- doc/v1/tutorial.qbk | 425 ------------------ doc/v1/windows_pseudocode.xml | 42 -- doc/v2.qbk | 11 - doc/v2/launcher.qbk | 128 ------ doc/v2/quickstart.qbk | 123 ----- doc/v2/start_dir.qbk | 16 - doc/v2/stdio.qbk | 89 ---- doc/{v2/introduction.qbk => version2.adoc} | 57 ++- include/boost/process/v1/detail/config.hpp | 2 +- include/boost/process/v2/detail/config.hpp | 2 +- 26 files changed, 443 insertions(+), 1583 deletions(-) rename doc/{acknowledgements.qbk => acknowledgements.adoc} (64%) rename doc/{v2/env.qbk => env.adoc} (52%) create mode 100644 doc/index.adoc create mode 100644 doc/launcher.adoc delete mode 100644 doc/process.qbk create mode 100644 doc/quickstart.adoc create mode 100644 doc/start_dir.adoc create mode 100644 doc/stdio.adoc delete mode 100644 doc/v1.qbk delete mode 100644 doc/v1/concepts.qbk delete mode 100644 doc/v1/design.qbk delete mode 100644 doc/v1/extend.qbk delete mode 100644 doc/v1/faq.qbk delete mode 100644 doc/v1/introduction.qbk delete mode 100644 doc/v1/posix_pseudocode.xml delete mode 100644 doc/v1/tutorial.qbk delete mode 100644 doc/v1/windows_pseudocode.xml delete mode 100644 doc/v2.qbk delete mode 100644 doc/v2/launcher.qbk delete mode 100644 doc/v2/quickstart.qbk delete mode 100644 doc/v2/start_dir.qbk delete mode 100644 doc/v2/stdio.qbk rename doc/{v2/introduction.qbk => version2.adoc} (65%) diff --git a/doc/Jamfile.jam b/doc/Jamfile.jam index 5ed200775..a993c8747 100644 --- a/doc/Jamfile.jam +++ b/doc/Jamfile.jam @@ -1,106 +1,31 @@ -# Copyright (c) 2006, 2007 Julio M. Merino Vidal -# Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -# Copyright (c) 2009 Boris Schaeling -# Copyright (c) 2010 Felipe Tanus, Boris Schaeling -# Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -# -# 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) +# Copyright 2022 Klemens D. Morgenstern +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt -using boostbook ; -using quickbook ; -using doxygen ; +import asciidoctor ; +html index.html : index.adoc ; -local images = [ glob images/*.svg ] ; -install images : $(images) : html/boost_process ; -install images_glob : $(images) : $(BOOST_ROOT)/doc/html/boost_process ; +install html_ : index.html : html ; -import type ; -type.register XMLPROCESSWORKAROUND : : XML ; -import generators ; -generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ; +pdf process.pdf : index.adoc ; +explicit process.pdf ; -xmlprocessworkaround posix_pseudocode : v1/posix_pseudocode.xml ; -xmlprocessworkaround windows_pseudocode : v1/windows_pseudocode.xml ; +install pdf_ : process.pdf : pdf ; +explicit pdf_ ; -path-constant INCLUDES : ../include ; - -doxygen reference_v1 -: - $(INCLUDES)/boost/process/v1.hpp - [ glob $(INCLUDES)/boost/process/v1/*.hpp ] - : - EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE - "PREDEFINED=\\ - BOOST_PROCESS_DOXYGEN=1 \\ - BOOST_PROCESS_V1_INLINE= - " - HIDE_UNDOC_CLASSES=YES - HIDE_UNDOC_MEMBERS=YES - EXAMPLE_PATH=. - posix_pseudocode - windows_pseudocode - . -; - - - -doxygen reference_v2 -: - $(INCLUDES)/boost/process/v2.hpp - [ glob $(INCLUDES)/boost/process/v2/*.hpp ] - : - EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE - PROJECT_NAME="Process V2" - PROJECT_BRIEF="The process library" - MACRO_EXPANSION=YES - EXPAND_ONLY_PREDEF=YES - "PREDEFINED=\\ - GENERATING_DOCUMENTATION=1 \\ - BOOST_PROCESS_V2_ASIO_NAMESPACE=boost::asio \\ - \"BOOST_PROCESS_V2_BEGIN_NAMESPACE=namespace boost { namespace process { namespace v2 { \" \\ - \"BOOST_PROCESS_V2_END_NAMESPACE= } } }\" \\ - BOOST_PROCESS_V2_NAMESPACE=boost::process::v2 \\ - BOOST_PROCESS_V2_DECL \\ - BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(x,y)=deduced \\ - BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(X)=Token \\ - BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(E)=DEFAULT_TYPE \\ - BOOST_ASIO_DEFAULT_COMPLETION_TOKEN=DEFAULT \\ - BOOST_CONSTEXPR=constexpr \\ - BOOST_CXX14_CONSTEXPR=constexpr \\ - BOOST_PROCESS_V2_INLINE= \\ - BOOST_ATTRIBUTE_NODISCARD=[[nodiscard]] - " - reference_v2 - SHOW_USED_FILES=NO - SHOW_FILES=NO - SHOW_NAMESPACES=YES - CLASS_DIAGRAMS=NO - SORT_MEMBERS_CTORS_1ST=YES - HIDE_UNDOC_CLASSES=NO - . -; - - -boostbook standalone -: - process.qbk -: - reference_v1 - reference_v2 - images - images_glob - boost.root=../../../.. - html.stylesheet=../../../../doc/src/boostbook.css -; - -############################################################################### -alias boostdoc - : standalone/docbook +install images + : + images/posix_exec_err.png + images/posix_fork_err.png + images/posix_success.png + images/windows_exec.png : - : images_glob - : ; + html/images + ; + +alias boostdoc ; explicit boostdoc ; -alias boostrelease ; -explicit boostrelease ; \ No newline at end of file +alias boostrelease : html_ ; +explicit boostrelease ; + diff --git a/doc/acknowledgements.qbk b/doc/acknowledgements.adoc similarity index 64% rename from doc/acknowledgements.qbk rename to doc/acknowledgements.adoc index 069868120..3b7c6d387 100644 --- a/doc/acknowledgements.qbk +++ b/doc/acknowledgements.adoc @@ -1,13 +1,13 @@ -[section Acknowledgements] += Acknowledgements The first Boost.Process draft was created in 2006. A lof of people have worked on various drafts since then. Especially Merino Vidal, Ilya Sokolov and Felipe Tanus spent a lot of time working on early drafts. They influenced Boost.Process over the years and wrote code which, to various extents, is still around in the library today. The design of earlier versions of Boost.Process was not always satisfying. In 2011 Jeff Flinn proposed the executor and initializer concepts Boost.Process is based on today. Without Jeff's idea the overall design of Boost.Process would not look like it does today. -A special thank you goes to [@http://www.intra2net.com/ Intra2net AG] (especially Thomas Jarosch) who sponsored a project to support the development of Boost.Process. It was this sponsorship which made it possible to create a new Boost.Process version in 2012. +A special thank you goes to [http://www.intra2net.com/(Intra2net AG) (especially Thomas Jarosch) who sponsored a project to support the development of Boost.Process. It was this sponsorship which made it possible to create a new Boost.Process version in 2012. 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. +Many Thanks, to [https://github.com/time-killer-games](Samuel Venable) for contributing the <> functionality and all the research that went into it. + -[endsect] diff --git a/doc/v2/env.qbk b/doc/env.adoc similarity index 52% rename from doc/v2/env.qbk rename to doc/env.adoc index 817582a82..d00bb7cfc 100644 --- a/doc/v2/env.qbk +++ b/doc/env.adoc @@ -1,4 +1,4 @@ -[section:env Environment] +== Environment The `environment` namespace provides all sorts of facilities to query and manipulate the environment of the current process. @@ -14,35 +14,33 @@ as to have the right value comparisons. To note is the `find_executable` functions, which searches in an environment for an executable. -``` - // search in the current environment - auto exe = environment::find_executable("g++"); +[source,cpp] +---- +// search in the current environment +auto exe = environment::find_executable("g++"); - std::unordered_map my_env = - { - {"SECRET", "THIS_IS_A_TEST"}, - {"PATH", {"/bin", "/usr/bin"}} - }; +std::unordered_map my_env = + { + {"SECRET", "THIS_IS_A_TEST"}, + {"PATH", {"/bin", "/usr/bin"}} + }; - auto other_exe = environment::find_executable("g++", my_env); -``` +auto other_exe = environment::find_executable("g++", my_env); +---- -[section:process_env Subprocess environment] +== Subprocess environment The subprocess environment assignment follows the same constraints: -``` - asio::io_context ctx; - std::unordered_map my_env = - { - {"SECRET", "THIS_IS_A_TEST"}, - {"PATH", {"/bin", "/usr/bin"}} - }; - 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)); -``` - -[endsect] - -[endsect] \ No newline at end of file +[source,cpp] +---- +asio::io_context ctx; +std::unordered_map my_env = + { + {"SECRET", "THIS_IS_A_TEST"}, + {"PATH", {"/bin", "/usr/bin"}} + }; +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)); +---- diff --git a/doc/index.adoc b/doc/index.adoc new file mode 100644 index 000000000..627f78380 --- /dev/null +++ b/doc/index.adoc @@ -0,0 +1,28 @@ += boost.process +Klemens Morgenstern +Version 2.0, 19.11.2024 +:source-highlighter: rouge +:toc: left +:toclevels: 4 +:icons: font +:idprefix: +:docinfo: private-footer +:source-highlighter: rouge +:source-language: c++ +:example-caption: Example + +:imagesdir: ./images + +:leveloffset: +1 + +include::quickstart.adoc[] +include::launcher.adoc[] + += Initializers + +include::start_dir.adoc[] +include::stdio.adoc[] +include::env.adoc[] + +include::version2.adoc[] +include::acknowledgements.adoc[] \ No newline at end of file diff --git a/doc/launcher.adoc b/doc/launcher.adoc new file mode 100644 index 000000000..f7ad56cdf --- /dev/null +++ b/doc/launcher.adoc @@ -0,0 +1,126 @@ += Launcher + +The process creation is done by a process_launcher. +The constructor of `process` will use the default_launcher, which varies by system. +There are additional launcher available on most systems. + +[cols="1,1,1,1"] +|=== +|Name | Summary | Default on | Available on + + + + +|`windows::default_launcher` | `CreateProcessW` | windows |windows +|`windows::as_user_launcher` | `CreateProcessAsUserW` | |windows +|`windows::with_logon_launcher` | `CreateProcessWithLogonW` | |windows +|`windows::with_token_launcher` | `CreateProcessWithTokenW` | |windows +|`posix::default_launcher` | fork & an error pipe | most of posix |posix +|`posix::fork_and_forget` | fork without error pipe | |posix +|`posix::vfork_launcher` | vfork | |posix +|=== + +A launcher is invoked through the call operator. + +[source,cpp] +---- +auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF); +asio::io_context ctx; +boost::system::error_code ec; +auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {}); +---- + +The launcher will call certain functions on the initializer if they're present, as documented below. +The initializer are used to modify the process behaviour. + + +== Linux Launchers + +The default launchers on linux open an internal pipe to communicate errors that occur after forking back to the parent process. + +NOTE: A pipe can be used if one end is open on the parent, the other on the child. +This allows the parents to select on his pipe-end to know if the child exited. + +This can be prevented by using the `fork_and_forget_launcher`. +Alternatively, the `vfork_launcher` can report errors directly back to the parent process. + +Thus some calls to the initializers occur after forking from the child process. + +[source,cpp] +---- +struct custom_initializer +{ + // called before a call to fork. A returned error will cancel the launch. + template + error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line)); + + // called for every initializer if an error occurred during setup or process creation + template + void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), + const error_code & ec); + + // called after successful process creation + template + void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line)); + + // called for every initializer if an error occurred when forking, in addition to on_error. + template + void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), + const error_code & ec); + + + // called before a call to execve. A returned error will cancel the launch. Called from the child process. + template + error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line)); + + + // called after a failed call to execve from the child process. + template + void on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line)); +}; +---- + +The call sequence on success: + +image::posix_success.svg[] + +The call sequence when fork fails: + +image::posix_fork_err.svg[] + +The call sequence when exec fails: + +image::posix_exec_err.svg[] + +The launcher will close all non-whitelisted file descriptors after `on_exec_setup`. + +== Windows Launchers + +Windows launchers are pretty straight forward, they will call the following functions on the initializer if present. + +[source,cpp] +---- +struct custom_initializer +{ + // called before a call to CreateProcess. A returned error will cancel the launch. + template + error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line); + + // called for every initializer if an error occurred during setup or process creation + template + void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line, + const error_code & ec); + + // called after successful process creation + template + void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line); + +}; +---- + +NTOE: All the additional launchers for windows inherit `default_launcher`. + +The call sequence is as follows: + +image::windows_exec.svg +''' \ No newline at end of file diff --git a/doc/process.qbk b/doc/process.qbk deleted file mode 100644 index 43cb6031d..000000000 --- a/doc/process.qbk +++ /dev/null @@ -1,18 +0,0 @@ -[library Boost.Process - [quickbook 1.5] - [authors [Morgenstern, Klemens David]] - [copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 Julio M. Merino Vidal, Ilya Sokolov, Felipe Tanus, Jeff Flinn, Boris Schaeling, 2016 Klemens D. Morgenstern] - [id process] - [dirname process] - [license - 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) - ] -] - -[note Process v1 will be deprecated in the next release (1.88). Use v2 for new projects.] - -[include v1.qbk] -[include v2.qbk] -[include acknowledgements.qbk] diff --git a/doc/quickstart.adoc b/doc/quickstart.adoc new file mode 100644 index 000000000..f3ddf9eef --- /dev/null +++ b/doc/quickstart.adoc @@ -0,0 +1,113 @@ += Quickstart + +A process needs four things to be launched: + +* an asio execution_context / executor +* a path to an executable +* a list of arguments +* a variadic set of initializers + +[source,cpp] +---- +// process(asio::any_io_executor, filesystem::path, range args, AdditionalInitializers...) +asio::io_context ctx; +process proc(ctx.get_executor(), // <1> + "/usr/bin/cp", // <2> + {"source.txt", "target.txt"} // <3> + ); // <4> +---- +<1> The executor for the process handle +<2> The Path to the executable +<3> The argument list in the form of an `std::initializer_list`. +<4> Not additional initializers + +The started process can then be awaited or terminated. + +== Lifetime + +If the process handle goes out of scope, it will terminate the subprocess. +You can prevent this, by calling `proc.detach()`; do however note that this +can lead to zombie processes. + +A process that completed will deliver an exit-code, +which can be obtained by calling `.exit_code` on the exited process and which is +also returned from `.wait()`. + +[source,cpp] +---- +process proc("/bin/ls", {}); +assert(proc.wait() == 0); +---- + +The normal exit-code is what the subprocess returned from `main`; +posix will however add additional information about the process. +This is called the `native_exit_code`. + + +The `.running()` function can be used to detect if the process is still active. + + +== Signalling the subprocess + +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. + +[source,cpp] +---- +process proc("/bin/totally-not-a-virus", {}); +proc.terminate(); +---- + +`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix), +which the subprocess might ignore. + +[source,cpp] +---- +process proc("/bin/bash", {}); +proc.request_exit(); +proc.wait(); +---- + +`.interrupt` will send an SIGINT to the subprocess, which a subprocess might +interpret as a signal to shutdown. + +WARNING: interrupt requires the initializer `windows::create_new_process_group` to be set on windows + +[source,cpp] +---- +process proc("/usr/bin/addr2line", {}); +proc.request_exit(); +proc.wait(); +---- + +[endsect] + +[section:execute Execute functions] + +Process v2 provides `execute` and `async_execute` functions that can be used for managed executions. + +[source,cpp] +---- +assert(execute(process("/bin/ls", {}) == 0)); +---- + +The async version supports cancellation and will forward cancellation types as follows: + +- `asio::cancellation_type::total` -> interrupt +- `asio::cancellation_type::partial` -> request_exit +- `asio::cancellation_type::terminal` -> terminate + +[source,cpp] +---- +asio::awaitable compile() +{ + co_await async_execute(process("/usr/bin/g++", {"hello_world.cpp"})) + (asio::cancel_after(std::chrono::seconds(10, asio::cancellation_type::partial)) // <1> + (asio::cancel_after(std::chrono::seconds(10, asio::cancellation_type::terminal)); //<2> +} +---- +<1> After 10 seconds send a request_exit. +<2> After 20 seconds terminate + diff --git a/doc/start_dir.adoc b/doc/start_dir.adoc new file mode 100644 index 000000000..c37ee2564 --- /dev/null +++ b/doc/start_dir.adoc @@ -0,0 +1,14 @@ +== `process_start_dir` + +The easier initializer to use is `process_start_dir`: + +[source,cpp] +---- +asio::io_context ctx; +process ls(ctx.get_executor(), "/ls", {}, process_start_dir("/home")); +ls.wait(); +---- + +This will run `ls` in the folder `/home` instead of the current folder. + +WARNING: If your path is relative, it may fail on posix, because the directory is changed before a call to execve. \ No newline at end of file diff --git a/doc/stdio.adoc b/doc/stdio.adoc new file mode 100644 index 000000000..bd2b2dc90 --- /dev/null +++ b/doc/stdio.adoc @@ -0,0 +1,81 @@ += stdio + +When using io with a subprocess, all three standard streams (stdin, stdout, stderr) get set for the child-process. +The default setting is to inherit the parent process. + +This feature meant to be flexible, which is why there is little checking on the arguments assigned to one of those streams. + +== Pipes + +asio pipes can be used for io. When using in process_stdio they will get +automatically connected and the other side will get assigned to the child process: + +[source,cpp] +---- +asio::io_context ctx; +asio::readable_pipe rp{ctx}; + +process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }}); +std::string output; + +system::error_code ec; +rp.read(asio::dynamic_buffer(output), ec); +assert(ec == asio::eof); +proc.wait(); +---- + +readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`. + +== `FILE*` + +`FILE*` can also be used for either side; this allows the `stdin`, `stderr`, `stdout` macros to be used: + +[source,cpp] +---- +asio::io_context ctx; +// forward both stderr & stdout to stdout of the parent process +process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, stdout, stdout}); +proc.wait(); +---- + +== `nullptr` + +`nullptr` may be used to set a given stream to be opened on the null-device (`/dev/null` on posix, `NUL` on windows). +This is used to ignore output or give only EOF as input. + +[source,cpp] +---- +asio::io_context ctx; +// ignore stderr +process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr}); +proc.wait(); +---- + +== `native_handle` + +A native handle can be used as well, which means an `int` on posix or a `HANDLE` on windows. +Furthermore, any object that has a `native_handle` returning that native handle type is valid, too. + +[source,cpp] +---- +asio::io_context ctx; +// ignore stderr +asio::ip::tcp::socket sock{ctx}; +connect_my_socket(sock); +process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr}); +proc.wait(); +---- + +== popen + +Additionally, process v2 provides a `popen` class. +It starts a process and connects pipes for stdin and stdout, so that the popen object can be used as a stream. + +[source,cpp] +---- +popen proc(executor, "/usr/bin/addr2line, {argv[0]}); +asio::write(proc, asio::buffer("main\n")); +std::string line; +asio::read_until(proc, asio::dynamic_buffer(line), '\n'); +---- + diff --git a/doc/v1.qbk b/doc/v1.qbk deleted file mode 100644 index f382af2fa..000000000 --- a/doc/v1.qbk +++ /dev/null @@ -1,11 +0,0 @@ -[section:v1 Process V1] - -[include v1/introduction.qbk] -[include v1/concepts.qbk] -[include v1/tutorial.qbk] -[include v1/design.qbk] -[include v1/extend.qbk] -[include v1/faq.qbk] -[xinclude reference_v1.xml] - -[endsect] diff --git a/doc/v1/concepts.qbk b/doc/v1/concepts.qbk deleted file mode 100644 index 3b028cddd..000000000 --- a/doc/v1/concepts.qbk +++ /dev/null @@ -1,82 +0,0 @@ -[section:concepts Concepts] -In this section, some of the underlying concepts of the operating system used in this library, will be explained. -In the following chapters we will presume knowledge of that. Though please note, -that this is a short summary and not conclusive of everything that can be done. - -The goal of this library is to implement a portable wrapper, so that we will explain mostly what -windows and posix have in common. - -[section:pipes Pipes] -Pipes are a facility for communication between different threads, processes and in some cases machines, the operating system provides. - -The typical feature of a pipe is, that it is one channel, to which two handles are given, one for reading (source), one for writing (sink). -In that it is different than other facilities (like sockets) and provides another way to manage the connectivity: if one side of the pipe is closed -(i.e. the pipe is broken), the other is notified. - -Pipes are typically used for interprocess communication. The main reason is, that pipes can be directly assigned to the process stdio, i.e. stderr, stdin and stdout. -Additionally, half of the pipe can be inherited to the child process and closed in the father process. This will cause the pipe to be broken when the child process exits. - -Though please note, that if the same thread reads and writes to a pipe, it will only talk to itself. - -[section:anonymous Anonymous Pipes] - -The most common pipes are anonymous. Since they have no name, -a handle to them can only be obtained from duplicating either handle. - -In this library the following functions are used for the creation of unnamed pipes: - -* [@http://pubs.opengroup.org/onlinepubs/7908799/xsh/pipe.html posix] -* [@https://msdn.microsoft.com/de-de/library/windows/desktop/aa365152.aspx windows] - -[endsect] - -[section:named Named Pipes] - -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], -which means, that the named pipe behaves like a file. - -Windows does provide a facility called [@https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx named pipes], -which also have file-like names, but are in a different scope than the actual file system. - -[note The main reason named pipes are part of this library, is because they need to be internally used for asynchronous communication on windows.] - -[endsect] - -[endsect] - - -[section:process Processes] - -A process is an independently executable entity, which is different from a thread, in that it has its own resources. -Those include memory and hardware resources. - -Every process is identified by a unique number[footnote it is unique as long as the process is active], called the process identification digit, `pid`. - -[section:exit_code Exit code] -A process will return an integer value indicating whether it was successful. On posix -there are more codes associated with that, but not so on windows. Therefore there is no such encoding currently in the library. -However an exit code of zero means the process was successful, while one different than zero indicates an error. -[endsect] - -[section:termination Termination] -Processes can also be forced to exit. There are two ways to do this, signal the process to do so and wait, and just terminate the process without conditions. - -Usually the first approach is to signal an exit request, but windows - unlike posix - does not provide a consistent way to do this. Hence this is not part of the -library and only the hard terminate is. - -[endsect] - -[endsect] - -[section:env Environment] - -The environment is a map of variables local to every process. The most significant one for this library - is the `PATH` variable, which contains a list of paths, that ought to be searched for executables. A shell will do this automatically, - while this library provides a function for that. - -[endsect] - -[endsect] diff --git a/doc/v1/design.qbk b/doc/v1/design.qbk deleted file mode 100644 index 0dd49f16e..000000000 --- a/doc/v1/design.qbk +++ /dev/null @@ -1,94 +0,0 @@ -[section:design Design Rationale] -[section Scope] -This library is meant to give a wrapper around the different OS-specific methods -to launch processes. Its aim is to provide all functionality that is available on -those systems and allow the user to do all related things, which require using the OS APIs. - -[*This library does not try to provide a full library for everything process related.] -In many discussions the proposal was made to build boost.process into a DSEL [footnote Domain Specific Embedded Language] of some sort. -This is not the goal, it rather provides the facilities to build such a DSEL-library on top of it. -Therefore the library also does [*not] force any particular use (such as only asynchronous communication) on its user. -It rather could be integrated with such a library. - -[endsect] -[section Interface Style] - -Boost.Process does use a very particular style when constructing a process. -This is because a process holds many properties, which are not members of the actual child class. -Those properties are in many cases not accessible by the father process, for example when using environments. -Here the child process can modify its own environment, but there is no way for the father process to know. -That means, that a child process has properties that cannot be accessed in C++. - -This now leads to the two styles supported and mixed by this library. Overloading and properties. -Consider that you may want to launch a process passing a number of arguments. This is supported in both styles, and would look like this: - -``` -system("gcc", "--version"); //overloading -system("gcc", args={"--version"}); //property style. -``` - -Both styles can also be mixed in some cases. - -``` -system("gcc", "-c", args+={"main.cpp"}); -``` - -In the following section the available styles will be described. Note that the -overload style is implemented via type traits, so the types will be listed. - -[caution There is no guarantee in which order the arguments will be applied! -There is however a guarantee for arguments belonging together, i.e. the string -argument and the args property will be evaluated in the order given.] - -[endsect] -[section:arg_cmd_style Arguments/Command Style] - -When passing arguments to the process, two styles are provided, the cmd-style and the exe-/args-style. - -The cmd style will interpret the string as a sequence of the exe and arguments and parse them as such, while the exe-/args-style will -interpret each string as an argument. - -[table:id Cmd vs Exe/Args - [[String] [Cmd] [Exe/Args]] - [["gcc --version"] [{"gcc", "--version"}] [{"\\"gcc --version\\""}]] -] - -When using the overloading variant, a single string will result in a cmd interpretation, -several strings will yield a exe-args interpretation. Both versions can be set explicitly: - -``` -system("grep -c false /etc/passwd"); //cmd style -system("grep", "-c", "false", "/etc/passwd"); //exe-/args- - -system(cmd="grep -c false /etc/passwd"); //cmd style -system(exe="grep", args={"-c", "false", "/etc/passwd"}); //exe-/args- -``` - -[note If a '"' sign is used in the argument style, it will be passed as part of the argument. -If the same effect is wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ] -[note The `PATH` variable will automatically be searched in the command style, -but the one of the launching process, not the one passed to the child process.] -[endsect] - -[section:plat_ext Extensions] - -The simplest form to extend functionality is to provide another handler, which -will be called on the respective events on process launching. The names are: - -*`boost::process::v1::on_setup` -*`boost::process::v1::on_error` -*`boost::process::v1::on_success` - - -As an example: - -``` -child c("ls", on_setup([](){cout << "On Setup" << endl;})); -``` - - -[note On posix all those callbacks will be handled by this process, not the created one. -This is different for the posix extensions, which can be executed on the forked process.] -[endsect] - -[endsect] diff --git a/doc/v1/extend.qbk b/doc/v1/extend.qbk deleted file mode 100644 index dfe4f8517..000000000 --- a/doc/v1/extend.qbk +++ /dev/null @@ -1,212 +0,0 @@ -[def __on_exit__ [globalref boost::process::v1::on_exit on_exit]] -[def __on_success__ [globalref boost::process::v1::extend::on_success ex::on_success]] -[def __child__ [classref boost::process::v1::child child]] -[def __handler__ [classref boost::process::v1::extend::handler handler]] -[def __on_success__ [memberref boost::process::v1::extend::handler::on_success on_success]] -[def __posix_executor__ [classref boost::process::v1::extend::posix_executor ex::posix_executor]] -[def __windows_executor__ [classref boost::process::v1::extend::windows_executor ex::windows_executor]] -[def __io_context__ [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_context.html boost::asio::io_context]] -[def __require_io_context__ [classref boost::process::v1::extend::require_io_context ex::require_io_context]] -[def __async_handler__ [classref boost::process::v1::extend::async_handler ex::async_handler]] -[def __get_io_context__ [funcref boost::process::v1::extend::get_io_context ex::get_io_context]] - -[section:extend Extensions] -To extend the library, the header [headerref boost/process/extend.hpp extend] is provided. - -It only provides the explicit style for custom properties, but no implicit style. - -What this means is, that a custom initializer can be implemented, a reference which can be passed to one of the launching functions. -If a class inherits [classref boost::process::v1::extend::handler] it will be regarded as an initializer and thus directly put into the sequence -the executor gets passed. - -[section:structure Structure] - -The executor calls different handlers of the initializers during the process launch. -The basic structure consists of three functions, as given below: - -* [globalref boost::process::v1::extend::on_setup on_setup] -* [globalref boost::process::v1::extend::on_error on_error] -* [globalref boost::process::v1::extend::on_success on_success] - -''' - -''' - -Additionally posix provides three more handlers, listed below: - -* [globalref boost::process::v1::extend::on_fork_error on_fork_error] -* [globalref boost::process::v1::extend::on_exec_setup on_exec_setup] -* [globalref boost::process::v1::extend::on_exec_error on_exec_error] - -For more information see the reference of [classref boost::process::v1::extend::posix_executor posix_executor]. - -[endsect] -[section:simple Simple extensions] - -The simplest extension just takes a single handler, which can be done in a functional style. -So let's start with a simple hello-world example, while we use a C++14 generic lambda. - -``` -using namespace boost::process; -namespace ex = bp::extend; - -__child__ c("foo", __on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;}); -``` - -Considering that lambdas can also capture values, data can easily be shared between handlers. - -To see which members the executor has, refer to [classref boost::process::v1::extend::windows_executor windows_executor] -and [classref boost::process::v1::extend::posix_executor posix_executor]. - -[note Combined with __on_exit__ this can also handle the process exit.] - -[caution The posix handler symbols are not defined on windows.] - -[endsect] - -[section:handler Handler Types] - -Since the previous example is in a functional style, it is not very reusable. -To solve that problem, the [classref boost::process::v1::extend::handler handler] has an alias in the `boost::process::v1::extend` namespace, to be inherited. -So let's implement the hello world example in a class. - -``` -struct hello_world : __handler__ -{ - template - void __on_success__(Executor & exec) const - { - std::cout << "hello world" << std::endl; - } -}; - -//in our function -__child__ c("foo", hello_world()); -``` - -[note The implementation is done via overloading, not overriding.] - -Every handler not implemented defaults to [classref boost::process::v1::extend::handler handler], where an empty handler is defined for each event. - -[endsect] - - - -[section:async Asynchronous Functionality] - -Since `boost.process` provides an interface for [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio], -this functionality is also available for extensions. If the class needs the __io_context__ for some reason, the following code will do that. - -``` -struct async_foo : __handler__, __require_io_context__ -{ - template - void on_setup(Executor & exec) - { - __io_context__ & ios = __get_io_context__(exec.seq); //gives us a reference and a compiler error if not present. - //do something with ios - } -}; -``` -[note Inheriting [globalref boost::process::v1::extend::require_io_context require_io_context] is necessary, so [funcref boost::process::v1::system system] provides one.] - -Additionally the handler can provide a function that is invoked when the child process exits. This is done through __async_handler__. - -[note [globalref boost::process::v1::extend::async_handler async_handler] implies [globalref boost::process::v1::extend::require_io_context require_io_context] .] - -``` -struct async_bar : __handler, __async_handler__ -{ - template - std::function on_exit_handler(Executor & exec) - { - auto handler_ = this->handler; - return [handler_](int exit_code, const std::error_code & ec) - { - std::cout << "hello world, I exited with " << exit_code << std::endl; - }; - - } -}; -``` - - -[caution `on_exit_handler` does not default and is always required when [classref boost::process::v1::extend::async_handler async_handler] is inherited. ] - -[caution `on_exit_handler` uses `boost::asio::signal_set` to listen for SIGCHLD on posix. The application must not also register a signal handler for SIGCHLD using functions such as `signal()` or `sigaction()` (but using `boost::asio::signal_set` is fine). ] - -[endsect] - -[section:error Error handling] - -If an error occurs in the initializers it shall be told to the executor and not handled directly. This is because -the behaviour can be changed through arguments passed to the launching function. Hence the executor -has the function `set_error`, which takes an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code] and a string. -Depending on the configuration of the executor, this may either throw, set an internal `error_code`, or do nothing. - -So let's take a simple example, where we set a randomly chosen `error_code`. - -``` -auto set_error = [](auto & exec) - { - std::error_code ec{42, std::system_category()}; - exec.set_error(ec, "a fake error"); - - }; -__child__ c("foo", on_setup=set_error); -``` - -Since we do not specify the error-handling mode in this example, this will throw [classref boost::process::v1::process_error process_error]. - -[endsect] - -[section:exec_over Executor Overloading] - -Now that we have a custom initializer, let's consider how we can handle differences between different executors. -The distinction is between posix and windows and `char` and `wchar_t` on windows. -One solution is to use the [@http://www.boost.org/doc/libs/master/boost/system/api_config.hpp BOOST_WINDOWS_API and BOOST_POSIX_API] macros, -which are automatically available as soon as any process-header is included. - -Another variant are the type aliases __posix_executor__ and __windows_executor__, where the executor, not on the current system is a forward-declaration. -This works fine, because the function will never get invoked. So let's implement another example, which prints the executable name __on_success__. - -``` -struct hello_exe : __handler__ -{ - template - void __on_success__(__posix_executor__ & exec) - { - std::cout << "posix-exe: " << exec.exe << std::endl; - } - - template - void __on_success__(__windows_executor__ & exec) - { - //note: exe might be a nullptr on windows. - if (exec.exe != nullptr) - std::cout << "windows-exe: " << exec.exe << std::endl; - else - std::cout << "windows didn't use exe" << std::endl; - } - - template - void __on_success__(__windows_executor__ & exec) - { - //note: exe might be a nullptr on windows. - if (exec.exe != nullptr) - std::wcout << L"windows-exe: " << exec.exe << std::endl; - else - std::cout << "windows didn't use exe" << std::endl; - } - -}; -``` - -So given our example, the definitions with the non-native executor are still a template so that they will not be evaluated if not used. Hence this provides a -way to implement system-specific code without using the preprocessor. - -[note If you only write a partial implementation, e.g. only for __posix_executor__, the other variants will default to __handler__]. - -[endsect] - -[endsect] diff --git a/doc/v1/faq.qbk b/doc/v1/faq.qbk deleted file mode 100644 index 33318cd0d..000000000 --- a/doc/v1/faq.qbk +++ /dev/null @@ -1,87 +0,0 @@ -[section:faq Frequently Asked Questions] - -[section:dead_lock Why does this produce a deadlock?] - -Now let's revisit our c++filt example and we will put in an obvious mistake. -This might however be not as obvious for more complex applications. - -``` -vector demangle(vector in) -{ - - ipstream is; - opstream os; - child c("c++filt", std_out > is, std_in < os); - - vector data; - for (auto & elem : data) - { - string line; - getline(is, line); - os << elem; - } -} - -``` -We switched the read and write operation up, so that's causing a dead-lock. -This locks immediately. This is because `c++filt` expects input, before -outputting any data. The launching process on the other hand waits for its output. - -[endsect] - -[section:closep Why does the pipe not close?] - -Now for another example, which might look correct, let's consider you want -to use `ls` to read the current directory. - -``` -ipstream is; -child c("ls", std_out > is); - -std::string file; -while (is >> file) - cout << "File: " << file << endl; - -``` - -This will also deadlock, because the pipe does not close when the subprocess exits. -So the `ipstream` will still look for data even though the process has ended. - -[note It is not possible to use automatic pipe-closing in this library, because -a pipe might be a file-handle (as for async pipes on windows).] - -But, since pipes are buffered, you might get incomplete data if you do this: - -``` -ipstream is; -child c("ls", std_out > is); - -std::string file; -while (c.running()) -{ - is >> file; - cout << "File: " << file << endl; -} -``` - -It is therefore highly recommended that you use the asynchronous API if you are -not absolutely sure how the output will look. - -[endsect] - -[section:wchar_t When will the codecvt be used?] - -Since windows does not use UTF-8 it is sometimes unavoidable to use the `wchar_t` version of the WinApi. -To keep this library consistent it provides `wchar_t` support on posix also. - -Since the posix api is purely `char` every `wchar_t` based type will be converted into `char`. - -Windows on the other hand is more selective; the default is to use `char`, -but if any parameter requires `wchar_t`, everything will be converted to `wchar_t`. -This also includes `boost::filesystem::path`. Additionally, if the system does not provide -the `char` api (as is the case with Windows CE) everything will also be converted. - - -[endsect] - -[endsect] \ No newline at end of file diff --git a/doc/v1/introduction.qbk b/doc/v1/introduction.qbk deleted file mode 100644 index e9fe67f2d..000000000 --- a/doc/v1/introduction.qbk +++ /dev/null @@ -1,24 +0,0 @@ -[section:introduction Introduction] - -Boost.Process is a library to manage system processes. It can be used to: - -* create child processes -* setup streams for child processes -* communicate with child processes through streams (synchronously or asynchronously) -* wait for processes to exit (synchronously or asynchronously) -* terminate processes - -Here's a simple example of how to start a program with Boost.Process: - -[def ipstream [classref boost::process::v1::ipstream ipstream]] -[def system [funcref boost::process::v1::system system]] -[def std_out [globalref boost::process::v1::std_out std_out]] -[def child [globalref boost::process::v1::child child]] -[def boost/process.hpp [headerref boost/process.hpp boost/process.hpp]] -[def std::string [@http://en.cppreference.com/w/cpp/string/basic_string std::string]] -[def std::getline [@http://en.cppreference.com/w/cpp/string/basic_string/getline std::getline]] - -[import ../../example/intro.cpp] -[intro] - -[endsect] diff --git a/doc/v1/posix_pseudocode.xml b/doc/v1/posix_pseudocode.xml deleted file mode 100644 index 699d087e5..000000000 --- a/doc/v1/posix_pseudocode.xml +++ /dev/null @@ -1,60 +0,0 @@ - - -for (auto & s : seq) - s.on_setup(*this); - -if (error()) -{ - for (auto & s : seq) - s.on_error(*this, error()); - return child(); -} - -pid = fork() -on_setup(*this); - -if (pid == -1) //fork error -{ - set_error(get_last_error()); - for (auto & s : seq) - s.on_fork_error(*this, error()); - for (auto & s : seq) - s.on_error(*this, error()); - return child() -} -else if (pid == 0) //child process -{ - for (auto & s : seq) - s.on_exec_setup(*this); - execve(exe, cmd_line, env); - auto ec = get_last_error(); - for (auto & s : seq) - s.on_exec_error(*this); - - unspecified();//here the error is sent to the father process internally - - std::exit(EXIT_FAILURE); - return child(); //for C++ compliance -} - -child c(pid, exit_code); - -unspecified();//here, we read the error from the child process - -if (error()) - for (auto & s : seq) - s.on_error(*this, error()); -else - for (auto & s : seq) - s.on_success(*this); - -//now we check again, because an on_success handler might've errored. -if (error()) -{ - for (auto & s : seq) - s.on_error(*this, error()); - return child(); -} -else - return c; - \ No newline at end of file diff --git a/doc/v1/tutorial.qbk b/doc/v1/tutorial.qbk deleted file mode 100644 index e7e98a2b0..000000000 --- a/doc/v1/tutorial.qbk +++ /dev/null @@ -1,425 +0,0 @@ -[def bp::system [funcref boost::process::v1::system bp::system]] -[def bp::async_system [funcref boost::process::v1::async_system bp::async_system]] -[def bp::spawn [funcref boost::process::v1::spawn bp::spawn]] -[def bp::child [classref boost::process::v1::child bp::child]] -[def bp::cmd [classref boost::process::v1::cmd bp::cmd]] -[def bp::group [classref boost::process::v1::group bp::group]] -[def bp::ipstream [classref boost::process::v1::ipstream bp::ipstream]] -[def bp::opstream [classref boost::process::v1::opstream bp::opstream]] -[def bp::pstream [classref boost::process::v1::pstream bp::pstream]] -[def bp::pipe [classref boost::process::v1::pipe bp::pipe]] -[def bp::async_pipe [classref boost::process::v1::async_pipe bp::async_pipe]] -[def bp::search_path [funcref boost::process::v1::search_path bp::search_path]] -[def boost_org [@www.boost.org "www.boost.org"]] -[def std::system [@http://en.cppreference.com/w/cpp/utility/program/system std::system]] -[def child_running [memberref boost::process::v1::child::running running]] -[def child_wait [memberref boost::process::v1::child::wait wait]] -[def child_wait_for [memberref boost::process::v1::child::wait_for wait_for]] -[def child_exit_code [memberref boost::process::v1::child::exit_code exit_code]] -[def group_wait_for [memberref boost::process::v1::group::wait_for wait_for]] -[def bp::on_exit [globalref boost::process::v1::on_exit bp::on_exit]] -[def bp::null [globalref boost::process::v1::null bp::null]] -[def child_terminate [memberref boost::process::v1::child::terminate terminate]] -[def group_terminate [memberref boost::process::v1::group::terminate terminate]] -[def group_wait [memberref boost::process::v1::group::wait wait]] -[def bp::std_in [globalref boost::process::v1::std_in bp::std_in]] -[def bp::std_out [globalref boost::process::v1::std_out bp::std_out]] -[def bp::std_err [globalref boost::process::v1::std_err bp::std_err]] -[def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]] -[def asio_buffer [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html boost::asio::buffer]] -[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]] -[def bp::environment [classref boost::process::v1::basic_environment bp::environment]] -[def bp::native_environment [classref boost::process::v1::basic_native_environment bp::native_environment]] -[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]] -[def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]] -[def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]] - -[def __wait_for__ [memberref boost::process::v1::child::wait_for wait_for]] -[def __wait_until__ [memberref boost::process::v1::child::wait_until wait_until]] -[def __detach__ [memberref boost::process::v1::child::detach detach]] - -[def __reference__ [link process.reference reference]] -[def __concepts__ [link boost_process.concepts concepts]] - -[def boost::asio::yield_context [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/yield_context.html boost::asio::yield_context]] -[def boost::asio::coroutine [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/coroutine.html boost::asio::coroutine]] -[def bp::env [globalref boost::process::v1::env bp::env]] - -[section:tutorial Tutorial] - -In this section we will go step by step through the different features of -boost.process. For a full description see the __reference__ and the __concepts__ sections. - -[section Starting a process] - -We want to start a process, so let's start with a simple process. We will -invoke the gcc compiler to compile a simple program. - -With the standard library this looks like this. - -``` -int result = std::system("g++ main.cpp"); -``` - -Which we can write exactly like this in boost.process. - -``` -namespace bp = boost::process; //we will assume this for all further examples -int result = bp::system("g++ main.cpp"); -``` - -If a single string is given (or the explicit form bp::cmd), it will be interpreted as a command line. -That will cause the execution function to search the `PATH` variable to find the executable. -The alternative is the `exe-args` style, where the first string will be interpreted as a filename (including the path), -and the rest as arguments passed to said function. - -[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here].] - -So as a first step, we'll use the `exe-args` style. - -``` -int result = bp::system("/usr/bin/g++", "main.cpp"); -``` - -With that syntax we still have "g++" hard-coded, so let's assume we get the string -from an external source as `boost::process::v1::filesystem::path`, we can do this too. - -``` -boost::process::v1::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else. -int result = bp::system(p, "main.cpp"); -``` - -Now we might want to find the `g++` executable in the `PATH`-variable, as the `cmd` syntax would do. -`Boost.process` provides a function to this end: bp::search_path. - -``` -boost::process::v1::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else. -int result = bp::system(p, "main.cpp"); -``` - -[note [funcref boost::process::v1::search_path search_path] will search for any executable with that name. -This also includes to add a file suffix on windows, such as `.exe` or `.bat`.] - -[endsect] - -[section:launch_mode Launch functions] - -Given that our example used the [funcref boost::process::v1::system system] function, -our program will wait until the child process is completed. This may be unwanted, -especially since compiling can take a while. - -In order to avoid that, boost.process provides several ways to launch a process. -Besides the already mentioned [funcref boost::process::v1::system system] function and its -asynchronous version [funcref boost::process::v1::async_system async_system], -we can also use the [funcref boost::process::v1::spawn spawn] function or the -[classref boost::process::v1::child child] class. - -The [funcref boost::process::v1::spawn spawn] function launches a process and -immediately detaches it, so no handle will be returned and the process will be ignored. -This is not what we need for compiling, but maybe we want to entertain the user, -while compiling: - -``` -bp::spawn(bp::search_path("chrome"), boost_org); -``` - -Now for the more sensible approach for compiling: a non-blocking execution. -To implement that, we directly call the constructor of [classref boost::process::v1::child child]. - -``` -bp::child c(bp::search_path("g++"), "main.cpp"); - -while (c.child_running()) - do_some_stuff(); - -c.child_wait(); //wait for the process to exit -int result = c.child_exit_code(); -``` - -So we launch the process, by calling the child constructor. Then we check and do other -things while the process is running and afterwards get the exit code. The call -to child_wait is necessary, to obtain it and tell the operating system, that no -one is waiting for the process anymore. - -[note You can also wait for a time span or until a time point with __wait_for__ and __wait_until__.] - -[warning If you don't call wait on a child object, it will be terminated on destruction. -This can be avoided by calling __detach__ beforehand] - -[endsect] -[section:error_handling Error] - -Until now, we have assumed that everything works out, but it is not impossible, -that "g++" is not present. That will cause the launch of the process to fail. -The default behaviour of all functions is to throw a -[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure. -As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code] -will change the behaviour, so that instead of throwing an exception, the error will be assigned to the error code. - -``` -std::error_code ec; -bp::system("g++ main.cpp", ec); -``` -[endsect] -[section:io Synchronous I/O] - -In the examples given above, we have only started a program, but did not consider the output. -The default depends on the system, but usually this will just write it to the same output as the launching process. -If this shall be guaranteed, the streams can be explicitly forwarded like this. - -``` - bp::system("g++ main.cpp", bp::std_out > stdout, bp::std_err > stderr, bp::std_in < stdin); -``` - -Now for the first example, we might want to just ignore the output, which can be done by redirecting it to the null-device. -This can be achieved this way: - -``` -bp::system("g++ main.cpp", bp::std_out > bp::null); -``` - -Alternatively we can also easily redirect the output to a file: - -``` -bp::system("g++ main.cpp", bp::std_out > "gcc_out.log"); -``` - -Now, let's take a more visual example for reading data. -[@http://pubs.opengroup.org/onlinepubs/009696699/utilities/nm.html nm] is a tool on posix, -which reads the outline, i.e. a list of all entry points, of a binary. -Every entry point will be put into a single line, and we will use a pipe to read it. -At the end an empty line is appended, which we use as the indication to stop reading. -Boost.process provides the pipestream ([classref boost::process::v1::ipstream ipstream], -[classref boost::process::v1::opstream opstream], [classref boost::process::v1::pstream pstream]) to -wrap around the [classref boost::process::v1::pipe pipe] and provide an implementation of the -[@http://en.cppreference.com/w/cpp/io/basic_istream std::istream], -[@http://en.cppreference.com/w/cpp/io/basic_ostream std::ostream] and -[@http://en.cppreference.com/w/cpp/io/basic_iostream std::iostream] interface. - -``` -std::vector read_outline(std::string & file) -{ - bp::ipstream is; //reading pipe-stream - bp::child c(bp::search_path("nm"), file, bp::std_out > is); - - std::vector data; - std::string line; - - while (c.child_running() && std::getline(is, line) && !line.empty()) - data.push_back(line); - - c.child_wait(); - - return data; -} -``` - -What this does is redirect the `stdout` of the process into a pipe and we read this -synchronously. - -[note You can do the same thing with [globalref boost::process::v1::std_err std_err].] - -Now we get the name from `nm` and we might want to demangle it, so we use input and output. -`nm` has a demangle option, but for the sake of the example, we'll use -[@https://sourceware.org/binutils/docs/binutils/c_002b_002bfilt.html c++filt] for this. - -``` -bp::opstream in; -bp::ipstream out; - -bp::child c("c++filt", std_out > out, std_in < in); - -in << "_ZN5boost7process8tutorialE" << endl; -std::string value; -out >> value; - -c.child_terminate(); -``` - -Now you might want to forward output from one process to another processes input. - -``` -std::vector read_demangled_outline(const std::string & file) -{ - bp::pipe p; - bp::ipstream is; - - std::vector outline; - - //we just use the same pipe, so the output of nm is directly passed as input to c++filt - bp::child nm(bp::search_path("nm"), file, bp::std_out > p); - bp::child filt(bp::search_path("c++filt"), bp::std_in < p, bp::std_out > is); - - std::string line; - while (filt.running() && std::getline(is, line)) //when nm finished the pipe closes and c++filt exits - outline.push_back(line); - - nm.child_wait(); - filt.wait(); -} - -``` - -This forwards the data from `nm` to `c++filt` without your process needing to do anything. - -[endsect] -[section:async_io Asynchronous I/O] - -Boost.process allows the usage of boost.asio to implement asynchronous I/O. -If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] (which we highly recommend), -you can use [classref boost::process::v1::async_pipe async_pipe] which is implemented -as an I/O-Object and can be used like [classref boost::process::v1::pipe pipe] as shown above. - -Now we get back to our compiling example. For `nm` we might analyze the output line by line, -but the compiler output will just be put into one large buffer. - -With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what it looks like. - -``` -io_service ios; -std::vector buf(4096); - -bp::async_pipe ap(ios); - -bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > ap); - -asio_async_read(ap, asio_buffer(buf), - [](const boost::system::error_code &ec, std::size_t size){}); - -ios.run(); -int result = c.exit_code(); -``` - -To make it easier, boost.process provides a simpler interface for that, so that the buffer can be passed directly, -provided we also pass a reference to an io_service. - -``` -io_service ios; -std::vector buf(4096); - -bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios); - -ios.run(); -int result = c.exit_code(); -``` - -[note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of -[memberref boost::process::v1::child::wait wait] is needed.] - -To make it even easier, you can use [@http://en.cppreference.com/w/cpp/thread/future std::future] for asynchronous operations -(you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system or bp::async_system. - -Now we will revisit our first example and read the compiler output asynchronously: - -``` -boost::asio::io_service ios; - -std::future data; - -child c("g++", "main.cpp", //set the input - bp::std_in.close(), - bp::std_out > bp::null, //so it can be written without anything - bp::std_err > data, - ios); - - -ios.run(); //this will actually block until the compiler is finished - -auto err = data.get(); -``` - -[endsect] -[section:group Groups] - -When launching several processes, they can be grouped together. -This will also apply for a child process, that launches other processes, -if they do not modify the group membership. E.g. if you call `make` which -launches other processes and call terminate on it, -it will not terminate all the child processes of the child unless you use a group. - -The two main reasons to use groups are: - -# Being able to terminate child processes of the child process -# Grouping several processes into one, just so they can be terminated at once - -If we have a program like `make`, which does launch its own child processes, -a call of child_terminate might not suffice. I.e. if we have a makefile launching `gcc` -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 - c.child_terminate(); //then terminate -``` - -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))) - g.group_terminate(); - -c.child_wait(); //to avoid a zombie process & get the exit code -``` - -Now given the example, we still call child_wait to avoid a zombie process. -An easier solution for that might be to use [funcref boost::process::v1::spawn spawn]. - - -To put two processes into one group, the following code suffices. Spawn already -launches a detached process (i.e. without a child-handle), but they can be grouped, -to that in the case of a problem, RAII is still a given. - -``` -void f() -{ - bp::group g; - bp::spawn("foo", g); - bp::spawn("bar", g); - - do_something(); - - g.group_wait(); -}; -``` - -In the example, it will wait for both processes at the end of the function unless -an exception occurs. I.e. if an exception is thrown, the group will be terminated. - - -Please see the [headerref boost/process/group.hpp reference] for more information. - -[endsect] -[section:env Environment] - -This library provides access to the environment of the current process and allows -setting it for the child process. - -``` -//get a handle to the current environment -auto env = boost::this_process::environment(); -//add a variable to the current environment -env["VALUE_1"] = "foo"; - -//copy it into an environment separate to the one of this process -bp::environment env_ = env; -//append two values to a variable in the new env -env_["VALUE_2"] += {"bar1", "bar2"}; - -//launch a process with `env_` -bp::system("stuff", env_); -``` - -A more convenient way to modify the environment for the child is the -[globalref boost::process::v1::env env] property, which can be used in the example as following: - -``` -bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"}); - -``` - -Please see the [headerref boost/process/environment.hpp reference] for more information. - -[endsect] -[endsect] diff --git a/doc/v1/windows_pseudocode.xml b/doc/v1/windows_pseudocode.xml deleted file mode 100644 index 8cca87bd2..000000000 --- a/doc/v1/windows_pseudocode.xml +++ /dev/null @@ -1,42 +0,0 @@ - - -for (auto & s : seq) - s.on_setup(*this); - -if (error()) -{ - for (auto & s : seq) - s.on_error(*this, error()); - return child(); -} -int err_code = CreateProcess( - exe, - cmd_line, - proc_attrs, - thread_attrs, - creation_flags, - env, - work_dir, - startup_info, - proc_info); - -child c(proc_info, exit_code); - -if (error()) - for (auto & s : seq) - s.on_error(*this, error()); -else - for (auto & s : seq) - s.on_success(*this); - -//now we check again, because an on_success handler might've errored. -if (error()) -{ - for (auto & s : seq) - s.on_error(*this, error()); - return child(); -} -else - return c; - - \ No newline at end of file diff --git a/doc/v2.qbk b/doc/v2.qbk deleted file mode 100644 index 3b6bb08ef..000000000 --- a/doc/v2.qbk +++ /dev/null @@ -1,11 +0,0 @@ -[section:v2 Process V2] - -[include v2/introduction.qbk] -[include v2/quickstart.qbk] -[include v2/launcher.qbk] -[include v2/start_dir.qbk] -[include v2/stdio.qbk] -[include v2/env.qbk] -[xinclude reference_v2.xml] - -[endsect] diff --git a/doc/v2/launcher.qbk b/doc/v2/launcher.qbk deleted file mode 100644 index 80d368706..000000000 --- a/doc/v2/launcher.qbk +++ /dev/null @@ -1,128 +0,0 @@ -[section:launchers Launcher] - -The process creation is done by a process_launcher. -The constructor of `process` will use the default_launcher, which varies by system. -There are additional launcher available on most systems. - -[table:launchers Launcher overview - [[Name] [Summary] [Default on] [Available on]] - [[`windows::default_launcher`] [Launcher using `CreateProcessW`] [windows] [windows]] - [[`windows::as_user_launcher`] [Launcher using `CreateProcessAsUserW`] [] [windows]] - [[`windows::with_logon_launcher`] [Launcher using `CreateProcessWithLogonW`] [] [windows]] - [[`windows::with_token_launcher`] [Launcher using `CreateProcessWithTokenW`] [] [windows]] - [[`posix::default_launcher`] [Launcher using fork & an error pipe] [most of posix] [posix]] - [[`posix::fork_and_forget`] [Launcher using fork without error pipe] [] [posix]] - [[`posix::pdfork_launcher`] [Launcher using pdfork with an error pipe] [FreeBSD] [FreeBSD]] - [[`posix::vfork_launcher`] [Launcher using vfork] [] [posix]] -] - -A launcher is invoked through the call operator. - -``` - auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF); - asio::io_context ctx; - boost::system::error_code ec; - auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {}); -``` - -The launcher will call certain functions on the initializer if they're present, as documented below. -The initializer are used to modify the process behaviour. - -[section:linux Linux Launchers] - -The default and pdfork launchers on linux open an internal pipe to communicate errors that occur after forking back to the parent process. - -This can be prevented by using the `fork_and_forget_launcher`. -Alternatively, the `vfork_launcher` can report errors directly back to the parent process. - -Thus some calls to the initializers occur after forking from the child process. - -``` - struct custom_initializer - { - // functions called from the parent process: - - - // called before a call to fork. A returned error will cancel the launch. - template - error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line)); - - // called for every initializer if an error occurred during setup or process creation - template - void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), - const error_code & ec); - - // called after successful process creation - template - void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line)); - - // called for every initializer if an error occurred when forking, in addition to on_error. - template - void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), - const error_code & ec); - - - // called before a call to execve. A returned error will cancel the launch. Called from the child process. - template - error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line)); - - - // called after a failed call to execve from the child process. - template - void on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line)); - }; -``` - -The call sequence on success: -''' - -''' - -The call sequence when fork fails: -''' - -''' - -The call sequence when exec fails: -''' - -''' - -The launcher will close all non-whitelisted file descriptors after `on_exec_setup`. - -[endsect] - -[section:windows Windows Launchers] - -Windows launchers are pretty straight forward, they will call the following functions on the initializer if present. - -``` - struct custom_initializer - { - // called before a call to CreateProcess. A returned error will cancel the launch. - template - error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line); - - // called for every initializer if an error occurred during setup or process creation - template - void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line, - const error_code & ec); - - // called after successful process creation - template - void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line); - - }; -``` - -[note All the additional launchers for windows inherit `default_launcher`] - -The call sequence is as follows: -''' - -''' - -[endsect] - - -[endsect] \ No newline at end of file diff --git a/doc/v2/quickstart.qbk b/doc/v2/quickstart.qbk deleted file mode 100644 index 7bd80ed5f..000000000 --- a/doc/v2/quickstart.qbk +++ /dev/null @@ -1,123 +0,0 @@ -[section:quickstart Quickstart] - -A process needs four things to be launched: - -* an asio execution_context / executor -* a path to an executable -* a list of arguments -* a variadic set of initializers - -``` - // process(asio::any_io_executor, filesystem::path, range args, AdditionalInitializers...) - asio::io_context ctx; - process proc(ctx, "/usr/bin/cp", {"source.txt", "target.txt"}); -``` - - -The started process can then be awaited or terminated. - -[section:lifetime Lifetime] - -If the process handle goes out of scope, it will terminate the subprocess. -You can prevent this, by calling `proc.detach()`; do however note that this -can lead to zombie processes. - -A process that completed will deliver an exit-code, -which can be obtained by calling `.exit_code` on the exited process and which is -also returned from `.wait()`. - -``` - process proc("/bin/ls", {}); - assert(proc.wait() == 0); -``` - -The normal exit-code is what the subprocess returned from `main`; -posix will however add additional information about the process. -This is called the `native_exit_code`. - - -The `.running()` function can be used to detect if the process is still active. - -[endsect] - -[section:signal Signalling the subprocess] - -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. - -``` - process proc("/bin/totally-not-a-virus", {}); - proc.terminate(); -``` - -`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix), -which the subprocess might ignore. - -``` - process proc("/bin/bash", {}); - proc.request_exit(); - proc.wait(); -``` - -`.interrupt` will send an SIGINT to the subprocess, which a subprocess might -interpret as a signal to shutdown. - -[warning interrupt requires the initializer `windows::create_new_process_group` to be set] - -``` - process proc("/usr/bin/addr2line", {}); - proc.request_exit(); - proc.wait(); -``` - -[endsect] - -[section:execute Execute functions] - -Process v2 provides `execute` and `async_execute` functions that can be used for managed executions. - -``` - assert(execute(process("/bin/ls", {}) == 0)); -``` - -The async version supports cancellation and will forward cancellation types as follows: - -- asio::cancellation_type::total -> interrupt -- asio::cancellation_type::partial -> request_exit -- asio::cancellation_type::terminal -> terminate - -``` - asio::io_context ctx; - asio::steady_timer timeout{ctx, std::chrono::seconds(10)}; - - asio::cancellation_signal sig; - async_execute(process("/usr/bin/g++", {"hello_world.cpp"}), - asio::bind_cancellation_slot(sig.slot(), - [&](error_code ec, int exit_code) - { - timeout.cancel(); // we're done earlier - })); - - timeout.async_wait( - [&](error_code ec) - { - if (ec) // we were cancelled, do nothing - return ; - sig.emit(asio::cancellation_type::partial); - // request exit first, but terminate after another 10 sec - timeout.expires_after(std::chrono::seconds(10)); - timeout.async_wait( - [&](error_code ec) - { - if (!ec) - sig.emit(asio::cancellation_type::terminal); - }); - }); - -``` - -[endsect] - -[endsect] \ No newline at end of file diff --git a/doc/v2/start_dir.qbk b/doc/v2/start_dir.qbk deleted file mode 100644 index 3751edff9..000000000 --- a/doc/v2/start_dir.qbk +++ /dev/null @@ -1,16 +0,0 @@ -[section:start_dir process_start_dir] - -The easier initializer to use is `process_start_dir`: - -``` - asio::io_context ctx; - process ls(ctx, "/ls", {}, process_start_dir("/home")); - ls.wait(); -``` - -This will run `ls` in the folder `/home` instead of the current folder. - -[warning If your path is relative, it may fail on posix, because the directory is changed before a call to execve.] - - -[endsect] \ No newline at end of file diff --git a/doc/v2/stdio.qbk b/doc/v2/stdio.qbk deleted file mode 100644 index 915cdfd2c..000000000 --- a/doc/v2/stdio.qbk +++ /dev/null @@ -1,89 +0,0 @@ -[section:stdio stdio] - -When using io with a subprocess, all three standard streams (stdin, stdout, stderr) get set for the child-process. -The default setting is to inherit the parent process. - -This feature meant to be flexible, which is why there is little checking on the arguments assigned to one of those streams. - -[section:pipe Pipe] - -asio pipes can be used for io. When using in process_stdio they will get -automatically connected and the other side will get assigned to the child process: - -``` - asio::io_context ctx; - asio::readable_pipe rp{ctx}; - - process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }}); - std::string output; - - system::error_code ec; - rp.read(asio::dynamic_buffer(output), ec); - assert(ec == asio::eof); - proc.wait(); -``` - -readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`. - -[endsect] - -[section:file `FILE*`] - -`FILE*` can also be used for either side; this allows the `stdin`, `stderr`, `stdout` macros to be used: - -``` - asio::io_context ctx; - // forward both stderr & stdout to stdout of the parent process - process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, stdout, stdout}); - proc.wait(); -``` - -[endsect] - -[section:null `nullptr`] - -`nullptr` may be used to set a given stream to be opened on the null-device (`/dev/null` on posix, `NUL` on windows). -This is used to ignore output or give only EOF as input. - -``` - asio::io_context ctx; - // ignore stderr - process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr}); - proc.wait(); -``` - -[endsect] - - -[section:native_handle `native_handle`] - -A native handle can be used as well, which means an `int` on posix or a `HANDLE` on windows. -Furthermore, any object that has a `native_handle` returning that native handle type is valid, too. - - -``` - asio::io_context ctx; - // ignore stderr - asio::ip::tcp::socket sock{ctx}; - connect_my_socket(sock); - process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr}); - proc.wait(); -``` - -[endsect] - -[section:popen popen] - -Additionally, process v2 provides a `popen` class. -It starts a process and connects pipes for stdin and stdout, so that the popen object can be used as a stream. - -``` - popen proc(executor, "/usr/bin/addr2line, {argv[0]}); - asio::write(proc, asio::buffer("main\n")); - std::string line; - asio::read_until(proc, asio::dynamic_buffer(line), '\n'); -``` - -[endsect] - -[endsect] diff --git a/doc/v2/introduction.qbk b/doc/version2.adoc similarity index 65% rename from doc/v2/introduction.qbk rename to doc/version2.adoc index f762296e5..726ecc33b 100644 --- a/doc/v2/introduction.qbk +++ b/doc/version2.adoc @@ -1,4 +1,4 @@ -[section:introduction Introduction] += Version 2 Boost.process V2 is an redesign of boost.process, based on previous design mistakes & improved system APIs. @@ -13,47 +13,52 @@ The major changes are * separate compilation * fd safe by default -[section:simplified Simplified Interface] +Version 2 is now the defauled. In order to discourage usage of the deprecated v1, it's documentation has been removed. + +== Simplified Interface In process v1 one can define partial settings in the constructor of the process, which has lead to a small DSL. - child c{exe="test", args+="--help", std_in < null(), env["FOO"] += "BAR"}; +[source,cpp] +---- +child c{exe="test", args+="--help", std_in < null(), env["FOO"] += "BAR"}; +---- While this looks fancy at first, it really does not scale well with more parameters. -For process v2, the interfaces is simple: +For process v2, the interfaces is simple: - extern std::unordered_map my_env; - extern asio::io_context ctx; - process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env)); +[source,cpp] +---- +extern std::unordered_map my_env; +extern asio::io_context ctx; +process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env)); +---- Every initializer addresses one logical component (e.g. stdio) instead of multiple ones accumulating. 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. -[endsect] -[section:pidfd_open pidfd_open] +== `pidfd_open` -Since process v1 came out, linux has moved along and added pidfd_open which allows users to get a -file descriptor for a process. This is much more reliable since it is not as easy to miss as a `SIGCHLD`. -FreeBSD has a similar feature with `pdfork` which is also supported, while windows has provided `HANDLE`s -for processes all along. +Since process v1 came out, linux has moved along and added [pidfd_open](https://man7.org/linux/man-pages/man2/pidfd_open.2.html) +which allows users to obtain a descriptor for a process. +This is much more reliable since it is not as easy to miss as a `SIGCHLD`. +Windows has provided `HANDLE`s for processes all along. Unless the OS doesn't support it, process v2 will use file descriptors and handles to implement waiting for processes. -[endsect] -[section:asio Full asio integration] + +== Full asio integration Process v1 aimed to make asio optional, but synchronous IO with subprocesses usually means one is begging for deadlocks. Since asio added pipes in boost 1.78, boost process V2 is fully asio based and uses it's pipes and file-handles for the subprocess. -[endsect] - -[section:unreliable Unreliable functionality] +== Unreliable functionality Certain parts of boost.process were not as reliable as they should've been. @@ -63,17 +68,12 @@ Thus the wait_for used signals or fork, which was all but safe. Since process v2 is based on asio and thus supports cancellation, a wait_for can not safely be implemented with an async_wait + timeout. -[endsect] - -[section:utf8 UTF-8] +== UTF-8 -["UTF-8 or GTFO]--Vinnie Falco +Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere +and uses the UTF-16 APIs. -Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere. - -[endsect] - -[section:limit_fd Fd safe by default] +== Fd safe by default While not a problem on windows (since HANDLEs get manually enabled for inheritance), posix systems create a problem with inheriting file handles by default. @@ -81,6 +81,3 @@ posix systems create a problem with inheriting file handles by default. Process V2 will automatically close all non-whitelisted descriptors, without needing any option to enable it. -[endsect] - -[endsect] diff --git a/include/boost/process/v1/detail/config.hpp b/include/boost/process/v1/detail/config.hpp index 60978cc01..4a8080cac 100644 --- a/include/boost/process/v1/detail/config.hpp +++ b/include/boost/process/v1/detail/config.hpp @@ -22,7 +22,7 @@ #include #if !defined(BOOST_PROCESS_VERSION) -#define BOOST_PROCESS_VERSION 1 +#define BOOST_PROCESS_VERSION 2 #endif #if BOOST_PROCESS_VERSION == 1 diff --git a/include/boost/process/v2/detail/config.hpp b/include/boost/process/v2/detail/config.hpp index 17f50c22b..43bf441ad 100644 --- a/include/boost/process/v2/detail/config.hpp +++ b/include/boost/process/v2/detail/config.hpp @@ -68,7 +68,7 @@ BOOST_PROCESS_V2_END_NAMESPACE #if !defined(BOOST_PROCESS_VERSION) -#define BOOST_PROCESS_VERSION 1 +#define BOOST_PROCESS_VERSION 2 #endif From 2ccd97cd48c5468b0609a488b59253efaa381711 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Tue, 19 Nov 2024 09:05:51 +0800 Subject: [PATCH 11/32] made v2 the default --- include/boost/process.hpp | 31 ++-- include/boost/process/args.hpp | 9 -- include/boost/process/async.hpp | 9 -- include/boost/process/async_pipe.hpp | 9 -- include/boost/process/async_system.hpp | 9 -- include/boost/process/bind_launcher.hpp | 1 + include/boost/process/child.hpp | 9 -- include/boost/process/cmd.hpp | 9 -- include/boost/process/cstring_ref.hpp | 1 + include/boost/process/default_launcher.hpp | 1 + include/boost/process/env.hpp | 9 -- include/boost/process/environment.hpp | 10 +- include/boost/process/error.hpp | 10 +- include/boost/process/exception.hpp | 9 -- include/boost/process/exe.hpp | 9 -- include/boost/process/execute.hpp | 1 + include/boost/process/exit_code.hpp | 1 + include/boost/process/ext.hpp | 1 + include/boost/process/ext/cmd.hpp | 1 + include/boost/process/ext/cwd.hpp | 1 + include/boost/process/ext/env.hpp | 1 + include/boost/process/ext/exe.hpp | 1 + include/boost/process/extend.hpp | 9 -- include/boost/process/filesystem.hpp | 9 -- include/boost/process/group.hpp | 9 -- include/boost/process/handles.hpp | 9 -- include/boost/process/io.hpp | 9 -- include/boost/process/locale.hpp | 9 -- include/boost/process/pid.hpp | 1 + include/boost/process/pipe.hpp | 9 -- include/boost/process/popen.hpp | 1 + include/boost/process/posix.hpp | 9 -- include/boost/process/posix/bind_fd.hpp | 1 + .../boost/process/posix/default_launcher.hpp | 1 + .../posix/fork_and_forget_launcher.hpp | 1 + .../boost/process/posix/pdfork_launcher.hpp | 1 + .../boost/process/posix/vfork_launcher.hpp | 1 + include/boost/process/process.hpp | 1 + include/boost/process/process_handle.hpp | 1 + include/boost/process/search_path.hpp | 9 -- include/boost/process/shell.hpp | 10 +- include/boost/process/spawn.hpp | 9 -- include/boost/process/start_dir.hpp | 10 +- include/boost/process/stdio.hpp | 1 + include/boost/process/system.hpp | 9 -- include/boost/process/v1.hpp | 28 ---- include/boost/process/v2.hpp | 19 --- include/boost/process/windows.hpp | 9 -- .../process/windows/as_user_launcher.hpp | 1 + .../boost/process/windows/creation_flags.hpp | 1 + .../process/windows/default_launcher.hpp | 1 + include/boost/process/windows/show_window.hpp | 53 +++++++ .../process/windows/with_logon_launcher.hpp | 140 ++++++++++++++++++ .../process/windows/with_token_launcher.hpp | 135 +++++++++++++++++ test/Jamfile.jam | 2 +- 55 files changed, 369 insertions(+), 291 deletions(-) delete mode 100644 include/boost/process/args.hpp delete mode 100644 include/boost/process/async.hpp delete mode 100644 include/boost/process/async_pipe.hpp delete mode 100644 include/boost/process/async_system.hpp create mode 100644 include/boost/process/bind_launcher.hpp delete mode 100644 include/boost/process/child.hpp delete mode 100644 include/boost/process/cmd.hpp create mode 100644 include/boost/process/cstring_ref.hpp create mode 100644 include/boost/process/default_launcher.hpp delete mode 100644 include/boost/process/env.hpp delete mode 100644 include/boost/process/exception.hpp delete mode 100644 include/boost/process/exe.hpp create mode 100644 include/boost/process/execute.hpp create mode 100644 include/boost/process/exit_code.hpp create mode 100644 include/boost/process/ext.hpp create mode 100644 include/boost/process/ext/cmd.hpp create mode 100644 include/boost/process/ext/cwd.hpp create mode 100644 include/boost/process/ext/env.hpp create mode 100644 include/boost/process/ext/exe.hpp delete mode 100644 include/boost/process/extend.hpp delete mode 100644 include/boost/process/filesystem.hpp delete mode 100644 include/boost/process/group.hpp delete mode 100644 include/boost/process/handles.hpp delete mode 100644 include/boost/process/io.hpp delete mode 100644 include/boost/process/locale.hpp create mode 100644 include/boost/process/pid.hpp delete mode 100644 include/boost/process/pipe.hpp create mode 100644 include/boost/process/popen.hpp delete mode 100644 include/boost/process/posix.hpp create mode 100644 include/boost/process/posix/bind_fd.hpp create mode 100644 include/boost/process/posix/default_launcher.hpp create mode 100644 include/boost/process/posix/fork_and_forget_launcher.hpp create mode 100644 include/boost/process/posix/pdfork_launcher.hpp create mode 100644 include/boost/process/posix/vfork_launcher.hpp create mode 100644 include/boost/process/process.hpp create mode 100644 include/boost/process/process_handle.hpp delete mode 100644 include/boost/process/search_path.hpp delete mode 100644 include/boost/process/spawn.hpp create mode 100644 include/boost/process/stdio.hpp delete mode 100644 include/boost/process/system.hpp delete mode 100644 include/boost/process/v1.hpp delete mode 100644 include/boost/process/v2.hpp delete mode 100644 include/boost/process/windows.hpp create mode 100644 include/boost/process/windows/as_user_launcher.hpp create mode 100644 include/boost/process/windows/creation_flags.hpp create mode 100644 include/boost/process/windows/default_launcher.hpp create mode 100644 include/boost/process/windows/show_window.hpp create mode 100644 include/boost/process/windows/with_logon_launcher.hpp create mode 100644 include/boost/process/windows/with_token_launcher.hpp diff --git a/include/boost/process.hpp b/include/boost/process.hpp index 5702e5b52..4a7f21f9a 100644 --- a/include/boost/process.hpp +++ b/include/boost/process.hpp @@ -12,23 +12,18 @@ #ifndef BOOST_PROCESS_HPP #define BOOST_PROCESS_HPP -/** - * \file boost/process.hpp - * - * Convenience header which includes all public and platform-independent - * boost.process header files. - */ - -#if !defined(BOOST_PROCESS_VERSION) -#define BOOST_PROCESS_VERSION 1 -#endif - -#if BOOST_PROCESS_VERSION == 1 -#include -#elif BOOST_PROCESS_VERSION == 2 -#include -#else -#error "Unknown boost process version" -#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif diff --git a/include/boost/process/args.hpp b/include/boost/process/args.hpp deleted file mode 100644 index 09584fbb0..000000000 --- a/include/boost/process/args.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/async.hpp b/include/boost/process/async.hpp deleted file mode 100644 index 65137600a..000000000 --- a/include/boost/process/async.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/async_pipe.hpp b/include/boost/process/async_pipe.hpp deleted file mode 100644 index 1e91d28fb..000000000 --- a/include/boost/process/async_pipe.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/async_system.hpp b/include/boost/process/async_system.hpp deleted file mode 100644 index 86b967365..000000000 --- a/include/boost/process/async_system.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/bind_launcher.hpp b/include/boost/process/bind_launcher.hpp new file mode 100644 index 000000000..b61e37d1e --- /dev/null +++ b/include/boost/process/bind_launcher.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/child.hpp b/include/boost/process/child.hpp deleted file mode 100644 index ad02db72b..000000000 --- a/include/boost/process/child.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/cmd.hpp b/include/boost/process/cmd.hpp deleted file mode 100644 index ccf44fd21..000000000 --- a/include/boost/process/cmd.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/cstring_ref.hpp b/include/boost/process/cstring_ref.hpp new file mode 100644 index 000000000..a35d2998c --- /dev/null +++ b/include/boost/process/cstring_ref.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/default_launcher.hpp b/include/boost/process/default_launcher.hpp new file mode 100644 index 000000000..accced3c8 --- /dev/null +++ b/include/boost/process/default_launcher.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/env.hpp b/include/boost/process/env.hpp deleted file mode 100644 index aa8145aeb..000000000 --- a/include/boost/process/env.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/environment.hpp b/include/boost/process/environment.hpp index 9c9727fb5..8f0f18f8f 100644 --- a/include/boost/process/environment.hpp +++ b/include/boost/process/environment.hpp @@ -1,9 +1 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include +#include diff --git a/include/boost/process/error.hpp b/include/boost/process/error.hpp index 347947457..1cd3eb9bb 100644 --- a/include/boost/process/error.hpp +++ b/include/boost/process/error.hpp @@ -1,9 +1 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include +#include diff --git a/include/boost/process/exception.hpp b/include/boost/process/exception.hpp deleted file mode 100644 index a9416db45..000000000 --- a/include/boost/process/exception.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/exe.hpp b/include/boost/process/exe.hpp deleted file mode 100644 index 61383c95d..000000000 --- a/include/boost/process/exe.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/execute.hpp b/include/boost/process/execute.hpp new file mode 100644 index 000000000..99b928106 --- /dev/null +++ b/include/boost/process/execute.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/exit_code.hpp b/include/boost/process/exit_code.hpp new file mode 100644 index 000000000..a65f3b8f7 --- /dev/null +++ b/include/boost/process/exit_code.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/ext.hpp b/include/boost/process/ext.hpp new file mode 100644 index 000000000..338da1fd1 --- /dev/null +++ b/include/boost/process/ext.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/ext/cmd.hpp b/include/boost/process/ext/cmd.hpp new file mode 100644 index 000000000..77b638f52 --- /dev/null +++ b/include/boost/process/ext/cmd.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/ext/cwd.hpp b/include/boost/process/ext/cwd.hpp new file mode 100644 index 000000000..045c6b317 --- /dev/null +++ b/include/boost/process/ext/cwd.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/ext/env.hpp b/include/boost/process/ext/env.hpp new file mode 100644 index 000000000..b73cd9c26 --- /dev/null +++ b/include/boost/process/ext/env.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/ext/exe.hpp b/include/boost/process/ext/exe.hpp new file mode 100644 index 000000000..a891b31ca --- /dev/null +++ b/include/boost/process/ext/exe.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/extend.hpp b/include/boost/process/extend.hpp deleted file mode 100644 index aaa0e8651..000000000 --- a/include/boost/process/extend.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/filesystem.hpp b/include/boost/process/filesystem.hpp deleted file mode 100644 index bb42d8e92..000000000 --- a/include/boost/process/filesystem.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/group.hpp b/include/boost/process/group.hpp deleted file mode 100644 index f441adf99..000000000 --- a/include/boost/process/group.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/handles.hpp b/include/boost/process/handles.hpp deleted file mode 100644 index 82a502109..000000000 --- a/include/boost/process/handles.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/io.hpp b/include/boost/process/io.hpp deleted file mode 100644 index 665354597..000000000 --- a/include/boost/process/io.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/locale.hpp b/include/boost/process/locale.hpp deleted file mode 100644 index cd741c753..000000000 --- a/include/boost/process/locale.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/pid.hpp b/include/boost/process/pid.hpp new file mode 100644 index 000000000..1dfcc2b91 --- /dev/null +++ b/include/boost/process/pid.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/pipe.hpp b/include/boost/process/pipe.hpp deleted file mode 100644 index 0cf85bc9b..000000000 --- a/include/boost/process/pipe.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/popen.hpp b/include/boost/process/popen.hpp new file mode 100644 index 000000000..b8a983431 --- /dev/null +++ b/include/boost/process/popen.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/posix.hpp b/include/boost/process/posix.hpp deleted file mode 100644 index ce1d8e60d..000000000 --- a/include/boost/process/posix.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/posix/bind_fd.hpp b/include/boost/process/posix/bind_fd.hpp new file mode 100644 index 000000000..1aa72d484 --- /dev/null +++ b/include/boost/process/posix/bind_fd.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/posix/default_launcher.hpp b/include/boost/process/posix/default_launcher.hpp new file mode 100644 index 000000000..accced3c8 --- /dev/null +++ b/include/boost/process/posix/default_launcher.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/posix/fork_and_forget_launcher.hpp b/include/boost/process/posix/fork_and_forget_launcher.hpp new file mode 100644 index 000000000..f3da2c209 --- /dev/null +++ b/include/boost/process/posix/fork_and_forget_launcher.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/posix/pdfork_launcher.hpp b/include/boost/process/posix/pdfork_launcher.hpp new file mode 100644 index 000000000..a537a72aa --- /dev/null +++ b/include/boost/process/posix/pdfork_launcher.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/posix/vfork_launcher.hpp b/include/boost/process/posix/vfork_launcher.hpp new file mode 100644 index 000000000..8ec37eb5d --- /dev/null +++ b/include/boost/process/posix/vfork_launcher.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/process.hpp b/include/boost/process/process.hpp new file mode 100644 index 000000000..27139c8ce --- /dev/null +++ b/include/boost/process/process.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/process_handle.hpp b/include/boost/process/process_handle.hpp new file mode 100644 index 000000000..3184a63bf --- /dev/null +++ b/include/boost/process/process_handle.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/search_path.hpp b/include/boost/process/search_path.hpp deleted file mode 100644 index 4a8690255..000000000 --- a/include/boost/process/search_path.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/shell.hpp b/include/boost/process/shell.hpp index 218aa34f6..33b319298 100644 --- a/include/boost/process/shell.hpp +++ b/include/boost/process/shell.hpp @@ -1,9 +1 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include +#include diff --git a/include/boost/process/spawn.hpp b/include/boost/process/spawn.hpp deleted file mode 100644 index 2d48987bc..000000000 --- a/include/boost/process/spawn.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/start_dir.hpp b/include/boost/process/start_dir.hpp index 1fc31b436..d56dadf91 100644 --- a/include/boost/process/start_dir.hpp +++ b/include/boost/process/start_dir.hpp @@ -1,9 +1 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include +#include diff --git a/include/boost/process/stdio.hpp b/include/boost/process/stdio.hpp new file mode 100644 index 000000000..92d685d7c --- /dev/null +++ b/include/boost/process/stdio.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/system.hpp b/include/boost/process/system.hpp deleted file mode 100644 index 3fd073791..000000000 --- a/include/boost/process/system.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/v1.hpp b/include/boost/process/v1.hpp deleted file mode 100644 index 9d081cda6..000000000 --- a/include/boost/process/v1.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2024 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_V1_HPP -#define BOOST_PROCESS_V1_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif //BOOST_PROCESS_V1_HPP diff --git a/include/boost/process/v2.hpp b/include/boost/process/v2.hpp deleted file mode 100644 index c3f54bd91..000000000 --- a/include/boost/process/v2.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_PROCESS_V2_HPP -#define BOOST_PROCESS_V2_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif //BOOST_PROCESS_V2_HPP diff --git a/include/boost/process/windows.hpp b/include/boost/process/windows.hpp deleted file mode 100644 index 8bc2893b6..000000000 --- a/include/boost/process/windows.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 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) - - -#include -BOOST_HEADER_DEPRECATED("") -#include diff --git a/include/boost/process/windows/as_user_launcher.hpp b/include/boost/process/windows/as_user_launcher.hpp new file mode 100644 index 000000000..1886ebf13 --- /dev/null +++ b/include/boost/process/windows/as_user_launcher.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/windows/creation_flags.hpp b/include/boost/process/windows/creation_flags.hpp new file mode 100644 index 000000000..1bc946c7a --- /dev/null +++ b/include/boost/process/windows/creation_flags.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/windows/default_launcher.hpp b/include/boost/process/windows/default_launcher.hpp new file mode 100644 index 000000000..1ced22685 --- /dev/null +++ b/include/boost/process/windows/default_launcher.hpp @@ -0,0 +1 @@ +#include diff --git a/include/boost/process/windows/show_window.hpp b/include/boost/process/windows/show_window.hpp new file mode 100644 index 000000000..1c75b79b8 --- /dev/null +++ b/include/boost/process/windows/show_window.hpp @@ -0,0 +1,53 @@ +// +// boost/process/v2/windows/default_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_WINDOWS_SHOW_WINDOW_HPP +#define BOOST_PROCESS_V2_WINDOWS_SHOW_WINDOW_HPP + +#include + +BOOST_PROCESS_V2_BEGIN_NAMESPACE +namespace windows +{ + +/// A templated initializer to add wShowWindow flags. +template +struct process_show_window +{ + constexpr process_show_window() {} + + error_code on_setup(windows::default_launcher & launcher, + const filesystem::path &, + const std::wstring &) const + { + launcher.startup_info.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; + launcher.startup_info.StartupInfo.wShowWindow |= Flags; + + return error_code {}; + }; +}; + +///Hides the window and activates another window. +constexpr static process_show_window show_window_hide; +///Activates the window and displays it as a maximized window. +constexpr static process_show_window show_window_maximized; +///Activates the window and displays it as a minimized window. +constexpr static process_show_window show_window_minimized; +///Displays the window as a minimized window. This value is similar to `minimized`, except the window is not activated. +constexpr static process_show_window show_window_minimized_not_active; +///Displays a window in its most recent size and position. This value is similar to show_normal`, except that the window is not activated. +constexpr static process_show_window show_window_not_active; +///Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time. +constexpr static process_show_window show_window_normal; + +} +BOOST_PROCESS_V2_END_NAMESPACE + +#endif // BOOST_PROCESS_V2_WINDOWS_SHOW_WINDOW_HPP \ No newline at end of file diff --git a/include/boost/process/windows/with_logon_launcher.hpp b/include/boost/process/windows/with_logon_launcher.hpp new file mode 100644 index 000000000..a71540cac --- /dev/null +++ b/include/boost/process/windows/with_logon_launcher.hpp @@ -0,0 +1,140 @@ +// +// boost/process/v2/windows/default_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_WINDOWS_WITH_LOGON_LAUNCHER_HPP +#define BOOST_PROCESS_V2_WINDOWS_WITH_LOGON_LAUNCHER_HPP + +#include + +BOOST_PROCESS_V2_BEGIN_NAMESPACE +namespace windows +{ + +/// A windows launcher using CreateProcessWithLogon instead of CreateProcess +struct with_logon_launcher : default_launcher +{ + std::wstring username, password, domain; + DWORD logon_flags{0u}; + + with_logon_launcher(std::wstring username = L"", + std::wstring password = L"", + std::wstring domain = L"", + DWORD logon_flags = 0u) : + username(std::move(username)), + password(std::move(password)), + domain(std::move(domain)), + logon_flags(logon_flags) + { + } + + + template + auto operator()(ExecutionContext & context, + error_code & ec, + const typename std::enable_if::value, + filesystem::path >::type & executable, + Args && args, + Inits && ... inits ) -> basic_process + { + return (*this)(context.get_executor(), ec, executable, std::forward(args), std::forward(inits)...); + } + + + template + auto operator()(ExecutionContext & context, + const typename std::enable_if::value, + filesystem::path >::type & executable, + Args && args, + Inits && ... inits ) -> basic_process + { + return (*this)(context.get_executor(), executable, std::forward(args), std::forward(inits)...); + } + + template + auto operator()(Executor exec, + const typename std::enable_if< + net::execution::is_executor::value || + net::is_executor::value, + filesystem::path >::type & executable, + Args && args, + Inits && ... inits ) -> basic_process + { + error_code ec; + auto proc = (*this)(std::move(exec), ec, executable, std::forward(args), std::forward(inits)...); + + if (ec) + v2::detail::throw_error(ec, "with_logon_launcher"); + + return proc; + } + + template + auto operator()(Executor exec, + error_code & ec, + const typename std::enable_if< + net::execution::is_executor::value || + net::is_executor::value, + filesystem::path >::type & executable, + Args && args, + Inits && ... inits ) -> basic_process + { + auto command_line = this->build_command_line(executable, args); + + ec = detail::on_setup(*this, executable, command_line, inits...); + if (ec) + { + detail::on_error(*this, executable, command_line, ec, inits...); + return basic_process(exec); + } + auto ok = ::CreateProcessWithLogonW( + username.c_str(), + domain.empty() ? nullptr : domain.c_str(), + password.c_str(), + logon_flags, + executable.empty() ? nullptr : executable.c_str(), + command_line.empty() ? nullptr : &command_line.front(), + creation_flags, + environment, + current_directory.empty() ? nullptr : current_directory.c_str(), + &startup_info.StartupInfo, + &process_information); + + + if (ok == 0) + { + BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec); + detail::on_error(*this, executable, command_line, ec, inits...); + + if (process_information.hProcess != INVALID_HANDLE_VALUE) + ::CloseHandle(process_information.hProcess); + if (process_information.hThread != INVALID_HANDLE_VALUE) + ::CloseHandle(process_information.hThread); + + return basic_process(exec); + } else + { + detail::on_success(*this, executable, command_line, inits...); + + if (process_information.hThread != INVALID_HANDLE_VALUE) + ::CloseHandle(process_information.hThread); + + return basic_process(exec, + this->process_information.dwProcessId, + this->process_information.hProcess); + } + } +}; + +} +BOOST_PROCESS_V2_END_NAMESPACE + +#endif // BOOST_PROCESS_V2_WINDOWS_WITH_LOGON_LAUNCHER_HPP \ No newline at end of file diff --git a/include/boost/process/windows/with_token_launcher.hpp b/include/boost/process/windows/with_token_launcher.hpp new file mode 100644 index 000000000..48efab698 --- /dev/null +++ b/include/boost/process/windows/with_token_launcher.hpp @@ -0,0 +1,135 @@ +// +// boost/process/v2/windows/default_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_WINDOWS_WITH_TOKEN_LAUNCHER_HPP +#define BOOST_PROCESS_V2_WINDOWS_WITH_TOKEN_LAUNCHER_HPP + +#include + +BOOST_PROCESS_V2_BEGIN_NAMESPACE +namespace windows +{ + +/// A windows launcher using CreateProcessWithToken instead of CreateProcess +struct with_token_launcher : default_launcher +{ + HANDLE token; + DWORD logon_flags; + with_token_launcher(HANDLE token = INVALID_HANDLE_VALUE, + DWORD logon_flags = 0u) : token(token), logon_flags(logon_flags) {} + + + template + auto operator()(ExecutionContext & context, + const typename std::enable_if::value, + filesystem::path >::type & executable, + Args && args, + Inits && ... inits ) -> basic_process + { + error_code ec; + auto proc = (*this)(context, ec, executable, std::forward(args), std::forward(inits)...); + + if (ec) + v2::detail::throw_error(ec, "with_token_launcher"); + + return proc; + } + + + template + auto operator()(ExecutionContext & context, + error_code & ec, + const typename std::enable_if::value, + filesystem::path >::type & executable, + Args && args, + Inits && ... inits ) -> basic_process + { + return (*this)(context.get_executor(), ec, executable, std::forward(args), std::forward(inits)...); + } + + template + auto operator()(Executor exec, + const typename std::enable_if< + net::execution::is_executor::value || + net::is_executor::value, + filesystem::path >::type & executable, + Args && args, + Inits && ... inits ) -> basic_process + { + error_code ec; + auto proc = (*this)(std::move(exec), ec, executable, std::forward(args), std::forward(inits)...); + + if (ec) + detail::throw_error(ec, "with_token_launcher"); + + return proc; + } + + template + auto operator()(Executor exec, + error_code & ec, + const typename std::enable_if< + net::execution::is_executor::value || + net::is_executor::value, + filesystem::path >::type & executable, + Args && args, + Inits && ... inits ) -> basic_process + { + auto command_line = this->build_command_line(executable, args); + + ec = detail::on_setup(*this, executable, command_line, inits...); + if (ec) + { + detail::on_error(*this, executable, command_line, ec, inits...); + return basic_process(exec); + } + auto ok = ::CreateProcessWithTokenW( + token, + logon_flags, + executable.empty() ? nullptr : executable.c_str(), + command_line.empty() ? nullptr : &command_line.front(), + creation_flags, + environment, + current_directory.empty() ? nullptr : current_directory.c_str(), + &startup_info.StartupInfo, + &process_information); + + + if (ok == 0) + { + BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec); + detail::on_error(*this, executable, command_line, ec, inits...); + + if (process_information.hProcess != INVALID_HANDLE_VALUE) + ::CloseHandle(process_information.hProcess); + if (process_information.hThread != INVALID_HANDLE_VALUE) + ::CloseHandle(process_information.hThread); + + return basic_process(exec); + } else + { + detail::on_success(*this, executable, command_line, inits...); + + if (process_information.hThread != INVALID_HANDLE_VALUE) + ::CloseHandle(process_information.hThread); + + return basic_process(exec, + this->process_information.dwProcessId, + this->process_information.hProcess); + } + } +}; + +} +BOOST_PROCESS_V2_END_NAMESPACE + +#endif // BOOST_PROCESS_V2_WINDOWS_WITH_TOKEN_LAUNCHER_HPP \ No newline at end of file diff --git a/test/Jamfile.jam b/test/Jamfile.jam index 55e04504a..cd1b744b0 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -3,5 +3,5 @@ # 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) -alias v1-tests : v1//bare v1//with-valgrind v1//without-valgrind ; +# alias v1-tests : v1//bare v1//with-valgrind v1//without-valgrind ; alias v2-tests : v2//standalone v2//with_target ; From c33828a166afd207c5aed4c90037ca0a283b434f Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Wed, 20 Nov 2024 04:42:46 +0800 Subject: [PATCH 12/32] reference docs --- doc/configuration.adoc | 11 + doc/index.adoc | 23 + doc/reference/bind_launcher.adoc | 15 + doc/reference/cstring_ref.adoc | 3 + doc/reference/default_launcher.adoc | 22 + doc/reference/environment.adoc | 735 ++++++++++++++++++ doc/reference/error.adoc | 36 + doc/reference/execute.adoc | 33 + doc/reference/exit_code.adoc | 43 + doc/reference/ext.adoc | 46 ++ doc/reference/pid.adoc | 23 + doc/reference/popen.adoc | 163 ++++ doc/reference/posix/bind_fd.adoc | 70 ++ doc/reference/process.adoc | 174 +++++ doc/reference/process_handle.adoc | 108 +++ doc/reference/shell.adoc | 57 ++ doc/reference/start_dir.adoc | 16 + doc/reference/stdio.adoc | 55 ++ doc/reference/windows/creation_flags.adoc | 27 + doc/reference/windows/show_window.adoc | 32 + include/boost/process/v2/exit_code.hpp | 13 +- include/boost/process/v2/popen.hpp | 4 +- .../process/v2/windows/creation_flags.hpp | 2 +- 23 files changed, 1701 insertions(+), 10 deletions(-) create mode 100644 doc/configuration.adoc create mode 100644 doc/reference/bind_launcher.adoc create mode 100644 doc/reference/cstring_ref.adoc create mode 100644 doc/reference/default_launcher.adoc create mode 100644 doc/reference/environment.adoc create mode 100644 doc/reference/error.adoc create mode 100644 doc/reference/execute.adoc create mode 100644 doc/reference/exit_code.adoc create mode 100644 doc/reference/ext.adoc create mode 100644 doc/reference/pid.adoc create mode 100644 doc/reference/popen.adoc create mode 100644 doc/reference/posix/bind_fd.adoc create mode 100644 doc/reference/process.adoc create mode 100644 doc/reference/process_handle.adoc create mode 100644 doc/reference/shell.adoc create mode 100644 doc/reference/start_dir.adoc create mode 100644 doc/reference/stdio.adoc create mode 100644 doc/reference/windows/creation_flags.adoc create mode 100644 doc/reference/windows/show_window.adoc diff --git a/doc/configuration.adoc b/doc/configuration.adoc new file mode 100644 index 000000000..b44790a62 --- /dev/null +++ b/doc/configuration.adoc @@ -0,0 +1,11 @@ += Configuration + +Boost process v2 can be configured in the following ways: + +[cols="1,1"] +|=== +| Macro | Description + +| `BOOST_PROCESS_V2_STANDALONE` | Build boost.process for standalone asio +| `BOOST_PROCESS_USE_STD_FS` | Use std::filesystem instead of boost::filsystem +| `BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE` | Disable usage of `close_range`. diff --git a/doc/index.adoc b/doc/index.adoc index 627f78380..0fca5dd14 100644 --- a/doc/index.adoc +++ b/doc/index.adoc @@ -24,5 +24,28 @@ include::start_dir.adoc[] include::stdio.adoc[] include::env.adoc[] += Reference + + +include::reference/bind_launcher.adoc[] +include::reference/cstring_ref.adoc[] +include::reference/default_launcher.adoc[] +include::reference/environment.adoc[] +include::reference/error.adoc[] +include::reference/execute.adoc[] +include::reference/exit_code.adoc[] +include::reference/ext.adoc[] +include::reference/pid.adoc[] +include::reference/popen.adoc[] +include::reference/process.adoc[] +include::reference/process_handle.adoc[] +include::reference/shell.adoc[] +include::reference/start_dir.adoc[] +include::reference/stdio.adoc[] +include::reference/ext.adoc[] +include::reference/posix/bind_fd.adoc[] +include::reference/windows/creation_flags.adoc[] +include::reference/windows/show_window.adoc[] + include::version2.adoc[] include::acknowledgements.adoc[] \ No newline at end of file diff --git a/doc/reference/bind_launcher.adoc b/doc/reference/bind_launcher.adoc new file mode 100644 index 000000000..997a7953f --- /dev/null +++ b/doc/reference/bind_launcher.adoc @@ -0,0 +1,15 @@ +== `bind_launcher.hpp` + +The `bind_launcher` utlitities allow on the fly construction of a launcher with bound initializers. + +[source,cpp] +---- +// Creates a new launcher with the bound initializer. +template +auto bind_launcher(Launcher && launcher, Init && ... init); + +// Calls bind_launcher with the default_launcher as the first parameter. +// The new launcher with bound paramaters +template +auto bind_default_launcher(Init && ... init); +---- \ No newline at end of file diff --git a/doc/reference/cstring_ref.adoc b/doc/reference/cstring_ref.adoc new file mode 100644 index 000000000..7bbcdcf4f --- /dev/null +++ b/doc/reference/cstring_ref.adoc @@ -0,0 +1,3 @@ +== `cstring_ref.hpp` + +The `cstring_ref` is a string-view like type that holds a null-terminated string. \ No newline at end of file diff --git a/doc/reference/default_launcher.adoc b/doc/reference/default_launcher.adoc new file mode 100644 index 000000000..fcd194c26 --- /dev/null +++ b/doc/reference/default_launcher.adoc @@ -0,0 +1,22 @@ +== `default_launcher.hpp` +[#default_launcher] + +The `default_launcher` is the standard way of creating a process. + +[source,cpp] +---- +asio::io_context ctx; +process proc(ctx.get_executor(), "test", {}); +// equivalent to +process prod = default_launcher()(ctx.get_executor(), "test", {}); +---- + +It has four overloads: + +[source,cpp] +---- +(ExecutionContext &, filesystem::path, Args && args, Inits && ... inits) -> basic_process +(Executor &, filesystem::path, Args && args, Inits && ... inits) -> basic_process; +(ExecutionContext &, error_code&, filesystem::path, Args && args, Inits && ... inits) -> basic_process;` +(Executor &, error_code&, filesystem::path, Args && args, Inits && ... inits) -> basic_process +---- diff --git a/doc/reference/environment.adoc b/doc/reference/environment.adoc new file mode 100644 index 000000000..f7fef54c0 --- /dev/null +++ b/doc/reference/environment.adoc @@ -0,0 +1,735 @@ +== `environment.hpp` +[#environment] + +=== `environment` + +The `environment` header provides facilities to maniuplate the current environment and set it for new processes. + + +An environment is a a `range` of `T` fulfilling these requirements: + +For `T value` + * - std::get<0>(value) must return a type comparable to `key_view`. + * - std::get<1>(value) must return a type convertible to `value_view`. + +[source,cpp] +---- + +// Namespace for information and functions regarding the calling process. +namespace environment +{ + +// A char traits type that reflects the OS rules for string representing environment keys. +/* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. + * + * Windows treats keys as case-insensitive yet perserving. The char traits are made to reflect + * that behaviour. +*/ +tempalte +using key_char_traits = implementation_defined ; + +// A char traits type that reflects the OS rules for string representing environment values. +/* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. +*/ +tempalte +using value_char_traits = implementation_defined ; + +// The character type used by the environment. Either `char` or `wchar_t`. +using char_type = implementation_defined ; + +// The equal character in an environment string used to separate key and value. +constexpr char_type equality_sign = implementation_defined; + +// The delimiter in environemtn lists. Commonly used by the `PATH` variable. +constexpr char_type delimiter = implementation_defined; + +// The native handle of an environment. Note that this can be an owning pointer and is generally not thread safe. +using native_handle = implementation_defined; + + +// A forward iterator over string_view used by a value or value_view to iterator through environments that are lists. +struct value_iterator; + +// A view type for a key of an environment +struct key_view +{ + using value_type = char_type; + using traits_type = key_char_traits; + using string_view_type = basic_string_view; + using string_type = std::basic_string>; + + key_view() noexcept = default; + key_view( const key_view& p ) = default; + key_view( key_view&& p ) noexcept = default; + template + key_view( const Source& source ); + key_view( const char_type * p); + key_view( char_type * p); + + ~key_view() = default; + + key_view& operator=( const key_view& p ) = default; + key_view& operator=( key_view&& p ) noexcept = default; + key_view& operator=( string_view_type source ); + + void swap( key_view& other ) noexcept; + + string_view_type native() const noexcept; + + operator string_view_type() const; + + int compare( const key_view& p ) const noexcept; + int compare( string_view_type str ) const; + int compare( const value_type* s ) const; + + template< class CharT, class Traits = std::char_traits, + class Alloc = std::allocator > + std::basic_string + basic_string( const Alloc& alloc = Alloc()) const; + + std::string string() const; + std::wstring wstring() const; + + string_type native_string() const; + + friend bool operator==(key_view l, key_view r); + friend bool operator!=(key_view l, key_view r); + friend bool operator<=(key_view l, key_view r); + friend bool operator>=(key_view l, key_view r); + friend bool operator< (key_view l, key_view r); + friend bool operator> (key_view l, key_view r); + + bool empty() const; + + template< class CharT, class Traits > + friend std::basic_ostream& + operator<<( std::basic_ostream& os, const key_view& p ); + + template< class CharT, class Traits > + friend std::basic_istream& + operator>>( std::basic_istream& is, key_view& p ); + + const value_type * data() const; + std::size_t size() const; +}; + +// A view for a value in an environment +struct value_view +{ + using value_type = char_type; + using string_view_type = basic_cstring_ref>; + using string_type = std::basic_string>; + using traits_type = value_char_traits; + + value_view() noexcept = default; + value_view( const value_view& p ) = default; + value_view( value_view&& p ) noexcept = default; + template + value_view( const Source& source ); + value_view( const char_type * p); + value_view( char_type * p); + + ~value_view() = default; + + value_view& operator=( const value_view& p ) = default; + value_view& operator=( value_view&& p ) noexcept = default; + value_view& operator=( string_view_type source ); + + void swap( value_view& other ) noexcept; + + string_view_type native() const noexcept ; + + operator string_view_type() const; + operator typename string_view_type::string_view_type() const; + + int compare( const value_view& p ) const noexcept; + int compare( string_view_type str ) const; + int compare( const value_type* s ) const; + + template< class CharT, class Traits = std::char_traits, + class Alloc = std::allocator > + std::basic_string + basic_string( const Alloc& alloc = Alloc() ) const; + std::string string() const; + std::wstring wstring() const; + + string_type native_string() const; + bool empty() const; + + friend bool operator==(value_view l, value_view r); + friend bool operator!=(value_view l, value_view r); + friend bool operator<=(value_view l, value_view r); + friend bool operator>=(value_view l, value_view r); + friend bool operator< (value_view l, value_view r); + friend bool operator> (value_view l, value_view r); + + + template< class CharT, class Traits > + friend std::basic_ostream& + operator<<( std::basic_ostream& os, const value_view& p ); + + template< class CharT, class Traits > + friend std::basic_istream& + operator>>( std::basic_istream& is, value_view& p ); + value_iterator begin() const; + value_iterator end() const; + + const char_type * c_str(); + const value_type * data() const; + std::size_t size() const; +}; + +// A view for a key value pair in an environment +struct key_value_pair_view +{ + using value_type = char_type; + using string_type = std::basic_string; + using string_view_type = basic_cstring_ref; + using traits_type = std::char_traits; + + key_value_pair_view() noexcept = default; + key_value_pair_view( const key_value_pair_view& p ) = default; + key_value_pair_view( key_value_pair_view&& p ) noexcept = default; + template::value>::type> + key_value_pair_view( const Source& source ); + + key_value_pair_view( const char_type * p); + key_value_pair_view( char_type * p); + + + ~key_value_pair_view() = default; + + key_value_pair_view& operator=( const key_value_pair_view& p ) = default; + key_value_pair_view& operator=( key_value_pair_view&& p ) noexcept = default; + + void swap( key_value_pair_view& other ) noexcept; + + string_view_type native() const noexcept; + + operator string_view_type() const; + operator typename string_view_type::string_view_type() const; + + int compare( key_value_pair_view p ) const noexcept; + int compare( const string_type& str ) const; + int compare( string_view_type str ) const; + int compare( const value_type* s ) const; + + template< class CharT, class Traits = std::char_traits, class Alloc = std::allocator > + std::basic_string + basic_string( const Alloc& alloc = Alloc()) const; + std::string string() const; + std::wstring wstring() const; + + string_type native_string() const; + + bool empty() const; + + key_view key() const; + value_view value() const; + + friend bool operator==(key_value_pair_view l, key_value_pair_view r); + friend bool operator!=(key_value_pair_view l, key_value_pair_view r); + friend bool operator<=(key_value_pair_view l, key_value_pair_view r); + friend bool operator>=(key_value_pair_view l, key_value_pair_view r); + friend bool operator< (key_value_pair_view l, key_value_pair_view r); + friend bool operator> (key_value_pair_view l, key_value_pair_view r); + + + template< class CharT, class Traits > + friend std::basic_ostream& + operator<<( std::basic_ostream& os, const key_value_pair_view& p ); + + template< class CharT, class Traits > + friend std::basic_istream& + operator>>( std::basic_istream& is, key_value_pair_view& p ); + + template + inline auto get() const -> typename conditional::type; + const value_type * c_str() const noexcept; + const value_type * data() const; + std::size_t size() const; + +}; + +// Allow tuple-likg getters & structured bindings. +template<> key_view key_value_pair_view::get<0u>() const; +template<> value_view key_value_pair_view::get<1u>() const; + +// A class representing a key within an environment. +struct key +{ + using value_type = char_type; + using traits_type = key_char_traits; + using string_type = std::basic_string; + using string_view_type = basic_string_view; + + key(); + key( const key& p ) = default; + key( key&& p ) noexcept = default; + key( const string_type& source ); + key( string_type&& source ); + key( const value_type * raw ); + key( value_type * raw ); + + explicit key(key_view kv); + + + template< class Source > + key( const Source& source); + + key(const typename conditional::value, wchar_t, char>::type * raw); + + template< class InputIt > + key( InputIt first, InputIt last); + + ~key() = default; + + key& operator=( const key& p ) = default; + key& operator=( key&& p ); + key& operator=( string_type&& source ); + + template< class Source > + key& operator=( const Source& source ); + + key& assign( string_type&& source ); + + template< class Source > + key& assign( const Source& source ); + template< class InputIt > + key& assign( InputIt first, InputIt last ); + + void clear(); + + void swap( key& other ) noexcept; + + const value_type* c_str() const noexcept; + const string_type& native() const noexcept; + string_view_type native_view() const noexcept; + + operator string_type() const; + operator string_view_type() const; + + int compare( const key& p ) const noexcept; + int compare( const string_type& str ) const; + int compare( string_view_type str ) const; + int compare( const value_type* s ) const; + + template< class CharT, class Traits = std::char_traits, + class Alloc = std::allocator > + std::basic_string + basic_string( const Alloc& alloc = Alloc()) const; + + + std::string string() const; + std::wstring wstring() const; + + const string_type & native_string() const; + bool empty() const; + + friend bool operator==(const key & l, const key & r); + friend bool operator!=(const key & l, const key & r); + friend bool operator<=(const key & l, const key & r); + friend bool operator>=(const key & l, const key & r); + friend bool operator< (const key & l, const key & r); + friend bool operator> (const key & l, const key & r); + + template< class CharT, class Traits > + friend std::basic_ostream& + operator<<( std::basic_ostream& os, const key& p ); + + template< class CharT, class Traits > + friend std::basic_istream& + operator>>( std::basic_istream& is, key& p ); + const value_type * data() const; + std::size_t size() const; +}; + +bool operator==(const value_view &, const value_view); +bool operator!=(const value_view &, const value_view); +bool operator<=(const value_view &, const value_view); +bool operator< (const value_view &, const value_view); +bool operator> (const value_view &, const value_view); +bool operator>=(const value_view &, const value_view); + + +struct value +{ + using value_type = char_type; + using traits_type = value_char_traits; + using string_type = std::basic_string; + using string_view_type = basic_cstring_ref; + + value(); + value( const value& p ) = default; + + value( const string_type& source ); + value( string_type&& source ); + value( const value_type * raw ); + value( value_type * raw ); + + explicit value(value_view kv); + + template< class Source > + value( const Source& source ); + value(const typename conditional::value, wchar_t, char>::type * raw); + + template< class InputIt > + value( InputIt first, InputIt last); + + ~value() = default; + + value& operator=( const value& p ) = default; + value& operator=( value&& p ); + value& operator=( string_type&& source ); + template< class Source > + value& operator=( const Source& source ); + + value& assign( string_type&& source ); + template< class Source > + value& assign( const Source& source ); + + template< class InputIt > + value& assign( InputIt first, InputIt last ); + + void push_back(const value & sv); + void clear() {value_.clear();} + + void swap( value& other ) noexcept; + + const value_type* c_str() const noexcept; + const string_type& native() const noexcept; + string_view_type native_view() const noexcept; + + operator string_type() const; + operator string_view_type() const; + operator typename string_view_type::string_view_type() const; + + int compare( const value& p ) const noexcept; + int compare( const string_type& str ) const; + int compare( string_view_type str ) const; + int compare( const value_type* s ) const; + + template< class CharT, class Traits = std::char_traits, + class Alloc = std::allocator > + std::basic_string + basic_string( const Alloc& alloc = Alloc()) const; + + std::string string() const; + std::wstring wstring() const; + + + const string_type & native_string() const; + + bool empty() const; + + friend bool operator==(const value & l, const value & r); + friend bool operator!=(const value & l, const value & r); + friend bool operator<=(const value & l, const value & r); + friend bool operator>=(const value & l, const value & r); + friend bool operator< (const value & l, const value & r); + friend bool operator> (const value & l, const value & r); + + template< class CharT, class Traits > + friend std::basic_ostream& + operator<<( std::basic_ostream& os, const value& p ); + + template< class CharT, class Traits > + friend std::basic_istream& + operator>>( std::basic_istream& is, value& p ); + + value_iterator begin() const; + value_iterator end() const; + const value_type * data() const; + std::size_t size() const; +}; + + +bool operator==(const value_view &, const value_view); +bool operator!=(const value_view &, const value_view); +bool operator<=(const value_view &, const value_view); +bool operator< (const value_view &, const value_view); +bool operator> (const value_view &, const value_view); +bool operator>=(const value_view &, const value_view); + +struct key_value_pair +{ + using value_type = char_type; + using traits_type = std::char_traits; + using string_type = std::basic_string; + using string_view_type = basic_cstring_ref; + + key_value_pair()l + 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); + + key_value_pair(key_view key, std::initializer_list> values); + key_value_pair( const string_type& source ); + key_value_pair( string_type&& source ); + key_value_pair( const value_type * raw ); + key_value_pair( value_type * raw ); + + explicit key_value_pair(key_value_pair_view kv) : value_(kv.c_str()) {} + + template< class Source > + key_value_pair( const Source& source); + + template< typename Key, + typename Value > + key_value_pair( + const std::pair & kv); + + key_value_pair(const typename conditional::value, wchar_t, char>::type * raw); + + template< class InputIt , typename std::iterator_traits::iterator_category> + key_value_pair( InputIt first, InputIt last ); + + ~key_value_pair() = default; + + key_value_pair& operator=( const key_value_pair& p ) = default; + key_value_pair& operator=( key_value_pair&& p ); + key_value_pair& operator=( string_type&& source ); + template< class Source > + key_value_pair& operator=( const Source& source ); + + key_value_pair& assign( string_type&& source ); + + template< class Source > + key_value_pair& assign( const Source& source ); + + + template< class InputIt > + key_value_pair& assign( InputIt first, InputIt last ); + + void clear(); + + void swap( key_value_pair& other ) noexcept; + + const value_type* c_str() const noexcept; + const string_type& native() const noexcept; + string_view_type native_view() const noexcept; + + operator string_type() const; + operator string_view_type() const; + operator typename string_view_type::string_view_type() const; + operator key_value_pair_view() const; + + int compare( const key_value_pair& p ) const noexcept; + int compare( const string_type& str ) const; + int compare( string_view_type str ) const; + int compare( const value_type* s ) const; + + template< class CharT, class Traits = std::char_traits, class Alloc = std::allocator > + std::basic_string + basic_string( const Alloc& alloc = Alloc() ) const; + std::string string() const {return basic_string();} + std::wstring wstring() const {return basic_string();} + + const string_type & native_string() const; + friend bool operator==(const key_value_pair & l, const key_value_pair & r); + friend bool operator!=(const key_value_pair & l, const key_value_pair & r); + friend bool operator<=(const key_value_pair & l, const key_value_pair & r); + friend bool operator>=(const key_value_pair & l, const key_value_pair & r); + friend bool operator< (const key_value_pair & l, const key_value_pair & r); + friend bool operator> (const key_value_pair & l, const key_value_pair & r); + + bool empty() const; + + struct key_view key() const; + struct value_view value() const; + + template< class CharT, class Traits > + friend std::basic_ostream& + operator<<( std::basic_ostream& os, const key_value_pair& p ); + + template< class CharT, class Traits > + friend std::basic_istream& + operator>>( std::basic_istream& is, key_value_pair& p ); + + const value_type * data() const; + std::size_t size() const; + + template + inline auto get() const -> typename conditional::type; +}; + +bool operator==(const key_value_pair_view &, const key_value_pair_view); +bool operator!=(const key_value_pair_view &, const key_value_pair_view); +bool operator<=(const key_value_pair_view &, const key_value_pair_view); +bool operator< (const key_value_pair_view &, const key_value_pair_view); +bool operator> (const key_value_pair_view &, const key_value_pair_view); +bool operator>=(const key_value_pair_view &, const key_value_pair_view); + + +// Allow tuple-likg getters & structured bindings. +template<> +key_view key_value_pair::get<0u>() const; + +template<> +value_view key_value_pair::get<1u>() const; + +// A view object for the current environment of this process. +/* + * The view might (windows) or might not (posix) be owning; + * if it owns it will deallocate the on destruction, like a unique_ptr. + * + * Note that accessing the environment in this way is not thread-safe. + * + * @code + * + * void dump_my_env(current_view env = current()) + * { + * for (auto & [k, v] : env) + * std::cout << k.string() << " = " << v.string() << std::endl; + * } + * + * @endcode + * + * + */ +struct current_view +{ + using native_handle_type = environment::native_handle_type; + using value_type = key_value_pair_view; + + current_view() = default; + current_view(current_view && nt) = default; + + native_handle_type native_handle() { return handle_.get(); } + + struct iterator + { + using value_type = key_value_pair_view; + using difference_type = int; + using reference = key_value_pair_view; + using pointer = key_value_pair_view; + using iterator_category = std::forward_iterator_tag; + + iterator() = default; + iterator(const iterator & ) = default; + iterator(const native_iterator &native_handle) : iterator_(native_handle) {} + + iterator & operator++() + { + iterator_ = detail::next(iterator_); + return *this; + } + + iterator operator++(int) + { + auto last = *this; + iterator_ = detail::next(iterator_); + return last; + } + key_value_pair_view operator*() const + { + return detail::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: + environment::native_iterator iterator_; + }; + + iterator begin() const {return iterator(handle_.get());} + iterator end() const {return iterator(detail::find_end(handle_.get()));} + + private: + + std::unique_ptr::type, + detail::native_handle_deleter> handle_{environment::detail::load_native_handle()}; +}; + +// Obtain a handle to the current environment +inline current_view current() {return current_view();} + +// Find the home folder in an environment-like type. +/* + * @param env The environment to search. Defaults to the current environment of this process + * + * The environment type passed in must be a range with value T that fulfills the following requirements: + * + * For `T value` + * + * - std::get<0>(value) must return a type comparable to `key_view`. + * - std::get<1>(value) must return a type convertible to filesystem::path. + * + * @return A filesystem::path to the home directory or an empty path if it cannot be found. + * + */ +template +inline filesystem::path home(Environment && env = current()); + +// Find the executable `name` in an environment-like type. +template +filesystem::path find_executable(BOOST_PROCESS_V2_NAMESPACE::filesystem::path name, + Environment && env = current()); + +// Get an environment variable from the current process. +value get(const key & k, error_code & ec); +value get(const key & k); +value get(basic_cstring_ref> k, error_code & ec); +value get(basic_cstring_ref> k); +value get(const char_type * c, error_code & ec); +value get(const char_type * c); + +// Set an environment variable for the current process. +void set(const key & k, value_view vw, error_code & ec); +void set(const key & k, value_view vw); +void set(basic_cstring_ref> k, value_view vw, error_code & ec); +void set(basic_cstring_ref> k, value_view vw); +void set(const char_type * k, value_view vw, error_code & ec); +void set(const char_type * k, value_view vw); +template +void set(const key & k, const Char * vw, error_code & ec); +template +void set(const key & k, const Char * vw); +template +void set(basic_cstring_ref> k, const Char * vw, error_code & ec); +template +void set(basic_cstring_ref> k, const Char * vw); +template +void set(const char_type * k, const Char * vw, error_code & ec); +template +void set(const char_type * k, const Char * vw); + +// Remove an environment variable from the current process. +void unset(const key & k, error_code & ec); +void unset(const key & k); +void unset(basic_cstring_ref> k, error_code & ec); +void unset(basic_cstring_ref> k); +void unset(const char_type * c, error_code & ec); +void unset(const char_type * c); + +} +---- + + +=== `process_environment` + +In order to set the environment of a child process, `process_environment` can be used. + + + +[source, cpp] +.This will set the environment in a subprocess: +---- +process proc{executor, find_executable("printenv"), {"foo"}, process_environment{"foo=bar"}}; +---- + +The environment initializer will persist it's state, so that it can +be used multiple times. Do however note the the Operating System is +allowed to modify the internal state. + +[source,cpp] +---- +auto exe = find_executable("printenv"); +process_environment env = {"FOO=BAR", "BAR=FOO"}; + +process proc1(executor, exe, {"FOO"}, env); +process proc2(executor, exe, {"BAR"}, env); +---- diff --git a/doc/reference/error.adoc b/doc/reference/error.adoc new file mode 100644 index 000000000..f0ecc0085 --- /dev/null +++ b/doc/reference/error.adoc @@ -0,0 +1,36 @@ +== `error.hpp` +[#error] + +The error header provides two error categories: + +[source,cpp] +---- +// Errors used for utf8 <-> UCS-2 conversions. +enum utf8_conv_error +{ + insufficient_buffer = 1, + invalid_character, +}; + +extern const error_category& get_utf8_category(); +static const error_category& utf8_category = get_utf8_category(); + +extern const error_category& get_exit_code_category(); + +/// An error category that can be used to interpret exit codes of subprocesses. +static const error_category& exit_code_category = get_exit_code_category(); + +} +---- + +The `get_exit_code_category` can be used as follows: + +[source,cpp] +---- +void run_my_process(filesystem::path pt, error_code & ec) +{ + process proc(pt, {}); + proc.wait(); + ec.assign(proc.native_exit_code(), error::get_exit_code_category()); +} +---- \ No newline at end of file diff --git a/doc/reference/execute.adoc b/doc/reference/execute.adoc new file mode 100644 index 000000000..1649d0637 --- /dev/null +++ b/doc/reference/execute.adoc @@ -0,0 +1,33 @@ + +== `execute.hpp` +[#execute] + +The execute header provides two error categories: + +[source,cpp] +---- + +// Run a process and wait for it to complete. +template int execute(basic_process proc); +template int execute(basic_process proc, error_code & ec) + +// Execute a process asynchronously +template> +auto async_execute(basic_process proc, + WaitHandler && handler = net::default_completion_token_t()); +---- + +The `async_execute` function asynchronously for a process to complete. + + Cancelling the execution will signal the child process to exit + 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 use the lowest selected cancellation +type. A subprocess might ignore anything not terminal. + diff --git a/doc/reference/exit_code.adoc b/doc/reference/exit_code.adoc new file mode 100644 index 000000000..c80eed033 --- /dev/null +++ b/doc/reference/exit_code.adoc @@ -0,0 +1,43 @@ +== `exit_code.hpp` +[#exit_code] + +The exit code header provides portable handles for exit codes. + +[source,cpp] +---- +// The native exit-code type, usually an integral value +/* The OS may have a value different from `int` to represent + * the exit codes of subprocesses. It might also + * contain additional information. + */ +typedef implementation_defined native_exit_code_type; + + +// Check if the native exit code indicates the process is still running +bool process_is_running(native_exit_code_type code); + +// Obtain the portable part of the exit code, i.e. what the subprocess has returned from main. +int evaluate_exit_code(native_exit_code_type code); + +// Helper to subsume an exit-code into an error_code if there's no actual error isn't set. +error_code check_exit_code( + error_code &ec, native_exit_code_type native_code, + const error_category & category = error::get_exit_code_category()); +---- + + +The `check_exit_code` can be used like this: + +[source,cpp] +---- + +process proc{co_await this_coro::executor, "exit", {"1"}}; + +co_await proc.async_wait( + asio::deferred( + [&proc](error_code ec, int) + { + return asio::deferred.values( + check_exit_code(ec, proc.native_exit_code()) + ); +---- diff --git a/doc/reference/ext.adoc b/doc/reference/ext.adoc new file mode 100644 index 000000000..ac0007d97 --- /dev/null +++ b/doc/reference/ext.adoc @@ -0,0 +1,46 @@ +== `ext` + +The headers in `process/ext` provides features to obtain information about third part processes. + +[source,cpp] +---- +// Get the cmd line used to launche the process +template +shell cmd(basic_process_handle & handle, error_code & ec); +template +shell cmd(basic_process_handle & handle); +shell cmd(pid_type pid, error_code & ec); +shell cmd(pid_type pid); + + +// Get the current working directory of the process. +template +filesystem::path cwd(basic_process_handle & handle, error_code & ec); +template +filesystem::path cwd(basic_process_handle & handle) +filesystem::path cwd(pid_type pid, error_code & ec); +filesystem::path cwd(pid_type pid); + + +// Get the current environment of the process. +template +env_view cwd(basic_process_handle & handle, error_code & ec); +template +env_view cwd(basic_process_handle & handle) +env_view env(pid_type pid, error_code & ec); +env_view env(pid_type pid); + + +// Get the executable of the process. +template +filesystem::path exe(basic_process_handle & handle, error_code & ec); +template +filesystem::path exe(basic_process_handle & handle) +filesystem::path exe(pid_type pid, error_code & ec); +filesystem::path exe(pid_type pid); +---- + +WARNING: The function may fail with "operation_not_supported" on some niche platforms. + +NOTE: On windows overloads taking a `HANDLE` are also available. + diff --git a/doc/reference/pid.adoc b/doc/reference/pid.adoc new file mode 100644 index 000000000..61819b484 --- /dev/null +++ b/doc/reference/pid.adoc @@ -0,0 +1,23 @@ +== `pid.hpp` +[#pid] + +[source,cpp] +---- +//An integral type representing a process id. +typedef implementation_defined pid_type; + +// Get the process id of the current process. +pid_type current_pid(); + +// List all available pids. +std::vector all_pids(boost::system::error_code & ec); +std::vector all_pids(); + +// return parent pid of pid. +pid_type parent_pid(pid_type pid, boost::system::error_code & ec); +pid_type parent_pid(pid_type pid); + +// return child pids of pid. +std::vector child_pids(pid_type pid, boost::system::error_code & ec); +std::vector child_pids(pid_type pid); +---- diff --git a/doc/reference/popen.adoc b/doc/reference/popen.adoc new file mode 100644 index 000000000..449a3f70c --- /dev/null +++ b/doc/reference/popen.adoc @@ -0,0 +1,163 @@ +== `popen.hpp` +[#popen] + +`popen` is a class that launches a process and connect stdin & stderr to pipes. + +[source,cpp] +---- +popen proc(executor, find_executable("addr2line"), {argv[0]}); +asio::write(proc, asio::buffer("main\n")); +std::string line; +asio::read_until(proc, asio::dynamic_buffer(line), '\n'); +---- + +[source,cpp] +---- +// A subprocess with automatically assigned pipes. +template +struct basic_popen : basic_process +{ + // The executor of the process + using executor_type = Executor; + + // Rebinds the popen type to another executor. + template + struct rebind_executor + { + // The pipe type when rebound to the specified executor. + typedef basic_popen other; + }; + + // Move construct a popen + basic_popen(basic_popen &&) = default; + // Move assign a popen + basic_popen& operator=(basic_popen &&) = default; + + // Move construct a popen and change the executor type. + template + basic_popen(basic_popen&& lhs) + : basic_process(std::move(lhs)), + stdin_(std::move(lhs.stdin_)), stdout_(std::move(lhs.stdout_)) + { + } + + // Create a closed process handle + explicit basic_popen(executor_type exec); + + // Create a closed process handle + template + explicit basic_popen(ExecutionContext & context); + + // Construct a child from a property list and launch it using the default process launcher. + template + explicit basic_popen( + executor_type executor, + const filesystem::path& exe, + std::initializer_list args, + Inits&&... inits); + + // Construct a child from a property list and launch it using the default process launcher. + template + explicit basic_popen( + Launcher && launcher, + executor_type executor, + const filesystem::path& exe, + std::initializer_list args, + Inits&&... inits); + + // Construct a child from a property list and launch it using the default process launcher. + template + explicit basic_popen( + executor_type executor, + const filesystem::path& exe, + Args&& args, Inits&&... inits); + + // Construct a child from a property list and launch it using the default process launcher. + template + explicit basic_popen( + Launcher && launcher, + executor_type executor, + const filesystem::path& exe, + Args&& args, Inits&&... inits); + + // Construct a child from a property list and launch it using the default process launcher. + template + explicit basic_popen( + ExecutionContext & context, + const filesystem::path& exe, + std::initializer_list args, + Inits&&... inits); + + // Construct a child from a property list and launch it using the default process launcher. + template + explicit basic_popen( + Launcher && launcher, + ExecutionContext & context, + const filesystem::path& exe, + std::initializer_list args, + Inits&&... inits); + + // Construct a child from a property list and launch it using the default process launcher. + template + explicit basic_popen( + ExecutionContext & context, + const filesystem::path& exe, + Args&& args, Inits&&... inits); + + // Construct a child from a property list and launch it using the default process launcher. + template + explicit basic_popen( + Launcher && launcher, + ExecutionContext & context, + const filesystem::path& exe, + Args&& args, Inits&&... inits); + + // The type used for stdin on the parent process side. + using stdin_type = net::basic_writable_pipe; + // The type used for stdout on the parent process side. + using stdout_type = net::basic_readable_pipe; + + // Get the stdin pipe. + + // Get the stdout pipe. + + // Get the stdin pipe. + stdin_type & get_stdin(); + const stdin_type & get_stdin() const; + // Get the stdout pipe. + stdout_type & get_stdout(); + const stdout_type & get_stdout() const; + + // Write some data to the stdin pipe. + template + std::size_t write_some(const ConstBufferSequence& buffers); + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec); + + // Start an asynchronous write. + template > + auto async_write_some(const ConstBufferSequence& buffers, + WriteToken && token = net::default_completion_token_t()); + + // Read some data from the stdout pipe. + template + std::size_t read_some(const MutableBufferSequence& buffers); + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + + // Start an asynchronous read. template > + auto async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadToken) token + = net::default_completion_token_t()); +}; + +// A popen object with the default executor. +using popen = basic_popen<>; + +---- diff --git a/doc/reference/posix/bind_fd.adoc b/doc/reference/posix/bind_fd.adoc new file mode 100644 index 000000000..b28f8fe22 --- /dev/null +++ b/doc/reference/posix/bind_fd.adoc @@ -0,0 +1,70 @@ +== `posix/bind_fd.hpp` + +`bind_fd` is a utility class to bind a file descriptor to an explicit file descriptor for the child process. + +[source,cpp] +---- +struct bind_fd +{ + // Inherit file descriptor with the same value. + /* + * This will pass descriptor 42 as 42 to the child process: + * @code + * process p{"test", {}, posix::bind_fd(42)}; + * @endcode + */ + bind_fd(int target); + + // Inherit an asio io-object as a given file descriptor to the child process. + /* + * This will pass the tcp::socket, as 42 to the child process: + * @code + * extern tcp::socket sock; + * process p{"test", {}, posix::bind_fd(42, sock)}; + * @endcode + */ + + template + bind_fd(int target, Stream && str); + + // Inherit a `FILE` as a given file descriptor to the child process. + /* This will pass the given `FILE*`, as 42 to the child process: + + process p{"test", {}, posix::bind_fd(42, stderr)}; + + */ + bind_fd(int target, FILE * f); + + // Inherit a file descriptor with as a different value. + /* This will pass 24 as 42 to the child process: + + process p{"test", {}, posix::bind_fd(42, 24)}; + + */ + bind_fd(int target, int fd): + + // Inherit a null device as a set descriptor. + /* This will a null device as 42 to the child process: + + process p{"test", {}, posix::bind_fd(42, nullptr)}; + + */ + bind_fd(int target, std::nullptr_t); + + // Inherit a newly opened-file as a set descriptor. + /* This will pass a descriptor to "extra-output.txt" as 42 to the child process: + + process p{"test", {}, posix::bind_fd(42, "extra-output.txt")}; + + */ + bind_fd(int target, const filesystem::path & pth, int flags = O_RDWR | O_CREAT); + +}; +---- + +Using `bind_fd` can be used to inherit file descriptors explicitly, because no unused one will be. + +[source,cpp] +---- + +---- diff --git a/doc/reference/process.adoc b/doc/reference/process.adoc new file mode 100644 index 000000000..7c9ad335f --- /dev/null +++ b/doc/reference/process.adoc @@ -0,0 +1,174 @@ +== `process.hpp` +[#process] + +[source,cpp] +---- +// A class managing a subprocess +/* A `basic_process` object manages a subprocess; it tracks the status and exit-code, + * and will terminate the process on destruction if `detach` was not called. +*/ +template +struct basic_process +{ + // The executor of the process + using executor_type = Executor; + // Get the executor of the process + executor_type get_executor() {return process_handle_.get_executor();} + + // The non-closing handle type + using handle_type = basic_process_handle; + + // Get the underlying non-closing handle + handle_type & handle() { return process_handle_; } + + // Get the underlying non-closing handle + const handle_type & handle() const { return process_handle_; } + + // Provides access to underlying operating system facilities + using native_handle_type = typename handle_type::native_handle_type; + + // Rebinds the process_handle to another executor. + template + struct rebind_executor + { + // The socket type when rebound to the specified executor. + typedef basic_process other; + }; + + /** An empty process is similar to a default constructed thread. It holds an empty + handle and is a place holder for a process that is to be launched later. */ + basic_process() = default; + + basic_process(const basic_process&) = delete; + basic_process& operator=(const basic_process&) = delete; + + // Move construct the process. It will be detached from `lhs`. + basic_process(basic_process&& lhs) = default; + + // Move assign a process. It will be detached from `lhs`. + basic_process& operator=(basic_process&& lhs) = default; + + // Move construct and rebind the executor. + template + basic_process(basic_process&& lhs); + + // Construct a child from a property list and launch it using the default launcher.. + template + explicit basic_process( + executor_type executor, + const filesystem::path& exe, + std::initializer_list args, + Inits&&... inits); + + // Construct a child from a property list and launch it using the default launcher.. + template + explicit basic_process( + executor_type executor, + const filesystem::path& exe, + Args&& args, Inits&&... inits); + + // Construct a child from a property list and launch it using the default launcher.. + template + explicit basic_process( + ExecutionContext & context, + const filesystem::path& exe, + std::initializer_list args, + Inits&&... inits); + // Construct a child from a property list and launch it using the default launcher. + template + explicit basic_process( + ExecutionContext & context, + const filesystem::path&>::type exe, + Args&& args, Inits&&... inits); + + // Attach to an existing process + explicit basic_process(executor_type exec, pid_type pid); + + // Attach to an existing process and the internal handle + explicit basic_process(executor_type exec, pid_type pid, native_handle_type native_handle); + + // Create an invalid handle + explicit basic_process(executor_type exec); + + // Attach to an existing process + template + explicit basic_process(ExecutionContext & context, pid_type pid); + + // Attach to an existing process and the internal handle + template + explicit basic_process(ExecutionContext & context, pid_type pid, native_handle_type native_handle); + + // Create an invalid handle + template + explicit basic_process(ExecutionContext & context); + + + + // Destruct the handle and terminate the process if it wasn't detached. + ~basic_process(); + + // Sends the process a signal to ask for an interrupt, which the process may interpret as a shutdown. + /** Maybe be ignored by the subprocess. */ + void interrupt(error_code & ec); + void interrupt(); + + // Throwing @overload void interrupt() + + + // Sends the process a signal to ask for a graceful shutdown. Maybe be ignored by the subprocess. + void request_exit(error_code & ec); + void request_exit(); + + // Send the process a signal requesting it to stop. This may rely on undocumented functions. + void suspend(error_code &ec); + void suspend(); + + + // Send the process a signal requesting it to resume. This may rely on undocumented functions. + void resume(error_code &ec); + void resume(); + + // Unconditionally terminates the process and stores the exit code in exit_status. + void terminate(error_code & ec); + void terminate(); + + // Waits for the process to exit, store the exit code internally and return it. + int wait(error_code & ec); + int wait(); + + // Detach the process. + handle_type detach(); + // Get the native + native_handle_type native_handle() {return process_handle_.native_handle(); } + + // Return the evaluated exit_code. + int exit_code() cons; + + // Get the id of the process; + pid_type id() const; + + // The native handle of the process. + /** This might be undefined on posix systems that only support signals */ + native_exit_code_type native_exit_code() const; + + // Checks if the current process is running. + /* If it has already completed the exit code will be stored internally + * and can be obtained by calling `exit_code. + */ + bool running(); + bool running(error_code & ec) noexcept; + + // Check if the process is referring to an existing process. + /** Note that this might be a process that already exited.*/ + bool is_open() const; + + // Asynchronously wait for the process to exit and deliver the native exit-code in the completion handler. + template > + auto async_wait(WaitHandler && handler = net::default_completion_token_t()); +}; + +// Process with the default executor. +typedef basic_process<> process; + +---- \ No newline at end of file diff --git a/doc/reference/process_handle.adoc b/doc/reference/process_handle.adoc new file mode 100644 index 000000000..c85ed36ce --- /dev/null +++ b/doc/reference/process_handle.adoc @@ -0,0 +1,108 @@ +== `process_handle.hpp` +[#process_handle] + +A process handle is an unmanaged version of a process. +This means it does not terminate the proces on destruction and +will not keep track of the exit-code. + +NOTE: that the exit code might be discovered early, during a call to `running`. +Thus it can only be discovered that process has exited already. + +[source,cpp] +---- + +template +struct basic_process_handle +{ + // The native handle of the process. + /* This might be undefined on posix systems that only support signals */ + using native_handle_type = implementation_defined; + + // The executor_type of the process_handle + using executor_type = Executor; + + // Getter for the executor + executor_type get_executor(); + + // Rebinds the process_handle to another executor. + template + struct rebind_executor + { + // The socket type when rebound to the specified executor. + typedef basic_process_handle other; + }; + + + // Construct a basic_process_handle from an execution_context. + /* + * @tparam ExecutionContext The context must fulfill the asio::execution_context requirements + */ + template + basic_process_handle(ExecutionContext &context); + + // Construct an empty process_handle from an executor. + basic_process_handle(executor_type executor); + + // Construct an empty process_handle from an executor and bind it to a pid. + /* On NON-linux posix systems this call is not able to obtain a file-descriptor and will thus + * rely on signals. + */ + basic_process_handle(executor_type executor, pid_type pid); + + // Construct an empty process_handle from an executor and bind it to a pid and the native-handle + /* On some non-linux posix systems this overload is not present. + */ + basic_process_handle(executor_type executor, pid_type pid, native_handle_type process_handle); + + // Move construct and rebind the executor. + template + basic_process_handle(basic_process_handle &&handle); + + // Get the id of the process + pid_type id() const + { return pid_; } + + // Terminate the process if it's still running and ignore the result + void terminate_if_running(error_code &); + + // Throwing @overload void terminate_if_running(error_code & ec; + void terminate_if_running(); + // wait for the process to exit and store the exit code in exit_status. + void wait(native_exit_code_type &exit_status, error_code &ec); + // Throwing @overload wait(native_exit_code_type &exit_code, error_code & ec) + void wait(native_exit_code_type &exit_status); + + // Sends the process a signal to ask for an interrupt, which the process may interpret as a shutdown. + /* Maybe be ignored by the subprocess. */ + void interrupt(error_code &ec); + + // Throwing @overload void interrupt() + void interrupt(); + + // Sends the process a signal to ask for a graceful shutdown. Maybe be ignored by the subprocess. + void request_exit(error_code &ec); + + // Throwing @overload void request_exit(error_code & ec) + void request_exit() + + // Unconditionally terminates the process and stores the exit code in exit_status. + void terminate(native_exit_code_type &exit_status, error_code &ec);\ + // Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec) + void terminate(native_exit_code_type &exit_status);/ + + // Checks if the current process is running. + /*If it has already completed, it assigns the exit code to `exit_code`. + */ + bool running(native_exit_code_type &exit_code, error_code &ec); + // Throwing @overload bool running(native_exit_code_type &exit_code, error_code & ec) + bool running(native_exit_code_type &exit_code); + + // Check if the process handle is referring to an existing process. + bool is_open() const; + + // Asynchronously wait for the process to exit and deliver the native exit-code in the completion handler. + template> + auto async_wait(WaitHandler &&handler = net::default_completion_token_t()); +}; +---- \ No newline at end of file diff --git a/doc/reference/shell.adoc b/doc/reference/shell.adoc new file mode 100644 index 000000000..1d3b4e1fb --- /dev/null +++ b/doc/reference/shell.adoc @@ -0,0 +1,57 @@ +== `shell.hpp` +[#shell] + +This utility class parses command lines into tokens +and allows users to execute processes 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. + +.Example +[source,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()}; + +---- + +[source,cpp] +---- +/// Utility to parse commands +struct shell +{ + shell() = default; + template + shell(basic_string_view input); + + shell(basic_cstring_ref input); + shell(const shell &) = delete; + shell(shell && lhs) noexcept; + shell& operator=(const shell &) = delete; + shell& operator=(shell && lhs) noexcept; + + + // the length of the parsed shell, including the executable + int argc() const ; + char_type** argv() const; + + char_type** begin() const; + char_type** end() const; + + bool empty() const; + std::size_t size() const; + + // Native representation of the arguments to be used - excluding the executable + args_type args() const; + template + filesystem::path exe(Environment && env = environment::current()) const; +}; +---- \ No newline at end of file diff --git a/doc/reference/start_dir.adoc b/doc/reference/start_dir.adoc new file mode 100644 index 000000000..9d5b3d049 --- /dev/null +++ b/doc/reference/start_dir.adoc @@ -0,0 +1,16 @@ +== `start_dir.hpp` +[#start_dir] + + +[source,cpp] +---- +/// Initializer for the starting directory of a subprocess to be launched. +struct process_start_dir +{ + filesystem::path start_dir; + + process_start_dir(filesystem::path start_dir); + { + } +}; +---- \ No newline at end of file diff --git a/doc/reference/stdio.adoc b/doc/reference/stdio.adoc new file mode 100644 index 000000000..cca6082ee --- /dev/null +++ b/doc/reference/stdio.adoc @@ -0,0 +1,55 @@ +== `stdio.hpp` +[#stdio] + + The initializer for the stdio of a subprocess +The subprocess stdio initializer has three members: + + - in for stdin + - out for stdout + - err for stderr + +If the initializer is present all three will be set for the subprocess. +By default they will inherit the stdio handles from the parent process. +This means that this will forward stdio to the subprocess: + +[source,cpp] +---- +asio::io_context ctx; +v2::process proc(ctx, "/bin/bash", {}, v2::process_stdio{}); +---- + +No constructors are provided in order to support designated initializers +in later version of C++. + +[source,cpp] +---- +asio::io_context ctx; + +/// C++17 +v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{.stderr=nullptr}); +/// C++11 & C++14 +v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{ {}, {}, nullptr}); +---- + +Valid initializers for any stdio are: + + - `std::nullptr_t` assigning a null-device + - `FILE*` any open file, including `stdin`, `stdout` and `stderr` + - a filesystem::path, which will open a readable or writable depending on the direction of the stream + - `native_handle` any native file handle (`HANDLE` on windows) or file descriptor (`int` on posix) + - any io-object with a .native_handle() function that is compatible with the above. E.g. a asio::ip::tcp::socket + - an asio::basic_writeable_pipe for stdin or asio::basic_readable_pipe for stderr/stdout. + + + + +[source,cpp] +---- +/// The initializer for the stdio of a subprocess +struct process_stdio +{ + __implementation_defined__ in; + __implementation_defined__ out; + __implementation_defined__ err; +}; +---- \ No newline at end of file diff --git a/doc/reference/windows/creation_flags.adoc b/doc/reference/windows/creation_flags.adoc new file mode 100644 index 000000000..b28840b87 --- /dev/null +++ b/doc/reference/windows/creation_flags.adoc @@ -0,0 +1,27 @@ +== `windows/creation_flags.hpp` + +Creation flags allows explicitly setting `dwFlags` + +[source,cpp] +---- +// An initializer to add to the dwFlags in the startup-info +template +struct process_creation_flags; + +// A flag to create a new process group. Necessary to allow interrupts for the subprocess. +constexpr static process_creation_flags create_new_process_group; + +// Breakaway from the current job object. +constexpr static process_creation_flags create_breakaway_from_job; +// Allocate a new console. +constexpr static process_creation_flags create_new_console; + +---- + + +The flags can be used like this: + +[source,cpp] +---- +process p{"C:\\not-a-virus.exe", {}, process::windows::create_new_console}; +---- \ No newline at end of file diff --git a/doc/reference/windows/show_window.adoc b/doc/reference/windows/show_window.adoc new file mode 100644 index 000000000..8cd813a45 --- /dev/null +++ b/doc/reference/windows/show_window.adoc @@ -0,0 +1,32 @@ +== `windows/show_window.hpp` + +Creation flags allows explicitly setting `wShowWindow` options + +[source,cpp] +---- +/// A templated initializer to set wShowWindow flags. +template +struct process_show_window; + +//Hides the window and activates another window. +constexpr static process_show_window show_window_hide; +//Activates the window and displays it as a maximized window. +constexpr static process_show_window show_window_maximized; +//Activates the window and displays it as a minimized window. +constexpr static process_show_window show_window_minimized; +//Displays the window as a minimized window. This value is similar to `minimized`, except the window is not activated. +constexpr static process_show_window show_window_minimized_not_active; +//Displays a window in its most recent size and position. This value is similar to show_normal`, except that the window is not activated. +constexpr static process_show_window show_window_not_active; +//Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time. +constexpr static process_show_window show_window_normal; + +---- + + +The flags can be used like this: + +[source,cpp] +---- +process p{"C:\\not-a-virus.exe", {}, process::windows::show_window_minimized}; +---- \ No newline at end of file diff --git a/include/boost/process/v2/exit_code.hpp b/include/boost/process/v2/exit_code.hpp index 485b3d674..24e51fa67 100644 --- a/include/boost/process/v2/exit_code.hpp +++ b/include/boost/process/v2/exit_code.hpp @@ -109,13 +109,12 @@ inline int evaluate_exit_code(int code) * { * 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()); - * })); + * )) + * [](error_code ec) + * { + * assert(ec.value() == 10); + * assert(ec.category() == error::get_exit_code_category()); + * })); * * @endcode */ diff --git a/include/boost/process/v2/popen.hpp b/include/boost/process/v2/popen.hpp index 31b4e8962..3d6c22705 100644 --- a/include/boost/process/v2/popen.hpp +++ b/include/boost/process/v2/popen.hpp @@ -336,7 +336,7 @@ struct basic_popen : basic_process * std::vector. */ template > auto async_write_some(const ConstBufferSequence& buffers, WriteToken && token = net::default_completion_token_t()) @@ -448,7 +448,7 @@ struct basic_popen : basic_process * std::vector. */ template > auto async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadToken) token diff --git a/include/boost/process/v2/windows/creation_flags.hpp b/include/boost/process/v2/windows/creation_flags.hpp index 967148487..25168673c 100644 --- a/include/boost/process/v2/windows/creation_flags.hpp +++ b/include/boost/process/v2/windows/creation_flags.hpp @@ -18,7 +18,7 @@ namespace windows { -/// An initializers to add to the dwFlags in the startup-info +/// An initializer to add to the dwFlags in the startup-info /** * @tparam Flags The flags to be set. */ From 3fd8b2608cca3cd7a6359110f9fc29075df42519 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 11:20:28 +0800 Subject: [PATCH 13/32] examples are compiled & included. --- doc/env.adoc | 25 ++------- doc/quickstart.adoc | 45 +++++++--------- doc/start_dir.adoc | 7 ++- doc/stdio.adoc | 40 ++++---------- doc/version2.adoc | 4 +- example/Jamfile.jam | 25 +++------ example/args.cpp | 29 ---------- example/async_io.cpp | 30 ----------- example/env.cpp | 33 +++++++++--- example/error_handling.cpp | 24 --------- example/intro.cpp | 30 +++++++---- example/{v2 => }/intro_popen.cpp | 9 +++- example/io.cpp | 91 -------------------------------- example/posix.cpp | 47 ----------------- example/quickstart.cpp | 63 ++++++++++++++++++++++ example/start_dir.cpp | 19 +++---- example/stdio.cpp | 68 ++++++++++++++++++++++++ example/sync_io.cpp | 28 ---------- example/terminate.cpp | 18 ------- example/v2/Jamfile.jam | 15 ------ example/v2/intro.cpp | 39 -------------- example/wait.cpp | 34 ------------ example/windows.cpp | 31 ----------- 23 files changed, 238 insertions(+), 516 deletions(-) delete mode 100644 example/args.cpp delete mode 100644 example/async_io.cpp delete mode 100644 example/error_handling.cpp rename example/{v2 => }/intro_popen.cpp (82%) delete mode 100644 example/io.cpp delete mode 100644 example/posix.cpp create mode 100644 example/quickstart.cpp create mode 100644 example/stdio.cpp delete mode 100644 example/sync_io.cpp delete mode 100644 example/terminate.cpp delete mode 100644 example/v2/Jamfile.jam delete mode 100644 example/v2/intro.cpp delete mode 100644 example/wait.cpp delete mode 100644 example/windows.cpp diff --git a/doc/env.adoc b/doc/env.adoc index d00bb7cfc..8421c9fbd 100644 --- a/doc/env.adoc +++ b/doc/env.adoc @@ -14,33 +14,18 @@ as to have the right value comparisons. To note is the `find_executable` functions, which searches in an environment for an executable. +.example/env.cpp:19-28 [source,cpp] ---- -// search in the current environment -auto exe = environment::find_executable("g++"); - -std::unordered_map my_env = - { - {"SECRET", "THIS_IS_A_TEST"}, - {"PATH", {"/bin", "/usr/bin"}} - }; - -auto other_exe = environment::find_executable("g++", my_env); +include::../example/env.cpp[tag=current_env] ---- == Subprocess environment The subprocess environment assignment follows the same constraints: -[source,cpp] +.example/env.cpp:34-42 +[source,cpp,ident=0] ---- -asio::io_context ctx; -std::unordered_map my_env = - { - {"SECRET", "THIS_IS_A_TEST"}, - {"PATH", {"/bin", "/usr/bin"}} - }; -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)); +include::../example/env.cpp[tag=subprocess_env] ---- diff --git a/doc/quickstart.adoc b/doc/quickstart.adoc index f3ddf9eef..dbf00777d 100644 --- a/doc/quickstart.adoc +++ b/doc/quickstart.adoc @@ -7,14 +7,10 @@ A process needs four things to be launched: * a list of arguments * a variadic set of initializers -[source,cpp] +.example/quickstart.cpp:13-17 +[source,cpp,indent=0] ---- -// process(asio::any_io_executor, filesystem::path, range args, AdditionalInitializers...) -asio::io_context ctx; -process proc(ctx.get_executor(), // <1> - "/usr/bin/cp", // <2> - {"source.txt", "target.txt"} // <3> - ); // <4> +include::../example/quickstart.cpp[tag=cp] ---- <1> The executor for the process handle <2> The Path to the executable @@ -33,10 +29,10 @@ A process that completed will deliver an exit-code, which can be obtained by calling `.exit_code` on the exited process and which is also returned from `.wait()`. -[source,cpp] +.example/quickstart.cpp:22-23 +[source,cpp, indent=0] ---- -process proc("/bin/ls", {}); -assert(proc.wait() == 0); +include::../example/quickstart.cpp[tag=ls] ---- The normal exit-code is what the subprocess returned from `main`; @@ -54,32 +50,30 @@ 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. -[source,cpp] +.example/quickstart.cpp:28-29 +[source,cpp,indent=0] ---- -process proc("/bin/totally-not-a-virus", {}); -proc.terminate(); +include::../example/quickstart.cpp[tag=terminate] ---- `.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix), which the subprocess might ignore. +.example/quickstart.cpp:34-36 [source,cpp] ---- -process proc("/bin/bash", {}); -proc.request_exit(); -proc.wait(); +include::../example/quickstart.cpp[tag=request_exit] ---- `.interrupt` will send an SIGINT to the subprocess, which a subprocess might -interpret as a signal to shutdown. +interpret as a signal for shutdown. WARNING: interrupt requires the initializer `windows::create_new_process_group` to be set on windows +.example/quickstart.cpp:41-43 [source,cpp] ---- -process proc("/usr/bin/addr2line", {}); -proc.request_exit(); -proc.wait(); +include::../example/quickstart.cpp[tag=interrupt] ---- [endsect] @@ -88,9 +82,10 @@ proc.wait(); Process v2 provides `execute` and `async_execute` functions that can be used for managed executions. +.example/quickstart.cpp:48 [source,cpp] ---- -assert(execute(process("/bin/ls", {}) == 0)); +include::../example/quickstart.cpp[tag=execute] ---- The async version supports cancellation and will forward cancellation types as follows: @@ -99,14 +94,10 @@ The async version supports cancellation and will forward cancellation types as f - `asio::cancellation_type::partial` -> request_exit - `asio::cancellation_type::terminal` -> terminate +.example/quickstart.cpp:53-56 [source,cpp] ---- -asio::awaitable compile() -{ - co_await async_execute(process("/usr/bin/g++", {"hello_world.cpp"})) - (asio::cancel_after(std::chrono::seconds(10, asio::cancellation_type::partial)) // <1> - (asio::cancel_after(std::chrono::seconds(10, asio::cancellation_type::terminal)); //<2> -} +include::../example/quickstart.cpp[tag=async_execute] ---- <1> After 10 seconds send a request_exit. <2> After 20 seconds terminate diff --git a/doc/start_dir.adoc b/doc/start_dir.adoc index c37ee2564..27f4bd6dd 100644 --- a/doc/start_dir.adoc +++ b/doc/start_dir.adoc @@ -2,11 +2,10 @@ The easier initializer to use is `process_start_dir`: -[source,cpp] +.example/start_dir.cpp:17-20 +[source,cpp,indent=0] ---- -asio::io_context ctx; -process ls(ctx.get_executor(), "/ls", {}, process_start_dir("/home")); -ls.wait(); +include::../example/start_dir.cpp[tag=start_dir] ---- This will run `ls` in the folder `/home` instead of the current folder. diff --git a/doc/stdio.adoc b/doc/stdio.adoc index bd2b2dc90..e0f0f7dc9 100644 --- a/doc/stdio.adoc +++ b/doc/stdio.adoc @@ -10,18 +10,10 @@ This feature meant to be flexible, which is why there is little checking on the asio pipes can be used for io. When using in process_stdio they will get automatically connected and the other side will get assigned to the child process: -[source,cpp] +.example/stdio.cpp:20-29 +[source,cpp,indent=0] ---- -asio::io_context ctx; -asio::readable_pipe rp{ctx}; - -process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }}); -std::string output; - -system::error_code ec; -rp.read(asio::dynamic_buffer(output), ec); -assert(ec == asio::eof); -proc.wait(); +include::../example/stdio.cpp[tag=readable_pipe] ---- readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`. @@ -30,12 +22,10 @@ readable pipes can be assigned to `out` an `err`, while writable_pipes can be as `FILE*` can also be used for either side; this allows the `stdin`, `stderr`, `stdout` macros to be used: +.example/stdio.cpp:35-38 [source,cpp] ---- -asio::io_context ctx; -// forward both stderr & stdout to stdout of the parent process -process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, stdout, stdout}); -proc.wait(); +include::../example/stdio.cpp[tag=file] ---- == `nullptr` @@ -43,12 +33,10 @@ proc.wait(); `nullptr` may be used to set a given stream to be opened on the null-device (`/dev/null` on posix, `NUL` on windows). This is used to ignore output or give only EOF as input. +.example/stdio.cpp:43-46 [source,cpp] ---- -asio::io_context ctx; -// ignore stderr -process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr}); -proc.wait(); +include::../example/stdio.cpp[tag=null] ---- == `native_handle` @@ -56,14 +44,10 @@ proc.wait(); A native handle can be used as well, which means an `int` on posix or a `HANDLE` on windows. Furthermore, any object that has a `native_handle` returning that native handle type is valid, too. +.example/stdio.cpp:51-56 [source,cpp] ---- -asio::io_context ctx; -// ignore stderr -asio::ip::tcp::socket sock{ctx}; -connect_my_socket(sock); -process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr}); -proc.wait(); +include::../example/stdio.cpp[tag=native_handle] ---- == popen @@ -71,11 +55,9 @@ proc.wait(); Additionally, process v2 provides a `popen` class. It starts a process and connects pipes for stdin and stdout, so that the popen object can be used as a stream. +.example/stdio.cpp:61-64 [source,cpp] ---- -popen proc(executor, "/usr/bin/addr2line, {argv[0]}); -asio::write(proc, asio::buffer("main\n")); -std::string line; -asio::read_until(proc, asio::dynamic_buffer(line), '\n'); +include::../example/stdio.cpp[tag=popen] ---- diff --git a/doc/version2.adoc b/doc/version2.adoc index 726ecc33b..7667705d1 100644 --- a/doc/version2.adoc +++ b/doc/version2.adoc @@ -32,7 +32,7 @@ For process v2, the interfaces is simple: ---- extern std::unordered_map my_env; extern asio::io_context ctx; -process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env)); +process proc(ctx, "./test", {"--help"}, process_stdio{nullptr, {}, {}}, process_environment(my_env)); ---- Every initializer addresses one logical component (e.g. stdio) instead of multiple ones accumulating. @@ -49,8 +49,6 @@ Windows has provided `HANDLE`s for processes all along. Unless the OS doesn't support it, process v2 will use file descriptors and handles to implement waiting for processes. - - == Full asio integration Process v1 aimed to make asio optional, but synchronous IO with subprocesses usually means one is begging diff --git a/example/Jamfile.jam b/example/Jamfile.jam index 5ec31f042..b837a8e02 100644 --- a/example/Jamfile.jam +++ b/example/Jamfile.jam @@ -1,28 +1,19 @@ -# Copyright (c) 2006, 2007 Julio M. Merino Vidal -# Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -# Copyright (c) 2009 Boris Schaeling -# Copyright (c) 2010 Felipe Tanus, Boris Schaeling -# Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +# 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) project : requirements - /boost/process//boost_process msvc:_SCL_SECURE_NO_WARNINGS windows:WIN32_LEAN_AND_MEAN + static ; import testing ; -compile args.cpp ; -compile async_io.cpp ; -compile env.cpp ; -compile error_handling.cpp ; -compile io.cpp ; -compile posix.cpp : no linux:yes ; -compile start_dir.cpp ; -compile sync_io.cpp ; -compile terminate.cpp ; -compile wait.cpp ; -compile windows.cpp : no windows:yes ; +exe intro : intro.cpp /boost//process : boost ; +exe intro_popen : intro_popen.cpp /boost//process : boost ; +exe quickstart : quickstart.cpp /boost//process : boost ; +exe env : env.cpp /boost//process : boost ; +exe start_dir : start_dir.cpp /boost//process : boost ; +exe stdio : stdio.cpp /boost//process : boost ; diff --git a/example/args.cpp b/example/args.cpp deleted file mode 100644 index efad00d10..000000000 --- a/example/args.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include - -namespace bp = boost::process; - -int main() -{ - bp::child c("test.exe", "--foo", "/bar"); - - //or explicit - - bp::child c2( - bp::exe="test.exe", - bp::args={"--foo", "/bar"} - ); - - c.wait(); - c2.wait(); -} diff --git a/example/async_io.cpp b/example/async_io.cpp deleted file mode 100644 index 6ac18de7c..000000000 --- a/example/async_io.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include - -namespace bp = boost::process; - -int main() -{ - boost::asio::io_context ios; - boost::asio::streambuf buffer; - - - bp::child c( - "test.exe", - bp::std_out > buffer, - ios - ); - - ios.run(); -} diff --git a/example/env.cpp b/example/env.cpp index cb9a609b6..5242b5d10 100644 --- a/example/env.cpp +++ b/example/env.cpp @@ -9,16 +9,37 @@ #include -namespace bp = boost::process; +using namespace boost::process; +namespace asio = boost::asio; int main() { - bp::environment my_env = boost::this_process::environment(); + { + // tag::current_env[] + // search in the current environment + auto exe = environment::find_executable("g++"); - my_env["PATH"] += "/foo"; - bp::system("test.exe", my_env); + std::unordered_map my_env = + { + {"SECRET", "THIS_IS_A_TEST"}, + {"PATH", {"/bin", "/usr/bin"}} + }; + auto other_exe = environment::find_executable("g++", my_env); + //end::current_env[] + } - - bp::system("test.exe", bp::env["PATH"]+="/bar"); + { + // tag::subprocess_env[] + asio::io_context ctx; + std::unordered_map my_env = + { + {"SECRET", "THIS_IS_A_TEST"}, + {"PATH", {"/bin", "/usr/bin"}} + }; + auto exe = environment::find_executable("g++", my_env); + process proc(ctx, exe, {"main.cpp"}, process_environment(my_env)); + process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env)); + // end::subprocess_env[] + } } diff --git a/example/error_handling.cpp b/example/error_handling.cpp deleted file mode 100644 index 1a0dad002..000000000 --- a/example/error_handling.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include - -namespace bp = boost::process; - -int main() -{ - - std::error_code ec; - bp::child c1("test.exe", ec); - - - bp::child c2("test.exe", bp::ignore_error); - -} diff --git a/example/intro.cpp b/example/intro.cpp index 85e65c29c..a8097c9ca 100644 --- a/example/intro.cpp +++ b/example/intro.cpp @@ -1,8 +1,4 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +// 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) @@ -10,21 +6,35 @@ //[intro #include +#include +#include +#include + #include #include -using namespace boost::process; +namespace proc = boost::process; +namespace asio = boost::asio; + int main() { - ipstream pipe_stream; - child c("gcc --version", std_out > pipe_stream); + asio::io_context ctx; + asio::readable_pipe p{ctx}; + + const auto exe = proc::environment::find_executable("gcc"); + + proc::process c{ctx, exe, {"--version"}, proc::process_stdio{nullptr, p}}; std::string line; + boost::system::error_code ec; + + auto sz = asio::read(p, asio::dynamic_buffer(line), ec); + assert(ec == asio::error::eof); - while (pipe_stream && std::getline(pipe_stream, line) && !line.empty()) - std::cerr << line << std::endl; + std::cout << "Gcc version: '" << line << "'" << std::endl; c.wait(); + return c.exit_code(); } //] diff --git a/example/v2/intro_popen.cpp b/example/intro_popen.cpp similarity index 82% rename from example/v2/intro_popen.cpp rename to example/intro_popen.cpp index 001f0bfbc..bb1d1f7cf 100644 --- a/example/v2/intro_popen.cpp +++ b/example/intro_popen.cpp @@ -3,8 +3,10 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include + //[intro -#include +#include #include #include @@ -13,7 +15,7 @@ #include #include -namespace proc = boost::process::v2; +namespace proc = boost::process; namespace asio = boost::asio; @@ -29,8 +31,11 @@ int main() auto sz = asio::read(c, asio::dynamic_buffer(line), ec); assert(ec == asio::error::eof); + boost::ignore_unused(sz); + std::cout << "Gcc version: '" << line << "'" << std::endl; c.wait(); + return c.exit_code(); } //] diff --git a/example/io.cpp b/example/io.cpp deleted file mode 100644 index 7b5142da8..000000000 --- a/example/io.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include - -namespace bp = boost::process; - -int main() -{ - // - bp::system( - "test.exe", - bp::std_out > stdout, //forward - bp::std_err.close(), //close - bp::std_in < bp::null //null in - ); - - boost::process::v1::filesystem::path p = "input.txt"; - - bp::system( - "test.exe", - (bp::std_out & bp::std_err) > "output.txt", //redirect both to one file - bp::std_in < p //read input from file - ); - - { - bp::opstream p1; - bp::ipstream p2; - bp::system( - "test.exe", - bp::std_out > p2, - bp::std_in < p1 - ); - p1 << "my_text"; - int i = 0; - p2 >> i; - - } - { - boost::asio::io_context io_context; - bp::async_pipe p1(io_context); - bp::async_pipe p2(io_context); - bp::system( - "test.exe", - bp::std_out > p2, - bp::std_in < p1, - io_context, - bp::on_exit([&](int exit, const std::error_code& ec_in) - { - p1.async_close(); - p2.async_close(); - }) - ); - std::vector in_buf; - std::string value = "my_string"; - boost::asio::async_write(p1, boost::asio::buffer(value), []( const boost::system::error_code&, std::size_t){}); - boost::asio::async_read (p2, boost::asio::buffer(in_buf), []( const boost::system::error_code&, std::size_t){}); - } - { - boost::asio::io_context io_context; - std::vector in_buf; - std::string value = "my_string"; - bp::system( - "test.exe", - bp::std_out > bp::buffer(in_buf), - bp::std_in < bp::buffer(value) - ); - } - - { - boost::asio::io_context io_context; - std::future> in_buf; - std::future write_fut; - std::string value = "my_string"; - bp::system( - "test.exe", - bp::std_out > in_buf, - bp::std_in < bp::buffer(value) > write_fut - ); - - write_fut.get(); - in_buf.get(); - } -} diff --git a/example/posix.cpp b/example/posix.cpp deleted file mode 100644 index e822af764..000000000 --- a/example/posix.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include -#include -#include -#include - -namespace bp = boost::process; - -int main() -{ - - //duplicate our pipe descriptor into literal position 4 - bp::pipe p; - bp::system("test", bp::posix::fd.bind(4, p.native_sink())); - - - //close file-descriptor from explicit integral value - bp::system("test", bp::posix::fd.close(STDIN_FILENO)); - - //close file-descriptors from explicit integral values - bp::system("test", bp::posix::fd.close({STDIN_FILENO, STDOUT_FILENO})); - - //add custom handlers - const char *env[2] = { 0 }; - env[0] = "LANG=de"; - bp::system("test", - bp::extend::on_setup([env](auto &e) { e.env = const_cast(env); }), - bp::extend::on_fork_error([](auto&, const std::error_code & ec) - { std::cerr << errno << std::endl; }), - bp::extend::on_exec_setup([](auto&) - { ::chroot("/new/root/directory/"); }), - bp::extend::on_exec_error([](auto&, const std::error_code & ec) - { std::ofstream ofs("log.txt"); if (ofs) ofs << errno; }) - ); - -} diff --git a/example/quickstart.cpp b/example/quickstart.cpp new file mode 100644 index 000000000..d3383f1c1 --- /dev/null +++ b/example/quickstart.cpp @@ -0,0 +1,63 @@ +#include +#include + +namespace asio = boost::asio; +using boost::process::process; + + +int main(int /*argv*/, char ** /*argv*/) +{ + asio::io_context ctx; + { + //tag::cp[] + // process(asio::any_io_executor, filesystem::path, range args, AdditionalInitializers...) + process proc(ctx.get_executor(), // <1> + "/usr/bin/cp", // <2> + {"source.txt", "target.txt"} // <3> + ); // <4> + //end::cp[] + } + { + //tag::ls[] + process proc(ctx, "/bin/ls", {}); + assert(proc.wait() == 0); + //end::ls[] + } + { + //tag::terminate[] + process proc(ctx, "/bin/totally-not-a-virus", {}); + proc.terminate(); + //end::terminate[] + } + { + //tag::request_exit[] + process proc(ctx, "/bin/bash", {}); + proc.request_exit(); + proc.wait(); + //end::request_exit[] + } + { + //tag::interrupt[] + process proc(ctx, "/usr/bin/addr2line", {}); + proc.interrupt(); + proc.wait(); + //end::interrupt[] + } + { + //tag::execute[] + assert(execute(process(ctx, "/bin/ls", {})) == 0); + //end::execute[] + } + { + //tag::async_execute[] + async_execute(process(ctx, "/usr/bin/g++", {"hello_world.cpp"})) + (asio::cancel_after(std::chrono::seconds(10), asio::cancellation_type::partial)) // <1> + (asio::cancel_after(std::chrono::seconds(10), asio::cancellation_type::terminal)) //<2> + (asio::detached); + //end::async_execute[] + ctx.run(); + } + return 0; +} + + diff --git a/example/start_dir.cpp b/example/start_dir.cpp index fa7ae7649..300f91ac5 100644 --- a/example/start_dir.cpp +++ b/example/start_dir.cpp @@ -8,20 +8,15 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include -namespace bp = boost::process; +using namespace boost::process; +namespace asio = boost::asio; int main() { - bp::system( - "test.exe", - bp::start_dir="../foo" - ); - - boost::process::v1::filesystem::path exe = "test.exe"; - bp::system( - boost::process::v1::filesystem::absolute(exe), - bp::start_dir="../foo" - ); + // tag::start_dir[] + asio::io_context ctx; + process ls(ctx.get_executor(), "/ls", {}, process_start_dir("/home")); + ls.wait(); + // end::start_dir[] } diff --git a/example/stdio.cpp b/example/stdio.cpp new file mode 100644 index 000000000..97a2bf42e --- /dev/null +++ b/example/stdio.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling +// Copyright (c) 2009 Boris Schaeling +// Copyright (c) 2010 Felipe Tanus, Boris Schaeling +// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +using namespace boost::process; +namespace asio = boost::asio; + +int main(int argc, char *argv[]) +{ + { + //tag::readable_pipe[] + asio::io_context ctx; + asio::readable_pipe rp{ctx}; + + process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }}); + std::string output; + + boost::system::error_code ec; + asio::read(rp, asio::dynamic_buffer(output), ec); + assert(!ec || (ec == asio::error::eof)); + proc.wait(); + //end::readable_pipe[] + } + + { + //tag::file[] + asio::io_context ctx; + // forward both stderr & stdout to stdout of the parent process + process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, stdout, stdout}); + proc.wait(); + //end::file[] + } + { + //tag::null[] + asio::io_context ctx; + // forward stderr to /dev/null or NUL + process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr}); + proc.wait(); + //end::null[] + } + { + //tag::native_handle[] + asio::io_context ctx; + // ignore stderr + asio::local::stream_protocol::socket sock{ctx}, other{ctx}; + asio::local::connect_pair(sock, other); + process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr}); + proc.wait(); + //end::native_handle[] + } + { + //tag::popen[] + asio::io_context ctx; + boost::process::popen proc(ctx, "/usr/bin/addr2line", {argv[0]}); + asio::write(proc, asio::buffer("main\n")); + std::string line; + asio::read_until(proc, asio::dynamic_buffer(line), '\n'); + //end::popen[] + } +} diff --git a/example/sync_io.cpp b/example/sync_io.cpp deleted file mode 100644 index a861e7ab1..000000000 --- a/example/sync_io.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include - -namespace bp = boost::process; - -int main() -{ - bp::ipstream p; - - bp::child c( - "test.exe", - bp::std_out > p - ); - - std::string s; - std::getline(p, s); - - c.wait(); -} diff --git a/example/terminate.cpp b/example/terminate.cpp deleted file mode 100644 index 7de2d8305..000000000 --- a/example/terminate.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include - -namespace bp = boost::process; - -int main() -{ - bp::child c("test.exe"); - c.terminate(); -} diff --git a/example/v2/Jamfile.jam b/example/v2/Jamfile.jam deleted file mode 100644 index 450fdc21d..000000000 --- a/example/v2/Jamfile.jam +++ /dev/null @@ -1,15 +0,0 @@ -# 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) - -project : requirements - msvc:_SCL_SECURE_NO_WARNINGS - windows:WIN32_LEAN_AND_MEAN - static -; - -import testing ; - -exe intro : intro.cpp ; -exe intro_popen : intro_popen.cpp : boost ; diff --git a/example/v2/intro.cpp b/example/v2/intro.cpp deleted file mode 100644 index 2e0f2363d..000000000 --- a/example/v2/intro.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// 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) - -//[intro -#include - -#include -#include -#include - -#include -#include - -namespace proc = boost::process::v2; -namespace asio = boost::asio; - - -int main() -{ - asio::io_context ctx; - asio::readable_pipe p{ctx}; - - const auto exe = proc::environment::find_executable("gcc"); - - proc::process c{ctx, exe, {"--version"}, proc::process_stdio{nullptr, p}}; - - std::string line; - boost::system::error_code ec; - - auto sz = asio::read(p, asio::dynamic_buffer(line), ec); - assert(ec == asio::error::eof); - - std::cout << "Gcc version: '" << line << "'" << std::endl; - - c.wait(); -} -//] diff --git a/example/wait.cpp b/example/wait.cpp deleted file mode 100644 index 9ebb53149..000000000 --- a/example/wait.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include - -namespace bp = boost::process; - -int main() -{ - { - bp::child c("test.exe"); - c.wait(); - auto exit_code = c.exit_code(); - } - - { - boost::asio::io_context io_context; - - bp::child c( - "test.exe", - io_context, - bp::on_exit([&](int exit, const std::error_code& ec_in){}) - ); - - io_context.run(); - } -} diff --git a/example/windows.cpp b/example/windows.cpp deleted file mode 100644 index 93b4f62c9..000000000 --- a/example/windows.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling -// Copyright (c) 2009 Boris Schaeling -// Copyright (c) 2010 Felipe Tanus, Boris Schaeling -// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include - -#include - -namespace bp = boost::process; - -int main() -{ - bp::system("test.exe", - bp::windows::show); - - - bp::system("test.exe", - bp::extend::on_setup([](auto &e) - { e.startup_info.dwFlags = STARTF_RUNFULLSCREEN; }), - bp::extend::on_error([](auto&, const std::error_code & ec) - { std::cerr << ec.message() << std::endl; }) - ); -} From 298b60caca3d96ebe9581ba6058c2fcd15b53006 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 11:25:43 +0800 Subject: [PATCH 14/32] fixed for v2 namespace inlining. --- include/boost/process/v2/detail/config.hpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/include/boost/process/v2/detail/config.hpp b/include/boost/process/v2/detail/config.hpp index 43bf441ad..24f374591 100644 --- a/include/boost/process/v2/detail/config.hpp +++ b/include/boost/process/v2/detail/config.hpp @@ -72,7 +72,7 @@ BOOST_PROCESS_V2_END_NAMESPACE #endif -#if BOOST_PROCESS_VERSION == 2 +#if BOOST_PROCESS_VERSION == 1 #define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 { #else #define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { inline namespace v2 { @@ -179,11 +179,4 @@ BOOST_PROCESS_V2_END_NAMESPACE #define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1 #endif -#if BOOST_PROCESS_VERSION == 2 -#define BOOST_PROCESS_V2_INLINE inline -#else -#define BOOST_PROCESS_V2_INLINE -#endif - - #endif //BOOST_PROCESS_V2_DETAIL_CONFIG_HPP From 65251a2316f4ab33580bc118526e31aa6588b193 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 11:29:23 +0800 Subject: [PATCH 15/32] replace png with svg in install. --- doc/Jamfile.jam | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/Jamfile.jam b/doc/Jamfile.jam index a993c8747..0ea7ae1c1 100644 --- a/doc/Jamfile.jam +++ b/doc/Jamfile.jam @@ -16,10 +16,10 @@ explicit pdf_ ; install images : - images/posix_exec_err.png - images/posix_fork_err.png - images/posix_success.png - images/windows_exec.png + images/posix_exec_err.svg + images/posix_fork_err.svg + images/posix_success.svg + images/windows_exec.svg : html/images ; From 9bd57d66b7e8b0de8263663b53bffab727bb96cc Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 11:41:00 +0800 Subject: [PATCH 16/32] aded missing include to example/env.cpp --- example/env.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/env.cpp b/example/env.cpp index 5242b5d10..d12cf990a 100644 --- a/example/env.cpp +++ b/example/env.cpp @@ -8,14 +8,14 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include using namespace boost::process; namespace asio = boost::asio; int main() { - { - // tag::current_env[] + { // tag::current_env[] // search in the current environment auto exe = environment::find_executable("g++"); From e1c6a9b09bd648d4ccf88a078f49a1a8318bf4c8 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 11:50:57 +0800 Subject: [PATCH 17/32] attempting to fix msvc build. --- include/boost/process/v2/process_handle.hpp | 2 +- include/boost/process/v2/stdio.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/process/v2/process_handle.hpp b/include/boost/process/v2/process_handle.hpp index e0894e338..d3bf6cc96 100644 --- a/include/boost/process/v2/process_handle.hpp +++ b/include/boost/process/v2/process_handle.hpp @@ -137,7 +137,7 @@ using basic_process_handle = detail::basic_process_handle_win; #if defined(BOOST_PROCESS_V2_PIDFD_OPEN) template using basic_process_handle = detail::basic_process_handle_fd; -#elif defined(BOOST_PROCESS_V2_PDFORK) +#elif defined(BOOST_PROCESS_V2_PDFORK) || defined(BOOST_PROCESS_V2_PIPE_LAUNCHER) template using basic_process_handle = detail::basic_process_handle_fd_or_signal; #else diff --git a/include/boost/process/v2/stdio.hpp b/include/boost/process/v2/stdio.hpp index 0568622e0..72d6152ac 100644 --- a/include/boost/process/v2/stdio.hpp +++ b/include/boost/process/v2/stdio.hpp @@ -82,7 +82,7 @@ struct process_io_binding process_io_binding() = default; template - process_io_binding(Stream && str, decltype(std::declval().native_handle()) = nullptr) + process_io_binding(Stream && str, decltype(std::declval().native_handle()) = {}) : process_io_binding(str.native_handle()) {} @@ -168,7 +168,7 @@ struct process_io_binding process_io_binding() = default; template - process_io_binding(Stream && str, decltype(std::declval().native_handle()) = -1) + process_io_binding(Stream && str, decltype(std::declval().native_handle()) = {}) : process_io_binding(str.native_handle()) {} From a6f2a1d00504c08035db1681824902dd00efe300 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 15:50:28 +0800 Subject: [PATCH 18/32] windows fixes. --- doc/reference/bind_launcher.adoc | 3 ++- doc/stdio.adoc | 8 +++++--- example/stdio.cpp | 2 ++ include/boost/process/v2/stdio.hpp | 6 +++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/doc/reference/bind_launcher.adoc b/doc/reference/bind_launcher.adoc index 997a7953f..9467129be 100644 --- a/doc/reference/bind_launcher.adoc +++ b/doc/reference/bind_launcher.adoc @@ -12,4 +12,5 @@ auto bind_launcher(Launcher && launcher, Init && ... init); // The new launcher with bound paramaters template auto bind_default_launcher(Init && ... init); ----- \ No newline at end of file +---- + diff --git a/doc/stdio.adoc b/doc/stdio.adoc index e0f0f7dc9..8c0e611cf 100644 --- a/doc/stdio.adoc +++ b/doc/stdio.adoc @@ -42,9 +42,11 @@ include::../example/stdio.cpp[tag=null] == `native_handle` A native handle can be used as well, which means an `int` on posix or a `HANDLE` on windows. -Furthermore, any object that has a `native_handle` returning that native handle type is valid, too. +Furthermore, any object that has a `native_handle` function which returns a valid type for a stdio stream. -.example/stdio.cpp:51-56 +E.g. a domain socket on linux. + +.example/stdio.cpp:52-57 [source,cpp] ---- include::../example/stdio.cpp[tag=native_handle] @@ -55,7 +57,7 @@ include::../example/stdio.cpp[tag=native_handle] Additionally, process v2 provides a `popen` class. It starts a process and connects pipes for stdin and stdout, so that the popen object can be used as a stream. -.example/stdio.cpp:61-64 +.example/stdio.cpp:63-66 [source,cpp] ---- include::../example/stdio.cpp[tag=popen] diff --git a/example/stdio.cpp b/example/stdio.cpp index 97a2bf42e..16264062c 100644 --- a/example/stdio.cpp +++ b/example/stdio.cpp @@ -46,6 +46,7 @@ int main(int argc, char *argv[]) proc.wait(); //end::null[] } +#if defined(BOOST_POSIX_API) { //tag::native_handle[] asio::io_context ctx; @@ -56,6 +57,7 @@ int main(int argc, char *argv[]) proc.wait(); //end::native_handle[] } +#endif { //tag::popen[] asio::io_context ctx; diff --git a/include/boost/process/v2/stdio.hpp b/include/boost/process/v2/stdio.hpp index 72d6152ac..ddd4fcea8 100644 --- a/include/boost/process/v2/stdio.hpp +++ b/include/boost/process/v2/stdio.hpp @@ -82,11 +82,11 @@ struct process_io_binding process_io_binding() = default; template - process_io_binding(Stream && str, decltype(std::declval().native_handle()) = {}) + process_io_binding(Stream && str, decltype(std::declval().native_handle())* = nullptr) : process_io_binding(str.native_handle()) {} - process_io_binding(FILE * f) : process_io_binding(::_get_osfhandle(_fileno(f))) {} + process_io_binding(FILE * f) : process_io_binding(reinterpret_cast(::_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")) {} template::value>::type> @@ -168,7 +168,7 @@ struct process_io_binding process_io_binding() = default; template - process_io_binding(Stream && str, decltype(std::declval().native_handle()) = {}) + process_io_binding(Stream && str, decltype(std::declval().native_handle()) * = nullptr) : process_io_binding(str.native_handle()) {} From d75ffb30eea6c6bbc129ec556db86b463a49cee4 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 18:49:49 +0800 Subject: [PATCH 19/32] windows link fixes. --- include/boost/process/v2/detail/process_handle_windows.hpp | 2 -- src/detail/process_handle_windows.cpp | 1 - src/ext/exe.cpp | 5 ++++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/process/v2/detail/process_handle_windows.hpp b/include/boost/process/v2/detail/process_handle_windows.hpp index 20330e985..36dbf9d47 100644 --- a/include/boost/process/v2/detail/process_handle_windows.hpp +++ b/include/boost/process/v2/detail/process_handle_windows.hpp @@ -318,8 +318,6 @@ struct basic_process_handle_win } }; -extern template struct basic_process_handle_win<>; - } BOOST_PROCESS_V2_END_NAMESPACE diff --git a/src/detail/process_handle_windows.cpp b/src/detail/process_handle_windows.cpp index afe821cd8..6fc77e5fb 100644 --- a/src/detail/process_handle_windows.cpp +++ b/src/detail/process_handle_windows.cpp @@ -158,7 +158,6 @@ void resume_(HANDLE handle, error_code & ec) } #endif -template struct basic_process_handle_win<>; } diff --git a/src/ext/exe.cpp b/src/ext/exe.cpp index 0f05f8ab0..3476937a6 100644 --- a/src/ext/exe.cpp +++ b/src/ext/exe.cpp @@ -75,6 +75,7 @@ filesystem::path exe(HANDLE process_handle) filesystem::path exe(HANDLE proc, boost::system::error_code & ec) { +#if _WIN32_WINNT >= 0x0600 wchar_t buffer[MAX_PATH]; // On input, specifies the size of the lpExeName buffer, in characters. DWORD size = MAX_PATH; @@ -84,7 +85,9 @@ filesystem::path exe(HANDLE proc, boost::system::error_code & ec) } else BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec); - +#else + BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::operation_not_supported); +#endif return ""; } From b529769eb5d08d9f95b0130fd2f1a49acad330f4 Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Fri, 20 Dec 2024 19:05:07 +0800 Subject: [PATCH 20/32] removed boost::system:: scope spec for error_code. --- .../v2/detail/process_handle_windows.hpp | 2 +- .../boost/process/v2/ext/detail/proc_info.hpp | 4 +- include/boost/process/v2/pid.hpp | 6 +- include/boost/process/v2/popen.hpp | 20 +++---- src/ext/cmd.cpp | 20 +++---- src/ext/cwd.cpp | 20 +++---- src/ext/env.cpp | 20 +++---- src/ext/exe.cpp | 18 +++--- src/ext/proc_info.cpp | 4 +- src/pid.cpp | 60 +++++++++---------- test/v2/environment.cpp | 2 + 11 files changed, 89 insertions(+), 87 deletions(-) diff --git a/include/boost/process/v2/detail/process_handle_windows.hpp b/include/boost/process/v2/detail/process_handle_windows.hpp index 36dbf9d47..3aa4142b1 100644 --- a/include/boost/process/v2/detail/process_handle_windows.hpp +++ b/include/boost/process/v2/detail/process_handle_windows.hpp @@ -287,7 +287,7 @@ struct basic_process_handle_win sl.assign( [&h](asio::cancellation_type ct) { - boost::system::error_code ec; + error_code ec; h.cancel(ec); }); handle.async_wait(std::move(self)); diff --git a/include/boost/process/v2/ext/detail/proc_info.hpp b/include/boost/process/v2/ext/detail/proc_info.hpp index 2cbdd0060..d182b75c3 100644 --- a/include/boost/process/v2/ext/detail/proc_info.hpp +++ b/include/boost/process/v2/ext/detail/proc_info.hpp @@ -105,8 +105,8 @@ typedef struct { #else #include #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); +BOOST_PROCESS_V2_DECL std::wstring cwd_cmd_from_proc(HANDLE proc, int type, error_code & ec); +BOOST_PROCESS_V2_DECL HANDLE open_process_with_debug_privilege(boost::process::v2::pid_type pid, error_code & ec); #endif } // namespace ext diff --git a/include/boost/process/v2/pid.hpp b/include/boost/process/v2/pid.hpp index e705b949e..20985e68e 100644 --- a/include/boost/process/v2/pid.hpp +++ b/include/boost/process/v2/pid.hpp @@ -42,19 +42,19 @@ constexpr static pid_type root_pid = 1; BOOST_PROCESS_V2_DECL pid_type current_pid(); /// List all available pids. -BOOST_PROCESS_V2_DECL std::vector all_pids(boost::system::error_code & ec); +BOOST_PROCESS_V2_DECL std::vector all_pids(error_code & ec); /// List all available pids. BOOST_PROCESS_V2_DECL std::vector all_pids(); // return parent pid of pid. -BOOST_PROCESS_V2_DECL pid_type parent_pid(pid_type pid, boost::system::error_code & ec); +BOOST_PROCESS_V2_DECL pid_type parent_pid(pid_type pid, 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 child_pids(pid_type pid, boost::system::error_code & ec); +BOOST_PROCESS_V2_DECL std::vector child_pids(pid_type pid, error_code & ec); // return child pids of pid. BOOST_PROCESS_V2_DECL std::vector child_pids(pid_type pid); diff --git a/include/boost/process/v2/popen.hpp b/include/boost/process/v2/popen.hpp index 3d6c22705..21c248ab1 100644 --- a/include/boost/process/v2/popen.hpp +++ b/include/boost/process/v2/popen.hpp @@ -248,7 +248,7 @@ struct basic_popen : basic_process * * @returns The number of bytes written. * - * @throws boost::system::system_error Thrown on failure. An error code of + * @throws system_error Thrown on failure. An error code of * boost::asio::error::eof indicates that the connection was closed by the * subprocess. * @@ -289,7 +289,7 @@ struct basic_popen : basic_process */ template std::size_t write_some(const ConstBufferSequence& buffers, - boost::system::error_code& ec) + error_code& ec) { return stdin_.write_some(buffers, ec); } @@ -311,7 +311,7 @@ struct basic_popen : basic_process * @ref yield_context, or a function object with the correct completion * signature. The function signature of the completion handler must be: * @code void handler( - * const boost::system::error_code& error, // Result of operation. + * const error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or @@ -320,7 +320,7 @@ struct basic_popen : basic_process * manner equivalent to using boost::asio::post(). * * @par Completion Signature - * @code void(boost::system::error_code, std::size_t) @endcode + * @code void(error_code, std::size_t) @endcode * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -336,7 +336,7 @@ struct basic_popen : basic_process * std::vector. */ template > auto async_write_some(const ConstBufferSequence& buffers, WriteToken && token = net::default_completion_token_t()) @@ -356,7 +356,7 @@ struct basic_popen : basic_process * * @returns The number of bytes read. * - * @throws boost::system::system_error Thrown on failure. An error code of + * @throws system_error Thrown on failure. An error code of * boost::asio::error::eof indicates that the connection was closed by the * peer. * @@ -399,7 +399,7 @@ struct basic_popen : basic_process */ template std::size_t read_some(const MutableBufferSequence& buffers, - boost::system::error_code& ec) + error_code& ec) { return stdout_.read_some(buffers, ec); } @@ -421,7 +421,7 @@ struct basic_popen : basic_process * @ref yield_context, or a function object with the correct completion * signature. The function signature of the completion handler must be: * @code void handler( - * const boost::system::error_code& error, // Result of operation. + * const error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or @@ -430,7 +430,7 @@ struct basic_popen : basic_process * manner equivalent to using boost::asio::post(). * * @par Completion Signature - * @code void(boost::system::error_code, std::size_t) @endcode + * @code void(error_code, std::size_t) @endcode * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -448,7 +448,7 @@ struct basic_popen : basic_process * std::vector. */ template > auto async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadToken) token diff --git a/src/ext/cmd.cpp b/src/ext/cmd.cpp index 34b2668c1..57f8cc5ca 100644 --- a/src/ext/cmd.cpp +++ b/src/ext/cmd.cpp @@ -133,14 +133,14 @@ shell cmd(HANDLE proc, error_code & ec) shell cmd(HANDLE proc) { - boost::system::error_code ec; + 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) +shell cmd(boost::process::v2::pid_type pid, error_code & ec) { struct del { @@ -162,7 +162,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) #elif (defined(__APPLE__) && defined(__MACH__)) && !TARGET_OS_IOS -shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +shell cmd(boost::process::v2::pid_type pid, error_code & ec) { int mib[3] = {CTL_KERN, KERN_ARGMAX, 0}; int argmax = 0; @@ -213,7 +213,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) #elif (defined(__linux__) || defined(__ANDROID__)) -shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +shell cmd(boost::process::v2::pid_type pid, error_code & ec) { std::string procargs; procargs.resize(4096); @@ -269,7 +269,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) #elif (defined(__FreeBSD__) || defined(__DragonFly__)) -shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +shell cmd(boost::process::v2::pid_type pid, error_code & ec) { int cntp = 0; kinfo_proc *proc_info = nullptr; @@ -301,7 +301,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) #elif defined(__NetBSD__) -shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +shell cmd(boost::process::v2::pid_type pid, error_code & ec) { int cntp = 0; kinfo_proc2 *proc_info = nullptr; @@ -332,7 +332,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) #elif defined(__OpenBSD__) -shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +shell cmd(boost::process::v2::pid_type pid, error_code & ec) { int cntp = 0; kinfo_proc *proc_info = nullptr; @@ -362,7 +362,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) #elif defined(__sun) -shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +shell cmd(boost::process::v2::pid_type pid, error_code & ec) { char **cmd = nullptr; proc *proc_info = nullptr; @@ -403,7 +403,7 @@ shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec) } #else -filesystem::path cmd(boost::process::v2::pid_type, boost::system::error_code & ec) +filesystem::path cmd(boost::process::v2::pid_type, error_code & ec) { BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); return ""; @@ -412,7 +412,7 @@ filesystem::path cmd(boost::process::v2::pid_type, boost::system::error_code & e shell cmd(boost::process::v2::pid_type pid) { - boost::system::error_code ec; + error_code ec; auto res = cmd(pid, ec); if (ec) detail::throw_error(ec, "cmd"); diff --git a/src/ext/cwd.cpp b/src/ext/cwd.cpp index 6aee83de1..bf65e2e8c 100644 --- a/src/ext/cwd.cpp +++ b/src/ext/cwd.cpp @@ -67,7 +67,7 @@ namespace ext { #if defined(BOOST_PROCESS_V2_WINDOWS) -filesystem::path cwd(HANDLE proc, boost::system::error_code & ec) +filesystem::path cwd(HANDLE proc, error_code & ec) { auto buffer = boost::process::v2::detail::ext::cwd_cmd_from_proc(proc, 1/*=MEMCWD*/, ec); if (!buffer.empty()) @@ -77,7 +77,7 @@ filesystem::path cwd(HANDLE proc, boost::system::error_code & ec) return ""; } -filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec) { struct del { @@ -96,7 +96,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code filesystem::path cwd(HANDLE proc) { - boost::system::error_code ec; + error_code ec; auto res = cwd(proc, ec); if (ec) detail::throw_error(ec, "cwd"); @@ -105,7 +105,7 @@ filesystem::path cwd(HANDLE proc) #elif (defined(__APPLE__) && defined(__MACH__)) && !TARGET_OS_IOS -filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec) { proc_vnodepathinfo vpi; if (proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi)) > 0) @@ -117,7 +117,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code #elif (defined(__linux__) || defined(__ANDROID__) || defined(__sun)) -filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec) { #if (defined(__linux__) || defined(__ANDROID__)) return filesystem::canonical( @@ -132,7 +132,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code #elif defined(__FreeBSD__) -filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec) { filesystem::path path; struct kinfo_file kif; @@ -155,7 +155,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code #elif defined(__DragonFly__) -filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec) { filesystem::path path; char buffer[PATH_MAX]; @@ -172,7 +172,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code #elif (defined(__NetBSD__) || defined(__OpenBSD__)) -filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec) { filesystem::path path; #if defined(__NetBSD__) @@ -200,7 +200,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code } #else -filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec) { BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); return ""; @@ -209,7 +209,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code filesystem::path cwd(boost::process::v2::pid_type pid) { - boost::system::error_code ec; + error_code ec; auto res = cwd(pid, ec); if (ec) detail::throw_error(ec, "cwd"); diff --git a/src/ext/env.cpp b/src/ext/env.cpp index 35af73a05..2f2152500 100644 --- a/src/ext/env.cpp +++ b/src/ext/env.cpp @@ -172,7 +172,7 @@ namespace ext #if defined(BOOST_PROCESS_V2_WINDOWS) -env_view env(HANDLE proc, boost::system::error_code & ec) +env_view env(HANDLE proc, error_code & ec) { wchar_t *buffer = nullptr; PEB peb; @@ -221,14 +221,14 @@ env_view env(HANDLE proc, boost::system::error_code & ec) env_view env(HANDLE handle) { - boost::system::error_code ec; + 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) +env_view env(boost::process::v2::pid_type pid, error_code & ec) { struct del { @@ -248,7 +248,7 @@ env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) #elif (defined(__APPLE___) || defined(__MACH__)) && !TARGET_OS_IOS -env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) +env_view env(boost::process::v2::pid_type pid, error_code & ec) { int mib[3] = {CTL_KERN, KERN_ARGMAX, 0}; int argmax = 0; @@ -311,7 +311,7 @@ env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) #elif (defined(__linux__) || defined(__ANDROID__)) -env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) +env_view env(boost::process::v2::pid_type pid, error_code & ec) { std::size_t size = 0; std::unique_ptr procargs{}; @@ -346,7 +346,7 @@ env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) } #elif defined(__FreeBSD__) || defined(__DragonFly__) -env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) +env_view env(boost::process::v2::pid_type pid, error_code & ec) { std::vector vec; int cntp = 0; @@ -388,7 +388,7 @@ env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) } #elif defined(__NetBSD__) -env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) +env_view env(boost::process::v2::pid_type pid, error_code & ec) { std::vector vec; int cntp = 0; @@ -427,7 +427,7 @@ env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) return ev; } #elif defined(__OpenBSD__) -env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) +env_view env(boost::process::v2::pid_type pid, error_code & ec) { std::vector vec; int cntp = 0; @@ -468,7 +468,7 @@ env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) return ev; } #elif defined(__sun) -env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) +env_view env(boost::process::v2::pid_type pid, error_code & ec) { std::vector vec; char **env = nullptr; @@ -518,7 +518,7 @@ env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec) env_view env(boost::process::v2::pid_type pid) { - boost::system::error_code ec; + error_code ec; auto res = env(pid, ec); if (ec) detail::throw_error(ec, "env"); diff --git a/src/ext/exe.cpp b/src/ext/exe.cpp index 3476937a6..f84b262e3 100644 --- a/src/ext/exe.cpp +++ b/src/ext/exe.cpp @@ -65,7 +65,7 @@ namespace ext { filesystem::path exe(HANDLE process_handle) { - boost::system::error_code ec; + error_code ec; auto res = exe(process_handle, ec); if (ec) detail::throw_error(ec, "exe"); @@ -73,7 +73,7 @@ filesystem::path exe(HANDLE process_handle) } -filesystem::path exe(HANDLE proc, boost::system::error_code & ec) +filesystem::path exe(HANDLE proc, error_code & ec) { #if _WIN32_WINNT >= 0x0600 wchar_t buffer[MAX_PATH]; @@ -91,7 +91,7 @@ filesystem::path exe(HANDLE proc, boost::system::error_code & ec) return ""; } -filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path exe(boost::process::v2::pid_type pid, error_code & ec) { if (pid == GetCurrentProcessId()) { @@ -121,7 +121,7 @@ filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code #elif (defined(__APPLE__) && defined(__MACH__)) && !TARGET_OS_IOS -filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path exe(boost::process::v2::pid_type pid, error_code & ec) { char buffer[PROC_PIDPATHINFO_MAXSIZE]; if (proc_pidpath(pid, buffer, sizeof(buffer)) > 0) @@ -134,7 +134,7 @@ filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code #elif (defined(__linux__) || defined(__ANDROID__) || defined(__sun)) -filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path exe(boost::process::v2::pid_type pid, error_code & ec) { #if (defined(__linux__) || defined(__ANDROID__)) return filesystem::canonical( @@ -149,7 +149,7 @@ filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code #elif (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)) -filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path exe(boost::process::v2::pid_type pid, error_code & ec) { #if (defined(__FreeBSD__) || defined(__DragonFly__)) int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}; @@ -174,14 +174,14 @@ filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code #elif defined(__OpenBSD__) -filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path exe(boost::process::v2::pid_type pid, error_code & ec) { BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); return ""; } #else -filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec) +filesystem::path exe(boost::process::v2::pid_type pid, error_code & ec) { BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); return ""; @@ -190,7 +190,7 @@ filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code filesystem::path exe(boost::process::v2::pid_type pid) { - boost::system::error_code ec; + error_code ec; auto res = exe(pid, ec); if (ec) detail::throw_error(ec, "exe"); diff --git a/src/ext/proc_info.cpp b/src/ext/proc_info.cpp index aef9d1b75..343be98c8 100644 --- a/src/ext/proc_info.cpp +++ b/src/ext/proc_info.cpp @@ -27,7 +27,7 @@ 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 cwd_cmd_from_proc(HANDLE proc, int type, error_code & ec) { std::wstring buffer; PEB peb; @@ -84,7 +84,7 @@ std::wstring cwd_cmd_from_proc(HANDLE proc, int type, boost::system::error_code // 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 open_process_with_debug_privilege(boost::process::v2::pid_type pid, error_code & ec) { HANDLE proc = nullptr; HANDLE hToken = nullptr; diff --git a/src/pid.cpp b/src/pid.cpp index 53af87f4b..7fa5f822c 100644 --- a/src/pid.cpp +++ b/src/pid.cpp @@ -70,7 +70,7 @@ pid_type current_pid() {return ::getpid();} #if defined(BOOST_PROCESS_V2_WINDOWS) -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { std::vector vec; HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -92,7 +92,7 @@ std::vector all_pids(boost::system::error_code & ec) return vec; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { pid_type ppid = static_cast(-1); HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -119,7 +119,7 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec) return ppid; } -std::vector child_pids(pid_type pid, boost::system::error_code & ec) +std::vector child_pids(pid_type pid, error_code & ec) { std::vector vec; HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -147,7 +147,7 @@ std::vector child_pids(pid_type pid, boost::system::error_code & ec) #elif (defined(__APPLE__) && defined(__MACH__)) && !TARGET_OS_IOS -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { std::vector vec; vec.resize(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0) / sizeof(pid_type)); @@ -161,7 +161,7 @@ std::vector all_pids(boost::system::error_code & ec) return vec; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { pid_type ppid = static_cast(-1); proc_bsdinfo proc_info; @@ -175,7 +175,7 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec) return ppid; } -std::vector child_pids(pid_type pid, boost::system::error_code & ec) +std::vector child_pids(pid_type pid, error_code & ec) { std::vector vec; vec.resize(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0) / sizeof(pid_type)); @@ -191,7 +191,7 @@ std::vector child_pids(pid_type pid, boost::system::error_code & ec) #elif (defined(__linux__) || defined(__ANDROID__)) -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { std::vector vec; DIR *proc = opendir("/proc"); @@ -211,7 +211,7 @@ std::vector all_pids(boost::system::error_code & ec) return vec; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { pid_type ppid = static_cast(-1); char buffer[BUFSIZ]; @@ -256,7 +256,7 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec) return ppid; } -std::vector child_pids(pid_type pid, boost::system::error_code & ec) +std::vector child_pids(pid_type pid, error_code & ec) { std::vector vec; std::vector pids = all_pids(ec); @@ -275,7 +275,7 @@ std::vector child_pids(pid_type pid, boost::system::error_code & ec) #elif defined(__FreeBSD__) -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { std::vector vec; int cntp = 0; @@ -308,7 +308,7 @@ std::vector all_pids(boost::system::error_code & ec) return vec; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { pid_type ppid = static_cast(-1); int cntp = 0; @@ -339,7 +339,7 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec) return ppid; } -std::vector child_pids(pid_type pid, boost::system::error_code & ec) +std::vector child_pids(pid_type pid, error_code & ec) { std::vector vec; int cntp = 0; @@ -379,7 +379,7 @@ std::vector child_pids(pid_type pid, boost::system::error_code & ec) #elif defined(__DragonFly__) -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { std::vector vec; int cntp = 0; @@ -413,7 +413,7 @@ std::vector all_pids(boost::system::error_code & ec) return vec; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { pid_type ppid = static_cast(-1); int cntp = 0; @@ -447,7 +447,7 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec) return ppid; } -std::vector child_pids(pid_type pid, boost::system::error_code & ec) +std::vector child_pids(pid_type pid, error_code & ec) { std::vector vec; int cntp = 0; @@ -487,7 +487,7 @@ std::vector child_pids(pid_type pid, boost::system::error_code & ec) #elif defined(__NetBSD__) -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { std::vector vec; int cntp = 0; @@ -520,7 +520,7 @@ std::vector all_pids(boost::system::error_code & ec) return vec; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { pid_type ppid = static_cast(-1); int cntp = 0; @@ -549,7 +549,7 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec) return ppid; } -std::vector child_pids(pid_type pid, boost::system::error_code & ec) +std::vector child_pids(pid_type pid, error_code & ec) { std::vector vec; int cntp = 0; @@ -587,7 +587,7 @@ std::vector child_pids(pid_type pid, boost::system::error_code & ec) #elif defined(__OpenBSD__) -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { std::vector vec; int cntp = 0; @@ -623,7 +623,7 @@ std::vector all_pids(boost::system::error_code & ec) return vec; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { pid_type ppid = static_cast(-1); int cntp = 0; @@ -652,7 +652,7 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec) return ppid; } -std::vector child_pids(pid_type pid, boost::system::error_code & ec) +std::vector child_pids(pid_type pid, error_code & ec) { std::vector vec; int cntp = 0; @@ -691,7 +691,7 @@ std::vector child_pids(pid_type pid, boost::system::error_code & ec) #elif defined(__sun) -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { std::vector vec; struct pid cur_pid; @@ -726,7 +726,7 @@ std::vector all_pids(boost::system::error_code & ec) return vec; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { pid_type ppid = static_cast(-1); proc *proc_info = nullptr; @@ -754,7 +754,7 @@ pid_type parent_pid(pid_type pid, boost::system::error_code & ec) return ppid; } -std::vector child_pids(pid_type pid, boost::system::error_code & ec) +std::vector child_pids(pid_type pid, error_code & ec) { std::vector vec; struct pid cur_pid; @@ -793,17 +793,17 @@ std::vector child_pids(pid_type pid, boost::system::error_code & ec) } #else -std::vector all_pids(boost::system::error_code & ec) +std::vector all_pids(error_code & ec) { BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); return {}; } -pid_type parent_pid(pid_type pid, boost::system::error_code & ec) +pid_type parent_pid(pid_type pid, error_code & ec) { BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); return pid; } -std::vector child_pids(pid_type, boost::system::error_code & ec) +std::vector child_pids(pid_type, error_code & ec) { BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); return {}; @@ -812,7 +812,7 @@ std::vector child_pids(pid_type, boost::system::error_code & ec) std::vector all_pids() { - boost::system::error_code ec; + error_code ec; auto res = all_pids(ec); if (ec) detail::throw_error(ec, "all_pids"); @@ -821,7 +821,7 @@ std::vector all_pids() pid_type parent_pid(pid_type pid) { - boost::system::error_code ec; + error_code ec; auto res = parent_pid(pid, ec); if (ec) detail::throw_error(ec, "parent_pid"); @@ -830,7 +830,7 @@ pid_type parent_pid(pid_type pid) std::vector child_pids(pid_type pid) { - boost::system::error_code ec; + error_code ec; auto res = child_pids(pid, ec); if (ec) detail::throw_error(ec, "child_pids"); diff --git a/test/v2/environment.cpp b/test/v2/environment.cpp index 8cde59bfa..d9f86182e 100644 --- a/test/v2/environment.cpp +++ b/test/v2/environment.cpp @@ -63,7 +63,9 @@ BOOST_AUTO_TEST_CASE(environment) for (auto && ke : bpe::current()) if (!std::get<1>(ke).empty()) + { BOOST_CHECK_EQUAL(bpe::get(std::get<0>(ke)), std::get<1>(ke)); + } #if defined(BOOST_PROCESS_V2_POSIX) From 359820097bac662361148fcf8d763b9c3d1f9cc7 Mon Sep 17 00:00:00 2001 From: Jonas Greitemann Date: Sun, 12 Jan 2025 16:43:16 +0100 Subject: [PATCH 21/32] add test case for initializing `process_stdio` with complementary pipe ends `process_stdio` holds on to the handles for `in`/`out`/`err`. In case of pipes, `in` needs the handles of a `readable_pipe`, whereas `out` and `err` need the handles of `writable_pipe`s. So far, the tests all create a new pair using `connect_pipe`, pass the "correct" end into `process_stdio`, and use the other end to interface with the process. However, `process_io_binding` also supports construction from the complementary pipe types, i.e., constructing `in`'s binding from a `writable_pipe` and `out`/`err`'s bindings from `readable_pipe`s. In this case, the constructor will create the corresponding pipe itself and keep ownership of it. This mode was thus far not tested. --- test/v2/process.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/v2/process.cpp b/test/v2/process.cpp index b2b71dfd4..6d0e6ce2a 100644 --- a/test/v2/process.cpp +++ b/test/v2/process.cpp @@ -30,9 +30,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -328,6 +330,37 @@ BOOST_AUTO_TEST_CASE(echo_file) BOOST_CHECK_MESSAGE(proc.exit_code() == 0, proc.exit_code()); } +BOOST_AUTO_TEST_CASE(stdio_creates_complementary_pipes) +{ + using boost::unit_test::framework::master_test_suite; + const auto pth = master_test_suite().argv[1]; + + asio::io_context ctx; + + asio::readable_pipe rp{ctx}; + asio::writable_pipe wp{ctx}; + // Pipes intentionally not connected. `process_stdio` will create pipes + // complementing both of these and retains ownership of those pipes. + + bpv::process proc(ctx, pth, {"echo"}, bpv::process_stdio{/*.in=*/wp, /*.out=*/rp, /*.err=*/nullptr}); + + asio::write(wp, asio::buffer("foo", 3)); + asio::write(wp, asio::buffer("bar", 3)); + wp.close(); + + bpv::error_code ec; + std::string out; + auto sz = asio::read(rp, asio::dynamic_buffer(out), ec); + while (ec == asio::error::interrupted) + sz += asio::read(rp, asio::dynamic_buffer(out), ec); + BOOST_CHECK_EQUAL(sz, 6u); + BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message()); + BOOST_CHECK_EQUAL(out, "foobar"); + + proc.wait(); + BOOST_CHECK(proc.exit_code() == 0); +} + BOOST_AUTO_TEST_CASE(print_same_cwd) { using boost::unit_test::framework::master_test_suite; From 4bb842564ffe4fb7cd5de66133eb1d883f7c3928 Mon Sep 17 00:00:00 2001 From: Jonas Greitemann Date: Sun, 12 Jan 2025 18:56:54 +0100 Subject: [PATCH 22/32] add a (failing) test for `process_stdio` move semantics This test currently fails on POSIX, as `process_io_binding` does not explicitly implement move operations but holds on to a file descriptor which exhibits reference semantics and has a non-trivial destructor. The same test should pass on Windows as the Windows implementation makes use of `unique_ptr` which gives it correct move semantics by virtue of the rule of zero. --- test/v2/process.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/v2/process.cpp b/test/v2/process.cpp index 6d0e6ce2a..694afea2d 100644 --- a/test/v2/process.cpp +++ b/test/v2/process.cpp @@ -361,6 +361,43 @@ BOOST_AUTO_TEST_CASE(stdio_creates_complementary_pipes) BOOST_CHECK(proc.exit_code() == 0); } +BOOST_AUTO_TEST_CASE(stdio_move_semantics) +{ + using boost::unit_test::framework::master_test_suite; + const auto pth = master_test_suite().argv[1]; + + asio::io_context ctx; + + asio::readable_pipe rp{ctx}; + asio::writable_pipe wp{ctx}; + + auto make_stdio = [&]() -> bpv::process_stdio { + bpv::process_stdio stdio{}; + stdio.in = wp; + stdio.out = rp; + stdio.err = nullptr; + // intentionally pessimizing move, preventing NRVO + return std::move(stdio); + }; + bpv::process proc(ctx, pth, {"echo"}, make_stdio()); + + bpv::error_code ec; + asio::write(wp, asio::buffer("foobar", 6), ec); + BOOST_CHECK_MESSAGE(!ec, ec.message()); + wp.close(); + + std::string out; + auto sz = asio::read(rp, asio::dynamic_buffer(out), ec); + while (ec == asio::error::interrupted) + sz += asio::read(rp, asio::dynamic_buffer(out), ec); + BOOST_CHECK_EQUAL(sz, 6u); + BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message()); + BOOST_CHECK_EQUAL(out, "foobar"); + + proc.wait(); + BOOST_CHECK(proc.exit_code() == 0); +} + BOOST_AUTO_TEST_CASE(print_same_cwd) { using boost::unit_test::framework::master_test_suite; From e842a060f11c564ba8cd30b9044dcad09cc28bf0 Mon Sep 17 00:00:00 2001 From: Jonas Greitemann Date: Sun, 12 Jan 2025 20:08:36 +0100 Subject: [PATCH 23/32] implement move operations for `process_io_binding` and delete copy operations This makes the test added in the previous commit pass. --- include/boost/process/v2/stdio.hpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/boost/process/v2/stdio.hpp b/include/boost/process/v2/stdio.hpp index ddd4fcea8..f1bf08049 100644 --- a/include/boost/process/v2/stdio.hpp +++ b/include/boost/process/v2/stdio.hpp @@ -166,6 +166,31 @@ struct process_io_binding } process_io_binding() = default; + process_io_binding(const process_io_binding &) = delete; + process_io_binding & operator=(const process_io_binding &) = delete; + + process_io_binding(process_io_binding && other) noexcept + : fd(other.fd), fd_needs_closing(other.fd), ec(other.ec) + { + other.fd = target; + other.fd_needs_closing = false; + other.ec = {}; + } + + process_io_binding & operator=(process_io_binding && other) noexcept + { + if (fd_needs_closing) + ::close(fd); + + fd = other.fd; + fd_needs_closing = other.fd_needs_closing; + ec = other.ec; + + other.fd = target; + other.fd_needs_closing = false; + other.ec = {}; + return *this; + } template process_io_binding(Stream && str, decltype(std::declval().native_handle()) * = nullptr) From 1b5272a9e1a3b0cf8dd2c4a26f25c6903211066b Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Mon, 13 Jan 2025 08:36:05 +0800 Subject: [PATCH 24/32] changed cwd comparison to `equivalent`. --- test/v2/ext.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/v2/ext.cpp b/test/v2/ext.cpp index 0ed55c9c0..5fa9b3b2e 100644 --- a/test/v2/ext.cpp +++ b/test/v2/ext.cpp @@ -110,10 +110,10 @@ BOOST_AUTO_TEST_CASE(test_cwd_exe) boost::asio::io_context ctx; bp2::process proc(ctx, pth, {"sleep", "10000"}, bp2::process_start_dir{tmp}); - auto tt = bp2::ext::cwd(proc.handle()).string(); - if (tt.back() == '\\') - tt.pop_back(); - BOOST_CHECK_EQUAL(tt, tmp); + auto tt = bp2::ext::cwd(proc.handle()); + + + BOOST_CHECK_MESSAGE(bp2::filesystem::equivalent(tmp, tt), tmp << " == " << tt); bp2::error_code ec; bp2::filesystem::remove(tmp, ec); } From a2d2753aa8fe4f58b163f76d17d1c43f144146bc Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Mon, 13 Jan 2025 09:31:48 +0800 Subject: [PATCH 25/32] zombie process fixes closes #445, #447 --- .../process/v2/posix/default_launcher.hpp | 44 +++---------------- .../v2/posix/fork_and_forget_launcher.hpp | 1 + .../process/v2/posix/pdfork_launcher.hpp | 1 + .../boost/process/v2/posix/vfork_launcher.hpp | 1 + .../process/v2/windows/default_launcher.hpp | 2 +- test/v2/process.cpp | 36 +++++++++++++++ 6 files changed, 46 insertions(+), 39 deletions(-) diff --git a/include/boost/process/v2/posix/default_launcher.hpp b/include/boost/process/v2/posix/default_launcher.hpp index 0ed0b9211..d17bda5e7 100644 --- a/include/boost/process/v2/posix/default_launcher.hpp +++ b/include/boost/process/v2/posix/default_launcher.hpp @@ -26,6 +26,8 @@ #endif #include +#include +#include #include @@ -96,7 +98,7 @@ template inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), const error_code & ec, Init && init, derived && ) --> decltype(init.on_error(launcher, ec, executable, cmd_line, ec)) +-> decltype(init.on_error(launcher, executable, cmd_line, ec)) { init.on_error(launcher, executable, cmd_line, ec); } @@ -160,7 +162,7 @@ template inline auto invoke_on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), const error_code & ec, Init && init, derived && ) --> decltype(init.on_fork_error(launcher, ec, executable, cmd_line, ec)) +-> decltype(init.on_fork_error(launcher, executable, cmd_line, ec)) { init.on_fork_error(launcher, executable, cmd_line, ec); } @@ -182,41 +184,6 @@ inline void on_fork_error(Launcher & launcher, const filesystem::path &executabl on_fork_error(launcher, executable, cmd_line, ec, inits...); } - - -template -inline void invoke_on_fork_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, - const char * const * (&/*cmd_line*/), - Init && /*init*/, base && ) -{ - -} - -template -inline auto invoke_on_fork_success(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - Init && init, derived && ) --> decltype(init.on_fork_success(launcher, executable, cmd_line)) -{ - init.on_fork_success(launcher, executable, cmd_line); -} - -template -inline void on_fork_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, - const char * const * (&/*cmd_line*/)) -{ -} - -template -inline void on_fork_success(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - Init1 && init1, Inits && ... inits) -{ - invoke_on_fork_success(launcher, executable, cmd_line, init1, derived{}); - on_fork_success(launcher, executable, cmd_line, inits...); -} - - template inline error_code invoke_on_exec_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/, const char * const * (&/*cmd_line*/), @@ -266,7 +233,7 @@ template inline auto invoke_on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), const error_code & ec, Init && init, derived && ) --> decltype(init.on_exec_error(launcher, ec, executable, cmd_line, ec)) +-> decltype(init.on_exec_error(launcher, executable, cmd_line, ec)) { init.on_exec_error(launcher, executable, cmd_line, ec); } @@ -440,6 +407,7 @@ struct default_launcher if (ec) { detail::on_error(*this, executable, argv, ec, inits...); + do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR); return basic_process{exec}; } } diff --git a/include/boost/process/v2/posix/fork_and_forget_launcher.hpp b/include/boost/process/v2/posix/fork_and_forget_launcher.hpp index 91a622d3b..f86314dee 100644 --- a/include/boost/process/v2/posix/fork_and_forget_launcher.hpp +++ b/include/boost/process/v2/posix/fork_and_forget_launcher.hpp @@ -124,6 +124,7 @@ struct fork_and_forget_launcher : default_launcher if (ec) { detail::on_error(*this, executable, argv, ec, inits...); + do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR); return basic_process{exec}; } } diff --git a/include/boost/process/v2/posix/pdfork_launcher.hpp b/include/boost/process/v2/posix/pdfork_launcher.hpp index 16e5ca821..0a082f562 100644 --- a/include/boost/process/v2/posix/pdfork_launcher.hpp +++ b/include/boost/process/v2/posix/pdfork_launcher.hpp @@ -161,6 +161,7 @@ struct pdfork_launcher : default_launcher if (ec) { detail::on_error(*this, executable, argv, ec, inits...); + do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR); return basic_process{exec}; } } diff --git a/include/boost/process/v2/posix/vfork_launcher.hpp b/include/boost/process/v2/posix/vfork_launcher.hpp index cec0ca1eb..bb1b9f2ca 100644 --- a/include/boost/process/v2/posix/vfork_launcher.hpp +++ b/include/boost/process/v2/posix/vfork_launcher.hpp @@ -121,6 +121,7 @@ struct vfork_launcher : default_launcher if (ec) { detail::on_error(*this, executable, argv, ec, inits...); + do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR); return basic_process{exec}; } diff --git a/include/boost/process/v2/windows/default_launcher.hpp b/include/boost/process/v2/windows/default_launcher.hpp index b41f87c49..d0ca19b4d 100644 --- a/include/boost/process/v2/windows/default_launcher.hpp +++ b/include/boost/process/v2/windows/default_launcher.hpp @@ -97,7 +97,7 @@ inline void invoke_on_error(Launcher & /*launcher*/, const filesystem::path &/*e template inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line, const error_code & ec, Init && init, derived && ) --> decltype(init.on_error(launcher, ec, executable, cmd_line, ec)) +-> decltype(init.on_error(launcher, executable, cmd_line, ec)) { init.on_error(launcher, executable, cmd_line, ec); } diff --git a/test/v2/process.cpp b/test/v2/process.cpp index 694afea2d..276625ec2 100644 --- a/test/v2/process.cpp +++ b/test/v2/process.cpp @@ -734,6 +734,42 @@ BOOST_AUTO_TEST_CASE(async_cancel_wait) ctx.run(); } +#if defined(BOOST_POSIX_API) + +struct capture_pid +{ + pid_t &pid; + template + void on_error(Launcher &launcher, const bpv::filesystem::path& executable, + const char * const * (&/*cmd_line*/), const bpv::error_code & ec) + { + BOOST_REQUIRE(!bpv::filesystem::exists(executable)); + this->pid = launcher.pid; + } +}; + +BOOST_AUTO_TEST_CASE(no_zombie) +{ + asio::io_context ctx; + using boost::unit_test::framework::master_test_suite; + const auto pth = bpv::filesystem::absolute(master_test_suite().argv[1]); + + pid_t res{-1}; + + + boost::system::error_code ec; + bpv::default_process_launcher()(ctx, ec, "/send/more/cops", std::vector{}, capture_pid{res}); + BOOST_CHECK(ec == boost::system::errc::no_such_file_or_directory); + + BOOST_REQUIRE(res != -1); + BOOST_CHECK(res != 0); + auto r = waitpid(res, nullptr, 0); + BOOST_CHECK(r < 0); + BOOST_CHECK_EQUAL(errno, ECHILD); +} + +#endif + BOOST_AUTO_TEST_SUITE_END(); From b781b49a9754ce12f31363eab5dec157d9e7d420 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 20 Jan 2025 11:56:29 -0600 Subject: [PATCH 26/32] doc: fix typo in stdio --- doc/stdio.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/stdio.adoc b/doc/stdio.adoc index 8c0e611cf..f77e89acc 100644 --- a/doc/stdio.adoc +++ b/doc/stdio.adoc @@ -16,7 +16,7 @@ automatically connected and the other side will get assigned to the child proces include::../example/stdio.cpp[tag=readable_pipe] ---- -readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`. +readable pipes can be assigned to `out` and `err`, while writable_pipes can be assigned to `in`. == `FILE*` From c329e05fb69e7ea2ce8cf4e2bcbf048c21e13adc Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Tue, 21 Jan 2025 00:51:50 +0100 Subject: [PATCH 27/32] chore: remove executable flags from .cpp files See . [ci skip] --- test/v2/shell.cpp | 0 test/v2/utf8.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 test/v2/shell.cpp mode change 100755 => 100644 test/v2/utf8.cpp diff --git a/test/v2/shell.cpp b/test/v2/shell.cpp old mode 100755 new mode 100644 diff --git a/test/v2/utf8.cpp b/test/v2/utf8.cpp old mode 100755 new mode 100644 From bb375f50bd5b362b087aab326df158a440882e29 Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Tue, 21 Jan 2025 00:46:56 +0100 Subject: [PATCH 28/32] Fix several typos --- doc/configuration.adoc | 2 +- doc/reference/bind_launcher.adoc | 2 +- doc/reference/environment.adoc | 4 ++-- doc/reference/process_handle.adoc | 2 +- include/boost/process/v1/child.hpp | 2 +- .../boost/process/v1/detail/windows/environment.hpp | 2 +- include/boost/process/v1/environment.hpp | 10 +++++----- include/boost/process/v1/extend.hpp | 6 +++--- include/boost/process/v2/environment.hpp | 4 ++-- include/boost/process/v2/process_handle.hpp | 2 +- src/ext/cwd.cpp | 2 +- src/ext/exe.cpp | 2 +- 12 files changed, 20 insertions(+), 20 deletions(-) diff --git a/doc/configuration.adoc b/doc/configuration.adoc index b44790a62..97a3efae3 100644 --- a/doc/configuration.adoc +++ b/doc/configuration.adoc @@ -7,5 +7,5 @@ Boost process v2 can be configured in the following ways: | Macro | Description | `BOOST_PROCESS_V2_STANDALONE` | Build boost.process for standalone asio -| `BOOST_PROCESS_USE_STD_FS` | Use std::filesystem instead of boost::filsystem +| `BOOST_PROCESS_USE_STD_FS` | Use std::filesystem instead of boost::filesystem | `BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE` | Disable usage of `close_range`. diff --git a/doc/reference/bind_launcher.adoc b/doc/reference/bind_launcher.adoc index 9467129be..44c1395b5 100644 --- a/doc/reference/bind_launcher.adoc +++ b/doc/reference/bind_launcher.adoc @@ -9,7 +9,7 @@ template auto bind_launcher(Launcher && launcher, Init && ... init); // Calls bind_launcher with the default_launcher as the first parameter. -// The new launcher with bound paramaters +// The new launcher with bound parameters template auto bind_default_launcher(Init && ... init); ---- diff --git a/doc/reference/environment.adoc b/doc/reference/environment.adoc index f7fef54c0..b861285da 100644 --- a/doc/reference/environment.adoc +++ b/doc/reference/environment.adoc @@ -25,13 +25,13 @@ namespace environment * Windows treats keys as case-insensitive yet perserving. The char traits are made to reflect * that behaviour. */ -tempalte +template using key_char_traits = implementation_defined ; // A char traits type that reflects the OS rules for string representing environment values. /* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. */ -tempalte +template using value_char_traits = implementation_defined ; // The character type used by the environment. Either `char` or `wchar_t`. diff --git a/doc/reference/process_handle.adoc b/doc/reference/process_handle.adoc index c85ed36ce..f6905a2a0 100644 --- a/doc/reference/process_handle.adoc +++ b/doc/reference/process_handle.adoc @@ -2,7 +2,7 @@ [#process_handle] A process handle is an unmanaged version of a process. -This means it does not terminate the proces on destruction and +This means it does not terminate the process on destruction and will not keep track of the exit-code. NOTE: that the exit code might be discovered early, during a call to `running`. diff --git a/include/boost/process/v1/child.hpp b/include/boost/process/v1/child.hpp index ee0c4f726..5967f9ed4 100644 --- a/include/boost/process/v1/child.hpp +++ b/include/boost/process/v1/child.hpp @@ -39,7 +39,7 @@ child::child(Args&&...args) typedef ::boost::process::v1::detail::api::pid_t pid_t; #if defined(BOOST_PROCESS_DOXYGEN) -/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread), +/** The main class to hold a child process. It is similar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread), * in that it has a join and detach function. * * @attention The destructor will call terminate on the process if not joined or detached without any warning. diff --git a/include/boost/process/v1/detail/windows/environment.hpp b/include/boost/process/v1/detail/windows/environment.hpp index 420d0181e..63d28e5dd 100644 --- a/include/boost/process/v1/detail/windows/environment.hpp +++ b/include/boost/process/v1/detail/windows/environment.hpp @@ -222,7 +222,7 @@ basic_environment_impl::basic_environment_impl(const native_environment_im while ((*p != null_char()) || (*(p+1) != null_char())) p++; p++; //pointing to the second nullchar - p++; //to get the pointer behing the second nullchar, so it's end. + p++; //to get the pointer behind the second nullchar, so it's end. this->_data.assign(beg, p); this->reload(); diff --git a/include/boost/process/v1/environment.hpp b/include/boost/process/v1/environment.hpp index 6ba67c4f3..5308d3c92 100644 --- a/include/boost/process/v1/environment.hpp +++ b/include/boost/process/v1/environment.hpp @@ -627,7 +627,7 @@ class basic_native_environment : public basic_environment_impl class basic_environment : public basic_environment_impl { @@ -646,10 +646,10 @@ typedef basic_native_environment native_environment; typedef basic_native_environment wnative_environment; #if !defined(BOOST_NO_ANSI_APIS) -///Type definition to hold a seperate environment. +///Type definition to hold a separate environment. typedef basic_environment environment; #endif -///Type definition to hold a seperate environment. +///Type definition to hold a separate environment. typedef basic_environment wenvironment; }} @@ -673,10 +673,10 @@ inline int get_id() { return ::boost::process::v1::detail::a ///Get the native handle of the current process. inline native_handle_type native_handle() { return ::boost::process::v1::detail::api::native_handle();} #if !defined(BOOST_NO_ANSI_APIS) -///Get the enviroment of the current process. +///Get the environment of the current process. inline native_environment environment() { return ::boost::process::v1:: native_environment(); } #endif -///Get the enviroment of the current process. +///Get the environment of the current process. inline wnative_environment wenvironment() { return ::boost::process::v1::wnative_environment(); } ///Get the path environment variable of the current process runs. inline std::vector path() diff --git a/include/boost/process/v1/extend.hpp b/include/boost/process/v1/extend.hpp index fced1619e..185972225 100644 --- a/include/boost/process/v1/extend.hpp +++ b/include/boost/process/v1/extend.hpp @@ -124,7 +124,7 @@ struct handler template void on_setup(Executor&) const {} - /** This function is invoked if an error occured while trying to launch the process. + /** This function is invoked if an error occurred while trying to launch the process. * \note It is not required to be const. */ template @@ -136,7 +136,7 @@ struct handler template void on_success(Executor&) const {} - /**This function is invoked if an error occured during the call of `fork`. + /**This function is invoked if an error occurred during the call of `fork`. * \note This function will only be called on posix. */ template @@ -335,7 +335,7 @@ struct windows_executor void set_startup_info_ex(); ///This element is an instance or a reference (if \ref startup_info_ex exists) to the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx) for the process. startup_info_t startup_info; - ///This element is the instance of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx). It is only available with a winapi-version equal or highter than 6. + ///This element is the instance of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx). It is only available with a winapi-version equal or higher than 6. startup_info_ex_t startup_info_ex; }; diff --git a/include/boost/process/v2/environment.hpp b/include/boost/process/v2/environment.hpp index dec87ac10..0c6a0875b 100644 --- a/include/boost/process/v2/environment.hpp +++ b/include/boost/process/v2/environment.hpp @@ -43,13 +43,13 @@ namespace environment * Windows treats keys as case-insensitive yet perserving. The char traits are made to reflect * that behaviour. */ -tempalte +template using key_char_traits = implementation_defined ; /// A char traits type that reflects the OS rules for string representing environment values. /** Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. */ -tempalte +template using value_char_traits = implementation_defined ; /// The character type used by the environment. Either `char` or `wchar_t`. diff --git a/include/boost/process/v2/process_handle.hpp b/include/boost/process/v2/process_handle.hpp index d3bf6cc96..cc00a069c 100644 --- a/include/boost/process/v2/process_handle.hpp +++ b/include/boost/process/v2/process_handle.hpp @@ -26,7 +26,7 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE #if defined(GENERATING_DOCUMENTATION) /** A process handle is an unmanaged version of a process. - * This means it does not terminate the proces on destruction and + * This means it does not terminate the process on destruction and * will not keep track of the exit-code. * * Note that the exit code might be discovered early, during a call to `running`. diff --git a/src/ext/cwd.cpp b/src/ext/cwd.cpp index bf65e2e8c..2a3ea8859 100644 --- a/src/ext/cwd.cpp +++ b/src/ext/cwd.cpp @@ -124,7 +124,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec) filesystem::path("/proc") / std::to_string(pid) / "cwd", ec ); #elif defined(__sun) - return fileystem::canonical( + return filesystem::canonical( filesystem::path("/proc") / std::to_string(pid) / "path/cwd", ec ); #endif diff --git a/src/ext/exe.cpp b/src/ext/exe.cpp index f84b262e3..645724811 100644 --- a/src/ext/exe.cpp +++ b/src/ext/exe.cpp @@ -141,7 +141,7 @@ filesystem::path exe(boost::process::v2::pid_type pid, error_code & ec) filesystem::path("/proc") / std::to_string(pid) / "exe", ec ); #elif defined(__sun) - return fileystem::canonical( + return filesystem::canonical( filesystem::path("/proc") / std::to_string(pid) / "path/a.out", ec ); #endif From d534ed6c346920c36b40d2a5b565d46d8df58bba Mon Sep 17 00:00:00 2001 From: Jens Diewald <37327966+jens-diewald@users.noreply.github.com> Date: Wed, 5 Feb 2025 10:50:34 +0100 Subject: [PATCH 29/32] Fix small yet confusing Typo in Doc --- doc/version2.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/version2.adoc b/doc/version2.adoc index 7667705d1..1af14c8c5 100644 --- a/doc/version2.adoc +++ b/doc/version2.adoc @@ -64,7 +64,7 @@ This concerns especially the `wait_for` and `wait_until` functions on the proces 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, -a wait_for can not safely be implemented with an async_wait + timeout. +a wait_for can now safely be implemented with an async_wait + timeout. == UTF-8 From 529fb1e2224bd4390ab9c5e37ce0ff14eadaa765 Mon Sep 17 00:00:00 2001 From: SimonMaracine Date: Thu, 23 Jan 2025 22:49:46 +0200 Subject: [PATCH 30/32] Fix include directives from boost/process/posix/*.hpp having wrong paths --- include/boost/process/posix/bind_fd.hpp | 2 +- include/boost/process/posix/default_launcher.hpp | 2 +- include/boost/process/posix/fork_and_forget_launcher.hpp | 2 +- include/boost/process/posix/pdfork_launcher.hpp | 2 +- include/boost/process/posix/vfork_launcher.hpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/process/posix/bind_fd.hpp b/include/boost/process/posix/bind_fd.hpp index 1aa72d484..55766e441 100644 --- a/include/boost/process/posix/bind_fd.hpp +++ b/include/boost/process/posix/bind_fd.hpp @@ -1 +1 @@ -#include +#include diff --git a/include/boost/process/posix/default_launcher.hpp b/include/boost/process/posix/default_launcher.hpp index accced3c8..bff107dd5 100644 --- a/include/boost/process/posix/default_launcher.hpp +++ b/include/boost/process/posix/default_launcher.hpp @@ -1 +1 @@ -#include +#include diff --git a/include/boost/process/posix/fork_and_forget_launcher.hpp b/include/boost/process/posix/fork_and_forget_launcher.hpp index f3da2c209..d0703d687 100644 --- a/include/boost/process/posix/fork_and_forget_launcher.hpp +++ b/include/boost/process/posix/fork_and_forget_launcher.hpp @@ -1 +1 @@ -#include +#include diff --git a/include/boost/process/posix/pdfork_launcher.hpp b/include/boost/process/posix/pdfork_launcher.hpp index a537a72aa..b9509e1b7 100644 --- a/include/boost/process/posix/pdfork_launcher.hpp +++ b/include/boost/process/posix/pdfork_launcher.hpp @@ -1 +1 @@ -#include +#include diff --git a/include/boost/process/posix/vfork_launcher.hpp b/include/boost/process/posix/vfork_launcher.hpp index 8ec37eb5d..0daca00c3 100644 --- a/include/boost/process/posix/vfork_launcher.hpp +++ b/include/boost/process/posix/vfork_launcher.hpp @@ -1 +1 @@ -#include +#include From ab28b511a962dc075001780c95d65f42b2ec4853 Mon Sep 17 00:00:00 2001 From: Jonas Greitemann Date: Sat, 11 Jan 2025 18:37:48 +0100 Subject: [PATCH 31/32] fix v1 tests after v2 became the default As of 2ccd97cd48, v2 is the default when using the unversioned includes. This broke the v1 tests which were still using those. --- test/v1/args_cmd.cpp | 4 +--- test/v1/args_handling.cpp | 2 +- test/v1/asio_no_deprecated.cpp | 27 +++++++++++++++++++-- test/v1/async.cpp | 2 +- test/v1/async_fut.cpp | 4 ++-- test/v1/async_pipe.cpp | 2 +- test/v1/async_system_fail.cpp | 2 +- test/v1/async_system_future.cpp | 2 +- test/v1/async_system_stackful.cpp | 2 +- test/v1/async_system_stackful_error.cpp | 2 +- test/v1/async_system_stackful_except.cpp | 2 +- test/v1/async_system_stackless.cpp | 2 +- test/v1/bind_stderr.cpp | 2 +- test/v1/bind_stdin.cpp | 2 +- test/v1/bind_stdin_stdout.cpp | 2 +- test/v1/bind_stdout.cpp | 2 +- test/v1/bind_stdout_stderr.cpp | 2 +- test/v1/close_stderr.cpp | 2 +- test/v1/close_stdin.cpp | 2 +- test/v1/close_stdout.cpp | 2 +- test/v1/cmd_test.cpp | 2 +- test/v1/env.cpp | 2 +- test/v1/environment.cpp | 2 +- test/v1/error.cpp | 2 +- test/v1/exit_code.cpp | 2 +- test/v1/extensions.cpp | 2 +- test/v1/group.cpp | 2 +- test/v1/group_wait.cpp | 2 +- test/v1/limit_fd.cpp | 7 ++---- test/v1/multi_ref1.cpp | 30 +++++++++++++++++++++++- test/v1/multi_ref2.cpp | 30 +++++++++++++++++++++++- test/v1/no_ansi_apps.cpp | 27 ++++++++++++++++++++- test/v1/on_exit.cpp | 5 ++-- test/v1/on_exit2.cpp | 5 ++-- test/v1/on_exit3.cpp | 5 ++-- test/v1/pipe.cpp | 2 +- test/v1/pipe_fwd.cpp | 2 +- test/v1/posix_specific.cpp | 12 ++++++---- test/v1/run_exe.cpp | 2 +- test/v1/run_exe_path.cpp | 2 +- test/v1/search_path.cpp | 2 +- test/v1/shell.cpp | 2 +- test/v1/shell_path.cpp | 2 +- test/v1/spawn.cpp | 2 +- test/v1/spawn_fail.cpp | 2 +- test/v1/start_dir.cpp | 11 ++++++--- test/v1/sub_launcher.cpp | 6 +++-- test/v1/system_test1.cpp | 2 +- test/v1/system_test2.cpp | 2 +- test/v1/terminate.cpp | 2 +- test/v1/throw_on_error.cpp | 4 ++-- test/v1/vfork.cpp | 4 ++-- test/v1/wait.cpp | 2 +- test/v1/wait_for.cpp | 2 +- test/v1/wargs_cmd.cpp | 2 +- test/v1/windows_specific.cpp | 4 ++-- 56 files changed, 189 insertions(+), 76 deletions(-) diff --git a/test/v1/args_cmd.cpp b/test/v1/args_cmd.cpp index 68d649573..70f531578 100644 --- a/test/v1/args_cmd.cpp +++ b/test/v1/args_cmd.cpp @@ -21,9 +21,7 @@ #include -namespace bp = boost::process; - -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(args, *boost::unit_test::timeout(2)) { diff --git a/test/v1/args_handling.cpp b/test/v1/args_handling.cpp index fefa7d525..459e7dff2 100644 --- a/test/v1/args_handling.cpp +++ b/test/v1/args_handling.cpp @@ -19,7 +19,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(implicit_args_fs_path) diff --git a/test/v1/asio_no_deprecated.cpp b/test/v1/asio_no_deprecated.cpp index eb48233dd..f991cf359 100644 --- a/test/v1/asio_no_deprecated.cpp +++ b/test/v1/asio_no_deprecated.cpp @@ -3,11 +3,34 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #define BOOST_ASIO_NO_DEPRECATED 1 -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + int main() {} #if defined(BOOST_POSIX_API) #include #else #include -#endif \ No newline at end of file +#endif diff --git a/test/v1/async.cpp b/test/v1/async.cpp index 0adac13a8..31197aed6 100644 --- a/test/v1/async.cpp +++ b/test/v1/async.cpp @@ -25,7 +25,7 @@ using namespace std; -namespace bp = boost::process; +namespace bp = boost::process::v1; #if __APPLE__ auto abort_sig = signal(SIGALRM, +[](int){std::terminate();}); diff --git a/test/v1/async_fut.cpp b/test/v1/async_fut.cpp index 74275abaa..356f4087f 100644 --- a/test/v1/async_fut.cpp +++ b/test/v1/async_fut.cpp @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_SUITE( async ); using namespace std; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(async_out_future, *boost::unit_test::timeout(2)) { @@ -103,4 +103,4 @@ BOOST_AUTO_TEST_CASE(emtpy_out, *boost::unit_test::timeout(2)) BOOST_CHECK_EQUAL(fut.get(), ""); } -BOOST_AUTO_TEST_SUITE_END(); \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END(); diff --git a/test/v1/async_pipe.cpp b/test/v1/async_pipe.cpp index 17e2a9f24..7ae3735ea 100644 --- a/test/v1/async_pipe.cpp +++ b/test/v1/async_pipe.cpp @@ -20,7 +20,7 @@ #include using namespace std; -namespace bp = boost::process; +namespace bp = boost::process::v1; namespace asio = boost::asio; BOOST_AUTO_TEST_SUITE( async ); diff --git a/test/v1/async_system_fail.cpp b/test/v1/async_system_fail.cpp index 28699f301..866d80dd9 100644 --- a/test/v1/async_system_fail.cpp +++ b/test/v1/async_system_fail.cpp @@ -18,7 +18,7 @@ #include #include -namespace bp = boost::process;; +namespace bp = boost::process::v1; void fail_func() { diff --git a/test/v1/async_system_future.cpp b/test/v1/async_system_future.cpp index 009fe4953..48b8999f2 100644 --- a/test/v1/async_system_future.cpp +++ b/test/v1/async_system_future.cpp @@ -23,7 +23,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_SUITE( async ); BOOST_AUTO_TEST_CASE(future, *boost::unit_test::timeout(15)) diff --git a/test/v1/async_system_stackful.cpp b/test/v1/async_system_stackful.cpp index bc6fc424e..68d966d7d 100644 --- a/test/v1/async_system_stackful.cpp +++ b/test/v1/async_system_stackful.cpp @@ -27,7 +27,7 @@ #include BOOST_AUTO_TEST_SUITE( async ); -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15)) { using boost::unit_test::framework::master_test_suite; diff --git a/test/v1/async_system_stackful_error.cpp b/test/v1/async_system_stackful_error.cpp index be0ce8a91..35cf6f4d7 100644 --- a/test/v1/async_system_stackful_error.cpp +++ b/test/v1/async_system_stackful_error.cpp @@ -26,7 +26,7 @@ #include BOOST_AUTO_TEST_SUITE( async ); -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15)) { using boost::unit_test::framework::master_test_suite; diff --git a/test/v1/async_system_stackful_except.cpp b/test/v1/async_system_stackful_except.cpp index 0efb34fde..d4d3051e4 100644 --- a/test/v1/async_system_stackful_except.cpp +++ b/test/v1/async_system_stackful_except.cpp @@ -26,7 +26,7 @@ #include BOOST_AUTO_TEST_SUITE( async ); -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(stackful_except, *boost::unit_test::timeout(15)) { using boost::unit_test::framework::master_test_suite; diff --git a/test/v1/async_system_stackless.cpp b/test/v1/async_system_stackless.cpp index f5ba6c07a..9dccf6993 100644 --- a/test/v1/async_system_stackless.cpp +++ b/test/v1/async_system_stackless.cpp @@ -25,7 +25,7 @@ #include BOOST_AUTO_TEST_SUITE( async ); -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(stackless, *boost::unit_test::timeout(15)) { using boost::unit_test::framework::master_test_suite; diff --git a/test/v1/bind_stderr.cpp b/test/v1/bind_stderr.cpp index 3750eb275..7e2e083cb 100644 --- a/test/v1/bind_stderr.cpp +++ b/test/v1/bind_stderr.cpp @@ -39,7 +39,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end; #endif namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_SUITE( bind_stderr ); BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(2)) diff --git a/test/v1/bind_stdin.cpp b/test/v1/bind_stdin.cpp index d539c695e..2a0bb78c8 100644 --- a/test/v1/bind_stdin.cpp +++ b/test/v1/bind_stdin.cpp @@ -43,7 +43,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end; namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(10)) { diff --git a/test/v1/bind_stdin_stdout.cpp b/test/v1/bind_stdin_stdout.cpp index 6cf4b1b05..b43a3111b 100644 --- a/test/v1/bind_stdin_stdout.cpp +++ b/test/v1/bind_stdin_stdout.cpp @@ -22,7 +22,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_SUITE( bind_stdin_stdout ); BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(10)) diff --git a/test/v1/bind_stdout.cpp b/test/v1/bind_stdout.cpp index f07125f0b..3a1a1f2f4 100644 --- a/test/v1/bind_stdout.cpp +++ b/test/v1/bind_stdout.cpp @@ -42,7 +42,7 @@ BOOST_AUTO_TEST_SUITE( bind_stdout ); namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(5)) { diff --git a/test/v1/bind_stdout_stderr.cpp b/test/v1/bind_stdout_stderr.cpp index 228cb9c68..c3d9dad40 100644 --- a/test/v1/bind_stdout_stderr.cpp +++ b/test/v1/bind_stdout_stderr.cpp @@ -34,7 +34,7 @@ typedef boost::asio::windows::stream_handle pipe_end; typedef boost::asio::posix::stream_descriptor pipe_end; #endif -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_SUITE( bind_stdout_stderr ); diff --git a/test/v1/close_stderr.cpp b/test/v1/close_stderr.cpp index b0811ffb8..bd08169d1 100644 --- a/test/v1/close_stderr.cpp +++ b/test/v1/close_stderr.cpp @@ -22,7 +22,7 @@ # include #endif -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(close_stderr) diff --git a/test/v1/close_stdin.cpp b/test/v1/close_stdin.cpp index 347860d9a..46f08307e 100644 --- a/test/v1/close_stdin.cpp +++ b/test/v1/close_stdin.cpp @@ -22,7 +22,7 @@ # include #endif -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(close_stdin) { diff --git a/test/v1/close_stdout.cpp b/test/v1/close_stdout.cpp index 3b31e77d7..70d6c611a 100644 --- a/test/v1/close_stdout.cpp +++ b/test/v1/close_stdout.cpp @@ -22,7 +22,7 @@ # include #endif -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(close_stdout) { diff --git a/test/v1/cmd_test.cpp b/test/v1/cmd_test.cpp index 4d5078a95..4e9013f98 100644 --- a/test/v1/cmd_test.cpp +++ b/test/v1/cmd_test.cpp @@ -26,7 +26,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; namespace fs = boost::process::v1::filesystem; diff --git a/test/v1/env.cpp b/test/v1/env.cpp index 31132bbf5..f236e4214 100644 --- a/test/v1/env.cpp +++ b/test/v1/env.cpp @@ -27,7 +27,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(inherit_env, *boost::unit_test::timeout(2)) { diff --git a/test/v1/environment.cpp b/test/v1/environment.cpp index 74952c2eb..8e747cf18 100644 --- a/test/v1/environment.cpp +++ b/test/v1/environment.cpp @@ -12,7 +12,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; namespace std diff --git a/test/v1/error.cpp b/test/v1/error.cpp index 83cb9a383..d2652c745 100644 --- a/test/v1/error.cpp +++ b/test/v1/error.cpp @@ -19,7 +19,7 @@ -namespace bp = boost::process; +namespace bp = boost::process::v1; struct err_set { diff --git a/test/v1/exit_code.cpp b/test/v1/exit_code.cpp index 8335033d0..cac8e263c 100644 --- a/test/v1/exit_code.cpp +++ b/test/v1/exit_code.cpp @@ -26,7 +26,7 @@ typedef boost::asio::windows::stream_handle pipe_end; typedef boost::asio::posix::stream_descriptor pipe_end; #endif -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(sync_wait, *boost::unit_test::timeout(10)) { diff --git a/test/v1/extensions.cpp b/test/v1/extensions.cpp index 46de3e39f..b079d6ee6 100644 --- a/test/v1/extensions.cpp +++ b/test/v1/extensions.cpp @@ -17,7 +17,7 @@ #include -namespace bp = boost::process; +namespace bp = boost::process::v1; struct run_exe diff --git a/test/v1/group.cpp b/test/v1/group.cpp index ae70dfd7f..41173835d 100644 --- a/test/v1/group.cpp +++ b/test/v1/group.cpp @@ -29,7 +29,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(group_test, *boost::unit_test::timeout(5)) { diff --git a/test/v1/group_wait.cpp b/test/v1/group_wait.cpp index 93eb15e9e..ccc512ac8 100644 --- a/test/v1/group_wait.cpp +++ b/test/v1/group_wait.cpp @@ -30,7 +30,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; diff --git a/test/v1/limit_fd.cpp b/test/v1/limit_fd.cpp index 2c2cb8716..df76b9759 100644 --- a/test/v1/limit_fd.cpp +++ b/test/v1/limit_fd.cpp @@ -7,9 +7,7 @@ #define BOOST_TEST_IGNORE_SIGCHLD #include -#include - -#include +#include #include #include #include @@ -32,8 +30,7 @@ #include #endif -namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; namespace bt = boost::this_process; BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5)) diff --git a/test/v1/multi_ref1.cpp b/test/v1/multi_ref1.cpp index 9ba9027d7..2301f5cc8 100644 --- a/test/v1/multi_ref1.cpp +++ b/test/v1/multi_ref1.cpp @@ -4,4 +4,32 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_POSIX_API) +#include +#else +#include +#endif diff --git a/test/v1/multi_ref2.cpp b/test/v1/multi_ref2.cpp index 450ed5b5e..1896ba252 100644 --- a/test/v1/multi_ref2.cpp +++ b/test/v1/multi_ref2.cpp @@ -3,4 +3,32 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_POSIX_API) +#include +#else +#include +#endif diff --git a/test/v1/no_ansi_apps.cpp b/test/v1/no_ansi_apps.cpp index fcd09dd8c..561025c17 100644 --- a/test/v1/no_ansi_apps.cpp +++ b/test/v1/no_ansi_apps.cpp @@ -6,5 +6,30 @@ #include #if defined(BOOST_WINDOWS_API) #define BOOST_NO_ANSI_APIS 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif -#include \ No newline at end of file + +int main() {} diff --git a/test/v1/on_exit.cpp b/test/v1/on_exit.cpp index e46e2ea84..c1f96fb2b 100644 --- a/test/v1/on_exit.cpp +++ b/test/v1/on_exit.cpp @@ -10,7 +10,8 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_IGNORE_SIGCHLD #include -#include +#include +#include #include #include #include @@ -26,7 +27,7 @@ BOOST_AUTO_TEST_CASE(single_ios, *boost::unit_test::timeout(6)) return; } - namespace bp = boost::process; + namespace bp = boost::process::v1; boost::asio::io_context ios; std::chrono::steady_clock::time_point p1, p2; diff --git a/test/v1/on_exit2.cpp b/test/v1/on_exit2.cpp index 20d401bb5..e6c219254 100644 --- a/test/v1/on_exit2.cpp +++ b/test/v1/on_exit2.cpp @@ -10,7 +10,8 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_IGNORE_SIGCHLD #include -#include +#include +#include #include #include #include @@ -26,7 +27,7 @@ BOOST_AUTO_TEST_CASE(double_ios, *boost::unit_test::timeout(6)) return; } - namespace bp = boost::process; + namespace bp = boost::process::v1; boost::asio::io_context ios; std::chrono::steady_clock::time_point p1, p2; diff --git a/test/v1/on_exit3.cpp b/test/v1/on_exit3.cpp index 84fe6845c..b69a63e1f 100644 --- a/test/v1/on_exit3.cpp +++ b/test/v1/on_exit3.cpp @@ -10,7 +10,8 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_IGNORE_SIGCHLD #include -#include +#include +#include #include #include #include @@ -26,7 +27,7 @@ BOOST_AUTO_TEST_CASE(double_ios_threaded, *boost::unit_test::timeout(6)) return; } - namespace bp = boost::process; + namespace bp = boost::process::v1; boost::asio::io_context ios; std::chrono::steady_clock::time_point p1, p2; diff --git a/test/v1/pipe.cpp b/test/v1/pipe.cpp index e32bbe066..f90054c26 100644 --- a/test/v1/pipe.cpp +++ b/test/v1/pipe.cpp @@ -14,7 +14,7 @@ #include using namespace std; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_SUITE( pipe_tests ); diff --git a/test/v1/pipe_fwd.cpp b/test/v1/pipe_fwd.cpp index 575a8e764..d346e93bd 100644 --- a/test/v1/pipe_fwd.cpp +++ b/test/v1/pipe_fwd.cpp @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_SUITE( pipe_tests ); -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(5)) { diff --git a/test/v1/posix_specific.cpp b/test/v1/posix_specific.cpp index e46e73414..480522ad7 100644 --- a/test/v1/posix_specific.cpp +++ b/test/v1/posix_specific.cpp @@ -11,10 +11,14 @@ #define BOOST_TEST_IGNORE_SIGCHLD #include -#include -#include - +#include +#include #include +#include +#include +#include +#include +#include #if !defined(BOOST_PROCESS_USE_STD_FS) #include @@ -29,7 +33,7 @@ #include namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(bind_fd, *boost::unit_test::timeout(2)) { diff --git a/test/v1/run_exe.cpp b/test/v1/run_exe.cpp index 3e3b86005..b49440f74 100644 --- a/test/v1/run_exe.cpp +++ b/test/v1/run_exe.cpp @@ -15,7 +15,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; int main(int argc, char* argv[]) { diff --git a/test/v1/run_exe_path.cpp b/test/v1/run_exe_path.cpp index d40f71afc..a5e1f8d87 100644 --- a/test/v1/run_exe_path.cpp +++ b/test/v1/run_exe_path.cpp @@ -18,7 +18,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(run_exe_success) diff --git a/test/v1/search_path.cpp b/test/v1/search_path.cpp index 9f149e8ea..4a090af1e 100644 --- a/test/v1/search_path.cpp +++ b/test/v1/search_path.cpp @@ -13,7 +13,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; namespace fs = boost::process::v1::filesystem; BOOST_AUTO_TEST_CASE(search_path) diff --git a/test/v1/shell.cpp b/test/v1/shell.cpp index 8c5e9c3a9..9349506db 100644 --- a/test/v1/shell.cpp +++ b/test/v1/shell.cpp @@ -22,7 +22,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(shell_simple, *boost::unit_test::timeout(5)) diff --git a/test/v1/shell_path.cpp b/test/v1/shell_path.cpp index 0b5d560a7..5c53b66c5 100644 --- a/test/v1/shell_path.cpp +++ b/test/v1/shell_path.cpp @@ -13,7 +13,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(shell_set_on_error) { diff --git a/test/v1/spawn.cpp b/test/v1/spawn.cpp index e952ff4b9..76207ec60 100644 --- a/test/v1/spawn.cpp +++ b/test/v1/spawn.cpp @@ -39,7 +39,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end; #endif namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(sync_spawn, *boost::unit_test::timeout(5)) { diff --git a/test/v1/spawn_fail.cpp b/test/v1/spawn_fail.cpp index c6b5c9490..c79d32d60 100644 --- a/test/v1/spawn_fail.cpp +++ b/test/v1/spawn_fail.cpp @@ -35,7 +35,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end; #endif namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; int main() { diff --git a/test/v1/start_dir.cpp b/test/v1/start_dir.cpp index 14cc7fc45..d77780e9a 100644 --- a/test/v1/start_dir.cpp +++ b/test/v1/start_dir.cpp @@ -10,14 +10,19 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_IGNORE_SIGCHLD #include -#include #include +#include +#include +#include #include +#include +#include +#include #include + #include -#include -namespace bp = boost::process; +namespace bp = boost::process::v1; struct test_dir diff --git a/test/v1/sub_launcher.cpp b/test/v1/sub_launcher.cpp index 3579b3bf0..35c752d31 100644 --- a/test/v1/sub_launcher.cpp +++ b/test/v1/sub_launcher.cpp @@ -2,7 +2,9 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include +#include +#include #include #include @@ -20,7 +22,7 @@ int main(int argc, char *argv[]) { using namespace std; using namespace boost::program_options; - using namespace boost::process; + using namespace boost::process::v1; bool launch_detached = false; bool launch_attached = false; diff --git a/test/v1/system_test1.cpp b/test/v1/system_test1.cpp index 612af9aef..23c218505 100644 --- a/test/v1/system_test1.cpp +++ b/test/v1/system_test1.cpp @@ -44,7 +44,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end; #endif namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(system_exit_code, *boost::unit_test::timeout(5)) { diff --git a/test/v1/system_test2.cpp b/test/v1/system_test2.cpp index c4bb7ab56..0ab809af5 100644 --- a/test/v1/system_test2.cpp +++ b/test/v1/system_test2.cpp @@ -38,7 +38,7 @@ #include namespace fs = boost::process::v1::filesystem; -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(explicit_async_io, *boost::unit_test::timeout(2)) { diff --git a/test/v1/terminate.cpp b/test/v1/terminate.cpp index 2a19598bc..b625ea8fe 100644 --- a/test/v1/terminate.cpp +++ b/test/v1/terminate.cpp @@ -20,7 +20,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(terminate_set_on_error, *boost::unit_test::timeout(5)) { diff --git a/test/v1/throw_on_error.cpp b/test/v1/throw_on_error.cpp index 56fb54e17..8f0962b2c 100644 --- a/test/v1/throw_on_error.cpp +++ b/test/v1/throw_on_error.cpp @@ -9,11 +9,11 @@ #include -#include +#include #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; int main(int argc, char* argv[]) { diff --git a/test/v1/vfork.cpp b/test/v1/vfork.cpp index 2bfc3fa7f..ddaef41df 100644 --- a/test/v1/vfork.cpp +++ b/test/v1/vfork.cpp @@ -11,7 +11,7 @@ #define BOOST_TEST_IGNORE_SIGCHLD #include -#include +#include #include #include @@ -21,7 +21,7 @@ #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; #if defined(BOOST_POSIX_HAS_VFORK) diff --git a/test/v1/wait.cpp b/test/v1/wait.cpp index b703f2e1d..73a093f98 100644 --- a/test/v1/wait.cpp +++ b/test/v1/wait.cpp @@ -22,7 +22,7 @@ # include #endif -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_SUITE( wait_test ); diff --git a/test/v1/wait_for.cpp b/test/v1/wait_for.cpp index 4dd5c3166..04f17dc96 100644 --- a/test/v1/wait_for.cpp +++ b/test/v1/wait_for.cpp @@ -21,7 +21,7 @@ # include #endif -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_SUITE( wait_test); BOOST_AUTO_TEST_CASE(wait_for) diff --git a/test/v1/wargs_cmd.cpp b/test/v1/wargs_cmd.cpp index 53756c065..e2beec803 100644 --- a/test/v1/wargs_cmd.cpp +++ b/test/v1/wargs_cmd.cpp @@ -21,7 +21,7 @@ #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(wargs, *boost::unit_test::timeout(2)) diff --git a/test/v1/windows_specific.cpp b/test/v1/windows_specific.cpp index 59b6c2214..fd999a969 100644 --- a/test/v1/windows_specific.cpp +++ b/test/v1/windows_specific.cpp @@ -10,14 +10,14 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_IGNORE_SIGCHLD #include -#include +#include #include #include #include #include -namespace bp = boost::process; +namespace bp = boost::process::v1; BOOST_AUTO_TEST_CASE(show_window) { From 8ae055bfbd4269560b9a65e2b4425d57fd44bdcc Mon Sep 17 00:00:00 2001 From: SimonMaracine Date: Tue, 14 Jan 2025 15:58:08 +0200 Subject: [PATCH 32/32] Remove optional dependency on filesystem when not meant to be Build previously failed when BOOST_PROCESS_USE_STD_FS was ON, because filesystem was linked to regardless. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a732519c1..19826d337 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,6 @@ target_link_libraries(boost_process Boost::asio Boost::config Boost::core - Boost::filesystem Boost::fusion Boost::iterator Boost::move