blob: 1d0f994bb8de3707ff1bee9090c6001d7269ba88 [file] [log] [blame]
// Copyright 2016 The Chromium OS 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 "authpolicy/process_executor.h"
#include <algorithm>
#include "base/files/file_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
namespace authpolicy {
namespace {
// The maximum number of bytes to get from a child process
// (from stdout and stderr).
const size_t kMaxReadSize = 100*1024; // 100 Kb
// The size of the buffer used to fetch stdout and stderr.
const size_t kBufferSize = 1024; // 1 Kb
// The maximum timeout on waiting a command to run.
const base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(30);
void ReadPipe(int fd, std::string* out) {
char buffer[kBufferSize];
size_t total_read = 0;
while (total_read < kMaxReadSize) {
const ssize_t bytes_read =
HANDLE_EINTR(read(fd, buffer,
std::min(kBufferSize, kMaxReadSize - total_read)));
if (bytes_read < 0)
PLOG(ERROR) << "Failed to read from pipe.";
if (bytes_read <= 0)
break;
total_read += bytes_read;
out->append(buffer, bytes_read);
}
}
} // namespace
ProcessExecutor& ProcessExecutor::SetInputFile(int fd) {
fds_to_remap_.push_back(std::make_pair(fd, STDIN_FILENO));
return *this;
}
ProcessExecutor& ProcessExecutor::SetEnv(
const std::map<std::string, std::string>& environ) {
launch_options_.environ = environ;
return *this;
}
bool ProcessExecutor::Execute() {
int stdout_pipe[2];
if (!base::CreateLocalNonBlockingPipe(stdout_pipe)) {
LOG(ERROR) << "Failed to create pipe.";
return false;
}
base::ScopedFD stdout_read_end(stdout_pipe[0]);
base::ScopedFD stdout_write_end(stdout_pipe[1]);
int stderr_pipe[2];
if (!base::CreateLocalNonBlockingPipe(stderr_pipe)) {
LOG(ERROR) << "Failed to create pipe.";
return false;
}
base::ScopedFD stderr_read_end(stderr_pipe[0]);
base::ScopedFD stderr_write_end(stderr_pipe[1]);
fds_to_remap_.push_back(std::make_pair(stdout_write_end.get(),
STDOUT_FILENO));
fds_to_remap_.push_back(std::make_pair(stderr_write_end.get(),
STDERR_FILENO));
launch_options_.fds_to_remap = &fds_to_remap_;
launch_options_.clear_environ = true;
if (LOG_IS_ON(INFO)) {
if (!args_.empty()) {
std::string cmd = args_[0];
for (size_t n = 1; n < args_.size(); ++n)
cmd += base::StringPrintf(" '%s'", args_[n].c_str());
LOG(INFO) << "Executing " << cmd;
}
}
base::Process process(base::LaunchProcess(args_, launch_options_));
if (!process.IsValid()) {
LOG(ERROR) << "Failed to create process";
return false;
}
stdout_write_end.reset();
stderr_write_end.reset();
if (!process.WaitForExitWithTimeout(kMaxTimeout, &exit_code_)) {
LOG(ERROR) << "Failed on waiting the process to stop";
return false;
}
ReadPipe(stdout_read_end.get(), &out_data_);
ReadPipe(stderr_read_end.get(), &err_data_);
LOG(INFO) << "Stdout: " << GetStdout();
LOG(INFO) << "Stderr: " << GetStderr();
LOG(INFO) << "Exit code: " << GetExitCode();
return GetExitCode() == 0;
}
} // namespace authpolicy