Apache Mesos
subprocess.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License
12 
13 #ifndef __PROCESS_SUBPROCESS_HPP__
14 #define __PROCESS_SUBPROCESS_HPP__
15 
16 #include <map>
17 #include <memory>
18 #include <string>
19 #include <vector>
20 
21 #include <process/future.hpp>
22 
23 #include <stout/flags.hpp>
24 #include <stout/lambda.hpp>
25 #include <stout/none.hpp>
26 #include <stout/option.hpp>
27 #include <stout/try.hpp>
28 
29 #include <stout/os/shell.hpp>
30 #include <stout/os/int_fd.hpp>
31 
32 
33 namespace process {
34 
44 {
45 public:
46  // Forward declarations.
47  struct ParentHook;
48  class ChildHook;
49 
61  class IO
62  {
63  public:
74  {
75  int_fd read = -1;
77  };
78 
89  {
91  int_fd write = -1;
92  };
93 
98  enum FDType {
104 
111  };
112 
113 
114  private:
115  friend class Subprocess;
116 
118  const std::string& path,
119  std::vector<std::string> argv,
120  const Subprocess::IO& in,
121  const Subprocess::IO& out,
122  const Subprocess::IO& err,
123  const flags::FlagsBase* flags,
124  const Option<std::map<std::string, std::string>>& environment,
125  const Option<lambda::function<
126  pid_t(const lambda::function<int()>&)>>& clone,
127  const std::vector<Subprocess::ParentHook>& parent_hooks,
128  const std::vector<Subprocess::ChildHook>& child_hooks,
129  const std::vector<int_fd>& whitelist_fds);
130 
131  IO(const lambda::function<Try<InputFileDescriptors>()>& _input,
132  const lambda::function<Try<OutputFileDescriptors>()>& _output)
133  : input(_input),
134  output(_output) {}
135 
139  lambda::function<Try<InputFileDescriptors>()> input;
140 
144  lambda::function<Try<OutputFileDescriptors>()> output;
145  };
146 
152  struct ParentHook
153  {
154  ParentHook(const lambda::function<Try<Nothing>(pid_t)>& _parent_setup);
155 
163  const lambda::function<Try<Nothing>(pid_t)> parent_setup;
164 
165  friend class Subprocess;
166 
167 #ifdef __WINDOWS__
168 
176  static ParentHook CREATE_JOB();
177 #endif // __WINDOWS__
178  };
179 
190  class ChildHook
191  {
192  public:
196  static ChildHook CHDIR(const std::string& working_directory);
197 
201  static ChildHook SETSID();
202 
203 #ifndef __WINDOWS__
204 
207  static ChildHook DUP2(int oldFd, int newFd);
208 
213  static ChildHook UNSET_CLOEXEC(int fd);
214 #endif // __WINDOWS__
215 
224  static ChildHook SUPERVISOR();
225 
226  Try<Nothing> operator()() const { return child_setup(); }
227 
228  private:
229  ChildHook(const lambda::function<Try<Nothing>()>& _child_setup);
230 
231  const lambda::function<Try<Nothing>()> child_setup;
232  };
233 
234  // Some syntactic sugar to create an IO::PIPE redirector.
235  static IO PIPE();
236  static IO PATH(const std::string& path);
237  static IO FD(int_fd fd, IO::FDType type = IO::DUPLICATED);
238 
242  pid_t pid() const { return data->pid; }
243 
250  {
251  return data->in;
252  }
253 
260  {
261  return data->out;
262  }
263 
270  {
271  return data->err;
272  }
273 
295  Future<Option<int>> status() const { return data->status; }
296 
297 private:
299  const std::string& path,
300  std::vector<std::string> argv,
301  const Subprocess::IO& in,
302  const Subprocess::IO& out,
303  const Subprocess::IO& err,
304  const flags::FlagsBase* flags,
305  const Option<std::map<std::string, std::string>>& environment,
306  const Option<lambda::function<
307  pid_t(const lambda::function<int()>&)>>& clone,
308  const std::vector<Subprocess::ParentHook>& parent_hooks,
309  const std::vector<Subprocess::ChildHook>& child_hooks,
310  const std::vector<int_fd>& whitelist_fds);
311 
312  struct Data
313  {
314  ~Data()
315  {
316  if (in.isSome()) { os::close(in.get()); }
317  if (out.isSome()) { os::close(out.get()); }
318  if (err.isSome()) { os::close(err.get()); }
319  }
320 
321  pid_t pid;
322 
323 #ifdef __WINDOWS__
325 #endif // __WINDOWS__
326 
327  // The parent side of the pipe for stdin/stdout/stderr. If the
328  // IO mode is not a pipe, `None` will be stored.
329  // NOTE: stdin, stdout, stderr are macros on some systems, hence
330  // these names instead.
334 
336  };
337 
338  Subprocess() : data(new Data()) {}
339 
340  std::shared_ptr<Data> data;
341 };
342 
345 
369 // TODO(jmlvanre): Consider removing default argument for
370 // `parent_hooks` to force the caller to think about setting them.
372  const std::string& path,
373  std::vector<std::string> argv,
377  const flags::FlagsBase* flags = nullptr,
378  const Option<std::map<std::string, std::string>>& environment = None(),
379  const Option<lambda::function<
380  pid_t(const lambda::function<int()>&)>>& clone = None(),
381  const std::vector<Subprocess::ParentHook>& parent_hooks = {},
382  const std::vector<Subprocess::ChildHook>& child_hooks = {},
383  const std::vector<int_fd>& whitelist_fds = {});
384 
385 
408 // TODO(jmlvanre): Consider removing default argument for
409 // `parent_hooks` to force the caller to think about setting them.
411  const std::string& command,
415  const Option<std::map<std::string, std::string>>& environment = None(),
416  const Option<lambda::function<
417  pid_t(const lambda::function<int()>&)>>& clone = None(),
418  const std::vector<Subprocess::ParentHook>& parent_hooks = {},
419  const std::vector<Subprocess::ChildHook>& child_hooks = {},
420  const std::vector<int_fd>& whitelist_fds = {})
421 {
422  std::vector<std::string> argv = {os::Shell::arg0, os::Shell::arg1, command};
423 
424  return subprocess(
426  argv,
427  in,
428  out,
429  err,
430  nullptr,
431  environment,
432  clone,
433  parent_hooks,
434  child_hooks,
435  whitelist_fds);
436 }
437 
438 } // namespace process {
439 
440 #endif // __PROCESS_SUBPROCESS_HPP__
Definition: path.hpp:26
Option< int_fd > in() const
Definition: subprocess.hpp:249
constexpr const char * arg1
Definition: shell.hpp:45
friend class Subprocess
Definition: subprocess.hpp:115
Try< pid_t > clone(pid_t target, int nstypes, const lambda::function< int()> &f, int flags)
Performs an os::clone after entering a set of namespaces for the specified target process...
Subprocess::IO::OutputFileDescriptors OutputFileDescriptors
Definition: subprocess.hpp:344
A ChildHook can be passed to a subprocess call.
Definition: subprocess.hpp:190
Definition: check.hpp:33
static IO PATH(const std::string &path)
The file descriptor is not duplicated before being passed to the subprocess.
Definition: subprocess.hpp:110
int_fd read
Definition: subprocess.hpp:75
For output file descriptors a child writes to the write file descriptor and a parent may read from th...
Definition: subprocess.hpp:88
pid_t pid() const
Definition: subprocess.hpp:242
#define STDERR_FILENO
Definition: windows.hpp:155
Subprocess::IO::InputFileDescriptors InputFileDescriptors
Definition: subprocess.hpp:343
constexpr const char * arg0
Definition: shell.hpp:44
Represents a fork() exec()ed subprocess.
Definition: subprocess.hpp:43
Environment * environment
DWORD pid_t
Definition: windows.hpp:181
static IO FD(int_fd fd, IO::FDType type=IO::DUPLICATED)
#define STDOUT_FILENO
Definition: windows.hpp:154
Option< int_fd > err() const
Definition: subprocess.hpp:269
Try< Nothing > close(int fd)
Definition: close.hpp:24
Describes how the I/O is redirected for stdin/stdout/stderr.
Definition: subprocess.hpp:61
Definition: flags.hpp:44
For input file descriptors a child reads from the read file descriptor and a parent may write to the ...
Definition: subprocess.hpp:73
The file descriptor is duplicated before being passed to the subprocess.
Definition: subprocess.hpp:103
#define STDIN_FILENO
Definition: windows.hpp:153
Option< int_fd > out() const
Definition: subprocess.hpp:259
friend Try< Subprocess > subprocess(const std::string &path, std::vector< std::string > argv, const Subprocess::IO &in, const Subprocess::IO &out, const Subprocess::IO &err, const flags::FlagsBase *flags, const Option< std::map< std::string, std::string >> &environment, const Option< lambda::function< pid_t(const lambda::function< int()> &)>> &clone, const std::vector< Subprocess::ParentHook > &parent_hooks, const std::vector< Subprocess::ChildHook > &child_hooks, const std::vector< int_fd > &whitelist_fds)
Definition: none.hpp:27
FDType
Describes the lifecycle of a file descriptor passed into a subprocess via the Subprocess::FD helper...
Definition: subprocess.hpp:98
Definition: executor.hpp:48
Try< uint32_t > type(const std::string &path)
Option< int_fd > write
Definition: subprocess.hpp:76
A hook can be passed to a subprocess call.
Definition: subprocess.hpp:152
int int_fd
Definition: int_fd.hpp:35
Definition: parse.hpp:33
constexpr const char * name
Definition: shell.hpp:43
Future< Option< int > > status() const
Exit status of this subprocess captured as a Future (completed when the subprocess exits)...
Definition: subprocess.hpp:295
Try< Nothing > operator()() const
Definition: subprocess.hpp:226
Definition: future.hpp:58