| Index: sandbox/linux/services/init_process_reaper.cc
|
| diff --git a/sandbox/linux/services/init_process_reaper.cc b/sandbox/linux/services/init_process_reaper.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f7410824de5c430951ba632e092a9335a5c753a9
|
| --- /dev/null
|
| +++ b/sandbox/linux/services/init_process_reaper.cc
|
| @@ -0,0 +1,103 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "sandbox/linux/services/init_process_reaper.h"
|
| +
|
| +#include <signal.h>
|
| +#include <string.h>
|
| +#include <sys/socket.h>
|
| +#include <sys/types.h>
|
| +#include <sys/wait.h>
|
| +#include <unistd.h>
|
| +
|
| +#include "base/callback.h"
|
| +#include "base/logging.h"
|
| +#include "base/posix/eintr_wrapper.h"
|
| +
|
| +namespace sandbox {
|
| +
|
| +namespace {
|
| +
|
| +void DoNothingSignalHandler(int signal) {}
|
| +
|
| +} // namespace
|
| +
|
| +bool CreateInitProcessReaper(base::Closure* post_fork_parent_callback) {
|
| + int sync_fds[2];
|
| + // We want to use send, so we can't use a pipe
|
| + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) {
|
| + PLOG(ERROR) << "Failed to create socketpair";
|
| + return false;
|
| + }
|
| + // We use normal fork, not the ForkDelegate in this case since we are not a
|
| + // true Zygote yet.
|
| + pid_t child_pid = fork();
|
| + if (child_pid == -1) {
|
| + int close_ret;
|
| + close_ret = HANDLE_EINTR(close(sync_fds[0]));
|
| + DPCHECK(!close_ret);
|
| + close_ret = HANDLE_EINTR(close(sync_fds[1]));
|
| + DPCHECK(!close_ret);
|
| + return false;
|
| + }
|
| + if (child_pid) {
|
| + // We are the parent, assuming the role of an init process.
|
| + // The disposition for SIGCHLD cannot be SIG_IGN or wait() will only return
|
| + // once all of our childs are dead. Since we're init we need to reap childs
|
| + // as they come.
|
| + struct sigaction action;
|
| + memset(&action, 0, sizeof(action));
|
| + action.sa_handler = &DoNothingSignalHandler;
|
| + CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
|
| +
|
| + int close_ret;
|
| + close_ret = HANDLE_EINTR(close(sync_fds[0]));
|
| + DPCHECK(!close_ret);
|
| + close_ret = shutdown(sync_fds[1], SHUT_RD);
|
| + DPCHECK(!close_ret);
|
| + if (post_fork_parent_callback)
|
| + post_fork_parent_callback->Run();
|
| + // Tell the child to continue
|
| + CHECK(HANDLE_EINTR(send(sync_fds[1], "C", 1, MSG_NOSIGNAL)) == 1);
|
| + close_ret = HANDLE_EINTR(close(sync_fds[1]));
|
| + DPCHECK(!close_ret);
|
| +
|
| + for (;;) {
|
| + // Loop until we have reaped our one natural child
|
| + siginfo_t reaped_child_info;
|
| + int wait_ret =
|
| + HANDLE_EINTR(waitid(P_ALL, 0, &reaped_child_info, WEXITED));
|
| + if (wait_ret)
|
| + _exit(1);
|
| + if (reaped_child_info.si_pid == child_pid) {
|
| + int exit_code = 0;
|
| + // We're done waiting
|
| + if (reaped_child_info.si_code == CLD_EXITED) {
|
| + exit_code = reaped_child_info.si_status;
|
| + }
|
| + // Exit with the same exit code as our parent. This is most likely
|
| + // useless. _exit with 0 if we got signaled.
|
| + _exit(exit_code);
|
| + }
|
| + }
|
| + } else {
|
| + // The child needs to wait for the parent to close kZygoteIdFd to avoid a
|
| + // race condition
|
| + int close_ret;
|
| + close_ret = HANDLE_EINTR(close(sync_fds[1]));
|
| + DPCHECK(!close_ret);
|
| + close_ret = shutdown(sync_fds[0], SHUT_WR);
|
| + DPCHECK(!close_ret);
|
| + char should_continue;
|
| + int read_ret = HANDLE_EINTR(read(sync_fds[0], &should_continue, 1));
|
| + close_ret = HANDLE_EINTR(close(sync_fds[0]));
|
| + DPCHECK(!close_ret);
|
| + if (read_ret == 1)
|
| + return true;
|
| + else
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +} // namespace sandbox.
|
|
|