1 #ifndef TINY_PROCESS_LIBRARY_HPP_ 2 #define TINY_PROCESS_LIBRARY_HPP_ 3 #include <functional> 4 #include <memory> 5 #include <mutex> 6 #include <string> 7 #include <thread> 8 #include <unordered_map> 9 #include <vector> 10 #ifndef _WIN32 11 #include <sys/wait.h> 12 #endif 13 14 namespace TinyProcessLib { 15 /// Additional parameters to Process constructors. 16 struct Config { 17 /// Buffer size for reading stdout and stderr. Default is 131072 (128 kB). 18 std::size_t buffer_size = 131072; 19 /// Set to true to inherit file descriptors from parent process. Default is false. 20 /// On Windows: has no effect unless read_stdout==nullptr, read_stderr==nullptr and open_stdin==false. 21 bool inherit_file_descriptors = false; 22 23 /// On Windows only: controls how the process is started, mimics STARTUPINFO's wShowWindow. 24 /// See: https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/ns-processthreadsapi-startupinfoa 25 /// and https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-showwindow 26 enum class ShowWindow { 27 hide = 0, 28 show_normal = 1, 29 show_minimized = 2, 30 maximize = 3, 31 show_maximized = 3, 32 show_no_activate = 4, 33 show = 5, 34 minimize = 6, 35 show_min_no_active = 7, 36 show_na = 8, 37 restore = 9, 38 show_default = 10, 39 force_minimize = 11 40 }; 41 /// On Windows only: controls how the window is shown. 42 ShowWindow show_window{ShowWindow::show_default}; 43 }; 44 45 /// Platform independent class for creating processes. 46 /// Note on Windows: it seems not possible to specify which pipes to redirect. 47 /// Thus, at the moment, if read_stdout==nullptr, read_stderr==nullptr and open_stdin==false, 48 /// the stdout, stderr and stdin are sent to the parent process instead. 49 class Process { 50 public: 51 #ifdef _WIN32 52 typedef unsigned long id_type; // Process id type 53 typedef void *fd_type; // File descriptor type 54 #ifdef UNICODE 55 typedef std::wstring string_type; 56 #else 57 typedef std::string string_type; 58 #endif 59 #else 60 typedef pid_t id_type; 61 typedef int fd_type; 62 typedef std::string string_type; 63 #endif 64 typedef std::unordered_map<string_type, string_type> environment_type; 65 66 private: 67 class Data { 68 public: 69 Data() noexcept; 70 id_type id; 71 #ifdef _WIN32 72 void *handle{nullptr}; 73 #endif 74 int exit_status{-1}; 75 }; 76 77 public: 78 /// Starts a process with the environment of the calling process. 79 Process(const std::vector<string_type> &arguments, const string_type &path = string_type(), 80 std::function<void(const char *bytes, size_t n)> read_stdout = nullptr, 81 std::function<void(const char *bytes, size_t n)> read_stderr = nullptr, 82 bool open_stdin = false, 83 const Config &config = {}) noexcept; 84 /// Starts a process with the environment of the calling process. 85 Process(const string_type &command, const string_type &path = string_type(), 86 std::function<void(const char *bytes, size_t n)> read_stdout = nullptr, 87 std::function<void(const char *bytes, size_t n)> read_stderr = nullptr, 88 bool open_stdin = false, 89 const Config &config = {}) noexcept; 90 91 /// Starts a process with specified environment. 92 Process(const std::vector<string_type> &arguments, 93 const string_type &path, 94 const environment_type &environment, 95 std::function<void(const char *bytes, size_t n)> read_stdout = nullptr, 96 std::function<void(const char *bytes, size_t n)> read_stderr = nullptr, 97 bool open_stdin = false, 98 const Config &config = {}) noexcept; 99 /// Starts a process with specified environment. 100 Process(const string_type &command, 101 const string_type &path, 102 const environment_type &environment, 103 std::function<void(const char *bytes, size_t n)> read_stdout = nullptr, 104 std::function<void(const char *bytes, size_t n)> read_stderr = nullptr, 105 bool open_stdin = false, 106 const Config &config = {}) noexcept; /// Starts a process with specified environment. 107 #ifndef _WIN32 108 /// Starts a process with the environment of the calling process. 109 /// Supported on Unix-like systems only. 110 Process(const std::function<void()> &function, 111 std::function<void(const char *bytes, size_t n)> read_stdout = nullptr, 112 std::function<void(const char *bytes, size_t n)> read_stderr = nullptr, 113 bool open_stdin = false, 114 const Config &config = {}) noexcept; 115 #endif 116 ~Process() noexcept; 117 118 /// Get the process id of the started process. 119 id_type get_id() const noexcept; 120 /// Wait until process is finished, and return exit status. 121 int get_exit_status() noexcept; 122 /// If process is finished, returns true and sets the exit status. Returns false otherwise. 123 bool try_get_exit_status(int &exit_status) noexcept; 124 /// Write to stdin. 125 bool write(const char *bytes, size_t n); 126 /// Write to stdin. Convenience function using write(const char *, size_t). 127 bool write(const std::string &str); 128 /// Close stdin. If the process takes parameters from stdin, use this to notify that all parameters have been sent. 129 void close_stdin() noexcept; 130 131 /// Kill the process. force=true is only supported on Unix-like systems. 132 void kill(bool force = false) noexcept; 133 /// Kill a given process id. Use kill(bool force) instead if possible. force=true is only supported on Unix-like systems. 134 static void kill(id_type id, bool force = false) noexcept; 135 #ifndef _WIN32 136 /// Send the signal signum to the process. 137 void signal(int signum) noexcept; 138 #endif 139 140 private: 141 Data data; 142 bool closed; 143 std::mutex close_mutex; 144 std::function<void(const char *bytes, size_t n)> read_stdout; 145 std::function<void(const char *bytes, size_t n)> read_stderr; 146 #ifndef _WIN32 147 std::thread stdout_stderr_thread; 148 #else 149 std::thread stdout_thread, stderr_thread; 150 #endif 151 bool open_stdin; 152 std::mutex stdin_mutex; 153 154 Config config; 155 156 std::unique_ptr<fd_type> stdout_fd, stderr_fd, stdin_fd; 157 158 id_type open(const std::vector<string_type> &arguments, const string_type &path, const environment_type *environment = nullptr) noexcept; 159 id_type open(const string_type &command, const string_type &path, const environment_type *environment = nullptr) noexcept; 160 #ifndef _WIN32 161 id_type open(const std::function<void()> &function) noexcept; 162 #endif 163 void async_read() noexcept; 164 void close_fds() noexcept; 165 }; 166 167 } // namespace TinyProcessLib 168 169 #endif // TINY_PROCESS_LIBRARY_HPP_ 170