Log stderr of secilc
This makes init log stderr of secilc invoked to compile SELinux policy. Having an explanation for why secilc failed is very useful for debugging boot issues. Test: Device with PRODUCT_FULL_TREBLE boots up just fine Test: Modified init.cpp to reference non-existent .cil file on a device with PRODUCT_FULL_TREBLE and confirmed that dmesg now contains the error message from secilc saying that the file was not found. Bug: 31363362 Change-Id: I6a3b3576daf0d6fd09e2c79bc43ae63850f44a00
This commit is contained in:
parent
f5dea8b393
commit
1185050767
|
@ -621,11 +621,21 @@ static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_
|
|||
|
||||
/*
|
||||
* 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).
|
||||
*
|
||||
* Returns true if the child exited with status code 0, returns false otherwise.
|
||||
*/
|
||||
static bool fork_execve_and_wait_for_completion(const char* filename, char* const argv[],
|
||||
char* const envp[]) {
|
||||
// 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;
|
||||
|
@ -634,6 +644,18 @@ static bool fork_execve_and_wait_for_completion(const char* filename, char* cons
|
|||
|
||||
if (child_pid == 0) {
|
||||
// fork succeeded -- this is executing in the child process
|
||||
|
||||
// Close the pipe FD not used by this process
|
||||
TEMP_FAILURE_RETRY(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;
|
||||
}
|
||||
TEMP_FAILURE_RETRY(close(pipe_fds[1]));
|
||||
|
||||
if (execve(filename, argv, envp) == -1) {
|
||||
PLOG(ERROR) << "Failed to execve " << filename;
|
||||
return false;
|
||||
|
@ -644,6 +666,30 @@ static bool fork_execve_and_wait_for_completion(const char* filename, char* cons
|
|||
return false;
|
||||
} else {
|
||||
// fork succeeded -- this is executing in the original/parent process
|
||||
|
||||
// Close the pipe FD not used by this process
|
||||
TEMP_FAILURE_RETRY(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;
|
||||
}
|
||||
TEMP_FAILURE_RETRY(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;
|
||||
|
|
Loading…
Reference in New Issue