1 // Copyright 2014 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include "utils/process/operations.hpp"
30
31 extern "C" {
32 #include <sys/types.h>
33 #include <sys/wait.h>
34
35 #include <signal.h>
36 #include <unistd.h>
37 }
38
39 #include <cerrno>
40 #include <iostream>
41
42 #include <atf-c++.hpp>
43
44 #include "utils/defs.hpp"
45 #include "utils/format/containers.ipp"
46 #include "utils/fs/path.hpp"
47 #include "utils/process/child.ipp"
48 #include "utils/process/exceptions.hpp"
49 #include "utils/process/status.hpp"
50 #include "utils/stacktrace.hpp"
51 #include "utils/test_utils.ipp"
52
53 namespace fs = utils::fs;
54 namespace process = utils::process;
55
56
57 namespace {
58
59
60 /// Type of the process::exec() and process::exec_unsafe() functions.
61 typedef void (*exec_function)(const fs::path&, const process::args_vector&);
62
63
64 /// Calculates the path to the test helpers binary.
65 ///
66 /// \param tc A pointer to the caller test case, needed to extract the value of
67 /// the "srcdir" property.
68 ///
69 /// \return The path to the helpers binary.
70 static fs::path
get_helpers(const atf::tests::tc * tc)71 get_helpers(const atf::tests::tc* tc)
72 {
73 return fs::path(tc->get_config_var("srcdir")) / "helpers";
74 }
75
76
77 /// Body for a subprocess that runs exec().
78 class child_exec {
79 /// Function to do the exec.
80 const exec_function _do_exec;
81
82 /// Path to the binary to exec.
83 const fs::path& _program;
84
85 /// Arguments to the binary, not including argv[0].
86 const process::args_vector& _args;
87
88 public:
89 /// Constructor.
90 ///
91 /// \param do_exec Function to do the exec.
92 /// \param program Path to the binary to exec.
93 /// \param args Arguments to the binary, not including argv[0].
child_exec(const exec_function do_exec,const fs::path & program,const process::args_vector & args)94 child_exec(const exec_function do_exec, const fs::path& program,
95 const process::args_vector& args) :
96 _do_exec(do_exec), _program(program), _args(args)
97 {
98 }
99
100 /// Body for the subprocess.
101 void
operator ()(void)102 operator()(void)
103 {
104 _do_exec(_program, _args);
105 }
106 };
107
108
109 /// Body for a process that returns a specific exit code.
110 ///
111 /// \tparam ExitStatus The exit status for the subprocess.
112 template< int ExitStatus >
113 static void
child_exit(void)114 child_exit(void)
115 {
116 std::exit(ExitStatus);
117 }
118
119
120 static void suspend(void) UTILS_NORETURN;
121
122
123 /// Blocks a subprocess from running indefinitely.
124 static void
suspend(void)125 suspend(void)
126 {
127 sigset_t mask;
128 sigemptyset(&mask);
129 for (;;) {
130 ::sigsuspend(&mask);
131 }
132 }
133
134
135 static void write_loop(const int) UTILS_NORETURN;
136
137
138 /// Provides an infinite stream of data in a subprocess.
139 ///
140 /// \param fd Descriptor into which to write.
141 static void
write_loop(const int fd)142 write_loop(const int fd)
143 {
144 const int cookie = 0x12345678;
145 for (;;) {
146 std::cerr << "Still alive in PID " << ::getpid() << '\n';
147 if (::write(fd, &cookie, sizeof(cookie)) != sizeof(cookie))
148 std::exit(EXIT_FAILURE);
149 ::sleep(1);
150 }
151 }
152
153
154 } // anonymous namespace
155
156
157 /// Tests an exec function with no arguments.
158 ///
159 /// \param tc The calling test case.
160 /// \param do_exec The exec function to test.
161 static void
check_exec_no_args(const atf::tests::tc * tc,const exec_function do_exec)162 check_exec_no_args(const atf::tests::tc* tc, const exec_function do_exec)
163 {
164 std::auto_ptr< process::child > child = process::child::fork_files(
165 child_exec(do_exec, get_helpers(tc), process::args_vector()),
166 fs::path("stdout"), fs::path("stderr"));
167 const process::status status = child->wait();
168 ATF_REQUIRE(status.exited());
169 ATF_REQUIRE_EQ(EXIT_FAILURE, status.exitstatus());
170 ATF_REQUIRE(atf::utils::grep_file("Must provide a helper name", "stderr"));
171 }
172
173
174 /// Tests an exec function with some arguments.
175 ///
176 /// \param tc The calling test case.
177 /// \param do_exec The exec function to test.
178 static void
check_exec_some_args(const atf::tests::tc * tc,const exec_function do_exec)179 check_exec_some_args(const atf::tests::tc* tc, const exec_function do_exec)
180 {
181 process::args_vector args;
182 args.push_back("print-args");
183 args.push_back("foo");
184 args.push_back("bar");
185
186 std::auto_ptr< process::child > child = process::child::fork_files(
187 child_exec(do_exec, get_helpers(tc), args),
188 fs::path("stdout"), fs::path("stderr"));
189 const process::status status = child->wait();
190 ATF_REQUIRE(status.exited());
191 ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
192 ATF_REQUIRE(atf::utils::grep_file("argv\\[1\\] = print-args", "stdout"));
193 ATF_REQUIRE(atf::utils::grep_file("argv\\[2\\] = foo", "stdout"));
194 ATF_REQUIRE(atf::utils::grep_file("argv\\[3\\] = bar", "stdout"));
195 }
196
197
198 ATF_TEST_CASE_WITHOUT_HEAD(exec__no_args);
ATF_TEST_CASE_BODY(exec__no_args)199 ATF_TEST_CASE_BODY(exec__no_args)
200 {
201 check_exec_no_args(this, process::exec);
202 }
203
204
205 ATF_TEST_CASE_WITHOUT_HEAD(exec__some_args);
ATF_TEST_CASE_BODY(exec__some_args)206 ATF_TEST_CASE_BODY(exec__some_args)
207 {
208 check_exec_some_args(this, process::exec);
209 }
210
211
212 ATF_TEST_CASE_WITHOUT_HEAD(exec__fail);
ATF_TEST_CASE_BODY(exec__fail)213 ATF_TEST_CASE_BODY(exec__fail)
214 {
215 utils::avoid_coredump_on_crash();
216
217 std::auto_ptr< process::child > child = process::child::fork_files(
218 child_exec(process::exec, fs::path("non-existent"),
219 process::args_vector()),
220 fs::path("stdout"), fs::path("stderr"));
221 const process::status status = child->wait();
222 ATF_REQUIRE(status.signaled());
223 ATF_REQUIRE_EQ(SIGABRT, status.termsig());
224 ATF_REQUIRE(atf::utils::grep_file("Failed to execute non-existent",
225 "stderr"));
226 }
227
228
229 ATF_TEST_CASE_WITHOUT_HEAD(exec_unsafe__no_args);
ATF_TEST_CASE_BODY(exec_unsafe__no_args)230 ATF_TEST_CASE_BODY(exec_unsafe__no_args)
231 {
232 check_exec_no_args(this, process::exec_unsafe);
233 }
234
235
236 ATF_TEST_CASE_WITHOUT_HEAD(exec_unsafe__some_args);
ATF_TEST_CASE_BODY(exec_unsafe__some_args)237 ATF_TEST_CASE_BODY(exec_unsafe__some_args)
238 {
239 check_exec_some_args(this, process::exec_unsafe);
240 }
241
242
243 ATF_TEST_CASE_WITHOUT_HEAD(exec_unsafe__fail);
ATF_TEST_CASE_BODY(exec_unsafe__fail)244 ATF_TEST_CASE_BODY(exec_unsafe__fail)
245 {
246 ATF_REQUIRE_THROW_RE(
247 process::system_error, "Failed to execute missing-program",
248 process::exec_unsafe(fs::path("missing-program"),
249 process::args_vector()));
250 }
251
252
253 ATF_TEST_CASE_WITHOUT_HEAD(terminate_group__setpgrp_executed);
ATF_TEST_CASE_BODY(terminate_group__setpgrp_executed)254 ATF_TEST_CASE_BODY(terminate_group__setpgrp_executed)
255 {
256 int first_fds[2], second_fds[2];
257 ATF_REQUIRE(::pipe(first_fds) != -1);
258 ATF_REQUIRE(::pipe(second_fds) != -1);
259
260 const pid_t pid = ::fork();
261 ATF_REQUIRE(pid != -1);
262 if (pid == 0) {
263 ::setpgid(::getpid(), ::getpid());
264 const pid_t pid2 = ::fork();
265 if (pid2 == -1) {
266 std::exit(EXIT_FAILURE);
267 } else if (pid2 == 0) {
268 ::close(first_fds[0]);
269 ::close(first_fds[1]);
270 ::close(second_fds[0]);
271 write_loop(second_fds[1]);
272 }
273 ::close(first_fds[0]);
274 ::close(second_fds[0]);
275 ::close(second_fds[1]);
276 write_loop(first_fds[1]);
277 }
278 ::close(first_fds[1]);
279 ::close(second_fds[1]);
280
281 int dummy;
282 std::cerr << "Waiting for children to start\n";
283 while (::read(first_fds[0], &dummy, sizeof(dummy)) <= 0 ||
284 ::read(second_fds[0], &dummy, sizeof(dummy)) <= 0) {
285 // Wait for children to come up.
286 }
287
288 process::terminate_group(pid);
289 std::cerr << "Waiting for children to die\n";
290 while (::read(first_fds[0], &dummy, sizeof(dummy)) > 0 ||
291 ::read(second_fds[0], &dummy, sizeof(dummy)) > 0) {
292 // Wait for children to terminate. If they don't, then the test case
293 // will time out.
294 }
295
296 int status;
297 ATF_REQUIRE(::wait(&status) != -1);
298 ATF_REQUIRE(WIFSIGNALED(status));
299 ATF_REQUIRE(WTERMSIG(status) == SIGKILL);
300 }
301
302
303 ATF_TEST_CASE_WITHOUT_HEAD(terminate_group__setpgrp_not_executed);
ATF_TEST_CASE_BODY(terminate_group__setpgrp_not_executed)304 ATF_TEST_CASE_BODY(terminate_group__setpgrp_not_executed)
305 {
306 const pid_t pid = ::fork();
307 ATF_REQUIRE(pid != -1);
308 if (pid == 0) {
309 // We do not call setgprp() here to simulate the race that happens when
310 // we invoke terminate_group on a process that has not yet had a chance
311 // to run the setpgrp() call.
312 suspend();
313 }
314
315 process::terminate_group(pid);
316
317 int status;
318 ATF_REQUIRE(::wait(&status) != -1);
319 ATF_REQUIRE(WIFSIGNALED(status));
320 ATF_REQUIRE(WTERMSIG(status) == SIGKILL);
321 }
322
323
324 ATF_TEST_CASE_WITHOUT_HEAD(terminate_self_with__exitstatus);
ATF_TEST_CASE_BODY(terminate_self_with__exitstatus)325 ATF_TEST_CASE_BODY(terminate_self_with__exitstatus)
326 {
327 const pid_t pid = ::fork();
328 ATF_REQUIRE(pid != -1);
329 if (pid == 0) {
330 const process::status status = process::status::fake_exited(123);
331 process::terminate_self_with(status);
332 }
333
334 int status;
335 ATF_REQUIRE(::wait(&status) != -1);
336 ATF_REQUIRE(WIFEXITED(status));
337 ATF_REQUIRE(WEXITSTATUS(status) == 123);
338 }
339
340
341 ATF_TEST_CASE_WITHOUT_HEAD(terminate_self_with__termsig);
ATF_TEST_CASE_BODY(terminate_self_with__termsig)342 ATF_TEST_CASE_BODY(terminate_self_with__termsig)
343 {
344 const pid_t pid = ::fork();
345 ATF_REQUIRE(pid != -1);
346 if (pid == 0) {
347 const process::status status = process::status::fake_signaled(
348 SIGKILL, false);
349 process::terminate_self_with(status);
350 }
351
352 int status;
353 ATF_REQUIRE(::wait(&status) != -1);
354 ATF_REQUIRE(WIFSIGNALED(status));
355 ATF_REQUIRE(WTERMSIG(status) == SIGKILL);
356 ATF_REQUIRE(!WCOREDUMP(status));
357 }
358
359
360 ATF_TEST_CASE_WITHOUT_HEAD(terminate_self_with__termsig_and_core);
ATF_TEST_CASE_BODY(terminate_self_with__termsig_and_core)361 ATF_TEST_CASE_BODY(terminate_self_with__termsig_and_core)
362 {
363 utils::prepare_coredump_test(this);
364
365 const pid_t pid = ::fork();
366 ATF_REQUIRE(pid != -1);
367 if (pid == 0) {
368 const process::status status = process::status::fake_signaled(
369 SIGABRT, true);
370 process::terminate_self_with(status);
371 }
372
373 int status;
374 ATF_REQUIRE(::wait(&status) != -1);
375 ATF_REQUIRE(WIFSIGNALED(status));
376 ATF_REQUIRE(WTERMSIG(status) == SIGABRT);
377 ATF_REQUIRE(WCOREDUMP(status));
378 }
379
380
381 ATF_TEST_CASE_WITHOUT_HEAD(wait__ok);
ATF_TEST_CASE_BODY(wait__ok)382 ATF_TEST_CASE_BODY(wait__ok)
383 {
384 std::auto_ptr< process::child > child = process::child::fork_capture(
385 child_exit< 15 >);
386 const pid_t pid = child->pid();
387 child.reset(); // Ensure there is no conflict between destructor and wait.
388
389 const process::status status = process::wait(pid);
390 ATF_REQUIRE(status.exited());
391 ATF_REQUIRE_EQ(15, status.exitstatus());
392 }
393
394
395 ATF_TEST_CASE_WITHOUT_HEAD(wait__fail);
ATF_TEST_CASE_BODY(wait__fail)396 ATF_TEST_CASE_BODY(wait__fail)
397 {
398 ATF_REQUIRE_THROW(process::system_error, process::wait(1));
399 }
400
401
402 ATF_TEST_CASE_WITHOUT_HEAD(wait_any__one);
ATF_TEST_CASE_BODY(wait_any__one)403 ATF_TEST_CASE_BODY(wait_any__one)
404 {
405 process::child::fork_capture(child_exit< 15 >);
406
407 const process::status status = process::wait_any();
408 ATF_REQUIRE(status.exited());
409 ATF_REQUIRE_EQ(15, status.exitstatus());
410 }
411
412
413 ATF_TEST_CASE_WITHOUT_HEAD(wait_any__many);
ATF_TEST_CASE_BODY(wait_any__many)414 ATF_TEST_CASE_BODY(wait_any__many)
415 {
416 process::child::fork_capture(child_exit< 15 >);
417 process::child::fork_capture(child_exit< 30 >);
418 process::child::fork_capture(child_exit< 45 >);
419
420 std::set< int > exit_codes;
421 for (int i = 0; i < 3; i++) {
422 const process::status status = process::wait_any();
423 ATF_REQUIRE(status.exited());
424 exit_codes.insert(status.exitstatus());
425 }
426
427 std::set< int > exp_exit_codes;
428 exp_exit_codes.insert(15);
429 exp_exit_codes.insert(30);
430 exp_exit_codes.insert(45);
431 ATF_REQUIRE_EQ(exp_exit_codes, exit_codes);
432 }
433
434
435 ATF_TEST_CASE_WITHOUT_HEAD(wait_any__none_is_failure);
ATF_TEST_CASE_BODY(wait_any__none_is_failure)436 ATF_TEST_CASE_BODY(wait_any__none_is_failure)
437 {
438 try {
439 const process::status status = process::wait_any();
440 fail("Expected exception but none raised");
441 } catch (const process::system_error& e) {
442 ATF_REQUIRE(atf::utils::grep_string("Failed to wait", e.what()));
443 ATF_REQUIRE_EQ(ECHILD, e.original_errno());
444 }
445 }
446
447
ATF_INIT_TEST_CASES(tcs)448 ATF_INIT_TEST_CASES(tcs)
449 {
450 ATF_ADD_TEST_CASE(tcs, exec__no_args);
451 ATF_ADD_TEST_CASE(tcs, exec__some_args);
452 ATF_ADD_TEST_CASE(tcs, exec__fail);
453
454 ATF_ADD_TEST_CASE(tcs, exec_unsafe__no_args);
455 ATF_ADD_TEST_CASE(tcs, exec_unsafe__some_args);
456 ATF_ADD_TEST_CASE(tcs, exec_unsafe__fail);
457
458 ATF_ADD_TEST_CASE(tcs, terminate_group__setpgrp_executed);
459 ATF_ADD_TEST_CASE(tcs, terminate_group__setpgrp_not_executed);
460
461 ATF_ADD_TEST_CASE(tcs, terminate_self_with__exitstatus);
462 ATF_ADD_TEST_CASE(tcs, terminate_self_with__termsig);
463 ATF_ADD_TEST_CASE(tcs, terminate_self_with__termsig_and_core);
464
465 ATF_ADD_TEST_CASE(tcs, wait__ok);
466 ATF_ADD_TEST_CASE(tcs, wait__fail);
467
468 ATF_ADD_TEST_CASE(tcs, wait_any__one);
469 ATF_ADD_TEST_CASE(tcs, wait_any__many);
470 ATF_ADD_TEST_CASE(tcs, wait_any__none_is_failure);
471 }
472