blob: 13f7eb776a8124a2248ae62b76d2e1826b09f9ef [file] [log] [blame]
Darin Petkov85d02b72011-05-17 13:25:51 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
adlr@google.com3defe6a2009-12-04 20:57:17 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gilad Arnoldcf175a02014-07-10 16:48:47 -07005#ifndef UPDATE_ENGINE_SUBPROCESS_H_
6#define UPDATE_ENGINE_SUBPROCESS_H_
adlr@google.com3defe6a2009-12-04 20:57:17 +00007
Ben Chan05735a12014-09-03 07:48:22 -07008#include <glib.h>
9
adlr@google.com3defe6a2009-12-04 20:57:17 +000010#include <map>
Alex Deymobc91a272014-05-20 16:45:33 -070011#include <memory>
adlr@google.com3defe6a2009-12-04 20:57:17 +000012#include <string>
13#include <vector>
Darin Petkov6f03a3b2010-11-10 14:27:14 -080014
Ben Chan05735a12014-09-03 07:48:22 -070015#include <base/logging.h>
16#include <base/macros.h>
Alex Deymo29b81532015-07-09 11:51:49 -070017#include <chromeos/message_loops/message_loop.h>
Alex Deymo60ca1a72015-06-18 18:19:15 -070018#include <gtest/gtest_prod.h> // for FRIEND_TEST
adlr@google.com3defe6a2009-12-04 20:57:17 +000019
20// The Subprocess class is a singleton. It's used to spawn off a subprocess
21// and get notified when the subprocess exits. The result of Exec() can
Alex Deymo29b81532015-07-09 11:51:49 -070022// be saved and used to cancel the callback request and kill your process. If
23// you know you won't call KillExec(), you may safely lose the return value
24// from Exec().
adlr@google.com3defe6a2009-12-04 20:57:17 +000025
26namespace chromeos_update_engine {
27
28class Subprocess {
29 public:
Darin Petkov6f03a3b2010-11-10 14:27:14 -080030 typedef void(*ExecCallback)(int return_code,
31 const std::string& output,
32 void *p);
33
adlr@google.com3defe6a2009-12-04 20:57:17 +000034 static void Init() {
35 CHECK(!subprocess_singleton_);
36 subprocess_singleton_ = new Subprocess;
37 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000038
39 // Returns a tag > 0 on success.
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070040 uint32_t Exec(const std::vector<std::string>& cmd,
41 ExecCallback callback,
42 void* p);
Alex Deymo29b81532015-07-09 11:51:49 -070043 uint32_t ExecFlags(const std::vector<std::string>& cmd,
44 GSpawnFlags flags,
45 bool redirect_stderr_to_stdout,
46 ExecCallback callback,
47 void* p);
adlr@google.com3defe6a2009-12-04 20:57:17 +000048
Alex Deymo29b81532015-07-09 11:51:49 -070049 // Kills the running process with SIGTERM and ignores the callback.
50 void KillExec(uint32_t tag);
adlr@google.com3defe6a2009-12-04 20:57:17 +000051
Darin Petkov85d02b72011-05-17 13:25:51 -070052 // Executes a command synchronously. Returns true on success. If |stdout| is
53 // non-null, the process output is stored in it, otherwise the output is
54 // logged. Note that stderr is redirected to stdout.
Andrew de los Reyes5a232832010-10-12 16:20:54 -070055 static bool SynchronousExecFlags(const std::vector<std::string>& cmd,
Darin Petkov85d02b72011-05-17 13:25:51 -070056 GSpawnFlags flags,
Andrew de los Reyes5a232832010-10-12 16:20:54 -070057 int* return_code,
Darin Petkov85d02b72011-05-17 13:25:51 -070058 std::string* stdout);
adlr@google.com3defe6a2009-12-04 20:57:17 +000059 static bool SynchronousExec(const std::vector<std::string>& cmd,
Darin Petkov85d02b72011-05-17 13:25:51 -070060 int* return_code,
61 std::string* stdout);
adlr@google.com3defe6a2009-12-04 20:57:17 +000062
Alex Deymo29b81532015-07-09 11:51:49 -070063 // Gets the one instance.
adlr@google.com3defe6a2009-12-04 20:57:17 +000064 static Subprocess& Get() {
65 return *subprocess_singleton_;
66 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080067
adlr@google.com3defe6a2009-12-04 20:57:17 +000068 // Returns true iff there is at least one subprocess we're waiting on.
Darin Petkov6f03a3b2010-11-10 14:27:14 -080069 bool SubprocessInFlight();
70
adlr@google.com3defe6a2009-12-04 20:57:17 +000071 private:
Alex Deymo60ca1a72015-06-18 18:19:15 -070072 FRIEND_TEST(SubprocessTest, CancelTest);
73
Darin Petkov6f03a3b2010-11-10 14:27:14 -080074 struct SubprocessRecord {
Alex Deymo29b81532015-07-09 11:51:49 -070075 SubprocessRecord() = default;
76
77 uint32_t tag{0};
78 chromeos::MessageLoop::TaskId task_id{chromeos::MessageLoop::kTaskIdNull};
79
80 ExecCallback callback{nullptr};
81 void* callback_data{nullptr};
82
83 GPid pid;
84
85 int stdout_fd{-1};
Darin Petkov6f03a3b2010-11-10 14:27:14 -080086 std::string stdout;
87 };
88
89 Subprocess() {}
adlr@google.com3defe6a2009-12-04 20:57:17 +000090
91 // Callback for when any subprocess terminates. This calls the user
92 // requested callback.
93 static void GChildExitedCallback(GPid pid, gint status, gpointer data);
94
Kenneth Watersa7fcafa2010-09-21 10:27:03 -070095 // Callback which runs in the child before exec to redirect stderr onto
96 // stdout.
97 static void GRedirectStderrToStdout(gpointer user_data);
98
Darin Petkov6f03a3b2010-11-10 14:27:14 -080099 // Callback which runs whenever there is input available on the subprocess
100 // stdout pipe.
Alex Deymo29b81532015-07-09 11:51:49 -0700101 static void OnStdoutReady(SubprocessRecord* record);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000102
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800103 // The global instance.
104 static Subprocess* subprocess_singleton_;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000105
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800106 // A map from the asynchronous subprocess tag (see Exec) to the subprocess
107 // record structure for all active asynchronous subprocesses.
Alex Deymo29b81532015-07-09 11:51:49 -0700108 std::map<uint32_t, std::shared_ptr<SubprocessRecord>> subprocess_records_;
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800109
adlr@google.com3defe6a2009-12-04 20:57:17 +0000110 DISALLOW_COPY_AND_ASSIGN(Subprocess);
111};
112
113} // namespace chromeos_update_engine
114
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700115#endif // UPDATE_ENGINE_SUBPROCESS_H_