uvw  1.11.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;
155  poStdio.reserve(poFdStdio.size() + poStreamStdio.size());
156  poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());
157  poStdio.insert(poStdio.end(), poStreamStdio.cbegin(), poStreamStdio.cend());
158 
159  po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
160  po.stdio = poStdio.data();
161 
162  // fake initialization so as to have leak invoked
163  // see init member function for more details
164  initialize([](auto...){ return 0; });
165 
166  invoke(&uv_spawn, parent(), get(), &po);
167  }
168 
173  void kill(int signum) {
174  invoke(&uv_process_kill, get(), signum);
175  }
176 
184  int pid() noexcept {
185  return get()->pid;
186  }
187 
193  ProcessHandle & cwd(std::string path) noexcept {
194  poCwd = path;
195  return *this;
196  }
197 
216  ProcessHandle & flags(Flags<Process> flags) noexcept {
217  poFlags = flags;
218  return *this;
219  }
220 
242  template<typename T, typename U>
244  uv_stdio_container_t container;
245  Flags<StdIO>::Type fgs = flags;
246  container.flags = static_cast<uv_stdio_flags>(fgs);
247  container.data.stream = get<uv_stream_t>(stream);
248  poStreamStdio.push_back(std::move(container));
249  return *this;
250  }
251 
279  auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags});
280 
281  auto actual = FileHandle::Type{fd};
282 
283  if(actual == FileHandle::Type{StdIN}) {
284  poFdStdio[0].flags = fgs;
285  } else {
286  auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container){
287  return container.data.fd == actual;
288  });
289 
290  if(it == poFdStdio.cend()) {
291  uv_stdio_container_t container;
292  container.flags = fgs;
293  container.data.fd = actual;
294  poFdStdio.push_back(std::move(container));
295  } else {
296  it->flags = fgs;
297  it->data.fd = actual;
298  }
299  }
300 
301  return *this;
302  }
303 
310  poUid = id;
311  return *this;
312  }
313 
320  poGid = id;
321  return *this;
322  }
323 
324 private:
325  std::string poCwd;
326  Flags<Process> poFlags;
327  std::vector<uv_stdio_container_t> poFdStdio;
328  std::vector<uv_stdio_container_t> poStreamStdio;
329  Uid poUid;
330  Gid poGid;
331 };
332 
333 
334 }
ProcessHandle & stdio(FileHandle fd, Flags< StdIO > flags)
Makes a file descriptor available to the child process.
Definition: process.hpp:278
ProcessHandle & cwd(std::string path) noexcept
Sets the current working directory for the subprocess.
Definition: process.hpp:193
int64_t status
Definition: process.hpp:55
details::UVTypeWrapper< uv_file > FileHandle
Definition: util.hpp:199
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:204
ProcessHandle & stdio(StreamHandle< T, U > &stream, Flags< StdIO > flags)
Makes a stdio handle available to the child process.
Definition: process.hpp:243
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:211
uv_uid_t Uid
Definition: util.hpp:210
int pid() noexcept
Gets the PID of the spawned process.
Definition: process.hpp:184
ProcessHandle & flags(Flags< Process > flags) noexcept
Sets flags that control how spawn() behaves.
Definition: process.hpp:216
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:309
ExitEvent event.
Definition: process.hpp:50
ProcessHandle & gid(Gid id)
Sets the child process&#39; group id.
Definition: process.hpp:319
void kill(int signum)
Sends the specified signal to the internal process handle.
Definition: process.hpp:173
uvw default namespace.
Definition: async.hpp:11