1//
2// Copyright (C) 2011 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef UPDATE_ENGINE_COMMON_SUBPROCESS_H_
18#define UPDATE_ENGINE_COMMON_SUBPROCESS_H_
19
20#include <unistd.h>
21
22#include <map>
23#include <memory>
24#include <string>
25#include <vector>
26
27#include <base/callback.h>
28#include <base/logging.h>
29#include <base/macros.h>
30#include <brillo/asynchronous_signal_handler_interface.h>
31#include <brillo/message_loops/message_loop.h>
32#include <brillo/process.h>
33#include <brillo/process_reaper.h>
34#include <gtest/gtest_prod.h>  // for FRIEND_TEST
35
36// The Subprocess class is a singleton. It's used to spawn off a subprocess
37// and get notified when the subprocess exits. The result of Exec() can
38// be saved and used to cancel the callback request and kill your process. If
39// you know you won't call KillExec(), you may safely lose the return value
40// from Exec().
41
42// To create the Subprocess singleton just instantiate it with and call Init().
43// You can't have two Subprocess instances initialized at the same time.
44
45namespace chromeos_update_engine {
46
47class Subprocess {
48 public:
49  enum Flags {
50    kSearchPath = 1 << 0,
51    kRedirectStderrToStdout = 1 << 1,
52  };
53
54  // Callback type used when an async process terminates. It receives the exit
55  // code and the stdout output (and stderr if redirected).
56  using ExecCallback = base::Callback<void(int, const std::string&)>;
57
58  Subprocess() = default;
59
60  // Destroy and unregister the Subprocess singleton.
61  ~Subprocess();
62
63  // Initialize and register the Subprocess singleton.
64  void Init(brillo::AsynchronousSignalHandlerInterface* async_signal_handler);
65
66  // Launches a process in the background and calls the passed |callback| when
67  // the process exits. The file descriptors specified in |output_pipes| will
68  // be available in the child as the writer end of a pipe. Use GetPipeFd() to
69  // know the reader end in the parent. Only stdin, stdout, stderr and the file
70  // descriptors in |output_pipes| will be open in the child.
71  // Returns the process id of the new launched process or 0 in case of failure.
72  pid_t Exec(const std::vector<std::string>& cmd, const ExecCallback& callback);
73  pid_t ExecFlags(const std::vector<std::string>& cmd,
74                  uint32_t flags,
75                  const std::vector<int>& output_pipes,
76                  const ExecCallback& callback);
77
78  // Kills the running process with SIGTERM and ignores the callback.
79  void KillExec(pid_t pid);
80
81  // Return the parent end of the pipe mapped onto |fd| in the child |pid|. This
82  // file descriptor is available until the callback for the child |pid|
83  // returns. After that the file descriptor will be closed. The passed |fd|
84  // must be one of the file descriptors passed to ExecFlags() in
85  // |output_pipes|, otherwise returns -1.
86  int GetPipeFd(pid_t pid, int fd) const;
87
88  // Executes a command synchronously. Returns true on success. If |stdout| is
89  // non-null, the process output is stored in it, otherwise the output is
90  // logged. Note that stderr is redirected to stdout.
91  static bool SynchronousExec(const std::vector<std::string>& cmd,
92                              int* return_code,
93                              std::string* stdout);
94  static bool SynchronousExecFlags(const std::vector<std::string>& cmd,
95                                   uint32_t flags,
96                                   int* return_code,
97                                   std::string* stdout);
98
99  // Gets the one instance.
100  static Subprocess& Get() {
101    return *subprocess_singleton_;
102  }
103
104  // Returns true iff there is at least one subprocess we're waiting on.
105  bool SubprocessInFlight();
106
107 private:
108  FRIEND_TEST(SubprocessTest, CancelTest);
109
110  struct SubprocessRecord {
111    explicit SubprocessRecord(const ExecCallback& callback)
112      : callback(callback) {}
113
114    // The callback supplied by the caller.
115    ExecCallback callback;
116
117    // The ProcessImpl instance managing the child process. Destroying this
118    // will close our end of the pipes we have open.
119    brillo::ProcessImpl proc;
120
121    // These are used to monitor the stdout of the running process, including
122    // the stderr if it was redirected.
123    brillo::MessageLoop::TaskId stdout_task_id{
124        brillo::MessageLoop::kTaskIdNull};
125    int stdout_fd{-1};
126    std::string stdout;
127  };
128
129  // Callback which runs whenever there is input available on the subprocess
130  // stdout pipe.
131  static void OnStdoutReady(SubprocessRecord* record);
132
133  // Callback for when any subprocess terminates. This calls the user
134  // requested callback.
135  void ChildExitedCallback(const siginfo_t& info);
136
137  // The global instance.
138  static Subprocess* subprocess_singleton_;
139
140  // A map from the asynchronous subprocess tag (see Exec) to the subprocess
141  // record structure for all active asynchronous subprocesses.
142  std::map<pid_t, std::unique_ptr<SubprocessRecord>> subprocess_records_;
143
144  // Used to watch for child processes.
145  brillo::ProcessReaper process_reaper_;
146
147  DISALLOW_COPY_AND_ASSIGN(Subprocess);
148};
149
150}  // namespace chromeos_update_engine
151
152#endif  // UPDATE_ENGINE_COMMON_SUBPROCESS_H_
153