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: 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 80 void ExpectedResults(int expected_return_code, const string& expected_output, 81 int return_code, const string& output) { 82 EXPECT_EQ(expected_return_code, return_code); 83 EXPECT_EQ(expected_output, output); 84 MessageLoop::current()->BreakLoop(); 85 } 86 87 void ExpectedEnvVars(int return_code, const string& output) { 88 EXPECT_EQ(0, return_code); 89 const std::set<string> allowed_envs = {"LD_LIBRARY_PATH", "PATH"}; 90 for (const string& key_value : brillo::string_utils::Split(output, "\n")) { 91 auto key_value_pair = brillo::string_utils::SplitAtFirst( 92 key_value, "=", true); 93 EXPECT_NE(allowed_envs.end(), allowed_envs.find(key_value_pair.first)); 94 } 95 MessageLoop::current()->BreakLoop(); 96 } 97 98 void ExpectedDataOnPipe(const Subprocess* subprocess, 99 pid_t* pid, 100 int child_fd, 101 const string& child_fd_data, 102 int expected_return_code, 103 int return_code, 104 const string& /* output */) { 105 EXPECT_EQ(expected_return_code, return_code); 106 107 // Verify that we can read the data from our end of |child_fd|. 108 int fd = subprocess->GetPipeFd(*pid, child_fd); 109 EXPECT_NE(-1, fd); 110 vector<char> buf(child_fd_data.size() + 1); 111 EXPECT_EQ(static_cast<ssize_t>(child_fd_data.size()), 112 HANDLE_EINTR(read(fd, buf.data(), buf.size()))); 113 EXPECT_EQ(child_fd_data, 114 string(buf.begin(), buf.begin() + child_fd_data.size())); 115 116 MessageLoop::current()->BreakLoop(); 117 } 118 119 } // namespace 120 121 TEST_F(SubprocessTest, IsASingleton) { 122 EXPECT_EQ(&subprocess_, &Subprocess::Get()); 123 } 124 125 TEST_F(SubprocessTest, InactiveInstancesDontChangeTheSingleton) { 126 std::unique_ptr<Subprocess> another_subprocess(new Subprocess()); 127 EXPECT_EQ(&subprocess_, &Subprocess::Get()); 128 another_subprocess.reset(); 129 EXPECT_EQ(&subprocess_, &Subprocess::Get()); 130 } 131 132 TEST_F(SubprocessTest, SimpleTest) { 133 EXPECT_TRUE(subprocess_.Exec({kBinPath "/false"}, 134 base::Bind(&ExpectedResults, 1, ""))); 135 loop_.Run(); 136 } 137 138 TEST_F(SubprocessTest, EchoTest) { 139 EXPECT_TRUE(subprocess_.Exec( 140 {kBinPath "/sh", "-c", "echo this is stdout; echo this is stderr >&2"}, 141 base::Bind(&ExpectedResults, 0, "this is stdout\nthis is stderr\n"))); 142 loop_.Run(); 143 } 144 145 TEST_F(SubprocessTest, StderrNotIncludedInOutputTest) { 146 EXPECT_TRUE(subprocess_.ExecFlags( 147 {kBinPath "/sh", "-c", "echo on stdout; echo on stderr >&2"}, 148 0, 149 {}, 150 base::Bind(&ExpectedResults, 0, "on stdout\n"))); 151 loop_.Run(); 152 } 153 154 TEST_F(SubprocessTest, PipeRedirectFdTest) { 155 pid_t pid; 156 pid = subprocess_.ExecFlags( 157 {kBinPath "/sh", "-c", "echo on pipe >&3"}, 158 0, 159 {3}, 160 base::Bind(&ExpectedDataOnPipe, &subprocess_, &pid, 3, "on pipe\n", 0)); 161 EXPECT_NE(0, pid); 162 163 // Wrong file descriptor values should return -1. 164 EXPECT_EQ(-1, subprocess_.GetPipeFd(pid, 123)); 165 loop_.Run(); 166 // Calling GetPipeFd() after the callback runs is invalid. 167 EXPECT_EQ(-1, subprocess_.GetPipeFd(pid, 3)); 168 } 169 170 // Test that a pipe file descriptor open in the parent is not open in the child. 171 TEST_F(SubprocessTest, PipeClosedWhenNotRedirectedTest) { 172 brillo::ScopedPipe pipe; 173 174 // test_subprocess will return with the errno of fstat, which should be EBADF 175 // if the passed file descriptor is closed in the child. 176 const vector<string> cmd = { 177 test_utils::GetBuildArtifactsPath("test_subprocess"), 178 "fstat", 179 std::to_string(pipe.writer)}; 180 EXPECT_TRUE(subprocess_.ExecFlags( 181 cmd, 0, {}, base::Bind(&ExpectedResults, EBADF, ""))); 182 loop_.Run(); 183 } 184 185 TEST_F(SubprocessTest, EnvVarsAreFiltered) { 186 EXPECT_TRUE( 187 subprocess_.Exec({kUsrBinPath "/env"}, base::Bind(&ExpectedEnvVars))); 188 loop_.Run(); 189 } 190 191 TEST_F(SubprocessTest, SynchronousTrueSearchsOnPath) { 192 int rc = -1; 193 EXPECT_TRUE(Subprocess::SynchronousExecFlags( 194 {"true"}, Subprocess::kSearchPath, &rc, nullptr)); 195 EXPECT_EQ(0, rc); 196 } 197 198 TEST_F(SubprocessTest, SynchronousEchoTest) { 199 vector<string> cmd = { 200 kBinPath "/sh", 201 "-c", 202 "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 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 { 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. 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([](int fifo_fd, uint32_t tag) { 263 char c; 264 EXPECT_EQ(1, HANDLE_EINTR(read(fifo_fd, &c, 1))); 265 EXPECT_EQ('X', c); 266 LOG(INFO) << "Killing tag " << tag; 267 Subprocess::Get().KillExec(tag); 268 }, fifo_fd, tag)); 269 270 // This test would leak a callback that runs when the child process exits 271 // unless we wait for it to run. 272 brillo::MessageLoopRunUntil( 273 &loop_, 274 TimeDelta::FromSeconds(120), 275 base::Bind([] { return Subprocess::Get().subprocess_records_.empty(); })); 276 EXPECT_TRUE(Subprocess::Get().subprocess_records_.empty()); 277 // Check that there isn't anything else to read from the pipe. 278 char c; 279 EXPECT_EQ(0, HANDLE_EINTR(read(fifo_fd, &c, 1))); 280 IGNORE_EINTR(close(fifo_fd)); 281 } 282 283 } // namespace chromeos_update_engine 284