blob: 02746fea3992948de3fb465c37cee6a885c792fb [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 Deymo60ca1a72015-06-18 18:19:15 -070017#include <gtest/gtest_prod.h> // for FRIEND_TEST
adlr@google.com3defe6a2009-12-04 20:57:17 +000018
19// The Subprocess class is a singleton. It's used to spawn off a subprocess
20// and get notified when the subprocess exits. The result of Exec() can
21// be saved and used to cancel the callback request. If you know you won't
22// call CancelExec(), you may safely lose the return value from Exec().
23
24namespace chromeos_update_engine {
25
26class Subprocess {
27 public:
Darin Petkov6f03a3b2010-11-10 14:27:14 -080028 typedef void(*ExecCallback)(int return_code,
29 const std::string& output,
30 void *p);
31
adlr@google.com3defe6a2009-12-04 20:57:17 +000032 static void Init() {
33 CHECK(!subprocess_singleton_);
34 subprocess_singleton_ = new Subprocess;
35 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000036
37 // Returns a tag > 0 on success.
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070038 uint32_t Exec(const std::vector<std::string>& cmd,
39 ExecCallback callback,
40 void* p);
adlr@google.com3defe6a2009-12-04 20:57:17 +000041
42 // Used to cancel the callback. The process will still run to completion.
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070043 void CancelExec(uint32_t tag);
adlr@google.com3defe6a2009-12-04 20:57:17 +000044
Darin Petkov85d02b72011-05-17 13:25:51 -070045 // Executes a command synchronously. Returns true on success. If |stdout| is
46 // non-null, the process output is stored in it, otherwise the output is
47 // logged. Note that stderr is redirected to stdout.
Andrew de los Reyes5a232832010-10-12 16:20:54 -070048 static bool SynchronousExecFlags(const std::vector<std::string>& cmd,
Darin Petkov85d02b72011-05-17 13:25:51 -070049 GSpawnFlags flags,
Andrew de los Reyes5a232832010-10-12 16:20:54 -070050 int* return_code,
Darin Petkov85d02b72011-05-17 13:25:51 -070051 std::string* stdout);
adlr@google.com3defe6a2009-12-04 20:57:17 +000052 static bool SynchronousExec(const std::vector<std::string>& cmd,
Darin Petkov85d02b72011-05-17 13:25:51 -070053 int* return_code,
54 std::string* stdout);
adlr@google.com3defe6a2009-12-04 20:57:17 +000055
56 // Gets the one instance
57 static Subprocess& Get() {
58 return *subprocess_singleton_;
59 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080060
adlr@google.com3defe6a2009-12-04 20:57:17 +000061 // Returns true iff there is at least one subprocess we're waiting on.
Darin Petkov6f03a3b2010-11-10 14:27:14 -080062 bool SubprocessInFlight();
63
adlr@google.com3defe6a2009-12-04 20:57:17 +000064 private:
Alex Deymo60ca1a72015-06-18 18:19:15 -070065 FRIEND_TEST(SubprocessTest, CancelTest);
66
Darin Petkov6f03a3b2010-11-10 14:27:14 -080067 struct SubprocessRecord {
68 SubprocessRecord()
69 : tag(0),
Alex Vakulenko88b591f2014-08-28 16:48:57 -070070 callback(nullptr),
71 callback_data(nullptr),
72 gioout(nullptr),
Darin Petkov6f03a3b2010-11-10 14:27:14 -080073 gioout_tag(0) {}
74 uint32_t tag;
75 ExecCallback callback;
76 void* callback_data;
77 GIOChannel* gioout;
78 guint gioout_tag;
79 std::string stdout;
80 };
81
82 Subprocess() {}
adlr@google.com3defe6a2009-12-04 20:57:17 +000083
84 // Callback for when any subprocess terminates. This calls the user
85 // requested callback.
86 static void GChildExitedCallback(GPid pid, gint status, gpointer data);
87
Kenneth Watersa7fcafa2010-09-21 10:27:03 -070088 // Callback which runs in the child before exec to redirect stderr onto
89 // stdout.
90 static void GRedirectStderrToStdout(gpointer user_data);
91
Darin Petkov6f03a3b2010-11-10 14:27:14 -080092 // Callback which runs whenever there is input available on the subprocess
93 // stdout pipe.
94 static gboolean GStdoutWatchCallback(GIOChannel* source,
95 GIOCondition condition,
96 gpointer data);
adlr@google.com3defe6a2009-12-04 20:57:17 +000097
Darin Petkov6f03a3b2010-11-10 14:27:14 -080098 // The global instance.
99 static Subprocess* subprocess_singleton_;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000100
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800101 // A map from the asynchronous subprocess tag (see Exec) to the subprocess
102 // record structure for all active asynchronous subprocesses.
Ben Chanf9cb98c2014-09-21 18:31:30 -0700103 std::map<int, std::shared_ptr<SubprocessRecord>> subprocess_records_;
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800104
adlr@google.com3defe6a2009-12-04 20:57:17 +0000105 DISALLOW_COPY_AND_ASSIGN(Subprocess);
106};
107
108} // namespace chromeos_update_engine
109
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700110#endif // UPDATE_ENGINE_SUBPROCESS_H_