Expose the method used for the next URLRequest redirect.
[chromium-blink-merge.git] / base / process_util_posix.cc
blob5b5121022bae21330193ab5cc57ffcbd308bb140
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <dirent.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <signal.h>
9 #include <stdlib.h>
10 #include <sys/resource.h>
11 #include <sys/time.h>
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <unistd.h>
16 #include <iterator>
17 #include <limits>
18 #include <set>
20 #include "base/allocator/type_profiler_control.h"
21 #include "base/command_line.h"
22 #include "base/compiler_specific.h"
23 #include "base/debug/debugger.h"
24 #include "base/debug/stack_trace.h"
25 #include "base/file_util.h"
26 #include "base/files/dir_reader_posix.h"
27 #include "base/logging.h"
28 #include "base/memory/scoped_ptr.h"
29 #include "base/posix/eintr_wrapper.h"
30 #include "base/process_util.h"
31 #include "base/strings/stringprintf.h"
32 #include "base/synchronization/waitable_event.h"
33 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
34 #include "base/threading/platform_thread.h"
35 #include "base/threading/thread_restrictions.h"
37 #if defined(OS_CHROMEOS)
38 #include <sys/ioctl.h>
39 #endif
41 #if defined(OS_FREEBSD)
42 #include <sys/event.h>
43 #include <sys/ucontext.h>
44 #endif
46 #if defined(OS_MACOSX)
47 #include <crt_externs.h>
48 #include <sys/event.h>
49 #else
50 extern char** environ;
51 #endif
53 namespace base {
55 namespace {
57 // Get the process's "environment" (i.e. the thing that setenv/getenv
58 // work with).
59 char** GetEnvironment() {
60 #if defined(OS_MACOSX)
61 return *_NSGetEnviron();
62 #else
63 return environ;
64 #endif
67 // Set the process's "environment" (i.e. the thing that setenv/getenv
68 // work with).
69 void SetEnvironment(char** env) {
70 #if defined(OS_MACOSX)
71 *_NSGetEnviron() = env;
72 #else
73 environ = env;
74 #endif
77 #if !defined(OS_LINUX) || \
78 (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
79 void ResetChildSignalHandlersToDefaults() {
80 // The previous signal handlers are likely to be meaningless in the child's
81 // context so we reset them to the defaults for now. http://crbug.com/44953
82 // These signal handlers are set up at least in browser_main_posix.cc:
83 // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc:
84 // EnableInProcessStackDumping.
85 signal(SIGHUP, SIG_DFL);
86 signal(SIGINT, SIG_DFL);
87 signal(SIGILL, SIG_DFL);
88 signal(SIGABRT, SIG_DFL);
89 signal(SIGFPE, SIG_DFL);
90 signal(SIGBUS, SIG_DFL);
91 signal(SIGSEGV, SIG_DFL);
92 signal(SIGSYS, SIG_DFL);
93 signal(SIGTERM, SIG_DFL);
96 #else
98 // TODO(jln): remove the Linux special case once kernels are fixed.
100 // Internally the kernel makes sigset_t an array of long large enough to have
101 // one bit per signal.
102 typedef uint64_t kernel_sigset_t;
104 // This is what struct sigaction looks like to the kernel at least on X86 and
105 // ARM. MIPS, for instance, is very different.
106 struct kernel_sigaction {
107 void* k_sa_handler; // For this usage it only needs to be a generic pointer.
108 unsigned long k_sa_flags;
109 void* k_sa_restorer; // For this usage it only needs to be a generic pointer.
110 kernel_sigset_t k_sa_mask;
113 // glibc's sigaction() will prevent access to sa_restorer, so we need to roll
114 // our own.
115 int sys_rt_sigaction(int sig, const struct kernel_sigaction* act,
116 struct kernel_sigaction* oact) {
117 return syscall(SYS_rt_sigaction, sig, act, oact, sizeof(kernel_sigset_t));
120 // This function is intended to be used in between fork() and execve() and will
121 // reset all signal handlers to the default.
122 // The motivation for going through all of them is that sa_restorer can leak
123 // from parents and help defeat ASLR on buggy kernels. We reset it to NULL.
124 // See crbug.com/177956.
125 void ResetChildSignalHandlersToDefaults(void) {
126 for (int signum = 1; ; ++signum) {
127 struct kernel_sigaction act = {0};
128 int sigaction_get_ret = sys_rt_sigaction(signum, NULL, &act);
129 if (sigaction_get_ret && errno == EINVAL) {
130 #if !defined(NDEBUG)
131 // Linux supports 32 real-time signals from 33 to 64.
132 // If the number of signals in the Linux kernel changes, someone should
133 // look at this code.
134 const int kNumberOfSignals = 64;
135 RAW_CHECK(signum == kNumberOfSignals + 1);
136 #endif // !defined(NDEBUG)
137 break;
139 // All other failures are fatal.
140 if (sigaction_get_ret) {
141 RAW_LOG(FATAL, "sigaction (get) failed.");
144 // The kernel won't allow to re-set SIGKILL or SIGSTOP.
145 if (signum != SIGSTOP && signum != SIGKILL) {
146 act.k_sa_handler = reinterpret_cast<void*>(SIG_DFL);
147 act.k_sa_restorer = NULL;
148 if (sys_rt_sigaction(signum, &act, NULL)) {
149 RAW_LOG(FATAL, "sigaction (set) failed.");
152 #if !defined(NDEBUG)
153 // Now ask the kernel again and check that no restorer will leak.
154 if (sys_rt_sigaction(signum, NULL, &act) || act.k_sa_restorer) {
155 RAW_LOG(FATAL, "Cound not fix sa_restorer.");
157 #endif // !defined(NDEBUG)
160 #endif // !defined(OS_LINUX) ||
161 // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
163 } // anonymous namespace
165 // A class to handle auto-closing of DIR*'s.
166 class ScopedDIRClose {
167 public:
168 inline void operator()(DIR* x) const {
169 if (x) {
170 closedir(x);
174 typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
176 #if defined(OS_LINUX)
177 static const char kFDDir[] = "/proc/self/fd";
178 #elif defined(OS_MACOSX)
179 static const char kFDDir[] = "/dev/fd";
180 #elif defined(OS_SOLARIS)
181 static const char kFDDir[] = "/dev/fd";
182 #elif defined(OS_FREEBSD)
183 static const char kFDDir[] = "/dev/fd";
184 #elif defined(OS_OPENBSD)
185 static const char kFDDir[] = "/dev/fd";
186 #elif defined(OS_ANDROID)
187 static const char kFDDir[] = "/proc/self/fd";
188 #endif
190 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
191 // DANGER: no calls to malloc are allowed from now on:
192 // http://crbug.com/36678
194 // Get the maximum number of FDs possible.
195 size_t max_fds = GetMaxFds();
197 DirReaderPosix fd_dir(kFDDir);
198 if (!fd_dir.IsValid()) {
199 // Fallback case: Try every possible fd.
200 for (size_t i = 0; i < max_fds; ++i) {
201 const int fd = static_cast<int>(i);
202 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
203 continue;
204 InjectiveMultimap::const_iterator j;
205 for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) {
206 if (fd == j->dest)
207 break;
209 if (j != saved_mapping.end())
210 continue;
212 // Since we're just trying to close anything we can find,
213 // ignore any error return values of close().
214 ignore_result(HANDLE_EINTR(close(fd)));
216 return;
219 const int dir_fd = fd_dir.fd();
221 for ( ; fd_dir.Next(); ) {
222 // Skip . and .. entries.
223 if (fd_dir.name()[0] == '.')
224 continue;
226 char *endptr;
227 errno = 0;
228 const long int fd = strtol(fd_dir.name(), &endptr, 10);
229 if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno)
230 continue;
231 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
232 continue;
233 InjectiveMultimap::const_iterator i;
234 for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) {
235 if (fd == i->dest)
236 break;
238 if (i != saved_mapping.end())
239 continue;
240 if (fd == dir_fd)
241 continue;
243 // When running under Valgrind, Valgrind opens several FDs for its
244 // own use and will complain if we try to close them. All of
245 // these FDs are >= |max_fds|, so we can check against that here
246 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758
247 if (fd < static_cast<int>(max_fds)) {
248 int ret = HANDLE_EINTR(close(fd));
249 DPCHECK(ret == 0);
254 char** AlterEnvironment(const EnvironmentVector& changes,
255 const char* const* const env) {
256 unsigned count = 0;
257 unsigned size = 0;
259 // First assume that all of the current environment will be included.
260 for (unsigned i = 0; env[i]; i++) {
261 const char *const pair = env[i];
262 count++;
263 size += strlen(pair) + 1 /* terminating NUL */;
266 for (EnvironmentVector::const_iterator j = changes.begin();
267 j != changes.end();
268 ++j) {
269 bool found = false;
270 const char *pair;
272 for (unsigned i = 0; env[i]; i++) {
273 pair = env[i];
274 const char *const equals = strchr(pair, '=');
275 if (!equals)
276 continue;
277 const unsigned keylen = equals - pair;
278 if (keylen == j->first.size() &&
279 memcmp(pair, j->first.data(), keylen) == 0) {
280 found = true;
281 break;
285 // if found, we'll either be deleting or replacing this element.
286 if (found) {
287 count--;
288 size -= strlen(pair) + 1;
289 if (j->second.size())
290 found = false;
293 // if !found, then we have a new element to add.
294 if (!found && !j->second.empty()) {
295 count++;
296 size += j->first.size() + 1 /* '=' */ + j->second.size() + 1 /* NUL */;
300 count++; // for the final NULL
301 uint8_t *buffer = new uint8_t[sizeof(char*) * count + size];
302 char **const ret = reinterpret_cast<char**>(buffer);
303 unsigned k = 0;
304 char *scratch = reinterpret_cast<char*>(buffer + sizeof(char*) * count);
306 for (unsigned i = 0; env[i]; i++) {
307 const char *const pair = env[i];
308 const char *const equals = strchr(pair, '=');
309 if (!equals) {
310 const unsigned len = strlen(pair);
311 ret[k++] = scratch;
312 memcpy(scratch, pair, len + 1);
313 scratch += len + 1;
314 continue;
316 const unsigned keylen = equals - pair;
317 bool handled = false;
318 for (EnvironmentVector::const_iterator
319 j = changes.begin(); j != changes.end(); j++) {
320 if (j->first.size() == keylen &&
321 memcmp(j->first.data(), pair, keylen) == 0) {
322 if (!j->second.empty()) {
323 ret[k++] = scratch;
324 memcpy(scratch, pair, keylen + 1);
325 scratch += keylen + 1;
326 memcpy(scratch, j->second.c_str(), j->second.size() + 1);
327 scratch += j->second.size() + 1;
329 handled = true;
330 break;
334 if (!handled) {
335 const unsigned len = strlen(pair);
336 ret[k++] = scratch;
337 memcpy(scratch, pair, len + 1);
338 scratch += len + 1;
342 // Now handle new elements
343 for (EnvironmentVector::const_iterator
344 j = changes.begin(); j != changes.end(); j++) {
345 if (j->second.empty())
346 continue;
348 bool found = false;
349 for (unsigned i = 0; env[i]; i++) {
350 const char *const pair = env[i];
351 const char *const equals = strchr(pair, '=');
352 if (!equals)
353 continue;
354 const unsigned keylen = equals - pair;
355 if (keylen == j->first.size() &&
356 memcmp(pair, j->first.data(), keylen) == 0) {
357 found = true;
358 break;
362 if (!found) {
363 ret[k++] = scratch;
364 memcpy(scratch, j->first.data(), j->first.size());
365 scratch += j->first.size();
366 *scratch++ = '=';
367 memcpy(scratch, j->second.c_str(), j->second.size() + 1);
368 scratch += j->second.size() + 1;
372 ret[k] = NULL;
373 return ret;
376 bool LaunchProcess(const std::vector<std::string>& argv,
377 const LaunchOptions& options,
378 ProcessHandle* process_handle) {
379 size_t fd_shuffle_size = 0;
380 if (options.fds_to_remap) {
381 fd_shuffle_size = options.fds_to_remap->size();
384 InjectiveMultimap fd_shuffle1;
385 InjectiveMultimap fd_shuffle2;
386 fd_shuffle1.reserve(fd_shuffle_size);
387 fd_shuffle2.reserve(fd_shuffle_size);
389 scoped_ptr<char*[]> argv_cstr(new char*[argv.size() + 1]);
390 scoped_ptr<char*[]> new_environ;
391 if (options.environ)
392 new_environ.reset(AlterEnvironment(*options.environ, GetEnvironment()));
394 pid_t pid;
395 #if defined(OS_LINUX)
396 if (options.clone_flags) {
397 pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0);
398 } else
399 #endif
401 pid = fork();
404 if (pid < 0) {
405 DPLOG(ERROR) << "fork";
406 return false;
407 } else if (pid == 0) {
408 // Child process
410 // DANGER: fork() rule: in the child, if you don't end up doing exec*(),
411 // you call _exit() instead of exit(). This is because _exit() does not
412 // call any previously-registered (in the parent) exit handlers, which
413 // might do things like block waiting for threads that don't even exist
414 // in the child.
416 // If a child process uses the readline library, the process block forever.
417 // In BSD like OSes including OS X it is safe to assign /dev/null as stdin.
418 // See http://crbug.com/56596.
419 int null_fd = HANDLE_EINTR(open("/dev/null", O_RDONLY));
420 if (null_fd < 0) {
421 RAW_LOG(ERROR, "Failed to open /dev/null");
422 _exit(127);
425 file_util::ScopedFD null_fd_closer(&null_fd);
426 int new_fd = HANDLE_EINTR(dup2(null_fd, STDIN_FILENO));
427 if (new_fd != STDIN_FILENO) {
428 RAW_LOG(ERROR, "Failed to dup /dev/null for stdin");
429 _exit(127);
432 if (options.new_process_group) {
433 // Instead of inheriting the process group ID of the parent, the child
434 // starts off a new process group with pgid equal to its process ID.
435 if (setpgid(0, 0) < 0) {
436 RAW_LOG(ERROR, "setpgid failed");
437 _exit(127);
441 // Stop type-profiler.
442 // The profiler should be stopped between fork and exec since it inserts
443 // locks at new/delete expressions. See http://crbug.com/36678.
444 base::type_profiler::Controller::Stop();
446 if (options.maximize_rlimits) {
447 // Some resource limits need to be maximal in this child.
448 std::set<int>::const_iterator resource;
449 for (resource = options.maximize_rlimits->begin();
450 resource != options.maximize_rlimits->end();
451 ++resource) {
452 struct rlimit limit;
453 if (getrlimit(*resource, &limit) < 0) {
454 RAW_LOG(WARNING, "getrlimit failed");
455 } else if (limit.rlim_cur < limit.rlim_max) {
456 limit.rlim_cur = limit.rlim_max;
457 if (setrlimit(*resource, &limit) < 0) {
458 RAW_LOG(WARNING, "setrlimit failed");
464 #if defined(OS_MACOSX)
465 RestoreDefaultExceptionHandler();
466 #endif // defined(OS_MACOSX)
468 ResetChildSignalHandlersToDefaults();
470 #if 0
471 // When debugging it can be helpful to check that we really aren't making
472 // any hidden calls to malloc.
473 void *malloc_thunk =
474 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095);
475 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
476 memset(reinterpret_cast<void*>(malloc), 0xff, 8);
477 #endif // 0
479 // DANGER: no calls to malloc are allowed from now on:
480 // http://crbug.com/36678
482 #if defined(OS_CHROMEOS)
483 if (options.ctrl_terminal_fd >= 0) {
484 // Set process' controlling terminal.
485 if (HANDLE_EINTR(setsid()) != -1) {
486 if (HANDLE_EINTR(
487 ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) {
488 RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set");
490 } else {
491 RAW_LOG(WARNING, "setsid failed, ctrl terminal not set");
494 #endif // defined(OS_CHROMEOS)
496 if (options.fds_to_remap) {
497 for (FileHandleMappingVector::const_iterator
498 it = options.fds_to_remap->begin();
499 it != options.fds_to_remap->end(); ++it) {
500 fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
501 fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
505 if (options.environ)
506 SetEnvironment(new_environ.get());
508 // fd_shuffle1 is mutated by this call because it cannot malloc.
509 if (!ShuffleFileDescriptors(&fd_shuffle1))
510 _exit(127);
512 CloseSuperfluousFds(fd_shuffle2);
514 for (size_t i = 0; i < argv.size(); i++)
515 argv_cstr[i] = const_cast<char*>(argv[i].c_str());
516 argv_cstr[argv.size()] = NULL;
517 execvp(argv_cstr[0], argv_cstr.get());
519 RAW_LOG(ERROR, "LaunchProcess: failed to execvp:");
520 RAW_LOG(ERROR, argv_cstr[0]);
521 _exit(127);
522 } else {
523 // Parent process
524 if (options.wait) {
525 // While this isn't strictly disk IO, waiting for another process to
526 // finish is the sort of thing ThreadRestrictions is trying to prevent.
527 base::ThreadRestrictions::AssertIOAllowed();
528 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0));
529 DPCHECK(ret > 0);
532 if (process_handle)
533 *process_handle = pid;
536 return true;
540 bool LaunchProcess(const CommandLine& cmdline,
541 const LaunchOptions& options,
542 ProcessHandle* process_handle) {
543 return LaunchProcess(cmdline.argv(), options, process_handle);
546 void RaiseProcessToHighPriority() {
547 // On POSIX, we don't actually do anything here. We could try to nice() or
548 // setpriority() or sched_getscheduler, but these all require extra rights.
551 // Return value used by GetAppOutputInternal to encapsulate the various exit
552 // scenarios from the function.
553 enum GetAppOutputInternalResult {
554 EXECUTE_FAILURE,
555 EXECUTE_SUCCESS,
556 GOT_MAX_OUTPUT,
559 // Executes the application specified by |argv| and wait for it to exit. Stores
560 // the output (stdout) in |output|. If |do_search_path| is set, it searches the
561 // path for the application; in that case, |envp| must be null, and it will use
562 // the current environment. If |do_search_path| is false, |argv[0]| should fully
563 // specify the path of the application, and |envp| will be used as the
564 // environment. Redirects stderr to /dev/null.
565 // If we successfully start the application and get all requested output, we
566 // return GOT_MAX_OUTPUT, or if there is a problem starting or exiting
567 // the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS.
568 // The GOT_MAX_OUTPUT return value exists so a caller that asks for limited
569 // output can treat this as a success, despite having an exit code of SIG_PIPE
570 // due to us closing the output pipe.
571 // In the case of EXECUTE_SUCCESS, the application exit code will be returned
572 // in |*exit_code|, which should be checked to determine if the application
573 // ran successfully.
574 static GetAppOutputInternalResult GetAppOutputInternal(
575 const std::vector<std::string>& argv,
576 char* const envp[],
577 std::string* output,
578 size_t max_output,
579 bool do_search_path,
580 int* exit_code) {
581 // Doing a blocking wait for another command to finish counts as IO.
582 base::ThreadRestrictions::AssertIOAllowed();
583 // exit_code must be supplied so calling function can determine success.
584 DCHECK(exit_code);
585 *exit_code = EXIT_FAILURE;
587 int pipe_fd[2];
588 pid_t pid;
589 InjectiveMultimap fd_shuffle1, fd_shuffle2;
590 scoped_ptr<char*[]> argv_cstr(new char*[argv.size() + 1]);
592 fd_shuffle1.reserve(3);
593 fd_shuffle2.reserve(3);
595 // Either |do_search_path| should be false or |envp| should be null, but not
596 // both.
597 DCHECK(!do_search_path ^ !envp);
599 if (pipe(pipe_fd) < 0)
600 return EXECUTE_FAILURE;
602 switch (pid = fork()) {
603 case -1: // error
604 close(pipe_fd[0]);
605 close(pipe_fd[1]);
606 return EXECUTE_FAILURE;
607 case 0: // child
609 #if defined(OS_MACOSX)
610 RestoreDefaultExceptionHandler();
611 #endif
612 // DANGER: no calls to malloc are allowed from now on:
613 // http://crbug.com/36678
615 // Obscure fork() rule: in the child, if you don't end up doing exec*(),
616 // you call _exit() instead of exit(). This is because _exit() does not
617 // call any previously-registered (in the parent) exit handlers, which
618 // might do things like block waiting for threads that don't even exist
619 // in the child.
620 int dev_null = open("/dev/null", O_WRONLY);
621 if (dev_null < 0)
622 _exit(127);
624 // Stop type-profiler.
625 // The profiler should be stopped between fork and exec since it inserts
626 // locks at new/delete expressions. See http://crbug.com/36678.
627 base::type_profiler::Controller::Stop();
629 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
630 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true));
631 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
632 // Adding another element here? Remeber to increase the argument to
633 // reserve(), above.
635 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(),
636 std::back_inserter(fd_shuffle2));
638 if (!ShuffleFileDescriptors(&fd_shuffle1))
639 _exit(127);
641 CloseSuperfluousFds(fd_shuffle2);
643 for (size_t i = 0; i < argv.size(); i++)
644 argv_cstr[i] = const_cast<char*>(argv[i].c_str());
645 argv_cstr[argv.size()] = NULL;
646 if (do_search_path)
647 execvp(argv_cstr[0], argv_cstr.get());
648 else
649 execve(argv_cstr[0], argv_cstr.get(), envp);
650 _exit(127);
652 default: // parent
654 // Close our writing end of pipe now. Otherwise later read would not
655 // be able to detect end of child's output (in theory we could still
656 // write to the pipe).
657 close(pipe_fd[1]);
659 output->clear();
660 char buffer[256];
661 size_t output_buf_left = max_output;
662 ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0|
663 // case in the logic below.
665 while (output_buf_left > 0) {
666 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer,
667 std::min(output_buf_left, sizeof(buffer))));
668 if (bytes_read <= 0)
669 break;
670 output->append(buffer, bytes_read);
671 output_buf_left -= static_cast<size_t>(bytes_read);
673 close(pipe_fd[0]);
675 // Always wait for exit code (even if we know we'll declare
676 // GOT_MAX_OUTPUT).
677 bool success = WaitForExitCode(pid, exit_code);
679 // If we stopped because we read as much as we wanted, we return
680 // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|).
681 if (!output_buf_left && bytes_read > 0)
682 return GOT_MAX_OUTPUT;
683 else if (success)
684 return EXECUTE_SUCCESS;
685 return EXECUTE_FAILURE;
690 bool GetAppOutput(const CommandLine& cl, std::string* output) {
691 return GetAppOutput(cl.argv(), output);
694 bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
695 // Run |execve()| with the current environment and store "unlimited" data.
696 int exit_code;
697 GetAppOutputInternalResult result = GetAppOutputInternal(
698 argv, NULL, output, std::numeric_limits<std::size_t>::max(), true,
699 &exit_code);
700 return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS;
703 // TODO(viettrungluu): Conceivably, we should have a timeout as well, so we
704 // don't hang if what we're calling hangs.
705 bool GetAppOutputRestricted(const CommandLine& cl,
706 std::string* output, size_t max_output) {
707 // Run |execve()| with the empty environment.
708 char* const empty_environ = NULL;
709 int exit_code;
710 GetAppOutputInternalResult result = GetAppOutputInternal(
711 cl.argv(), &empty_environ, output, max_output, false, &exit_code);
712 return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS &&
713 exit_code == EXIT_SUCCESS);
716 bool GetAppOutputWithExitCode(const CommandLine& cl,
717 std::string* output,
718 int* exit_code) {
719 // Run |execve()| with the current environment and store "unlimited" data.
720 GetAppOutputInternalResult result = GetAppOutputInternal(
721 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true,
722 exit_code);
723 return result == EXECUTE_SUCCESS;
726 } // namespace base