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