bind_fd.hpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Copyright (c) 2022 Klemens D. Morgenstern
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_PROCESS_V2_POSIX_BIND_FD_HPP
  6. #define BOOST_PROCESS_V2_POSIX_BIND_FD_HPP
  7. #include <boost/process/v2/detail/config.hpp>
  8. #include <boost/process/v2/default_launcher.hpp>
  9. #include <fcntl.h>
  10. BOOST_PROCESS_V2_BEGIN_NAMESPACE
  11. namespace posix
  12. {
  13. /// Utility class to bind a file descriptor to an explicit file descriptor for the child process.
  14. struct bind_fd
  15. {
  16. int target;
  17. int fd;
  18. bool fd_needs_closing{false};
  19. ~bind_fd()
  20. {
  21. if (fd_needs_closing)
  22. ::close(fd);
  23. }
  24. bind_fd() = delete;
  25. /// Inherit file descriptor with the same value.
  26. /**
  27. * This will pass descriptor 42 as 42 to the child process:
  28. * @code
  29. * process p{"test", {}, posix::bind_fd(42)};
  30. * @endcode
  31. */
  32. bind_fd(int target) : target(target), fd(target) {}
  33. /// Inherit an asio io-object as a given file descriptor to the child process.
  34. /**
  35. * This will pass the tcp::socket, as 42 to the child process:
  36. * @code
  37. * extern tcp::socket sock;
  38. * process p{"test", {}, posix::bind_fd(42, sock)};
  39. * @endcode
  40. */
  41. template<typename Stream>
  42. bind_fd(int target, Stream && str, decltype(std::declval<Stream>().native_handle()) = -1)
  43. : bind_fd(target, str.native_handle())
  44. {}
  45. /// Inherit a `FILE` as a given file descriptor to the child process.
  46. /**
  47. * This will pass the given `FILE*`, as 42 to the child process:
  48. * @code
  49. * process p{"test", {}, posix::bind_fd(42, stderr)};
  50. * @endcode
  51. */
  52. bind_fd(int target, FILE * f) : bind_fd(target, fileno(f)) {}
  53. /// Inherit a file descriptor with as a different value.
  54. /**
  55. * This will pass 24 as 42 to the child process:
  56. * @code
  57. * process p{"test", {}, posix::bind_fd(42, 24)};
  58. * @endcode
  59. */
  60. bind_fd(int target, int fd) : target(target), fd(fd) {}
  61. /// Inherit a null device as a set descriptor.
  62. /**
  63. * This will pass 24 as 42 to the child process:
  64. * @code
  65. * process p{"test", {}, posix::bind_fd(42, nullptr)};
  66. * @endcode
  67. */
  68. bind_fd(int target, std::nullptr_t) : bind_fd(target, filesystem::path("/dev/null")) {}
  69. /// Inherit a newly opened-file as a set descriptor.
  70. /**
  71. * This will pass 24 as 42 to the child process:
  72. * @code
  73. * process p{"test", {}, posix::bind_fd(42, "extra-output.txt")};
  74. * @endcode
  75. */
  76. bind_fd(int target, const filesystem::path & pth, int flags = O_RDWR | O_CREAT)
  77. : target(target), fd(::open(pth.c_str(), flags, 0660)), fd_needs_closing(true)
  78. {
  79. }
  80. error_code on_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
  81. {
  82. launcher.fd_whitelist.push_back(target);
  83. return {};
  84. }
  85. /// Implementation of the initialization function.
  86. error_code on_exec_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
  87. {
  88. if (::dup2(fd, target) == -1)
  89. return error_code(errno, system_category());
  90. return error_code ();
  91. }
  92. };
  93. }
  94. BOOST_PROCESS_V2_END_NAMESPACE
  95. #endif //BOOST_PROCESS_V2_POSIX_BIND_FD_HPP