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/exec.hpp>
30 #include <stout/os/shell.hpp>
31 #include <stout/os/int_fd.hpp>
32 
33 
34 namespace process {
35 
45 {
46 public:
47  // Forward declarations.
48  struct ParentHook;
49  class ChildHook;
50 
62  class IO
63  {
64  public:
75  {
76  int_fd read = -1;
78  };
79 
90  {
92  int_fd write = -1;
93  };
94 
99  enum FDType {
105 
112  };
113 
114 
115  private:
116  friend class Subprocess;
117 
119  const std::string& path,
120  std::vector<std::string> argv,
121  const Subprocess::IO& in,
122  const Subprocess::IO& out,
123  const Subprocess::IO& err,
124  const flags::FlagsBase* flags,
125  const Option<std::map<std::string, std::string>>& environment,
126  const Option<lambda::function<
127  pid_t(const lambda::function<int()>&)>>& clone,
128  const std::vector<Subprocess::ParentHook>& parent_hooks,
129  const std::vector<Subprocess::ChildHook>& child_hooks,
130  const std::vector<int_fd>& whitelist_fds);
131 
132  IO(const lambda::function<Try<InputFileDescriptors>()>& _input,
133  const lambda::function<Try<OutputFileDescriptors>()>& _output)
134  : input(_input),
135  output(_output) {}
136 
140  lambda::function<Try<InputFileDescriptors>()> input;
141 
145  lambda::function<Try<OutputFileDescriptors>()> output;
146  };
147 
153  struct ParentHook
154  {
155  ParentHook(const lambda::function<Try<Nothing>(pid_t)>& _parent_setup);
156 
164  const lambda::function<Try<Nothing>(pid_t)> parent_setup;
165 
166  friend class Subprocess;
167 
168 #ifdef __WINDOWS__
169 
177  static ParentHook CREATE_JOB();
178 #endif // __WINDOWS__
179  };
180 
191  class ChildHook
192  {
193  public:
197  static ChildHook CHDIR(const std::string& working_directory);
198 
202  static ChildHook SETSID();
203 
204 #ifndef __WINDOWS__
205 
208  static ChildHook DUP2(int oldFd, int newFd);
209 #endif // __WINDOWS__
210 
219  static ChildHook SUPERVISOR();
220 
221  Try<Nothing> operator()() const { return child_setup(); }
222 
223  private:
224  ChildHook(const lambda::function<Try<Nothing>()>& _child_setup);
225 
226  const lambda::function<Try<Nothing>()> child_setup;
227  };
228 
229  // Some syntactic sugar to create an IO::PIPE redirector.
230  static IO PIPE();
231  static IO PATH(const std::string& path);
232  static IO FD(int_fd fd, IO::FDType type = IO::DUPLICATED);
233 
237  pid_t pid() const { return data->pid; }
238 
245  {
246  return data->in;
247  }
248 
255  {
256  return data->out;
257  }
258 
265  {
266  return data->err;
267  }
268 
290  Future<Option<int>> status() const { return data->status; }
291 
292 private:
294  const std::string& path,
295  std::vector<std::string> argv,
296  const Subprocess::IO& in,
297  const Subprocess::IO& out,
298  const Subprocess::IO& err,
299  const flags::FlagsBase* flags,
300  const Option<std::map<std::string, std::string>>& environment,
301  const Option<lambda::function<
302  pid_t(const lambda::function<int()>&)>>& clone,
303  const std::vector<Subprocess::ParentHook>& parent_hooks,
304  const std::vector<Subprocess::ChildHook>& child_hooks,
305  const std::vector<int_fd>& whitelist_fds);
306 
307  struct Data
308  {
309  ~Data()
310  {
311  if (in.isSome()) { os::close(in.get()); }
312  if (out.isSome()) { os::close(out.get()); }
313  if (err.isSome()) { os::close(err.get()); }
314  }
315 
316  pid_t pid;
317 
318 #ifdef __WINDOWS__
320 #endif // __WINDOWS__
321 
322  // The parent side of the pipe for stdin/stdout/stderr. If the
323  // IO mode is not a pipe, `None` will be stored.
324  // NOTE: stdin, stdout, stderr are macros on some systems, hence
325  // these names instead.
329 
331  };
332 
333  Subprocess() : data(new Data()) {}
334 
335  std::shared_ptr<Data> data;
336 };
337 
340 
364 // TODO(jmlvanre): Consider removing default argument for
365 // `parent_hooks` to force the caller to think about setting them.
367  const std::string& path,
368  std::vector<std::string> argv,
372  const flags::FlagsBase* flags = nullptr,
373  const Option<std::map<std::string, std::string>>& environment = None(),
374  const Option<lambda::function<
375  pid_t(const lambda::function<int()>&)>>& clone = None(),
376  const std::vector<Subprocess::ParentHook>& parent_hooks = {},
377  const std::vector<Subprocess::ChildHook>& child_hooks = {},
378  const std::vector<int_fd>& whitelist_fds = {});
379 
380 
403 // TODO(jmlvanre): Consider removing default argument for
404 // `parent_hooks` to force the caller to think about setting them.
406  const std::string& command,
410  const Option<std::map<std::string, std::string>>& environment = None(),
411  const Option<lambda::function<
412  pid_t(const lambda::function<int()>&)>>& clone = None(),
413  const std::vector<Subprocess::ParentHook>& parent_hooks = {},
414  const std::vector<Subprocess::ChildHook>& child_hooks = {},
415  const std::vector<int_fd>& whitelist_fds = {})
416 {
417  std::vector<std::string> argv = {os::Shell::arg0, os::Shell::arg1, command};
418 
419  return subprocess(
421  argv,
422  in,
423  out,
424  err,
425  nullptr,
426  environment,
427  clone,
428  parent_hooks,
429  child_hooks,
430  whitelist_fds);
431 }
432 
433 } // namespace process {
434 
435 #endif // __PROCESS_SUBPROCESS_HPP__
Definition: path.hpp:29
Option< int_fd > in() const
Definition: subprocess.hpp:244
constexpr const char * arg1
Definition: shell.hpp:43
friend class Subprocess
Definition: subprocess.hpp:116
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:339
A ChildHook can be passed to a subprocess call.
Definition: subprocess.hpp:191
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:111
int_fd read
Definition: subprocess.hpp:76
For output file descriptors a child writes to the write file descriptor and a parent may read from th...
Definition: subprocess.hpp:89
pid_t pid() const
Definition: subprocess.hpp:237
#define STDERR_FILENO
Definition: windows.hpp:155
Subprocess::IO::InputFileDescriptors InputFileDescriptors
Definition: subprocess.hpp:338
constexpr const char * arg0
Definition: shell.hpp:42
Represents a fork() exec()ed subprocess.
Definition: subprocess.hpp:44
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:264
Try< Nothing > close(int fd)
Definition: close.hpp:24
Describes how the I/O is redirected for stdin/stdout/stderr.
Definition: subprocess.hpp:62
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:74
The file descriptor is duplicated before being passed to the subprocess.
Definition: subprocess.hpp:104
#define STDIN_FILENO
Definition: windows.hpp:153
Option< int_fd > out() const
Definition: subprocess.hpp:254
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:99
Definition: executor.hpp:48
Try< uint32_t > type(const std::string &path)
Option< int_fd > write
Definition: subprocess.hpp:77
A hook can be passed to a subprocess call.
Definition: subprocess.hpp:153
int int_fd
Definition: int_fd.hpp:35
Definition: parse.hpp:33
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:290
Try< Nothing > operator()() const
Definition: subprocess.hpp:221
Definition: future.hpp:58