1// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef LIBBRILLO_BRILLO_PROCESS_H_
6#define LIBBRILLO_BRILLO_PROCESS_H_
7
8#include <sys/types.h>
9
10#include <map>
11#include <string>
12#include <vector>
13
14#include <base/bind.h>
15#include <base/callback.h>
16#include <base/strings/string_util.h>
17#include <base/strings/stringprintf.h>
18#include <brillo/brillo_export.h>
19#include <gtest/gtest_prod.h>
20
21namespace brillo {
22// Manages a process.  Can create the process, attach to an existing
23// process by pid or pid file, and kill the process.  Upon destruction
24// any managed process is killed with SIGKILL.  Use Release() to
25// release the process from management.  A given system process may
26// only be managed by one Process at a time.
27class BRILLO_EXPORT Process {
28 public:
29  Process();
30  virtual ~Process();
31
32  // Adds |arg| to the executable command-line to be run.  The
33  // executable name itself is the first argument.
34  virtual void AddArg(const std::string& arg) = 0;
35
36  // Adds |option| and |value| as an option with a string value to the
37  // command line to be run.
38  inline void AddStringOption(const std::string& option,
39                              const std::string& value) {
40    AddArg(option);
41    AddArg(value);
42  }
43
44  // Adds |option| and |value| as an option which takes an integer
45  // value to the command line to be run.
46  inline void AddIntOption(const std::string& option, int value) {
47    AddArg(option);
48    AddArg(base::StringPrintf("%d", value));
49  }
50
51  // Redirects stderr and stdout to |output_file|.
52  virtual void RedirectOutput(const std::string& output_file) = 0;
53
54  // Indicates we want to redirect |child_fd| in the child process's
55  // file table to a pipe.  |child_fd| will be available for reading
56  // from child process's perspective iff |is_input|.
57  virtual void RedirectUsingPipe(int child_fd, bool is_input) = 0;
58
59  // Binds the given file descriptor in the parent to the given file
60  // descriptor in the child.
61  virtual void BindFd(int parent_fd, int child_fd) = 0;
62
63  // Set a flag |close_unused_fds| to indicate if the child process
64  // should close all unused file descriptors inherited from the
65  // parent process.  This will not close the file descriptors for
66  // the standard streams (stdin, stdout, and stderr).
67  virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds) = 0;
68
69  // Set the real/effective/saved user ID of the child process.
70  virtual void SetUid(uid_t uid) = 0;
71
72  // Set the real/effective/saved group ID of the child process.
73  virtual void SetGid(gid_t gid) = 0;
74
75  // Set the capabilities assigned to the child process.
76  // NOTE: |capmask| is indeed a mask and should be passed in as the result of
77  // the CAP_TO_MASK(capability) macro, e.g.
78  //     my_process.SetCapabilities(CAP_TO_MASK(CAP_SETUID) |
79  //                                CAP_TO_MASK(CAP_SETGID));
80  // NOTE: supporting this sandboxing feature is optional (provide no-op
81  // implementation if your Process implementation does not support this).
82  virtual void SetCapabilities(uint64_t capmask) = 0;
83
84  // Apply a syscall filter to the process using the policy file at |path|.
85  // NOTE: supporting this sandboxing feature is optional (provide no-op
86  // implementation if your Process implementation does not support this).
87  virtual void ApplySyscallFilter(const std::string& path) = 0;
88
89  // Enter new PID namespace when this process is run.
90  // NOTE: supporting this sandboxing feature is optional (provide no-op
91  // implementation if your Process implementation does not support this).
92  virtual void EnterNewPidNamespace() = 0;
93
94  // Set a flag |inherit| to indicate if the child process intend to
95  // inherit signal mask from the parent process. When |inherit| is
96  // set to true, the child process will inherit signal mask from the
97  // parent process. This could cause unintended side effect, where all
98  // the signals to the child process might be blocked if they are set
99  // in the parent's signal mask.
100  virtual void SetInheritParentSignalMask(bool inherit) = 0;
101
102  typedef base::Callback<bool(void)> PreExecCallback;
103
104  // Set the pre-exec callback. This is called after all setup is complete but
105  // before we exec() the process. The callback may return false to cause Start
106  // to return false without starting the process.
107  virtual void SetPreExecCallback(const PreExecCallback& cb) = 0;
108
109  // Sets whether starting the process should search the system path or not.
110  // By default the system path will not be searched.
111  virtual void SetSearchPath(bool search_path) = 0;
112
113  // Gets the pipe file descriptor mapped to the process's |child_fd|.
114  virtual int GetPipe(int child_fd) = 0;
115
116  // Starts this process, returning true if successful.
117  virtual bool Start() = 0;
118
119  // Waits for this process to finish.  Returns the process's exit
120  // status if it exited normally, or otherwise returns -1.  Note
121  // that kErrorExitStatus may be returned if an error occurred
122  // after forking and before execing the child process.
123  virtual int Wait() = 0;
124
125  // Start and wait for this process to finish.  Returns same value as
126  // Wait().
127  virtual int Run() = 0;
128
129  // Returns the pid of this process or else returns 0 if there is no
130  // corresponding process (either because it has not yet been started
131  // or has since exited).
132  virtual pid_t pid() = 0;
133
134  // Sends |signal| to process and wait |timeout| seconds until it
135  // dies.  If process is not a child, returns immediately with a
136  // value based on whether kill was successful.  If the process is a
137  // child and |timeout| is non-zero, returns true if the process is
138  // able to be reaped within the given |timeout| in seconds.
139  virtual bool Kill(int signal, int timeout) = 0;
140
141  // Resets this Process object to refer to the process with |pid|.
142  // If |pid| is zero, this object no longer refers to a process.
143  virtual void Reset(pid_t new_pid) = 0;
144
145  // Same as Reset but reads the pid from |pid_file|.  Returns false
146  // only when the file cannot be read/parsed.
147  virtual bool ResetPidByFile(const std::string& pid_file) = 0;
148
149  // Releases the process so that on destruction, the process is not killed.
150  virtual pid_t Release() = 0;
151
152  // Returns if |pid| is a currently running process.
153  static bool ProcessExists(pid_t pid);
154
155  // When returned from Wait or Run, indicates an error may have occurred
156  // creating the process.
157  enum { kErrorExitStatus = 127 };
158};
159
160class BRILLO_EXPORT ProcessImpl : public Process {
161 public:
162  ProcessImpl();
163  virtual ~ProcessImpl();
164
165  virtual void AddArg(const std::string& arg);
166  virtual void RedirectOutput(const std::string& output_file);
167  virtual void RedirectUsingPipe(int child_fd, bool is_input);
168  virtual void BindFd(int parent_fd, int child_fd);
169  virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds);
170  virtual void SetUid(uid_t uid);
171  virtual void SetGid(gid_t gid);
172  virtual void SetCapabilities(uint64_t capmask);
173  virtual void ApplySyscallFilter(const std::string& path);
174  virtual void EnterNewPidNamespace();
175  virtual void SetInheritParentSignalMask(bool inherit);
176  virtual void SetPreExecCallback(const PreExecCallback& cb);
177  virtual void SetSearchPath(bool search_path);
178  virtual int GetPipe(int child_fd);
179  virtual bool Start();
180  virtual int Wait();
181  virtual int Run();
182  virtual pid_t pid();
183  virtual bool Kill(int signal, int timeout);
184  virtual void Reset(pid_t pid);
185  virtual bool ResetPidByFile(const std::string& pid_file);
186  virtual pid_t Release();
187
188 protected:
189  struct PipeInfo {
190    PipeInfo() : parent_fd_(-1), child_fd_(-1), is_input_(false) {}
191    // Parent (our) side of the pipe to the child process.
192    int parent_fd_;
193    // Child's side of the pipe to the parent.
194    int child_fd_;
195    // Is this an input or output pipe from child's perspective.
196    bool is_input_;
197    // Is this a bound (pre-existing) file descriptor?
198    bool is_bound_;
199  };
200  typedef std::map<int, PipeInfo> PipeMap;
201
202  void UpdatePid(pid_t new_pid);
203  bool PopulatePipeMap();
204
205 private:
206  FRIEND_TEST(ProcessTest, ResetPidByFile);
207
208  bool IsFileDescriptorInPipeMap(int fd) const;
209  void CloseUnusedFileDescriptors();
210
211  // Pid of currently managed process or 0 if no currently managed
212  // process.  pid must not be modified except by calling
213  // UpdatePid(new_pid).
214  pid_t pid_;
215  std::string output_file_;
216  std::vector<std::string> arguments_;
217  // Map of child target file descriptors (first) to information about
218  // pipes created (second).
219  PipeMap pipe_map_;
220  uid_t uid_;
221  gid_t gid_;
222  PreExecCallback pre_exec_;
223  bool search_path_;
224  // Flag indicating to inherit signal mask from the parent process. It
225  // is set to false by default, which means by default the child process
226  // will not inherit signal mask from the parent process.
227  bool inherit_parent_signal_mask_;
228  // Flag indicating to close unused file descriptors inherited from the
229  // parent process when starting the child process, which avoids leaking
230  // unnecessary file descriptors to the child process.
231  bool close_unused_file_descriptors_;
232};
233
234}  // namespace brillo
235
236#endif  // LIBBRILLO_BRILLO_PROCESS_H_
237