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 #endif // __WINDOWS__
209 
218  static ChildHook SUPERVISOR();
219 
220  Try<Nothing> operator()() const { return child_setup(); }
221 
222  private:
223  ChildHook(const lambda::function<Try<Nothing>()>& _child_setup);
224 
225  const lambda::function<Try<Nothing>()> child_setup;
226  };
227 
228  // Some syntactic sugar to create an IO::PIPE redirector.
229  static IO PIPE();
230  static IO PATH(const std::string& path);
231  static IO FD(int_fd fd, IO::FDType type = IO::DUPLICATED);
232 
236  pid_t pid() const { return data->pid; }
237 
244  {
245  return data->in;
246  }
247 
254  {
255  return data->out;
256  }
257 
264  {
265  return data->err;
266  }
267 
289  Future<Option<int>> status() const { return data->status; }
290 
291 private:
293  const std::string& path,
294  std::vector<std::string> argv,
295  const Subprocess::IO& in,
296  const Subprocess::IO& out,
297  const Subprocess::IO& err,
298  const flags::FlagsBase* flags,
299  const Option<std::map<std::string, std::string>>& environment,
300  const Option<lambda::function<
301  pid_t(const lambda::function<int()>&)>>& clone,
302  const std::vector<Subprocess::ParentHook>& parent_hooks,
303  const std::vector<Subprocess::ChildHook>& child_hooks,
304  const std::vector<int_fd>& whitelist_fds);
305 
306  struct Data
307  {
308  ~Data()
309  {
310  if (in.isSome()) { os::close(in.get()); }
311  if (out.isSome()) { os::close(out.get()); }
312  if (err.isSome()) { os::close(err.get()); }
313  }
314 
315  pid_t pid;
316 
317 #ifdef __WINDOWS__
319 #endif // __WINDOWS__
320 
321  // The parent side of the pipe for stdin/stdout/stderr. If the
322  // IO mode is not a pipe, `None` will be stored.
323  // NOTE: stdin, stdout, stderr are macros on some systems, hence
324  // these names instead.
328 
330  };
331 
332  Subprocess() : data(new Data()) {}
333 
334  std::shared_ptr<Data> data;
335 };
336 
339 
363 // TODO(jmlvanre): Consider removing default argument for
364 // `parent_hooks` to force the caller to think about setting them.
366  const std::string& path,
367  std::vector<std::string> argv,
371  const flags::FlagsBase* flags = nullptr,
372  const Option<std::map<std::string, std::string>>& environment = None(),
373  const Option<lambda::function<
374  pid_t(const lambda::function<int()>&)>>& clone = None(),
375  const std::vector<Subprocess::ParentHook>& parent_hooks = {},
376  const std::vector<Subprocess::ChildHook>& child_hooks = {},
377  const std::vector<int_fd>& whitelist_fds = {});
378 
379 
402 // TODO(jmlvanre): Consider removing default argument for
403 // `parent_hooks` to force the caller to think about setting them.
405  const std::string& command,
409  const Option<std::map<std::string, std::string>>& environment = None(),
410  const Option<lambda::function<
411  pid_t(const lambda::function<int()>&)>>& clone = None(),
412  const std::vector<Subprocess::ParentHook>& parent_hooks = {},
413  const std::vector<Subprocess::ChildHook>& child_hooks = {},
414  const std::vector<int_fd>& whitelist_fds = {})
415 {
416  std::vector<std::string> argv = {os::Shell::arg0, os::Shell::arg1, command};
417 
418  return subprocess(
420  argv,
421  in,
422  out,
423  err,
424  nullptr,
425  environment,
426  clone,
427  parent_hooks,
428  child_hooks,
429  whitelist_fds);
430 }
431 
432 } // namespace process {
433 
434 #endif // __PROCESS_SUBPROCESS_HPP__
Definition: path.hpp:29
Option< int_fd > in() const
Definition: subprocess.hpp:243
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:338
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:236
#define STDERR_FILENO
Definition: windows.hpp:155
Subprocess::IO::InputFileDescriptors InputFileDescriptors
Definition: subprocess.hpp:337
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:263
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:253
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:289
Try< Nothing > operator()() const
Definition: subprocess.hpp:220
Definition: future.hpp:58