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 
130  IO(const lambda::function<Try<InputFileDescriptors>()>& _input,
131  const lambda::function<Try<OutputFileDescriptors>()>& _output)
132  : input(_input),
133  output(_output) {}
134 
138  lambda::function<Try<InputFileDescriptors>()> input;
139 
143  lambda::function<Try<OutputFileDescriptors>()> output;
144  };
145 
151  struct ParentHook
152  {
153  ParentHook(const lambda::function<Try<Nothing>(pid_t)>& _parent_setup);
154 
162  const lambda::function<Try<Nothing>(pid_t)> parent_setup;
163 
164  friend class Subprocess;
165 
166 #ifdef __WINDOWS__
167 
175  static ParentHook CREATE_JOB();
176 #endif // __WINDOWS__
177  };
178 
189  class ChildHook
190  {
191  public:
195  static ChildHook CHDIR(const std::string& working_directory);
196 
200  static ChildHook SETSID();
201 
202 #ifndef __WINDOWS__
203 
206  static ChildHook DUP2(int oldFd, int newFd);
207 
212  static ChildHook UNSET_CLOEXEC(int fd);
213 #endif // __WINDOWS__
214 
223  static ChildHook SUPERVISOR();
224 
225  Try<Nothing> operator()() const { return child_setup(); }
226 
227  private:
228  ChildHook(const lambda::function<Try<Nothing>()>& _child_setup);
229 
230  const lambda::function<Try<Nothing>()> child_setup;
231  };
232 
233  // Some syntactic sugar to create an IO::PIPE redirector.
234  static IO PIPE();
235  static IO PATH(const std::string& path);
236  static IO FD(int_fd fd, IO::FDType type = IO::DUPLICATED);
237 
241  pid_t pid() const { return data->pid; }
242 
249  {
250  return data->in;
251  }
252 
259  {
260  return data->out;
261  }
262 
269  {
270  return data->err;
271  }
272 
294  Future<Option<int>> status() const { return data->status; }
295 
296 private:
298  const std::string& path,
299  std::vector<std::string> argv,
300  const Subprocess::IO& in,
301  const Subprocess::IO& out,
302  const Subprocess::IO& err,
303  const flags::FlagsBase* flags,
304  const Option<std::map<std::string, std::string>>& environment,
305  const Option<lambda::function<
306  pid_t(const lambda::function<int()>&)>>& clone,
307  const std::vector<Subprocess::ParentHook>& parent_hooks,
308  const std::vector<Subprocess::ChildHook>& child_hooks);
309 
310  struct Data
311  {
312  ~Data()
313  {
314  if (in.isSome()) { os::close(in.get()); }
315  if (out.isSome()) { os::close(out.get()); }
316  if (err.isSome()) { os::close(err.get()); }
317  }
318 
319  pid_t pid;
320 
321 #ifdef __WINDOWS__
323 #endif // __WINDOWS__
324 
325  // The parent side of the pipe for stdin/stdout/stderr. If the
326  // IO mode is not a pipe, `None` will be stored.
327  // NOTE: stdin, stdout, stderr are macros on some systems, hence
328  // these names instead.
332 
333  Future<Option<int>> status;
334  };
335 
336  Subprocess() : data(new Data()) {}
337 
338  std::shared_ptr<Data> data;
339 };
340 
343 
367 // TODO(jmlvanre): Consider removing default argument for
368 // `parent_hooks` to force the caller to think about setting them.
370  const std::string& path,
371  std::vector<std::string> argv,
375  const flags::FlagsBase* flags = nullptr,
376  const Option<std::map<std::string, std::string>>& environment = None(),
377  const Option<lambda::function<
378  pid_t(const lambda::function<int()>&)>>& clone = None(),
379  const std::vector<Subprocess::ParentHook>& parent_hooks = {},
380  const std::vector<Subprocess::ChildHook>& child_hooks = {});
381 
382 
405 // TODO(jmlvanre): Consider removing default argument for
406 // `parent_hooks` to force the caller to think about setting them.
408  const std::string& command,
412  const Option<std::map<std::string, std::string>>& environment = None(),
413  const Option<lambda::function<
414  pid_t(const lambda::function<int()>&)>>& clone = None(),
415  const std::vector<Subprocess::ParentHook>& parent_hooks = {},
416  const std::vector<Subprocess::ChildHook>& child_hooks = {})
417 {
418  std::vector<std::string> argv = {os::Shell::arg0, os::Shell::arg1, command};
419 
420  return subprocess(
422  argv,
423  in,
424  out,
425  err,
426  nullptr,
427  environment,
428  clone,
429  parent_hooks,
430  child_hooks);
431 }
432 
433 } // namespace process {
434 
435 #endif // __PROCESS_SUBPROCESS_HPP__
Option< int_fd > in() const
Definition: subprocess.hpp:248
Try< Subprocess > subprocess(const std::string &path, std::vector< std::string > argv, const Subprocess::IO &in=Subprocess::FD(STDIN_FILENO), const Subprocess::IO &out=Subprocess::FD(STDOUT_FILENO), const Subprocess::IO &err=Subprocess::FD(STDERR_FILENO), const flags::FlagsBase *flags=nullptr, const Option< std::map< std::string, std::string >> &environment=None(), const Option< lambda::function< pid_t(const lambda::function< int()> &)>> &clone=None(), const std::vector< Subprocess::ParentHook > &parent_hooks={}, const std::vector< Subprocess::ChildHook > &child_hooks={})
Forks a subprocess and execs the specified &#39;path&#39; with the specified &#39;argv&#39;, redirecting stdin...
constexpr const char * arg1
Definition: shell.hpp:43
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:342
A ChildHook can be passed to a subprocess call.
Definition: subprocess.hpp:189
Definition: try.hpp:34
static ChildHook DUP2(int oldFd, int newFd)
ChildHook for duplicating a file descriptor.
static ChildHook SUPERVISOR()
ChildHook for starting a Supervisor process monitoring and killing the child process if the parent pr...
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:241
static ChildHook CHDIR(const std::string &working_directory)
ChildHook for changing the working directory.
#define STDERR_FILENO
Definition: windows.hpp:161
Subprocess::IO::InputFileDescriptors InputFileDescriptors
Definition: subprocess.hpp:341
constexpr const char * arg0
Definition: shell.hpp:42
Represents a fork() exec()ed subprocess.
Definition: subprocess.hpp:43
Environment * environment
DWORD pid_t
Definition: windows.hpp:187
static IO FD(int_fd fd, IO::FDType type=IO::DUPLICATED)
#define STDOUT_FILENO
Definition: windows.hpp:160
Option< int_fd > err() const
Definition: subprocess.hpp:268
int_fd write
Definition: subprocess.hpp:91
Try< Nothing > close(int fd)
Definition: close.hpp:24
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)
Describes how the I/O is redirected for stdin/stdout/stderr.
Definition: subprocess.hpp:61
Definition: flags.hpp:44
ParentHook(const lambda::function< Try< Nothing >(pid_t)> &_parent_setup)
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:159
Option< int_fd > out() const
Definition: subprocess.hpp:258
const lambda::function< Try< Nothing >pid_t)> parent_setup
The callback that must be specified for execution after the child has been cloned, but before it starts executing the new process.
Definition: subprocess.hpp:162
Result< Process > process(pid_t pid)
Definition: freebsd.hpp:30
#define flags
Definition: decoder.hpp:18
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
Try< uint32_t > type(const std::string &path)
Option< int_fd > read
Definition: subprocess.hpp:90
Option< int_fd > write
Definition: subprocess.hpp:76
A hook can be passed to a subprocess call.
Definition: subprocess.hpp:151
int int_fd
Definition: int_fd.hpp:35
constexpr const char * name
Definition: shell.hpp:41
Future< Option< int > > status() const
Exit status of this subprocess captured as a Future (completed when the subprocess exits)...
Definition: subprocess.hpp:294
Try< Nothing > operator()() const
Definition: subprocess.hpp:225
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)
static ChildHook SETSID()
ChildHook for generating a new session id.
Definition: future.hpp:57
static ChildHook UNSET_CLOEXEC(int fd)
ChildHook to unset CLOEXEC on a file descriptor.