uvw  1.3.0
process.hpp
1 #pragma once
2 
3 
4 #include <algorithm>
5 #include <utility>
6 #include <memory>
7 #include <string>
8 #include <vector>
9 #include <uv.h>
10 #include "handle.hpp"
11 #include "stream.hpp"
12 #include "util.hpp"
13 #include "loop.hpp"
14 
15 
16 namespace uvw {
17 
18 
19 namespace details {
20 
21 
22 enum class UVProcessFlags: std::underlying_type_t<uv_process_flags> {
23  SETUID = UV_PROCESS_SETUID,
24  SETGID = UV_PROCESS_SETGID,
25  WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
26  DETACHED = UV_PROCESS_DETACHED,
27  WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE
28 };
29 
30 
31 enum class UVStdIOFlags: std::underlying_type_t<uv_stdio_flags> {
32  IGNORE_STREAM = UV_IGNORE,
33  CREATE_PIPE = UV_CREATE_PIPE,
34  INHERIT_FD = UV_INHERIT_FD,
35  INHERIT_STREAM = UV_INHERIT_STREAM,
36  READABLE_PIPE = UV_READABLE_PIPE,
37  WRITABLE_PIPE = UV_WRITABLE_PIPE
38 };
39 
40 
41 }
42 
43 
49 struct ExitEvent {
50  explicit ExitEvent(int64_t code, int sig) noexcept
51  : status{code}, signal{sig}
52  {}
53 
54  int64_t status;
55  int signal;
56 };
57 
64 class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> {
65  static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) {
66  ProcessHandle &process = *(static_cast<ProcessHandle*>(handle->data));
67  process.publish(ExitEvent{exitStatus, termSignal});
68  }
69 
70 public:
71  using Process = details::UVProcessFlags;
72  using StdIO = details::UVStdIOFlags;
73 
74  ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref)
75  : Handle{ca, std::move(ref)}, poFdStdio{1}
76  {
77  // stdin container default initialization
78  poFdStdio[0].flags = static_cast<uv_stdio_flags>(StdIO::IGNORE_STREAM);
79  }
80 
95  static void disableStdIOInheritance() noexcept {
96  uv_disable_stdio_inheritance();
97  }
98 
105  static bool kill(int pid, int signum) noexcept {
106  return (0 == uv_kill(pid, signum));
107  }
108 
113  bool init() {
114  // deferred initialization: libuv initializes process handles only when
115  // uv_spawn is invoked and uvw stays true to the underlying library
116  return true;
117  }
118 
133  void spawn(const char *file, char **args, char **env = nullptr) {
134  uv_process_options_t po;
135 
136  po.exit_cb = &exitCallback;
137 
138  po.file = file;
139  po.args = args;
140  po.env = env;
141  po.cwd = poCwd.empty() ? nullptr : poCwd.data();
142  po.flags = poFlags;
143  po.uid = poUid;
144  po.gid = poGid;
145 
153  std::vector<uv_stdio_container_t> poStdio{poFdStdio.size() + poStreamStdio.size()};
154  poStdio.insert(poStdio.begin(), poStreamStdio.cbegin(), poStreamStdio.cend());
155  poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());
156  po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
157  po.stdio = poStdio.data();
158 
159  // fake initialization so as to have leak invoked
160  // see init member function for more details
161  initialize([](auto...){ return 0; });
162 
163  invoke(&uv_spawn, parent(), get(), &po);
164  }
165 
170  void kill(int signum) {
171  invoke(&uv_process_kill, get(), signum);
172  }
173 
181  int pid() noexcept {
182  return get()->pid;
183  }
184 
190  ProcessHandle & cwd(std::string path) noexcept {
191  poCwd = path;
192  return *this;
193  }
194 
213  ProcessHandle & flags(Flags<Process> flags) noexcept {
214  poFlags = flags;
215  return *this;
216  }
217 
238  template<typename T, typename U>
240  uv_stdio_container_t container;
241  Flags<StdIO>::Type fgs = flags;
242  container.flags = static_cast<uv_stdio_flags>(fgs);
243  container.data.stream = get<uv_stream_t>(stream);
244  poStreamStdio.push_back(std::move(container));
245  return *this;
246  }
247 
274  auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags});
275 
276  auto actual = FileHandle::Type{fd};
277 
278  if(actual == FileHandle::Type{StdIN}) {
279  poFdStdio[0].flags = fgs;
280  } else {
281  auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container){
282  return container.data.fd == actual;
283  });
284 
285  if(it == poFdStdio.cend()) {
286  uv_stdio_container_t container;
287  container.flags = fgs;
288  container.data.fd = actual;
289  poFdStdio.push_back(std::move(container));
290  } else {
291  it->flags = fgs;
292  it->data.fd = actual;
293  }
294  }
295 
296  return *this;
297  }
298 
305  poUid = id;
306  return *this;
307  }
308 
315  poGid = id;
316  return *this;
317  }
318 
319 private:
320  std::string poCwd;
321  Flags<Process> poFlags;
322  std::vector<uv_stdio_container_t> poFdStdio;
323  std::vector<uv_stdio_container_t> poStreamStdio;
324  Uid poUid;
325  Gid poGid;
326 };
327 
328 
329 }
ProcessHandle & stdio(FileHandle fd, Flags< StdIO > flags)
Makes a file descriptor available to the child process.
Definition: process.hpp:273
ProcessHandle & cwd(std::string path) noexcept
Sets the current working directory for the subprocess.
Definition: process.hpp:190
int64_t status
Definition: process.hpp:54
details::UVTypeWrapper< uv_file > FileHandle
Definition: util.hpp:186
bool init()
Initializes the handle.
Definition: process.hpp:113
void spawn(const char *file, char **args, char **env=nullptr)
spawn Starts the process.
Definition: process.hpp:133
constexpr FileHandle StdIN
Definition: util.hpp:190
ProcessHandle & stdio(StreamHandle< T, U > &stream, Flags< StdIO > flags)
Makes a stdio handle available to the child process.
Definition: process.hpp:239
Handle base class.
Definition: handle.hpp:29
static void disableStdIOInheritance() noexcept
Disables inheritance for file descriptors/handles.
Definition: process.hpp:95
The StreamHandle handle.
Definition: stream.hpp:130
The ProcessHandle handle.
Definition: process.hpp:64
uv_gid_t Gid
Definition: util.hpp:197
uv_uid_t Uid
Definition: util.hpp:196
int pid() noexcept
Gets the PID of the spawned process.
Definition: process.hpp:181
ProcessHandle & flags(Flags< Process > flags) noexcept
Sets flags that control how spawn() behaves.
Definition: process.hpp:213
static bool kill(int pid, int signum) noexcept
kill Sends the specified signal to the given PID.
Definition: process.hpp:105
ProcessHandle & uid(Uid id)
Sets the child process&#39; user id.
Definition: process.hpp:304
ExitEvent event.
Definition: process.hpp:49
ProcessHandle & gid(Gid id)
Sets the child process&#39; group id.
Definition: process.hpp:314
void kill(int signum)
Sends the specified signal to the internal process handle.
Definition: process.hpp:170
uvw default namespace.
Definition: async.hpp:11