• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2012 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 #include "update_engine/common/subprocess.h"
18 
19 #include <fcntl.h>
20 #include <poll.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #include <set>
25 #include <string>
26 #include <vector>
27 
28 #include <base/bind.h>
29 #include <base/files/scoped_temp_dir.h>
30 #include <base/location.h>
31 #include <base/message_loop/message_loop.h>
32 #include <base/strings/string_util.h>
33 #include <base/strings/stringprintf.h>
34 #include <base/time/time.h>
35 #include <brillo/message_loops/base_message_loop.h>
36 #include <brillo/message_loops/message_loop.h>
37 #include <brillo/message_loops/message_loop_utils.h>
38 #include <brillo/strings/string_utils.h>
39 #include <brillo/unittest_utils.h>
40 #include <gtest/gtest.h>
41 
42 #include "update_engine/common/test_utils.h"
43 #include "update_engine/common/utils.h"
44 
45 using base::TimeDelta;
46 using brillo::MessageLoop;
47 using std::string;
48 using std::vector;
49 
50 namespace {
51 
52 #ifdef __ANDROID__
53 #define kBinPath "/system/bin"
54 #define kUsrBinPath "/system/bin"
55 #else
56 #define kBinPath "/bin"
57 #define kUsrBinPath "/usr/bin"
58 #endif  // __ANDROID__
59 
60 }  // namespace
61 
62 namespace chromeos_update_engine {
63 
64 class SubprocessTest : public ::testing::Test {
65  protected:
SetUp()66   void SetUp() override {
67     loop_.SetAsCurrent();
68     async_signal_handler_.Init();
69     subprocess_.Init(&async_signal_handler_);
70   }
71 
72   base::MessageLoopForIO base_loop_;
73   brillo::BaseMessageLoop loop_{&base_loop_};
74   brillo::AsynchronousSignalHandler async_signal_handler_;
75   Subprocess subprocess_;
76 };
77 
78 namespace {
79 
ExpectedResults(int expected_return_code,const string & expected_output,int return_code,const string & output)80 void ExpectedResults(int expected_return_code,
81                      const string& expected_output,
82                      int return_code,
83                      const string& output) {
84   EXPECT_EQ(expected_return_code, return_code);
85   EXPECT_EQ(expected_output, output);
86   MessageLoop::current()->BreakLoop();
87 }
88 
ExpectedEnvVars(int return_code,const string & output)89 void ExpectedEnvVars(int return_code, const string& output) {
90   EXPECT_EQ(0, return_code);
91   const std::set<string> allowed_envs = {"LD_LIBRARY_PATH", "PATH"};
92   for (const string& key_value : brillo::string_utils::Split(output, "\n")) {
93     auto key_value_pair =
94         brillo::string_utils::SplitAtFirst(key_value, "=", true);
95     EXPECT_NE(allowed_envs.end(), allowed_envs.find(key_value_pair.first));
96   }
97   MessageLoop::current()->BreakLoop();
98 }
99 
ExpectedDataOnPipe(const Subprocess * subprocess,pid_t * pid,int child_fd,const string & child_fd_data,int expected_return_code,int return_code,const string &)100 void ExpectedDataOnPipe(const Subprocess* subprocess,
101                         pid_t* pid,
102                         int child_fd,
103                         const string& child_fd_data,
104                         int expected_return_code,
105                         int return_code,
106                         const string& /* output */) {
107   EXPECT_EQ(expected_return_code, return_code);
108 
109   // Verify that we can read the data from our end of |child_fd|.
110   int fd = subprocess->GetPipeFd(*pid, child_fd);
111   EXPECT_NE(-1, fd);
112   vector<char> buf(child_fd_data.size() + 1);
113   EXPECT_EQ(static_cast<ssize_t>(child_fd_data.size()),
114             HANDLE_EINTR(read(fd, buf.data(), buf.size())));
115   EXPECT_EQ(child_fd_data,
116             string(buf.begin(), buf.begin() + child_fd_data.size()));
117 
118   MessageLoop::current()->BreakLoop();
119 }
120 
121 }  // namespace
122 
TEST_F(SubprocessTest,IsASingleton)123 TEST_F(SubprocessTest, IsASingleton) {
124   EXPECT_EQ(&subprocess_, &Subprocess::Get());
125 }
126 
TEST_F(SubprocessTest,InactiveInstancesDontChangeTheSingleton)127 TEST_F(SubprocessTest, InactiveInstancesDontChangeTheSingleton) {
128   std::unique_ptr<Subprocess> another_subprocess(new Subprocess());
129   EXPECT_EQ(&subprocess_, &Subprocess::Get());
130   another_subprocess.reset();
131   EXPECT_EQ(&subprocess_, &Subprocess::Get());
132 }
133 
TEST_F(SubprocessTest,SimpleTest)134 TEST_F(SubprocessTest, SimpleTest) {
135   EXPECT_TRUE(subprocess_.Exec({kBinPath "/false"},
136                                base::Bind(&ExpectedResults, 1, "")));
137   loop_.Run();
138 }
139 
TEST_F(SubprocessTest,EchoTest)140 TEST_F(SubprocessTest, EchoTest) {
141   EXPECT_TRUE(subprocess_.Exec(
142       {kBinPath "/sh", "-c", "echo this is stdout; echo this is stderr >&2"},
143       base::Bind(&ExpectedResults, 0, "this is stdout\nthis is stderr\n")));
144   loop_.Run();
145 }
146 
TEST_F(SubprocessTest,StderrNotIncludedInOutputTest)147 TEST_F(SubprocessTest, StderrNotIncludedInOutputTest) {
148   EXPECT_TRUE(subprocess_.ExecFlags(
149       {kBinPath "/sh", "-c", "echo on stdout; echo on stderr >&2"},
150       0,
151       {},
152       base::Bind(&ExpectedResults, 0, "on stdout\n")));
153   loop_.Run();
154 }
155 
TEST_F(SubprocessTest,PipeRedirectFdTest)156 TEST_F(SubprocessTest, PipeRedirectFdTest) {
157   pid_t pid;
158   pid = subprocess_.ExecFlags(
159       {kBinPath "/sh", "-c", "echo on pipe >&3"},
160       0,
161       {3},
162       base::Bind(&ExpectedDataOnPipe, &subprocess_, &pid, 3, "on pipe\n", 0));
163   EXPECT_NE(0, pid);
164 
165   // Wrong file descriptor values should return -1.
166   EXPECT_EQ(-1, subprocess_.GetPipeFd(pid, 123));
167   loop_.Run();
168   // Calling GetPipeFd() after the callback runs is invalid.
169   EXPECT_EQ(-1, subprocess_.GetPipeFd(pid, 3));
170 }
171 
172 // Test that a pipe file descriptor open in the parent is not open in the child.
TEST_F(SubprocessTest,PipeClosedWhenNotRedirectedTest)173 TEST_F(SubprocessTest, PipeClosedWhenNotRedirectedTest) {
174   brillo::ScopedPipe pipe;
175 
176   // test_subprocess will return with the errno of fstat, which should be EBADF
177   // if the passed file descriptor is closed in the child.
178   const vector<string> cmd = {
179       test_utils::GetBuildArtifactsPath("test_subprocess"),
180       "fstat",
181       std::to_string(pipe.writer)};
182   EXPECT_TRUE(subprocess_.ExecFlags(
183       cmd, 0, {}, base::Bind(&ExpectedResults, EBADF, "")));
184   loop_.Run();
185 }
186 
TEST_F(SubprocessTest,EnvVarsAreFiltered)187 TEST_F(SubprocessTest, EnvVarsAreFiltered) {
188   EXPECT_TRUE(
189       subprocess_.Exec({kUsrBinPath "/env"}, base::Bind(&ExpectedEnvVars)));
190   loop_.Run();
191 }
192 
TEST_F(SubprocessTest,SynchronousTrueSearchsOnPath)193 TEST_F(SubprocessTest, SynchronousTrueSearchsOnPath) {
194   int rc = -1;
195   EXPECT_TRUE(Subprocess::SynchronousExecFlags(
196       {"true"}, Subprocess::kSearchPath, &rc, nullptr));
197   EXPECT_EQ(0, rc);
198 }
199 
TEST_F(SubprocessTest,SynchronousEchoTest)200 TEST_F(SubprocessTest, SynchronousEchoTest) {
201   vector<string> cmd = {
202       kBinPath "/sh", "-c", "echo -n stdout-here; echo -n stderr-there >&2"};
203   int rc = -1;
204   string stdout;
205   ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout));
206   EXPECT_EQ(0, rc);
207   EXPECT_EQ("stdout-herestderr-there", stdout);
208 }
209 
TEST_F(SubprocessTest,SynchronousEchoNoOutputTest)210 TEST_F(SubprocessTest, SynchronousEchoNoOutputTest) {
211   int rc = -1;
212   ASSERT_TRUE(Subprocess::SynchronousExec(
213       {kBinPath "/sh", "-c", "echo test"}, &rc, nullptr));
214   EXPECT_EQ(0, rc);
215 }
216 
217 namespace {
CallbackBad(int return_code,const string & output)218 void CallbackBad(int return_code, const string& output) {
219   ADD_FAILURE() << "should never be called.";
220 }
221 }  // namespace
222 
223 // Test that you can cancel a program that's already running.
TEST_F(SubprocessTest,CancelTest)224 TEST_F(SubprocessTest, CancelTest) {
225   base::ScopedTempDir tempdir;
226   ASSERT_TRUE(tempdir.CreateUniqueTempDir());
227   string fifo_path = tempdir.GetPath().Append("fifo").value();
228   EXPECT_EQ(0, mkfifo(fifo_path.c_str(), 0666));
229 
230   // Start a process, make sure it is running and try to cancel it. We write
231   // two bytes to the fifo, the first one marks that the program is running and
232   // the second one marks that the process waited for a timeout and was not
233   // killed. We should read the first byte but not the second one.
234   vector<string> cmd = {
235       kBinPath "/sh",
236       "-c",
237       base::StringPrintf(
238           // The 'sleep' launched below could be left behind as an orphaned
239           // process when the 'sh' process is terminated by SIGTERM. As a
240           // remedy, trap SIGTERM and kill the 'sleep' process, which requires
241           // launching 'sleep' in background and then waiting for it.
242           "cleanup() { kill \"${sleep_pid}\"; exit 0; }; "
243           "trap cleanup TERM; "
244           "sleep 60 & "
245           "sleep_pid=$!; "
246           "printf X >\"%s\"; "
247           "wait; "
248           "printf Y >\"%s\"; "
249           "exit 1",
250           fifo_path.c_str(),
251           fifo_path.c_str())};
252   uint32_t tag = Subprocess::Get().Exec(cmd, base::Bind(&CallbackBad));
253   EXPECT_NE(0U, tag);
254 
255   int fifo_fd = HANDLE_EINTR(open(fifo_path.c_str(), O_RDONLY));
256   EXPECT_GE(fifo_fd, 0);
257 
258   loop_.WatchFileDescriptor(FROM_HERE,
259                             fifo_fd,
260                             MessageLoop::WatchMode::kWatchRead,
261                             false,
262                             base::Bind(
263                                 [](int fifo_fd, uint32_t tag) {
264                                   char c;
265                                   EXPECT_EQ(1,
266                                             HANDLE_EINTR(read(fifo_fd, &c, 1)));
267                                   EXPECT_EQ('X', c);
268                                   LOG(INFO) << "Killing tag " << tag;
269                                   Subprocess::Get().KillExec(tag);
270                                 },
271                                 fifo_fd,
272                                 tag));
273 
274   // This test would leak a callback that runs when the child process exits
275   // unless we wait for it to run.
276   brillo::MessageLoopRunUntil(
277       &loop_, TimeDelta::FromSeconds(120), base::Bind([] {
278         return Subprocess::Get().subprocess_records_.empty();
279       }));
280   EXPECT_TRUE(Subprocess::Get().subprocess_records_.empty());
281   // Check that there isn't anything else to read from the pipe.
282   char c;
283   EXPECT_EQ(0, HANDLE_EINTR(read(fifo_fd, &c, 1)));
284   IGNORE_EINTR(close(fifo_fd));
285 }
286 
287 }  // namespace chromeos_update_engine
288