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 (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 const vector<string> cmd = {kBinPath "/sh", "-c", 175 base::StringPrintf("echo on pipe >/proc/self/fd/%d", pipe.writer)}; 176 EXPECT_TRUE(subprocess_.ExecFlags( 177 cmd, 178 0, 179 {}, 180 base::Bind(&ExpectedResults, 1, ""))); 181 loop_.Run(); 182 } 183 184 TEST_F(SubprocessTest, EnvVarsAreFiltered) { 185 EXPECT_TRUE( 186 subprocess_.Exec({kUsrBinPath "/env"}, base::Bind(&ExpectedEnvVars))); 187 loop_.Run(); 188 } 189 190 TEST_F(SubprocessTest, SynchronousTrueSearchsOnPath) { 191 int rc = -1; 192 EXPECT_TRUE(Subprocess::SynchronousExecFlags( 193 {"true"}, Subprocess::kSearchPath, &rc, nullptr)); 194 EXPECT_EQ(0, rc); 195 } 196 197 TEST_F(SubprocessTest, SynchronousEchoTest) { 198 vector<string> cmd = { 199 kBinPath "/sh", 200 "-c", 201 "echo -n stdout-here; echo -n stderr-there >&2"}; 202 int rc = -1; 203 string stdout; 204 ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout)); 205 EXPECT_EQ(0, rc); 206 EXPECT_EQ("stdout-herestderr-there", stdout); 207 } 208 209 TEST_F(SubprocessTest, SynchronousEchoNoOutputTest) { 210 int rc = -1; 211 ASSERT_TRUE(Subprocess::SynchronousExec( 212 {kBinPath "/sh", "-c", "echo test"}, &rc, nullptr)); 213 EXPECT_EQ(0, rc); 214 } 215 216 namespace { 217 void CallbackBad(int return_code, const string& output) { 218 ADD_FAILURE() << "should never be called."; 219 } 220 } // namespace 221 222 // Test that you can cancel a program that's already running. 223 TEST_F(SubprocessTest, CancelTest) { 224 base::ScopedTempDir tempdir; 225 ASSERT_TRUE(tempdir.CreateUniqueTempDir()); 226 string fifo_path = tempdir.path().Append("fifo").value(); 227 EXPECT_EQ(0, mkfifo(fifo_path.c_str(), 0666)); 228 229 // Start a process, make sure it is running and try to cancel it. We write 230 // two bytes to the fifo, the first one marks that the program is running and 231 // the second one marks that the process waited for a timeout and was not 232 // killed. We should read the first byte but not the second one. 233 vector<string> cmd = { 234 kBinPath "/sh", 235 "-c", 236 base::StringPrintf( 237 "echo -n X >\"%s\"; sleep 60; echo -n Y >\"%s\"; exit 1", 238 fifo_path.c_str(), 239 fifo_path.c_str())}; 240 uint32_t tag = Subprocess::Get().Exec(cmd, base::Bind(&CallbackBad)); 241 EXPECT_NE(0U, tag); 242 243 int fifo_fd = HANDLE_EINTR(open(fifo_path.c_str(), O_RDONLY)); 244 EXPECT_GE(fifo_fd, 0); 245 246 loop_.WatchFileDescriptor(FROM_HERE, 247 fifo_fd, 248 MessageLoop::WatchMode::kWatchRead, 249 false, 250 base::Bind([fifo_fd, tag] { 251 char c; 252 EXPECT_EQ(1, HANDLE_EINTR(read(fifo_fd, &c, 1))); 253 EXPECT_EQ('X', c); 254 LOG(INFO) << "Killing tag " << tag; 255 Subprocess::Get().KillExec(tag); 256 })); 257 258 // This test would leak a callback that runs when the child process exits 259 // unless we wait for it to run. 260 brillo::MessageLoopRunUntil( 261 &loop_, 262 TimeDelta::FromSeconds(120), 263 base::Bind([] { return Subprocess::Get().subprocess_records_.empty(); })); 264 EXPECT_TRUE(Subprocess::Get().subprocess_records_.empty()); 265 // Check that there isn't anything else to read from the pipe. 266 char c; 267 EXPECT_EQ(0, HANDLE_EINTR(read(fifo_fd, &c, 1))); 268 IGNORE_EINTR(close(fifo_fd)); 269 } 270 271 } // namespace chromeos_update_engine 272