Home | History | Annotate | Download | only in common
      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