uvw  1.10.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  OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE
39 };
40 
41 
42 }
43 
44 
50 struct ExitEvent {
51  explicit ExitEvent(int64_t code, int sig) noexcept
52  : status{code}, signal{sig}
53  {}
54 
55  int64_t status;
56  int signal;
57 };
58 
65 class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> {
66  static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) {
67  ProcessHandle &process = *(static_cast<ProcessHandle*>(handle->data));
68  process.publish(ExitEvent{exitStatus, termSignal});
69  }
70 
71 public:
72  using Process = details::UVProcessFlags;
73  using StdIO = details::UVStdIOFlags;
74 
75  ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref)
76  : Handle{ca, std::move(ref)}, poFdStdio{1}
77  {
78  // stdin container default initialization
79  poFdStdio[0].flags = static_cast<uv_stdio_flags>(StdIO::IGNORE_STREAM);
80  }
81 
96  static void disableStdIOInheritance() noexcept {
97  uv_disable_stdio_inheritance();
98  }
99 
106  static bool kill(int pid, int signum) noexcept {
107  return (0 == uv_kill(pid, signum));
108  }
109 
114  bool init() {
115  // deferred initialization: libuv initializes process handles only when
116  // uv_spawn is invoked and uvw stays true to the underlying library
117  return true;
118  }
119 
134  void spawn(const char *file, char **args, char **env = nullptr) {
135  uv_process_options_t po;
136 
137  po.exit_cb = &exitCallback;
138 
139  po.file = file;
140  po.args = args;
141  po.env = env;
142  po.cwd = poCwd.empty() ? nullptr : poCwd.data();
143  po.flags = poFlags;
144  po.uid = poUid;
145  po.gid = poGid;
146 
154  std::vector<uv_stdio_container_t> poStdio{poFdStdio.size() + poStreamStdio.size()};
155  poStdio.insert(poStdio.begin(), poStreamStdio.cbegin(), poStreamStdio.cend());
156  poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());
157  po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
158  po.stdio = poStdio.data();
159 
160  // fake initialization so as to have leak invoked
161  // see init member function for more details
162  initialize([](auto...){ return 0; });
163 
164  invoke(&uv_spawn, parent(), get(), &po);
165  }
166 
171  void kill(int signum) {
172  invoke(&uv_process_kill, get(), signum);
173  }
174 
182  int pid() noexcept {
183  return get()->pid;
184  }
185 
191  ProcessHandle & cwd(std::string path) noexcept {
192  poCwd = path;
193  return *this;
194  }
195 
214  ProcessHandle & flags(Flags<Process> flags) noexcept {
215  poFlags = flags;
216  return *this;
217  }
218 
240  template<typename T, typename U>
242  uv_stdio_container_t container;
243  Flags<StdIO>::Type fgs = flags;
244  container.flags = static_cast<uv_stdio_flags>(fgs);
245  container.data.stream = get<uv_stream_t>(stream);
246  poStreamStdio.push_back(std::move(container));
247  return *this;
248  }
249 
277  auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags});
278 
279  auto actual = FileHandle::Type{fd};
280 
281  if(actual == FileHandle::Type{StdIN}) {
282  poFdStdio[0].flags = fgs;
283  } else {
284  auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container){
285  return container.data.fd == actual;
286  });
287 
288  if(it == poFdStdio.cend()) {
289  uv_stdio_container_t container;
290  container.flags = fgs;
291  container.data.fd = actual;
292  poFdStdio.push_back(std::move(container));
293  } else {
294  it->flags = fgs;
295  it->data.fd = actual;
296  }
297  }
298 
299  return *this;
300  }
301 
308  poUid = id;
309  return *this;
310  }
311 
318  poGid = id;
319  return *this;
320  }
321 
322 private:
323  std::string poCwd;
324  Flags<Process> poFlags;
325  std::vector<uv_stdio_container_t> poFdStdio;
326  std::vector<uv_stdio_container_t> poStreamStdio;
327  Uid poUid;
328  Gid poGid;
329 };
330 
331 
332 }
ProcessHandle & stdio(FileHandle fd, Flags< StdIO > flags)
Makes a file descriptor available to the child process.
Definition: process.hpp:276
ProcessHandle & cwd(std::string path) noexcept
Sets the current working directory for the subprocess.
Definition: process.hpp:191
int64_t status
Definition: process.hpp:55
details::UVTypeWrapper< uv_file > FileHandle
Definition: util.hpp:198
bool init()
Initializes the handle.
Definition: process.hpp:114
void spawn(const char *file, char **args, char **env=nullptr)
spawn Starts the process.
Definition: process.hpp:134
constexpr FileHandle StdIN
Definition: util.hpp:203
ProcessHandle & stdio(StreamHandle< T, U > &stream, Flags< StdIO > flags)
Makes a stdio handle available to the child process.
Definition: process.hpp:241
Handle base class.
Definition: handle.hpp:29
static void disableStdIOInheritance() noexcept
Disables inheritance for file descriptors/handles.
Definition: process.hpp:96
The StreamHandle handle.
Definition: stream.hpp:130
The ProcessHandle handle.
Definition: process.hpp:65
uv_gid_t Gid
Definition: util.hpp:210
uv_uid_t Uid
Definition: util.hpp:209
int pid() noexcept
Gets the PID of the spawned process.
Definition: process.hpp:182
ProcessHandle & flags(Flags< Process > flags) noexcept
Sets flags that control how spawn() behaves.
Definition: process.hpp:214
static bool kill(int pid, int signum) noexcept
kill Sends the specified signal to the given PID.
Definition: process.hpp:106
ProcessHandle & uid(Uid id)
Sets the child process&#39; user id.
Definition: process.hpp:307
ExitEvent event.
Definition: process.hpp:50
ProcessHandle & gid(Gid id)
Sets the child process&#39; group id.
Definition: process.hpp:317
void kill(int signum)
Sends the specified signal to the internal process handle.
Definition: process.hpp:171
uvw default namespace.
Definition: async.hpp:11