You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
9.4 KiB
245 lines
9.4 KiB
4 months ago
|
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#ifndef LIBBRILLO_BRILLO_PROCESS_H_
|
||
|
#define LIBBRILLO_BRILLO_PROCESS_H_
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
|
||
|
#include <map>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
#include <base/bind.h>
|
||
|
#include <base/callback.h>
|
||
|
#include <base/files/file_path.h>
|
||
|
#include <base/strings/string_util.h>
|
||
|
#include <base/strings/stringprintf.h>
|
||
|
#include <brillo/brillo_export.h>
|
||
|
#include <gtest/gtest_prod.h>
|
||
|
|
||
|
namespace brillo {
|
||
|
// Manages a process. Can create the process, attach to an existing
|
||
|
// process by pid or pid file, and kill the process. Upon destruction
|
||
|
// any managed process is killed with SIGKILL. Use Release() to
|
||
|
// release the process from management. A given system process may
|
||
|
// only be managed by one Process at a time.
|
||
|
class BRILLO_EXPORT Process {
|
||
|
public:
|
||
|
Process();
|
||
|
virtual ~Process();
|
||
|
|
||
|
// Adds |arg| to the executable command-line to be run. The
|
||
|
// executable name itself is the first argument.
|
||
|
virtual void AddArg(const std::string& arg) = 0;
|
||
|
|
||
|
// Adds |option| and |value| as an option with a string value to the
|
||
|
// command line to be run.
|
||
|
inline void AddStringOption(const std::string& option,
|
||
|
const std::string& value) {
|
||
|
AddArg(option);
|
||
|
AddArg(value);
|
||
|
}
|
||
|
|
||
|
// Adds |option| and |value| as an option which takes an integer
|
||
|
// value to the command line to be run.
|
||
|
inline void AddIntOption(const std::string& option, int value) {
|
||
|
AddArg(option);
|
||
|
AddArg(base::StringPrintf("%d", value));
|
||
|
}
|
||
|
|
||
|
// Redirects to read stdin from |input_file|. |input_file| must not be
|
||
|
// a symlink.
|
||
|
virtual void RedirectInput(const std::string& input_file) = 0;
|
||
|
|
||
|
// Redirects stderr and stdout to |output_file|. |output_file| must not be
|
||
|
// a symlink.
|
||
|
virtual void RedirectOutput(const std::string& output_file) = 0;
|
||
|
|
||
|
// Indicates we want to redirect |child_fd| in the child process's
|
||
|
// file table to a pipe. |child_fd| will be available for reading
|
||
|
// from child process's perspective iff |is_input|.
|
||
|
virtual void RedirectUsingPipe(int child_fd, bool is_input) = 0;
|
||
|
|
||
|
// Binds the given file descriptor in the parent to the given file
|
||
|
// descriptor in the child.
|
||
|
virtual void BindFd(int parent_fd, int child_fd) = 0;
|
||
|
|
||
|
// Set a flag |close_unused_fds| to indicate if the child process
|
||
|
// should close all unused file descriptors inherited from the
|
||
|
// parent process. This will not close the file descriptors for
|
||
|
// the standard streams (stdin, stdout, and stderr).
|
||
|
virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds) = 0;
|
||
|
|
||
|
// Set the real/effective/saved user ID of the child process.
|
||
|
virtual void SetUid(uid_t uid) = 0;
|
||
|
|
||
|
// Set the real/effective/saved group ID of the child process.
|
||
|
virtual void SetGid(gid_t gid) = 0;
|
||
|
|
||
|
// Set the capabilities assigned to the child process.
|
||
|
// NOTE: |capmask| is indeed a mask and should be passed in as the result of
|
||
|
// the CAP_TO_MASK(capability) macro, e.g.
|
||
|
// my_process.SetCapabilities(CAP_TO_MASK(CAP_SETUID) |
|
||
|
// CAP_TO_MASK(CAP_SETGID));
|
||
|
// NOTE: supporting this sandboxing feature is optional (provide no-op
|
||
|
// implementation if your Process implementation does not support this).
|
||
|
virtual void SetCapabilities(uint64_t capmask) = 0;
|
||
|
|
||
|
// Apply a syscall filter to the process using the policy file at |path|.
|
||
|
// NOTE: supporting this sandboxing feature is optional (provide no-op
|
||
|
// implementation if your Process implementation does not support this).
|
||
|
virtual void ApplySyscallFilter(const std::string& path) = 0;
|
||
|
|
||
|
// Enter new PID namespace when this process is run.
|
||
|
// NOTE: supporting this sandboxing feature is optional (provide no-op
|
||
|
// implementation if your Process implementation does not support this).
|
||
|
virtual void EnterNewPidNamespace() = 0;
|
||
|
|
||
|
// Set a flag |inherit| to indicate if the child process intend to
|
||
|
// inherit signal mask from the parent process. When |inherit| is
|
||
|
// set to true, the child process will inherit signal mask from the
|
||
|
// parent process. This could cause unintended side effect, where all
|
||
|
// the signals to the child process might be blocked if they are set
|
||
|
// in the parent's signal mask.
|
||
|
virtual void SetInheritParentSignalMask(bool inherit) = 0;
|
||
|
|
||
|
typedef base::Callback<bool(void)> PreExecCallback;
|
||
|
|
||
|
// Set the pre-exec callback. This is called after all setup is complete but
|
||
|
// before we exec() the process. The callback may return false to cause Start
|
||
|
// to return false without starting the process.
|
||
|
virtual void SetPreExecCallback(const PreExecCallback& cb) = 0;
|
||
|
|
||
|
// Sets whether starting the process should search the system path or not.
|
||
|
// By default the system path will not be searched.
|
||
|
virtual void SetSearchPath(bool search_path) = 0;
|
||
|
|
||
|
// Gets the pipe file descriptor mapped to the process's |child_fd|.
|
||
|
virtual int GetPipe(int child_fd) = 0;
|
||
|
|
||
|
// Starts this process, returning true if successful.
|
||
|
virtual bool Start() = 0;
|
||
|
|
||
|
// Waits for this process to finish. Returns the process's exit
|
||
|
// status if it exited normally, or otherwise returns -1. Note
|
||
|
// that kErrorExitStatus may be returned if an error occurred
|
||
|
// after forking and before execing the child process.
|
||
|
virtual int Wait() = 0;
|
||
|
|
||
|
// Start and wait for this process to finish. Returns same value as
|
||
|
// Wait().
|
||
|
virtual int Run() = 0;
|
||
|
|
||
|
// Returns the pid of this process or else returns 0 if there is no
|
||
|
// corresponding process (either because it has not yet been started
|
||
|
// or has since exited).
|
||
|
virtual pid_t pid() = 0;
|
||
|
|
||
|
// Sends |signal| to process and wait |timeout| seconds until it
|
||
|
// dies. If process is not a child, returns immediately with a
|
||
|
// value based on whether kill was successful. If the process is a
|
||
|
// child and |timeout| is non-zero, returns true if the process is
|
||
|
// able to be reaped within the given |timeout| in seconds.
|
||
|
virtual bool Kill(int signal, int timeout) = 0;
|
||
|
|
||
|
// Resets this Process object to refer to the process with |pid|.
|
||
|
// If |pid| is zero, this object no longer refers to a process.
|
||
|
virtual void Reset(pid_t new_pid) = 0;
|
||
|
|
||
|
// Same as Reset but reads the pid from |pid_file|. Returns false
|
||
|
// only when the file cannot be read/parsed.
|
||
|
virtual bool ResetPidByFile(const std::string& pid_file) = 0;
|
||
|
|
||
|
// Releases the process so that on destruction, the process is not killed.
|
||
|
virtual pid_t Release() = 0;
|
||
|
|
||
|
// Returns if |pid| is a currently running process.
|
||
|
static bool ProcessExists(pid_t pid);
|
||
|
|
||
|
// When returned from Wait or Run, indicates an error may have occurred
|
||
|
// creating the process.
|
||
|
enum { kErrorExitStatus = 127 };
|
||
|
};
|
||
|
|
||
|
class BRILLO_EXPORT ProcessImpl : public Process {
|
||
|
public:
|
||
|
ProcessImpl();
|
||
|
virtual ~ProcessImpl();
|
||
|
|
||
|
virtual void AddArg(const std::string& arg);
|
||
|
virtual void RedirectInput(const std::string& input_file);
|
||
|
virtual void RedirectOutput(const std::string& output_file);
|
||
|
virtual void RedirectUsingPipe(int child_fd, bool is_input);
|
||
|
virtual void BindFd(int parent_fd, int child_fd);
|
||
|
virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds);
|
||
|
virtual void SetUid(uid_t uid);
|
||
|
virtual void SetGid(gid_t gid);
|
||
|
virtual void SetCapabilities(uint64_t capmask);
|
||
|
virtual void ApplySyscallFilter(const std::string& path);
|
||
|
virtual void EnterNewPidNamespace();
|
||
|
virtual void SetInheritParentSignalMask(bool inherit);
|
||
|
virtual void SetPreExecCallback(const PreExecCallback& cb);
|
||
|
virtual void SetSearchPath(bool search_path);
|
||
|
virtual int GetPipe(int child_fd);
|
||
|
virtual bool Start();
|
||
|
virtual int Wait();
|
||
|
virtual int Run();
|
||
|
virtual pid_t pid();
|
||
|
virtual bool Kill(int signal, int timeout);
|
||
|
virtual void Reset(pid_t pid);
|
||
|
virtual bool ResetPidByFile(const std::string& pid_file);
|
||
|
virtual pid_t Release();
|
||
|
|
||
|
protected:
|
||
|
struct PipeInfo {
|
||
|
PipeInfo() : parent_fd_(-1), child_fd_(-1), is_input_(false) {}
|
||
|
// Parent (our) side of the pipe to the child process.
|
||
|
int parent_fd_;
|
||
|
// Child's side of the pipe to the parent.
|
||
|
int child_fd_;
|
||
|
// Is this an input or output pipe from child's perspective.
|
||
|
bool is_input_;
|
||
|
// Is this a bound (pre-existing) file descriptor?
|
||
|
bool is_bound_;
|
||
|
};
|
||
|
typedef std::map<int, PipeInfo> PipeMap;
|
||
|
|
||
|
void UpdatePid(pid_t new_pid);
|
||
|
bool PopulatePipeMap();
|
||
|
|
||
|
private:
|
||
|
FRIEND_TEST(ProcessTest, ResetPidByFile);
|
||
|
|
||
|
bool IsFileDescriptorInPipeMap(int fd) const;
|
||
|
void CloseUnusedFileDescriptors();
|
||
|
|
||
|
// Pid of currently managed process or 0 if no currently managed
|
||
|
// process. pid must not be modified except by calling
|
||
|
// UpdatePid(new_pid).
|
||
|
pid_t pid_;
|
||
|
std::string input_file_;
|
||
|
std::string output_file_;
|
||
|
std::vector<std::string> arguments_;
|
||
|
// Map of child target file descriptors (first) to information about
|
||
|
// pipes created (second).
|
||
|
PipeMap pipe_map_;
|
||
|
uid_t uid_;
|
||
|
gid_t gid_;
|
||
|
PreExecCallback pre_exec_;
|
||
|
bool search_path_;
|
||
|
// Flag indicating to inherit signal mask from the parent process. It
|
||
|
// is set to false by default, which means by default the child process
|
||
|
// will not inherit signal mask from the parent process.
|
||
|
bool inherit_parent_signal_mask_;
|
||
|
// Flag indicating to close unused file descriptors inherited from the
|
||
|
// parent process when starting the child process, which avoids leaking
|
||
|
// unnecessary file descriptors to the child process.
|
||
|
bool close_unused_file_descriptors_;
|
||
|
};
|
||
|
|
||
|
} // namespace brillo
|
||
|
|
||
|
#endif // LIBBRILLO_BRILLO_PROCESS_H_
|