forward.cpp 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #include <iostream>
  2. #include <reproc++/drain.hpp>
  3. #include <reproc++/reproc.hpp>
  4. static int fail(std::error_code ec)
  5. {
  6. std::cerr << ec.message();
  7. return ec.value();
  8. }
  9. // The forward example forwards the program arguments to a child process and
  10. // prints its output on stdout.
  11. //
  12. // Example: "./forward cmake --help" will print CMake's help output.
  13. //
  14. // This program can be used to verify that manually executing a command and
  15. // executing it using reproc produces the same output.
  16. int main(int argc, const char **argv)
  17. {
  18. if (argc <= 1) {
  19. std::cerr << "No arguments provided. Example usage: ./forward cmake --help";
  20. return EXIT_FAILURE;
  21. }
  22. reproc::process process;
  23. // Stop actions can be passed to both `process::start` (via `options`) and
  24. // `process::stop`. Stop actions passed to `process::start` are passed to
  25. // `process::stop` in the `process` destructor. This can be used to make sure
  26. // that a child process is always stopped correctly when its corresponding
  27. // `process` instance is destroyed.
  28. //
  29. // Any program can be started with forward so we make sure the child process
  30. // is cleaned up correctly by specifying `reproc::terminate` which sends
  31. // `SIGTERM` (POSIX) or `CTRL-BREAK` (Windows) and waits five seconds. We also
  32. // add the `reproc::kill` flag which sends `SIGKILL` (POSIX) or calls
  33. // `TerminateProcess` (Windows) if the process hasn't exited after five
  34. // seconds and waits two more seconds for the child process to exit.
  35. //
  36. // If the `stop_actions` struct passed to `process::start` is
  37. // default-initialized, the `process` destructor will wait indefinitely for
  38. // the child process to exit.
  39. //
  40. // Note that C++14 has chrono literals which allows
  41. // `reproc::milliseconds(5000)` to be replaced with `5000ms`.
  42. reproc::stop_actions stop = {
  43. { reproc::stop::noop, reproc::milliseconds(0) },
  44. { reproc::stop::terminate, reproc::milliseconds(5000) },
  45. { reproc::stop::kill, reproc::milliseconds(2000) }
  46. };
  47. reproc::options options;
  48. options.stop = stop;
  49. // We have the child process inherit the parent's standard streams so the
  50. // child process reads directly from the stdin and writes directly to the
  51. // stdout/stderr of the parent process.
  52. options.redirect.parent = true;
  53. // Exclude `argv[0]` which is the current program's name.
  54. std::error_code ec = process.start(argv + 1, options);
  55. if (ec == std::errc::no_such_file_or_directory) {
  56. std::cerr << "Program not found. Make sure it's available from the PATH.";
  57. return ec.value();
  58. } else if (ec) {
  59. return fail(ec);
  60. }
  61. // Call `process::stop` manually so we can access the exit status. We add
  62. // `reproc::wait` with a timeout of ten seconds to give the process time to
  63. // exit on its own before sending `SIGTERM`.
  64. options.stop.first = { reproc::stop::wait, reproc::milliseconds(10000) };
  65. int status = 0;
  66. std::tie(status, ec) = process.stop(options.stop);
  67. if (ec) {
  68. return fail(ec);
  69. }
  70. return status;
  71. }