blob: 66b9d77a723392ba7dd7e7a296f11dfbb63a48a5 [file] [log] [blame]
Elly Jonesa44d22d2012-01-05 18:05:56 -05001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Elly Jones1c4c3a12011-12-20 15:01:59 -05002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Vakulenko262be3f2014-07-30 15:25:50 -07005#include "debugd/src/process_with_output.h"
Elly Jones1c4c3a12011-12-20 15:01:59 -05006
David Pursell300498a2014-11-03 15:47:36 -08007#include <signal.h>
8
Ben Chancd8fda42014-09-05 08:21:06 -07009#include <base/files/file_util.h>
Ben Chan9953a592014-02-05 23:32:00 -080010#include <base/strings/string_split.h>
Kevin Cernekee40dcb732018-03-20 15:08:51 -070011#include <base/strings/string_util.h>
Elly Jones1c4c3a12011-12-20 15:01:59 -050012
Eric Carusocc7106c2017-04-27 14:22:42 -070013#include "debugd/src/error_utils.h"
Hardik Goyalb09d6b02019-08-13 16:15:50 -070014#include "debugd/src/helper_utils.h"
Eric Carusocc7106c2017-04-27 14:22:42 -070015
Elly Jones1c4c3a12011-12-20 15:01:59 -050016namespace debugd {
17
David Pursell300498a2014-11-03 15:47:36 -080018namespace {
19
20const char kDBusErrorString[] = "org.chromium.debugd.error.RunProcess";
21const char kInitErrorString[] = "Process initialization failure.";
22const char kStartErrorString[] = "Process start failure.";
23const char kInputErrorString[] = "Process input write failure.";
24const char kPathLengthErrorString[] = "Path length is too long.";
25
David Pursell300498a2014-11-03 15:47:36 -080026} // namespace
27
28ProcessWithOutput::ProcessWithOutput()
29 : separate_stderr_(false), use_minijail_(true) {
30}
Ben Chan78f89532014-08-29 09:35:09 -070031
Elly Jones1c4c3a12011-12-20 15:01:59 -050032ProcessWithOutput::~ProcessWithOutput() {
David Pursell300498a2014-11-03 15:47:36 -080033 outfile_.reset();
34 errfile_.reset();
Ben Chan78f89532014-08-29 09:35:09 -070035
Elly Jones1c4c3a12011-12-20 15:01:59 -050036 if (!outfile_path_.empty())
Ben Chan9953a592014-02-05 23:32:00 -080037 base::DeleteFile(outfile_path_, false); // not recursive
David Pursell300498a2014-11-03 15:47:36 -080038 if (!errfile_path_.empty())
39 base::DeleteFile(errfile_path_, false);
Elly Jones1c4c3a12011-12-20 15:01:59 -050040}
41
42bool ProcessWithOutput::Init() {
David Pursell300498a2014-11-03 15:47:36 -080043 if (use_minijail_) {
44 if (!SandboxedProcess::Init())
45 return false;
46 }
Ben Chan78f89532014-08-29 09:35:09 -070047
David Pursell300498a2014-11-03 15:47:36 -080048 outfile_.reset(base::CreateAndOpenTemporaryFile(&outfile_path_));
49 if (!outfile_.get()) {
Elly Jones1c4c3a12011-12-20 15:01:59 -050050 return false;
David Pursell300498a2014-11-03 15:47:36 -080051 }
52 if (separate_stderr_) {
53 errfile_.reset(base::CreateAndOpenTemporaryFile(&errfile_path_));
54 if (!errfile_.get()) {
55 return false;
56 }
57 }
Ben Chan78f89532014-08-29 09:35:09 -070058
Elly Jones1c4c3a12011-12-20 15:01:59 -050059 // We can't just RedirectOutput to the file we just created, since
60 // RedirectOutput uses O_CREAT | O_EXCL to open the target file (i.e., it'll
61 // fail if the file already exists). We can't CreateTemporaryFile() and then
62 // use that filename, since we'd have to remove it before using
63 // RedirectOutput, which exposes us to a /tmp race. Instead, bind outfile_'s
64 // fd to the subprocess's stdout and stderr.
David Pursell300498a2014-11-03 15:47:36 -080065 BindFd(fileno(outfile_.get()), STDOUT_FILENO);
66 BindFd(fileno(separate_stderr_ ? errfile_.get() : outfile_.get()),
67 STDERR_FILENO);
Elly Jones1c4c3a12011-12-20 15:01:59 -050068 return true;
69}
70
Wei-Cheng Xiao9076cf52018-10-08 14:33:42 +080071bool ProcessWithOutput::GetOutputLines(std::vector<std::string>* output) const {
Elly Jones1c4c3a12011-12-20 15:01:59 -050072 std::string contents;
Wei-Cheng Xiao9076cf52018-10-08 14:33:42 +080073 if (!GetOutput(&contents))
Elly Jones1c4c3a12011-12-20 15:01:59 -050074 return false;
Ben Chan78f89532014-08-29 09:35:09 -070075
Kevin Cernekee40dcb732018-03-20 15:08:51 -070076 // If the file contains "a\nb\n", base::SplitString() will return a vector
77 // {"a", "b", ""} because it treats "\n" as a delimiter, not an EOL
78 // character. Removing the final "\n" fixes this.
79 if (base::EndsWith(contents, "\n", base::CompareCase::SENSITIVE)) {
80 contents.pop_back();
81 }
82
Alex Vakulenkoe50371c2016-01-20 16:06:19 -080083 *output = base::SplitString(contents, "\n", base::KEEP_WHITESPACE,
84 base::SPLIT_WANT_ALL);
Elly Jones1c4c3a12011-12-20 15:01:59 -050085 return true;
86}
87
Wei-Cheng Xiao9076cf52018-10-08 14:33:42 +080088bool ProcessWithOutput::GetOutput(std::string* output) const {
Ben Chan9953a592014-02-05 23:32:00 -080089 return base::ReadFileToString(outfile_path_, output);
Elly Jones1c4c3a12011-12-20 15:01:59 -050090}
91
David Pursell300498a2014-11-03 15:47:36 -080092bool ProcessWithOutput::GetError(std::string* error) {
93 return base::ReadFileToString(errfile_path_, error);
94}
95
96int ProcessWithOutput::RunProcess(const std::string& command,
97 const ArgList& arguments,
98 bool requires_root,
Wei-Cheng Xiao88aee2412018-10-15 16:03:45 +080099 bool disable_sandbox,
David Pursell300498a2014-11-03 15:47:36 -0800100 const std::string* stdin,
101 std::string* stdout,
102 std::string* stderr,
Eric Carusocc7106c2017-04-27 14:22:42 -0700103 brillo::ErrorPtr* error) {
David Pursell300498a2014-11-03 15:47:36 -0800104 ProcessWithOutput process;
Wei-Cheng Xiao88aee2412018-10-15 16:03:45 +0800105 if (disable_sandbox) {
106 process.DisableSandbox();
107 } else if (requires_root) {
David Pursell300498a2014-11-03 15:47:36 -0800108 process.SandboxAs("root", "root");
109 }
110 return DoRunProcess(
111 command, arguments, stdin, stdout, stderr, error, &process);
112}
113
114int ProcessWithOutput::RunHelper(const std::string& helper,
115 const ArgList& arguments,
116 bool requires_root,
117 const std::string* stdin,
118 std::string* stdout,
119 std::string* stderr,
Eric Carusocc7106c2017-04-27 14:22:42 -0700120 brillo::ErrorPtr* error) {
David Pursell300498a2014-11-03 15:47:36 -0800121 std::string helper_path;
Hardik Goyalb09d6b02019-08-13 16:15:50 -0700122 if (!GetHelperPath(helper, &helper_path)) {
Eric Carusocc7106c2017-04-27 14:22:42 -0700123 DEBUGD_ADD_ERROR(error, kDBusErrorString, kPathLengthErrorString);
David Pursell300498a2014-11-03 15:47:36 -0800124 return kRunError;
125 }
Wei-Cheng Xiao88aee2412018-10-15 16:03:45 +0800126 return RunProcess(helper_path, arguments, requires_root,
127 false /* disable_sandbox */, stdin, stdout, stderr, error);
David Pursell300498a2014-11-03 15:47:36 -0800128}
129
130int ProcessWithOutput::RunProcessFromHelper(const std::string& command,
131 const ArgList& arguments,
132 const std::string* stdin,
133 std::string* stdout,
134 std::string* stderr) {
135 ProcessWithOutput process;
136 process.set_use_minijail(false);
137 process.SetSearchPath(true);
138 return DoRunProcess(
139 command, arguments, stdin, stdout, stderr, nullptr, &process);
140}
141
142int ProcessWithOutput::DoRunProcess(const std::string& command,
143 const ArgList& arguments,
144 const std::string* stdin,
145 std::string* stdout,
146 std::string* stderr,
Eric Carusocc7106c2017-04-27 14:22:42 -0700147 brillo::ErrorPtr* error,
David Pursell300498a2014-11-03 15:47:36 -0800148 ProcessWithOutput* process) {
149 process->set_separate_stderr(true);
150 if (!process->Init()) {
Eric Carusocc7106c2017-04-27 14:22:42 -0700151 DEBUGD_ADD_ERROR(error, kDBusErrorString, kInitErrorString);
David Pursell300498a2014-11-03 15:47:36 -0800152 return kRunError;
153 }
154
155 process->AddArg(command);
156 for (const auto& argument : arguments) {
157 process->AddArg(argument);
158 }
159
160 int result = kRunError;
161 if (stdin) {
162 process->RedirectUsingPipe(STDIN_FILENO, true);
163 if (process->Start()) {
164 int stdin_fd = process->GetPipe(STDIN_FILENO);
165 // Kill the process if writing to or closing the pipe fails.
Alex Vakulenko26d26232014-12-10 12:52:31 -0800166 if (!base::WriteFileDescriptor(stdin_fd, stdin->c_str(),
167 stdin->length()) ||
David Pursell300498a2014-11-03 15:47:36 -0800168 IGNORE_EINTR(close(stdin_fd)) < 0) {
169 process->Kill(SIGKILL, 0);
Eric Carusocc7106c2017-04-27 14:22:42 -0700170 DEBUGD_ADD_ERROR(error, kDBusErrorString, kInputErrorString);
David Pursell300498a2014-11-03 15:47:36 -0800171 }
172 result = process->Wait();
173 } else {
Eric Carusocc7106c2017-04-27 14:22:42 -0700174 DEBUGD_ADD_ERROR(error, kDBusErrorString, kStartErrorString);
David Pursell300498a2014-11-03 15:47:36 -0800175 }
176 } else {
177 result = process->Run();
178 }
179
Eric Carusocc7106c2017-04-27 14:22:42 -0700180 if (stdout)
David Pursell300498a2014-11-03 15:47:36 -0800181 process->GetOutput(stdout);
Eric Carusocc7106c2017-04-27 14:22:42 -0700182
183 if (stderr)
David Pursell300498a2014-11-03 15:47:36 -0800184 process->GetError(stderr);
Eric Carusocc7106c2017-04-27 14:22:42 -0700185
David Pursell300498a2014-11-03 15:47:36 -0800186 return result;
187}
188
Ben Chana0011d82014-05-13 00:19:29 -0700189} // namespace debugd