File indexing completed on 2025-01-18 09:50:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_PROCESS_V2_STDIO_HPP
0011 #define BOOST_PROCESS_V2_STDIO_HPP
0012
0013 #include <boost/process/v2/detail/config.hpp>
0014 #include <boost/process/v2/detail/last_error.hpp>
0015 #include <boost/process/v2/default_launcher.hpp>
0016 #include <cstddef>
0017 #if defined(BOOST_PROCESS_V2_STANDALONE)
0018 #include <asio/connect_pipe.hpp>
0019 #else
0020 #include <boost/asio/connect_pipe.hpp>
0021 #endif
0022
0023 #if defined(BOOST_PROCESS_V2_POSIX)
0024 #include <fcntl.h>
0025 #include <stdio.h>
0026 #include <unistd.h>
0027 #endif
0028
0029 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0030 namespace detail
0031 {
0032 #if defined(BOOST_PROCESS_V2_WINDOWS)
0033
0034 extern "C" intptr_t _get_osfhandle(int fd);
0035
0036 struct handle_closer
0037 {
0038 handle_closer() = default;
0039 handle_closer(bool close) : close(close) {}
0040 handle_closer(DWORD flags) : close(false), flags{flags} {}
0041
0042
0043 void operator()(HANDLE h) const
0044 {
0045 if (close)
0046 ::CloseHandle(h);
0047 else if (flags != 0xFFFFFFFFu)
0048 ::SetHandleInformation(h, 0xFFFFFFFFu, flags);
0049
0050 }
0051
0052 bool close{false};
0053 DWORD flags{0xFFFFFFFFu};
0054 };
0055
0056 template<DWORD Target>
0057 struct process_io_binding
0058 {
0059 HANDLE prepare()
0060 {
0061 auto hh = h.get();
0062 ::SetHandleInformation(hh, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
0063 return hh;
0064 }
0065
0066 std::unique_ptr<void, handle_closer> h{::GetStdHandle(Target), false};
0067
0068 static DWORD get_flags(HANDLE h)
0069 {
0070 DWORD res;
0071 if (!::GetHandleInformation(h, &res))
0072 {
0073 error_code ec;
0074 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
0075 throw system_error(ec, "get_flags");
0076 }
0077 return res;
0078 }
0079
0080 process_io_binding() = default;
0081
0082 template<typename Stream>
0083 process_io_binding(Stream && str, decltype(std::declval<Stream>().native_handle()) = nullptr)
0084 : process_io_binding(str.native_handle())
0085 {}
0086
0087 process_io_binding(FILE * f) : process_io_binding(_get_osfhandle(_fileno(f))) {}
0088 process_io_binding(HANDLE h) : h{h, get_flags(h)} {}
0089 process_io_binding(std::nullptr_t) : process_io_binding(filesystem::path("NUL")) {}
0090 template<typename T, typename = typename std::enable_if<std::is_same<T, filesystem::path>::value>::type>
0091 process_io_binding(const T & pth)
0092 : h(::CreateFileW(
0093 pth.c_str(),
0094 Target == STD_INPUT_HANDLE ? GENERIC_READ : GENERIC_WRITE,
0095 FILE_SHARE_READ | FILE_SHARE_WRITE,
0096 nullptr,
0097 OPEN_ALWAYS,
0098 FILE_ATTRIBUTE_NORMAL,
0099 nullptr
0100 ), true)
0101 {
0102 }
0103
0104
0105 template<typename Executor>
0106 process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_readable_pipe<Executor> & pipe)
0107 {
0108 if (Target == STD_INPUT_HANDLE)
0109 {
0110 auto h_ = pipe.native_handle();
0111 h = std::unique_ptr<void, handle_closer>{h_, get_flags(h_)};
0112 return ;
0113 }
0114
0115 BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::native_pipe_handle p[2];
0116 error_code ec;
0117 BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::create_pipe(p, ec);
0118 if (ec)
0119 detail::throw_error(ec, "create_pipe");
0120
0121 h = std::unique_ptr<void, handle_closer>{p[1], true};
0122 pipe.assign(p[0]);
0123 }
0124
0125
0126 template<typename Executor>
0127 process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor> & pipe)
0128 {
0129 if (Target != STD_INPUT_HANDLE)
0130 {
0131 auto h_ = pipe.native_handle();
0132 h = std::unique_ptr<void, handle_closer>{h_, get_flags(h_)};
0133 return ;
0134 }
0135 BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::native_pipe_handle p[2];
0136 error_code ec;
0137 BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::create_pipe(p, ec);
0138 if (ec)
0139 detail::throw_error(ec, "create_pipe");
0140
0141 h = std::unique_ptr<void, handle_closer>{p[0], true};
0142 pipe.assign(p[1]);
0143 }
0144 };
0145
0146 typedef process_io_binding<STD_INPUT_HANDLE> process_input_binding;
0147 typedef process_io_binding<STD_OUTPUT_HANDLE> process_output_binding;
0148 typedef process_io_binding<STD_ERROR_HANDLE> process_error_binding;
0149
0150 #else
0151
0152 template<int Target>
0153 struct process_io_binding
0154 {
0155 constexpr static int target = Target;
0156 int fd{target};
0157 bool fd_needs_closing{false};
0158 error_code ec;
0159
0160 ~process_io_binding()
0161 {
0162 if (fd_needs_closing)
0163 ::close(fd);
0164 }
0165
0166 process_io_binding() = default;
0167
0168 template<typename Stream>
0169 process_io_binding(Stream && str, decltype(std::declval<Stream>().native_handle()) = -1)
0170 : process_io_binding(str.native_handle())
0171 {}
0172
0173 process_io_binding(FILE * f) : process_io_binding(fileno(f)) {}
0174 process_io_binding(int fd) : fd(fd) {}
0175 process_io_binding(std::nullptr_t) : process_io_binding(filesystem::path("/dev/null")) {}
0176 process_io_binding(const filesystem::path & pth)
0177 : fd(::open(pth.c_str(),
0178 Target == STDIN_FILENO ? O_RDONLY : (O_WRONLY | O_CREAT),
0179 0660)), fd_needs_closing(true)
0180 {
0181 }
0182
0183 template<typename Executor>
0184 process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_readable_pipe<Executor> & readable_pipe)
0185 {
0186 if (Target == STDIN_FILENO)
0187 {
0188 fd = readable_pipe.native_handle();
0189 return ;
0190 }
0191
0192 BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::native_pipe_handle p[2];
0193 BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::create_pipe(p, ec);
0194 if (ec)
0195 detail::throw_error(ec, "create_pipe");
0196
0197 fd = p[1];
0198 if (::fcntl(p[0], F_SETFD, FD_CLOEXEC) == -1)
0199 {
0200 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0201 return ;
0202 }
0203 fd_needs_closing = true;
0204 readable_pipe.assign(p[0], ec);
0205 }
0206
0207
0208 template<typename Executor>
0209 process_io_binding(BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor> & writable_pipe)
0210 {
0211
0212 if (Target != STDIN_FILENO)
0213 {
0214 fd = writable_pipe.native_handle();
0215 return ;
0216 }
0217 BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::native_pipe_handle p[2];
0218 error_code ec;
0219 BOOST_PROCESS_V2_ASIO_NAMESPACE::detail::create_pipe(p, ec);
0220 if (ec)
0221 detail::throw_error(ec, "create_pipe");
0222
0223 fd = p[0];
0224 if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
0225 {
0226 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0227 return ;
0228 }
0229 fd_needs_closing = true;
0230 writable_pipe.assign(p[1], ec);
0231 }
0232
0233 error_code on_setup(posix::default_launcher &,
0234 const filesystem::path &, const char * const *)
0235 {
0236 return ec;
0237 }
0238
0239 error_code on_exec_setup(posix::default_launcher & launcher,
0240 const filesystem::path &, const char * const *)
0241 {
0242 if (::dup2(fd, target) == -1)
0243 return get_last_error();
0244 else
0245 return error_code();
0246 }
0247 };
0248
0249 typedef process_io_binding<STDIN_FILENO> process_input_binding;
0250 typedef process_io_binding<STDOUT_FILENO> process_output_binding;
0251 typedef process_io_binding<STDERR_FILENO> process_error_binding;
0252
0253 #endif
0254
0255 }
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297 struct process_stdio
0298 {
0299 detail::process_input_binding in;
0300 detail::process_output_binding out;
0301 detail::process_error_binding err;
0302
0303 #if defined(BOOST_PROCESS_V2_WINDOWS)
0304 error_code on_setup(windows::default_launcher & launcher, const filesystem::path &, const std::wstring &)
0305 {
0306
0307 launcher.startup_info.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
0308 launcher.startup_info.StartupInfo.hStdInput = in.prepare();
0309 launcher.startup_info.StartupInfo.hStdOutput = out.prepare();
0310 launcher.startup_info.StartupInfo.hStdError = err.prepare();
0311 launcher.inherit_handles = true;
0312 return error_code {};
0313 };
0314 #else
0315 error_code on_exec_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
0316 {
0317 if (::dup2(in.fd, in.target) == -1)
0318 return error_code(errno, system_category());
0319
0320 if (::dup2(out.fd, out.target) == -1)
0321 return error_code(errno, system_category());
0322
0323 if (::dup2(err.fd, err.target) == -1)
0324 return error_code(errno, system_category());
0325
0326 return error_code {};
0327 };
0328 #endif
0329
0330 };
0331
0332 BOOST_PROCESS_V2_END_NAMESPACE
0333
0334 #endif