1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "brillo/process.h"
6
7 #include <unistd.h>
8
9 #include <base/files/file_path.h>
10 #include <base/files/file_util.h>
11 #include <base/files/scoped_temp_dir.h>
12 #include <gtest/gtest.h>
13
14 #include "brillo/process_mock.h"
15 #include "brillo/unittest_utils.h"
16 #include "brillo/test_helpers.h"
17
18 using base::FilePath;
19
20 // This test assumes the following standard binaries are installed.
21 #if defined(__ANDROID__)
22 # define SYSTEM_PREFIX "/system"
23 static const char kBinStat[] = SYSTEM_PREFIX "/bin/stat";
24 #else
25 # define SYSTEM_PREFIX ""
26 static const char kBinStat[] = "/usr/bin/stat";
27 #endif
28
29 static const char kBinSh[] = SYSTEM_PREFIX "/bin/sh";
30 static const char kBinCat[] = SYSTEM_PREFIX "/bin/cat";
31 static const char kBinCp[] = SYSTEM_PREFIX "/bin/cp";
32 static const char kBinEcho[] = SYSTEM_PREFIX "/bin/echo";
33 static const char kBinFalse[] = SYSTEM_PREFIX "/bin/false";
34 static const char kBinSleep[] = SYSTEM_PREFIX "/bin/sleep";
35 static const char kBinTrue[] = SYSTEM_PREFIX "/bin/true";
36
37 namespace brillo {
38
39 // Test that the mock has all the functions of the interface by
40 // instantiating it. This variable is not used elsewhere.
41 struct CompileMocks {
42 ProcessMock process_mock;
43 };
44
TEST(SimpleProcess,Basic)45 TEST(SimpleProcess, Basic) {
46 // Log must be cleared before running this test, just as ProcessTest::SetUp.
47 ClearLog();
48 ProcessImpl process;
49 process.AddArg(kBinEcho);
50 EXPECT_EQ(0, process.Run());
51 EXPECT_EQ("", GetLog());
52 }
53
TEST(SimpleProcess,NoSearchPath)54 TEST(SimpleProcess, NoSearchPath) {
55 ProcessImpl process;
56 process.AddArg("echo");
57 EXPECT_EQ(127, process.Run());
58 }
59
TEST(SimpleProcess,SearchPath)60 TEST(SimpleProcess, SearchPath) {
61 ProcessImpl process;
62 process.AddArg("echo");
63 process.SetSearchPath(true);
64 EXPECT_EQ(EXIT_SUCCESS, process.Run());
65 }
66
TEST(SimpleProcess,BindFd)67 TEST(SimpleProcess, BindFd) {
68 int fds[2];
69 char buf[16];
70 static const char* kMsg = "hello, world!";
71 ProcessImpl process;
72 EXPECT_EQ(0, pipe(fds));
73 process.AddArg(kBinEcho);
74 process.AddArg(kMsg);
75 process.BindFd(fds[1], 1);
76 process.Run();
77 memset(buf, 0, sizeof(buf));
78 EXPECT_EQ(read(fds[0], buf, sizeof(buf) - 1), strlen(kMsg) + 1);
79 EXPECT_EQ(std::string(kMsg) + "\n", std::string(buf));
80 }
81
82 class ProcessTest : public ::testing::Test {
83 public:
SetUp()84 void SetUp() {
85 CHECK(temp_dir_.CreateUniqueTempDir());
86 output_file_ = temp_dir_.path().Append("fork_out").value();
87 process_.RedirectOutput(output_file_);
88 ClearLog();
89 }
90
SetUpTestCase()91 static void SetUpTestCase() {
92 base::CommandLine::Init(0, nullptr);
93 ::brillo::InitLog(brillo::kLogToStderr);
94 ::brillo::LogToString(true);
95 }
96
97 protected:
98 void CheckStderrCaptured();
99 FilePath GetFdPath(int fd);
100
101 ProcessImpl process_;
102 std::vector<const char*> args_;
103 std::string output_file_;
104 base::ScopedTempDir temp_dir_;
105 };
106
TEST_F(ProcessTest,Basic)107 TEST_F(ProcessTest, Basic) {
108 process_.AddArg(kBinEcho);
109 process_.AddArg("hello world");
110 EXPECT_EQ(0, process_.Run());
111 ExpectFileEquals("hello world\n", output_file_.c_str());
112 EXPECT_EQ("", GetLog());
113 }
114
TEST_F(ProcessTest,AddStringOption)115 TEST_F(ProcessTest, AddStringOption) {
116 process_.AddArg(kBinEcho);
117 process_.AddStringOption("--hello", "world");
118 EXPECT_EQ(0, process_.Run());
119 ExpectFileEquals("--hello world\n", output_file_.c_str());
120 }
121
TEST_F(ProcessTest,AddIntValue)122 TEST_F(ProcessTest, AddIntValue) {
123 process_.AddArg(kBinEcho);
124 process_.AddIntOption("--answer", 42);
125 EXPECT_EQ(0, process_.Run());
126 ExpectFileEquals("--answer 42\n", output_file_.c_str());
127 }
128
TEST_F(ProcessTest,NonZeroReturnValue)129 TEST_F(ProcessTest, NonZeroReturnValue) {
130 process_.AddArg(kBinFalse);
131 EXPECT_EQ(1, process_.Run());
132 ExpectFileEquals("", output_file_.c_str());
133 EXPECT_EQ("", GetLog());
134 }
135
TEST_F(ProcessTest,BadOutputFile)136 TEST_F(ProcessTest, BadOutputFile) {
137 process_.AddArg(kBinEcho);
138 process_.RedirectOutput("/bad/path");
139 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
140 }
141
TEST_F(ProcessTest,BadExecutable)142 TEST_F(ProcessTest, BadExecutable) {
143 process_.AddArg("false");
144 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
145 }
146
CheckStderrCaptured()147 void ProcessTest::CheckStderrCaptured() {
148 std::string contents;
149 process_.AddArg(kBinSh);
150 process_.AddArg("-c");
151 process_.AddArg("echo errormessage 1>&2 && exit 1");
152 EXPECT_EQ(1, process_.Run());
153 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents));
154 EXPECT_NE(std::string::npos, contents.find("errormessage"));
155 EXPECT_EQ("", GetLog());
156 }
157
TEST_F(ProcessTest,StderrCaptured)158 TEST_F(ProcessTest, StderrCaptured) {
159 CheckStderrCaptured();
160 }
161
TEST_F(ProcessTest,StderrCapturedWhenPreviouslyClosed)162 TEST_F(ProcessTest, StderrCapturedWhenPreviouslyClosed) {
163 int saved_stderr = dup(STDERR_FILENO);
164 close(STDERR_FILENO);
165 CheckStderrCaptured();
166 dup2(saved_stderr, STDERR_FILENO);
167 }
168
GetFdPath(int fd)169 FilePath ProcessTest::GetFdPath(int fd) {
170 return FilePath(base::StringPrintf("/proc/self/fd/%d", fd));
171 }
172
TEST_F(ProcessTest,RedirectStderrUsingPipe)173 TEST_F(ProcessTest, RedirectStderrUsingPipe) {
174 std::string contents;
175 process_.RedirectOutput("");
176 process_.AddArg(kBinSh);
177 process_.AddArg("-c");
178 process_.AddArg("echo errormessage >&2 && exit 1");
179 process_.RedirectUsingPipe(STDERR_FILENO, false);
180 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO));
181 EXPECT_EQ(1, process_.Run());
182 int pipe_fd = process_.GetPipe(STDERR_FILENO);
183 EXPECT_GE(pipe_fd, 0);
184 EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO));
185 EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO));
186 EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents));
187 EXPECT_NE(std::string::npos, contents.find("errormessage"));
188 EXPECT_EQ("", GetLog());
189 }
190
TEST_F(ProcessTest,RedirectStderrUsingPipeWhenPreviouslyClosed)191 TEST_F(ProcessTest, RedirectStderrUsingPipeWhenPreviouslyClosed) {
192 int saved_stderr = dup(STDERR_FILENO);
193 close(STDERR_FILENO);
194 process_.RedirectOutput("");
195 process_.AddArg(kBinCp);
196 process_.RedirectUsingPipe(STDERR_FILENO, false);
197 EXPECT_FALSE(process_.Start());
198 EXPECT_TRUE(FindLog("Unable to fstat fd 2:"));
199 dup2(saved_stderr, STDERR_FILENO);
200 }
201
TEST_F(ProcessTest,RedirectStdoutUsingPipe)202 TEST_F(ProcessTest, RedirectStdoutUsingPipe) {
203 std::string contents;
204 process_.RedirectOutput("");
205 process_.AddArg(kBinEcho);
206 process_.AddArg("hello world\n");
207 process_.RedirectUsingPipe(STDOUT_FILENO, false);
208 EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO));
209 EXPECT_EQ(0, process_.Run());
210 int pipe_fd = process_.GetPipe(STDOUT_FILENO);
211 EXPECT_GE(pipe_fd, 0);
212 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO));
213 EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO));
214 EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents));
215 EXPECT_NE(std::string::npos, contents.find("hello world\n"));
216 EXPECT_EQ("", GetLog());
217 }
218
TEST_F(ProcessTest,RedirectStdinUsingPipe)219 TEST_F(ProcessTest, RedirectStdinUsingPipe) {
220 std::string contents;
221 const char kMessage[] = "made it!\n";
222 process_.AddArg(kBinCat);
223 process_.RedirectUsingPipe(STDIN_FILENO, true);
224 process_.RedirectOutput(output_file_);
225 EXPECT_TRUE(process_.Start());
226 int write_fd = process_.GetPipe(STDIN_FILENO);
227 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO));
228 EXPECT_TRUE(base::WriteFile(GetFdPath(write_fd), kMessage, strlen(kMessage)));
229 close(write_fd);
230 EXPECT_EQ(0, process_.Wait());
231 ExpectFileEquals(kMessage, output_file_.c_str());
232 }
233
TEST_F(ProcessTest,WithSameUid)234 TEST_F(ProcessTest, WithSameUid) {
235 gid_t uid = geteuid();
236 process_.AddArg(kBinEcho);
237 process_.SetUid(uid);
238 EXPECT_EQ(0, process_.Run());
239 }
240
TEST_F(ProcessTest,WithSameGid)241 TEST_F(ProcessTest, WithSameGid) {
242 gid_t gid = getegid();
243 process_.AddArg(kBinEcho);
244 process_.SetGid(gid);
245 EXPECT_EQ(0, process_.Run());
246 }
247
TEST_F(ProcessTest,WithIllegalUid)248 TEST_F(ProcessTest, WithIllegalUid) {
249 ASSERT_NE(0, geteuid());
250 process_.AddArg(kBinEcho);
251 process_.SetUid(0);
252 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
253 std::string contents;
254 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents));
255 EXPECT_NE(std::string::npos, contents.find("Unable to set UID to 0: 1\n"));
256 }
257
TEST_F(ProcessTest,WithIllegalGid)258 TEST_F(ProcessTest, WithIllegalGid) {
259 ASSERT_NE(0, getegid());
260 process_.AddArg(kBinEcho);
261 process_.SetGid(0);
262 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
263 std::string contents;
264 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents));
265 EXPECT_NE(std::string::npos, contents.find("Unable to set GID to 0: 1\n"));
266 }
267
TEST_F(ProcessTest,NoParams)268 TEST_F(ProcessTest, NoParams) {
269 EXPECT_EQ(-1, process_.Run());
270 }
271
272 #if !defined(__BIONIC__) // Bionic intercepts the segfault on Android.
TEST_F(ProcessTest,SegFaultHandling)273 TEST_F(ProcessTest, SegFaultHandling) {
274 process_.AddArg(kBinSh);
275 process_.AddArg("-c");
276 process_.AddArg("kill -SEGV $$");
277 EXPECT_EQ(-1, process_.Run());
278 EXPECT_TRUE(FindLog("did not exit normally: 11"));
279 }
280 #endif
281
TEST_F(ProcessTest,KillHandling)282 TEST_F(ProcessTest, KillHandling) {
283 process_.AddArg(kBinSh);
284 process_.AddArg("-c");
285 process_.AddArg("kill -KILL $$");
286 EXPECT_EQ(-1, process_.Run());
287 EXPECT_TRUE(FindLog("did not exit normally: 9"));
288 }
289
290
TEST_F(ProcessTest,KillNoPid)291 TEST_F(ProcessTest, KillNoPid) {
292 process_.Kill(SIGTERM, 0);
293 EXPECT_TRUE(FindLog("Process not running"));
294 }
295
TEST_F(ProcessTest,ProcessExists)296 TEST_F(ProcessTest, ProcessExists) {
297 EXPECT_FALSE(Process::ProcessExists(0));
298 EXPECT_TRUE(Process::ProcessExists(1));
299 EXPECT_TRUE(Process::ProcessExists(getpid()));
300 }
301
TEST_F(ProcessTest,ResetPidByFile)302 TEST_F(ProcessTest, ResetPidByFile) {
303 FilePath pid_path = temp_dir_.path().Append("pid");
304 EXPECT_FALSE(process_.ResetPidByFile(pid_path.value()));
305 EXPECT_TRUE(base::WriteFile(pid_path, "456\n", 4));
306 EXPECT_TRUE(process_.ResetPidByFile(pid_path.value()));
307 EXPECT_EQ(456, process_.pid());
308 // The purpose of this unit test is to check if Process::ResetPidByFile() can
309 // properly read a pid from a file. We don't really want to kill the process
310 // with pid 456, so update the pid to 0 to prevent the Process destructor from
311 // killing any innocent process.
312 process_.UpdatePid(0);
313 }
314
TEST_F(ProcessTest,KillSleeper)315 TEST_F(ProcessTest, KillSleeper) {
316 process_.AddArg(kBinSleep);
317 process_.AddArg("10000");
318 ASSERT_TRUE(process_.Start());
319 pid_t pid = process_.pid();
320 ASSERT_GT(pid, 1);
321 EXPECT_TRUE(process_.Kill(SIGTERM, 1));
322 EXPECT_EQ(0, process_.pid());
323 }
324
TEST_F(ProcessTest,Reset)325 TEST_F(ProcessTest, Reset) {
326 process_.AddArg(kBinFalse);
327 process_.Reset(0);
328 process_.AddArg(kBinEcho);
329 EXPECT_EQ(0, process_.Run());
330 }
331
ReturnFalse()332 bool ReturnFalse() { return false; }
333
TEST_F(ProcessTest,PreExecCallback)334 TEST_F(ProcessTest, PreExecCallback) {
335 process_.AddArg(kBinTrue);
336 process_.SetPreExecCallback(base::Bind(&ReturnFalse));
337 ASSERT_NE(0, process_.Run());
338 }
339
TEST_F(ProcessTest,LeakUnusedFileDescriptors)340 TEST_F(ProcessTest, LeakUnusedFileDescriptors) {
341 ScopedPipe pipe;
342 process_.AddArg(kBinStat);
343 process_.AddArg(GetFdPath(pipe.reader).value());
344 process_.AddArg(GetFdPath(pipe.writer).value());
345 process_.SetCloseUnusedFileDescriptors(false);
346 EXPECT_EQ(0, process_.Run());
347 }
348
TEST_F(ProcessTest,CloseUnusedFileDescriptors)349 TEST_F(ProcessTest, CloseUnusedFileDescriptors) {
350 ScopedPipe pipe;
351 process_.AddArg(kBinStat);
352 process_.AddArg(GetFdPath(pipe.reader).value());
353 process_.AddArg(GetFdPath(pipe.writer).value());
354 process_.SetCloseUnusedFileDescriptors(true);
355 // Stat should fail when running on these file descriptor because the files
356 // should not be there.
357 EXPECT_EQ(1, process_.Run());
358 }
359
360 } // namespace brillo
361