diff --git a/init/selinux.cpp b/init/selinux.cpp index 1f211ddfa..e191b60c0 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -111,97 +111,6 @@ bool IsEnforcing() { return true; } -// Forks, executes the provided program in the child, and waits for the completion in the parent. -// Child's stderr is captured and logged using LOG(ERROR). -bool ForkExecveAndWaitForCompletion(const char* filename, char* const argv[]) { - // Create a pipe used for redirecting child process's output. - // * pipe_fds[0] is the FD the parent will use for reading. - // * pipe_fds[1] is the FD the child will use for writing. - int pipe_fds[2]; - if (pipe(pipe_fds) == -1) { - PLOG(ERROR) << "Failed to create pipe"; - return false; - } - - pid_t child_pid = fork(); - if (child_pid == -1) { - PLOG(ERROR) << "Failed to fork for " << filename; - return false; - } - - if (child_pid == 0) { - // fork succeeded -- this is executing in the child process - - // Close the pipe FD not used by this process - close(pipe_fds[0]); - - // Redirect stderr to the pipe FD provided by the parent - if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) { - PLOG(ERROR) << "Failed to redirect stderr of " << filename; - _exit(127); - return false; - } - close(pipe_fds[1]); - - if (execv(filename, argv) == -1) { - PLOG(ERROR) << "Failed to execve " << filename; - return false; - } - // Unreachable because execve will have succeeded and replaced this code - // with child process's code. - _exit(127); - return false; - } else { - // fork succeeded -- this is executing in the original/parent process - - // Close the pipe FD not used by this process - close(pipe_fds[1]); - - // Log the redirected output of the child process. - // It's unfortunate that there's no standard way to obtain an istream for a file descriptor. - // As a result, we're buffering all output and logging it in one go at the end of the - // invocation, instead of logging it as it comes in. - const int child_out_fd = pipe_fds[0]; - std::string child_output; - if (!android::base::ReadFdToString(child_out_fd, &child_output)) { - PLOG(ERROR) << "Failed to capture full output of " << filename; - } - close(child_out_fd); - if (!child_output.empty()) { - // Log captured output, line by line, because LOG expects to be invoked for each line - std::istringstream in(child_output); - std::string line; - while (std::getline(in, line)) { - LOG(ERROR) << filename << ": " << line; - } - } - - // Wait for child to terminate - int status; - if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) { - PLOG(ERROR) << "Failed to wait for " << filename; - return false; - } - - if (WIFEXITED(status)) { - int status_code = WEXITSTATUS(status); - if (status_code == 0) { - return true; - } else { - LOG(ERROR) << filename << " exited with status " << status_code; - } - } else if (WIFSIGNALED(status)) { - LOG(ERROR) << filename << " killed by signal " << WTERMSIG(status); - } else if (WIFSTOPPED(status)) { - LOG(ERROR) << filename << " stopped by signal " << WSTOPSIG(status); - } else { - LOG(ERROR) << "waitpid for " << filename << " returned unexpected status: " << status; - } - - return false; - } -} - bool ReadFirstLine(const char* file, std::string* line) { line->clear(); diff --git a/init/util.cpp b/init/util.cpp index e760a5969..e5efc7da6 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -747,5 +748,96 @@ std::vector FilterVersionedConfigs(const std::vector& return filtered_configs; } +// Forks, executes the provided program in the child, and waits for the completion in the parent. +// Child's stderr is captured and logged using LOG(ERROR). +bool ForkExecveAndWaitForCompletion(const char* filename, char* const argv[]) { + // Create a pipe used for redirecting child process's output. + // * pipe_fds[0] is the FD the parent will use for reading. + // * pipe_fds[1] is the FD the child will use for writing. + int pipe_fds[2]; + if (pipe(pipe_fds) == -1) { + PLOG(ERROR) << "Failed to create pipe"; + return false; + } + + pid_t child_pid = fork(); + if (child_pid == -1) { + PLOG(ERROR) << "Failed to fork for " << filename; + return false; + } + + if (child_pid == 0) { + // fork succeeded -- this is executing in the child process + + // Close the pipe FD not used by this process + close(pipe_fds[0]); + + // Redirect stderr to the pipe FD provided by the parent + if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) { + PLOG(ERROR) << "Failed to redirect stderr of " << filename; + _exit(127); + return false; + } + close(pipe_fds[1]); + + if (execv(filename, argv) == -1) { + PLOG(ERROR) << "Failed to execve " << filename; + return false; + } + // Unreachable because execve will have succeeded and replaced this code + // with child process's code. + _exit(127); + return false; + } else { + // fork succeeded -- this is executing in the original/parent process + + // Close the pipe FD not used by this process + close(pipe_fds[1]); + + // Log the redirected output of the child process. + // It's unfortunate that there's no standard way to obtain an istream for a file descriptor. + // As a result, we're buffering all output and logging it in one go at the end of the + // invocation, instead of logging it as it comes in. + const int child_out_fd = pipe_fds[0]; + std::string child_output; + if (!android::base::ReadFdToString(child_out_fd, &child_output)) { + PLOG(ERROR) << "Failed to capture full output of " << filename; + } + close(child_out_fd); + if (!child_output.empty()) { + // Log captured output, line by line, because LOG expects to be invoked for each line + std::istringstream in(child_output); + std::string line; + while (std::getline(in, line)) { + LOG(ERROR) << filename << ": " << line; + } + } + + // Wait for child to terminate + int status; + if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) { + PLOG(ERROR) << "Failed to wait for " << filename; + return false; + } + + if (WIFEXITED(status)) { + int status_code = WEXITSTATUS(status); + if (status_code == 0) { + return true; + } else { + LOG(ERROR) << filename << " exited with status " << status_code; + } + } else if (WIFSIGNALED(status)) { + LOG(ERROR) << filename << " killed by signal " << WTERMSIG(status); + } else if (WIFSTOPPED(status)) { + LOG(ERROR) << filename << " stopped by signal " << WSTOPSIG(status); + } else { + LOG(ERROR) << "waitpid for " << filename << " returned unexpected status: " << status; + } + + return false; + } +} + } // namespace init } // namespace android diff --git a/init/util.h b/init/util.h index 2d0218271..aa24123df 100644 --- a/init/util.h +++ b/init/util.h @@ -117,5 +117,10 @@ std::string GetApexNameFromFileName(const std::string& path); // (.rc == .0rc for ranking purposes) std::vector FilterVersionedConfigs(const std::vector& configs, int active_sdk); + +// Forks, executes the provided program in the child, and waits for the completion in the parent. +// Child's stderr is captured and logged using LOG(ERROR). +bool ForkExecveAndWaitForCompletion(const char* filename, char* const argv[]); + } // namespace init } // namespace android