process_util_posix.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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. 4 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> 15 16#include <limits> 17#include <set> 18 19#include "base/command_line.h" 20#include "base/compiler_specific.h" 21#include "base/debug_util.h" 22#include "base/dir_reader_posix.h" 23#include "base/eintr_wrapper.h" 24#include "base/logging.h" 25#include "base/platform_thread.h" 26#include "base/process_util.h" 27#include "base/scoped_ptr.h" 28#include "base/stringprintf.h" 29#include "base/time.h" 30#include "base/waitable_event.h" 31 32#if defined(OS_MACOSX) 33#include <crt_externs.h> 34#define environ (*_NSGetEnviron()) 35#else 36extern char** environ; 37#endif 38 39namespace base { 40 41namespace { 42 43int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, 44 bool* success) { 45 // This POSIX version of this function only guarantees that we wait no less 46 // than |wait_milliseconds| for the process to exit. The child process may 47 // exit sometime before the timeout has ended but we may still block for up 48 // to 256 milliseconds after the fact. 49 // 50 // waitpid() has no direct support on POSIX for specifying a timeout, you can 51 // either ask it to block indefinitely or return immediately (WNOHANG). 52 // When a child process terminates a SIGCHLD signal is sent to the parent. 53 // Catching this signal would involve installing a signal handler which may 54 // affect other parts of the application and would be difficult to debug. 55 // 56 // Our strategy is to call waitpid() once up front to check if the process 57 // has already exited, otherwise to loop for wait_milliseconds, sleeping for 58 // at most 256 milliseconds each time using usleep() and then calling 59 // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and 60 // we double it every 4 sleep cycles. 61 // 62 // usleep() is speced to exit if a signal is received for which a handler 63 // has been installed. This means that when a SIGCHLD is sent, it will exit 64 // depending on behavior external to this function. 65 // 66 // This function is used primarily for unit tests, if we want to use it in 67 // the application itself it would probably be best to examine other routes. 68 int status = -1; 69 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); 70 static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. 71 int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. 72 int64 double_sleep_time = 0; 73 74 // If the process hasn't exited yet, then sleep and try again. 75 Time wakeup_time = Time::Now() + 76 TimeDelta::FromMilliseconds(wait_milliseconds); 77 while (ret_pid == 0) { 78 Time now = Time::Now(); 79 if (now > wakeup_time) 80 break; 81 // Guaranteed to be non-negative! 82 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); 83 // Sleep for a bit while we wait for the process to finish. 84 if (sleep_time_usecs > max_sleep_time_usecs) 85 sleep_time_usecs = max_sleep_time_usecs; 86 87 // usleep() will return 0 and set errno to EINTR on receipt of a signal 88 // such as SIGCHLD. 89 usleep(sleep_time_usecs); 90 ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); 91 92 if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && 93 (double_sleep_time++ % 4 == 0)) { 94 max_sleep_time_usecs *= 2; 95 } 96 } 97 98 if (success) 99 *success = (ret_pid != -1); 100 101 return status; 102} 103 104void StackDumpSignalHandler(int signal) { 105 LOG(ERROR) << "Received signal " << signal; 106 StackTrace().PrintBacktrace(); 107 _exit(1); 108} 109 110void ResetChildSignalHandlersToDefaults() { 111 // The previous signal handlers are likely to be meaningless in the child's 112 // context so we reset them to the defaults for now. http://crbug.com/44953 113 // These signal handlers are setup in browser_main.cc:BrowserMain 114 signal(SIGTERM, SIG_DFL); 115 signal(SIGHUP, SIG_DFL); 116 signal(SIGINT, SIG_DFL); 117} 118 119} // anonymous namespace 120 121ProcessId GetCurrentProcId() { 122 return getpid(); 123} 124 125ProcessHandle GetCurrentProcessHandle() { 126 return GetCurrentProcId(); 127} 128 129bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) { 130 // On Posix platforms, process handles are the same as PIDs, so we 131 // don't need to do anything. 132 *handle = pid; 133 return true; 134} 135 136bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) { 137 // On POSIX permissions are checked for each operation on process, 138 // not when opening a "handle". 139 return OpenProcessHandle(pid, handle); 140} 141 142void CloseProcessHandle(ProcessHandle process) { 143 // See OpenProcessHandle, nothing to do. 144 return; 145} 146 147ProcessId GetProcId(ProcessHandle process) { 148 return process; 149} 150 151// Attempts to kill the process identified by the given process 152// entry structure. Ignores specified exit_code; posix can't force that. 153// Returns true if this is successful, false otherwise. 154bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { 155 DCHECK_GT(process_id, 1) << " tried to kill invalid process_id"; 156 if (process_id <= 1) 157 return false; 158 static unsigned kMaxSleepMs = 1000; 159 unsigned sleep_ms = 4; 160 161 bool result = kill(process_id, SIGTERM) == 0; 162 163 if (result && wait) { 164 int tries = 60; 165 // The process may not end immediately due to pending I/O 166 bool exited = false; 167 while (tries-- > 0) { 168 pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG)); 169 if (pid == process_id) { 170 exited = true; 171 break; 172 } 173 if (pid == -1) { 174 if (errno == ECHILD) { 175 // The wait may fail with ECHILD if another process also waited for 176 // the same pid, causing the process state to get cleaned up. 177 exited = true; 178 break; 179 } 180 DPLOG(ERROR) << "Error waiting for process " << process_id; 181 } 182 183 usleep(sleep_ms * 1000); 184 if (sleep_ms < kMaxSleepMs) 185 sleep_ms *= 2; 186 } 187 188 if (!exited) 189 result = kill(process_id, SIGKILL) == 0; 190 } 191 192 if (!result) 193 DPLOG(ERROR) << "Unable to terminate process " << process_id; 194 195 return result; 196} 197 198bool KillProcessGroup(ProcessHandle process_group_id) { 199 bool result = kill(-1 * process_group_id, SIGKILL) == 0; 200 if (!result) 201 PLOG(ERROR) << "Unable to terminate process group " << process_group_id; 202 return result; 203} 204 205// A class to handle auto-closing of DIR*'s. 206class ScopedDIRClose { 207 public: 208 inline void operator()(DIR* x) const { 209 if (x) { 210 closedir(x); 211 } 212 } 213}; 214typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR; 215 216#if defined(OS_LINUX) 217 static const rlim_t kSystemDefaultMaxFds = 8192; 218 static const char kFDDir[] = "/proc/self/fd"; 219#elif defined(OS_MACOSX) 220 static const rlim_t kSystemDefaultMaxFds = 256; 221 static const char kFDDir[] = "/dev/fd"; 222#elif defined(OS_SOLARIS) 223 static const rlim_t kSystemDefaultMaxFds = 8192; 224 static const char kFDDir[] = "/dev/fd"; 225#elif defined(OS_FREEBSD) 226 static const rlim_t kSystemDefaultMaxFds = 8192; 227 static const char kFDDir[] = "/dev/fd"; 228#elif defined(OS_OPENBSD) 229 static const rlim_t kSystemDefaultMaxFds = 256; 230 static const char kFDDir[] = "/dev/fd"; 231#endif 232 233void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { 234 // DANGER: no calls to malloc are allowed from now on: 235 // http://crbug.com/36678 236 237 // Get the maximum number of FDs possible. 238 struct rlimit nofile; 239 rlim_t max_fds; 240 if (getrlimit(RLIMIT_NOFILE, &nofile)) { 241 // getrlimit failed. Take a best guess. 242 max_fds = kSystemDefaultMaxFds; 243 DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno; 244 } else { 245 max_fds = nofile.rlim_cur; 246 } 247 248 if (max_fds > INT_MAX) 249 max_fds = INT_MAX; 250 251 DirReaderPosix fd_dir(kFDDir); 252 253 if (!fd_dir.IsValid()) { 254 // Fallback case: Try every possible fd. 255 for (rlim_t i = 0; i < max_fds; ++i) { 256 const int fd = static_cast<int>(i); 257 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) 258 continue; 259 InjectiveMultimap::const_iterator j; 260 for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) { 261 if (fd == j->dest) 262 break; 263 } 264 if (j != saved_mapping.end()) 265 continue; 266 267 // Since we're just trying to close anything we can find, 268 // ignore any error return values of close(). 269 int unused ALLOW_UNUSED = HANDLE_EINTR(close(fd)); 270 } 271 return; 272 } 273 274 const int dir_fd = fd_dir.fd(); 275 276 for ( ; fd_dir.Next(); ) { 277 // Skip . and .. entries. 278 if (fd_dir.name()[0] == '.') 279 continue; 280 281 char *endptr; 282 errno = 0; 283 const long int fd = strtol(fd_dir.name(), &endptr, 10); 284 if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) 285 continue; 286 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) 287 continue; 288 InjectiveMultimap::const_iterator i; 289 for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) { 290 if (fd == i->dest) 291 break; 292 } 293 if (i != saved_mapping.end()) 294 continue; 295 if (fd == dir_fd) 296 continue; 297 298 // When running under Valgrind, Valgrind opens several FDs for its 299 // own use and will complain if we try to close them. All of 300 // these FDs are >= |max_fds|, so we can check against that here 301 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 302 if (fd < static_cast<int>(max_fds)) { 303 int ret = HANDLE_EINTR(close(fd)); 304 DPCHECK(ret == 0); 305 } 306 } 307} 308 309char** AlterEnvironment(const environment_vector& changes, 310 const char* const* const env) { 311 unsigned count = 0; 312 unsigned size = 0; 313 314 // First assume that all of the current environment will be included. 315 for (unsigned i = 0; env[i]; i++) { 316 const char *const pair = env[i]; 317 count++; 318 size += strlen(pair) + 1 /* terminating NUL */; 319 } 320 321 for (environment_vector::const_iterator 322 j = changes.begin(); j != changes.end(); j++) { 323 bool found = false; 324 const char *pair; 325 326 for (unsigned i = 0; env[i]; i++) { 327 pair = env[i]; 328 const char *const equals = strchr(pair, '='); 329 if (!equals) 330 continue; 331 const unsigned keylen = equals - pair; 332 if (keylen == j->first.size() && 333 memcmp(pair, j->first.data(), keylen) == 0) { 334 found = true; 335 break; 336 } 337 } 338 339 // if found, we'll either be deleting or replacing this element. 340 if (found) { 341 count--; 342 size -= strlen(pair) + 1; 343 if (j->second.size()) 344 found = false; 345 } 346 347 // if !found, then we have a new element to add. 348 if (!found && j->second.size() > 0) { 349 count++; 350 size += j->first.size() + 1 /* '=' */ + j->second.size() + 1 /* NUL */; 351 } 352 } 353 354 count++; // for the final NULL 355 uint8_t *buffer = new uint8_t[sizeof(char*) * count + size]; 356 char **const ret = reinterpret_cast<char**>(buffer); 357 unsigned k = 0; 358 char *scratch = reinterpret_cast<char*>(buffer + sizeof(char*) * count); 359 360 for (unsigned i = 0; env[i]; i++) { 361 const char *const pair = env[i]; 362 const char *const equals = strchr(pair, '='); 363 if (!equals) { 364 const unsigned len = strlen(pair); 365 ret[k++] = scratch; 366 memcpy(scratch, pair, len + 1); 367 scratch += len + 1; 368 continue; 369 } 370 const unsigned keylen = equals - pair; 371 bool handled = false; 372 for (environment_vector::const_iterator 373 j = changes.begin(); j != changes.end(); j++) { 374 if (j->first.size() == keylen && 375 memcmp(j->first.data(), pair, keylen) == 0) { 376 if (!j->second.empty()) { 377 ret[k++] = scratch; 378 memcpy(scratch, pair, keylen + 1); 379 scratch += keylen + 1; 380 memcpy(scratch, j->second.c_str(), j->second.size() + 1); 381 scratch += j->second.size() + 1; 382 } 383 handled = true; 384 break; 385 } 386 } 387 388 if (!handled) { 389 const unsigned len = strlen(pair); 390 ret[k++] = scratch; 391 memcpy(scratch, pair, len + 1); 392 scratch += len + 1; 393 } 394 } 395 396 // Now handle new elements 397 for (environment_vector::const_iterator 398 j = changes.begin(); j != changes.end(); j++) { 399 if (j->second.size() == 0) 400 continue; 401 402 bool found = false; 403 for (unsigned i = 0; env[i]; i++) { 404 const char *const pair = env[i]; 405 const char *const equals = strchr(pair, '='); 406 if (!equals) 407 continue; 408 const unsigned keylen = equals - pair; 409 if (keylen == j->first.size() && 410 memcmp(pair, j->first.data(), keylen) == 0) { 411 found = true; 412 break; 413 } 414 } 415 416 if (!found) { 417 ret[k++] = scratch; 418 memcpy(scratch, j->first.data(), j->first.size()); 419 scratch += j->first.size(); 420 *scratch++ = '='; 421 memcpy(scratch, j->second.c_str(), j->second.size() + 1); 422 scratch += j->second.size() + 1; 423 } 424 } 425 426 ret[k] = NULL; 427 return ret; 428} 429 430bool LaunchAppImpl( 431 const std::vector<std::string>& argv, 432 const environment_vector& env_changes, 433 const file_handle_mapping_vector& fds_to_remap, 434 bool wait, 435 ProcessHandle* process_handle, 436 bool start_new_process_group) { 437 pid_t pid; 438 InjectiveMultimap fd_shuffle1, fd_shuffle2; 439 fd_shuffle1.reserve(fds_to_remap.size()); 440 fd_shuffle2.reserve(fds_to_remap.size()); 441 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); 442 scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ)); 443 444 pid = fork(); 445 if (pid < 0) 446 return false; 447 448 if (pid == 0) { 449 // Child process 450 451 if (start_new_process_group) { 452 // Instead of inheriting the process group ID of the parent, the child 453 // starts off a new process group with pgid equal to its process ID. 454 if (setpgid(0, 0) < 0) 455 return false; 456 } 457#if defined(OS_MACOSX) 458 RestoreDefaultExceptionHandler(); 459#endif 460 461 ResetChildSignalHandlersToDefaults(); 462 463#if 0 464 // When debugging it can be helpful to check that we really aren't making 465 // any hidden calls to malloc. 466 void *malloc_thunk = 467 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); 468 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); 469 memset(reinterpret_cast<void*>(malloc), 0xff, 8); 470#endif 471 472 // DANGER: no calls to malloc are allowed from now on: 473 // http://crbug.com/36678 474 475 for (file_handle_mapping_vector::const_iterator 476 it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) { 477 fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); 478 fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); 479 } 480 481 environ = new_environ.get(); 482 483 // Obscure fork() rule: in the child, if you don't end up doing exec*(), 484 // you call _exit() instead of exit(). This is because _exit() does not 485 // call any previously-registered (in the parent) exit handlers, which 486 // might do things like block waiting for threads that don't even exist 487 // in the child. 488 489 // fd_shuffle1 is mutated by this call because it cannot malloc. 490 if (!ShuffleFileDescriptors(&fd_shuffle1)) 491 _exit(127); 492 493 CloseSuperfluousFds(fd_shuffle2); 494 495 for (size_t i = 0; i < argv.size(); i++) 496 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); 497 argv_cstr[argv.size()] = NULL; 498 execvp(argv_cstr[0], argv_cstr.get()); 499 RAW_LOG(ERROR, "LaunchApp: failed to execvp:"); 500 RAW_LOG(ERROR, argv_cstr[0]); 501 _exit(127); 502 } else { 503 // Parent process 504 if (wait) { 505 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0)); 506 DPCHECK(ret > 0); 507 } 508 509 if (process_handle) 510 *process_handle = pid; 511 } 512 513 return true; 514} 515 516bool LaunchApp( 517 const std::vector<std::string>& argv, 518 const environment_vector& env_changes, 519 const file_handle_mapping_vector& fds_to_remap, 520 bool wait, 521 ProcessHandle* process_handle) { 522 return LaunchAppImpl(argv, env_changes, fds_to_remap, 523 wait, process_handle, false); 524} 525 526bool LaunchAppInNewProcessGroup( 527 const std::vector<std::string>& argv, 528 const environment_vector& env_changes, 529 const file_handle_mapping_vector& fds_to_remap, 530 bool wait, 531 ProcessHandle* process_handle) { 532 return LaunchAppImpl(argv, env_changes, fds_to_remap, wait, 533 process_handle, true); 534} 535 536bool LaunchApp(const std::vector<std::string>& argv, 537 const file_handle_mapping_vector& fds_to_remap, 538 bool wait, ProcessHandle* process_handle) { 539 base::environment_vector no_env; 540 return LaunchApp(argv, no_env, fds_to_remap, wait, process_handle); 541} 542 543bool LaunchApp(const CommandLine& cl, 544 bool wait, bool start_hidden, 545 ProcessHandle* process_handle) { 546 file_handle_mapping_vector no_files; 547 return LaunchApp(cl.argv(), no_files, wait, process_handle); 548} 549 550ProcessMetrics::~ProcessMetrics() { } 551 552void EnableTerminationOnHeapCorruption() { 553 // On POSIX, there nothing to do AFAIK. 554} 555 556bool EnableInProcessStackDumping() { 557 // When running in an application, our code typically expects SIGPIPE 558 // to be ignored. Therefore, when testing that same code, it should run 559 // with SIGPIPE ignored as well. 560 struct sigaction action; 561 action.sa_handler = SIG_IGN; 562 action.sa_flags = 0; 563 sigemptyset(&action.sa_mask); 564 bool success = (sigaction(SIGPIPE, &action, NULL) == 0); 565 566 success &= (signal(SIGILL, &StackDumpSignalHandler) != SIG_ERR); 567 success &= (signal(SIGABRT, &StackDumpSignalHandler) != SIG_ERR); 568 success &= (signal(SIGFPE, &StackDumpSignalHandler) != SIG_ERR); 569 success &= (signal(SIGBUS, &StackDumpSignalHandler) != SIG_ERR); 570 success &= (signal(SIGSEGV, &StackDumpSignalHandler) != SIG_ERR); 571 success &= (signal(SIGSYS, &StackDumpSignalHandler) != SIG_ERR); 572 573 return success; 574} 575 576void AttachToConsole() { 577 // On POSIX, there nothing to do AFAIK. Maybe create a new console if none 578 // exist? 579} 580 581void RaiseProcessToHighPriority() { 582 // On POSIX, we don't actually do anything here. We could try to nice() or 583 // setpriority() or sched_getscheduler, but these all require extra rights. 584} 585 586bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { 587 int status; 588 const pid_t result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); 589 if (result == -1) { 590 PLOG(ERROR) << "waitpid(" << handle << ")"; 591 if (child_exited) 592 *child_exited = false; 593 return false; 594 } else if (result == 0) { 595 // the child hasn't exited yet. 596 if (child_exited) 597 *child_exited = false; 598 return false; 599 } 600 601 if (child_exited) 602 *child_exited = true; 603 604 if (WIFSIGNALED(status)) { 605 switch (WTERMSIG(status)) { 606 case SIGSEGV: 607 case SIGILL: 608 case SIGABRT: 609 case SIGFPE: 610 return true; 611 default: 612 return false; 613 } 614 } 615 616 if (WIFEXITED(status)) 617 return WEXITSTATUS(status) != 0; 618 619 return false; 620} 621 622bool WaitForExitCode(ProcessHandle handle, int* exit_code) { 623 int status; 624 if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) { 625 NOTREACHED(); 626 return false; 627 } 628 629 if (WIFEXITED(status)) { 630 *exit_code = WEXITSTATUS(status); 631 return true; 632 } 633 634 // If it didn't exit cleanly, it must have been signaled. 635 DCHECK(WIFSIGNALED(status)); 636 return false; 637} 638 639bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code, 640 int64 timeout_milliseconds) { 641 bool waitpid_success = false; 642 int status = WaitpidWithTimeout(handle, timeout_milliseconds, 643 &waitpid_success); 644 if (status == -1) 645 return false; 646 if (!waitpid_success) 647 return false; 648 if (!WIFEXITED(status)) 649 return false; 650 if (WIFSIGNALED(status)) { 651 *exit_code = -1; 652 return true; 653 } 654 *exit_code = WEXITSTATUS(status); 655 return true; 656} 657 658bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) { 659 bool waitpid_success; 660 int status; 661 if (wait_milliseconds == base::kNoTimeout) 662 waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1); 663 else 664 status = WaitpidWithTimeout(handle, wait_milliseconds, &waitpid_success); 665 if (status != -1) { 666 DCHECK(waitpid_success); 667 return WIFEXITED(status); 668 } else { 669 return false; 670 } 671} 672 673bool CrashAwareSleep(ProcessHandle handle, int64 wait_milliseconds) { 674 bool waitpid_success; 675 int status = WaitpidWithTimeout(handle, wait_milliseconds, &waitpid_success); 676 if (status != -1) { 677 DCHECK(waitpid_success); 678 return !(WIFEXITED(status) || WIFSIGNALED(status)); 679 } else { 680 // If waitpid returned with an error, then the process doesn't exist 681 // (which most probably means it didn't exist before our call). 682 return waitpid_success; 683 } 684} 685 686int64 TimeValToMicroseconds(const struct timeval& tv) { 687 static const int kMicrosecondsPerSecond = 1000000; 688 int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow. 689 ret *= kMicrosecondsPerSecond; 690 ret += tv.tv_usec; 691 return ret; 692} 693 694// Executes the application specified by |cl| and wait for it to exit. Stores 695// the output (stdout) in |output|. If |do_search_path| is set, it searches the 696// path for the application; in that case, |envp| must be null, and it will use 697// the current environment. If |do_search_path| is false, |cl| should fully 698// specify the path of the application, and |envp| will be used as the 699// environment. Redirects stderr to /dev/null. Returns true on success 700// (application launched and exited cleanly, with exit code indicating success). 701static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], 702 std::string* output, size_t max_output, 703 bool do_search_path) { 704 int pipe_fd[2]; 705 pid_t pid; 706 InjectiveMultimap fd_shuffle1, fd_shuffle2; 707 const std::vector<std::string>& argv = cl.argv(); 708 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); 709 710 fd_shuffle1.reserve(3); 711 fd_shuffle2.reserve(3); 712 713 // Either |do_search_path| should be false or |envp| should be null, but not 714 // both. 715 DCHECK(!do_search_path ^ !envp); 716 717 if (pipe(pipe_fd) < 0) 718 return false; 719 720 switch (pid = fork()) { 721 case -1: // error 722 close(pipe_fd[0]); 723 close(pipe_fd[1]); 724 return false; 725 case 0: // child 726 { 727#if defined(OS_MACOSX) 728 RestoreDefaultExceptionHandler(); 729#endif 730 // DANGER: no calls to malloc are allowed from now on: 731 // http://crbug.com/36678 732 733 // Obscure fork() rule: in the child, if you don't end up doing exec*(), 734 // you call _exit() instead of exit(). This is because _exit() does not 735 // call any previously-registered (in the parent) exit handlers, which 736 // might do things like block waiting for threads that don't even exist 737 // in the child. 738 int dev_null = open("/dev/null", O_WRONLY); 739 if (dev_null < 0) 740 _exit(127); 741 742 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); 743 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); 744 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); 745 // Adding another element here? Remeber to increase the argument to 746 // reserve(), above. 747 748 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), 749 std::back_inserter(fd_shuffle2)); 750 751 if (!ShuffleFileDescriptors(&fd_shuffle1)) 752 _exit(127); 753 754 CloseSuperfluousFds(fd_shuffle2); 755 756 for (size_t i = 0; i < argv.size(); i++) 757 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); 758 argv_cstr[argv.size()] = NULL; 759 if (do_search_path) 760 execvp(argv_cstr[0], argv_cstr.get()); 761 else 762 execve(argv_cstr[0], argv_cstr.get(), envp); 763 _exit(127); 764 } 765 default: // parent 766 { 767 // Close our writing end of pipe now. Otherwise later read would not 768 // be able to detect end of child's output (in theory we could still 769 // write to the pipe). 770 close(pipe_fd[1]); 771 772 output->clear(); 773 char buffer[256]; 774 size_t output_buf_left = max_output; 775 ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0| 776 // case in the logic below. 777 778 while (output_buf_left > 0) { 779 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, 780 std::min(output_buf_left, sizeof(buffer)))); 781 if (bytes_read <= 0) 782 break; 783 output->append(buffer, bytes_read); 784 output_buf_left -= static_cast<size_t>(bytes_read); 785 } 786 close(pipe_fd[0]); 787 788 // Always wait for exit code (even if we know we'll declare success). 789 int exit_code = EXIT_FAILURE; 790 bool success = WaitForExitCode(pid, &exit_code); 791 792 // If we stopped because we read as much as we wanted, we always declare 793 // success (because the child may exit due to |SIGPIPE|). 794 if (output_buf_left || bytes_read <= 0) { 795 if (!success || exit_code != EXIT_SUCCESS) 796 return false; 797 } 798 799 return true; 800 } 801 } 802} 803 804bool GetAppOutput(const CommandLine& cl, std::string* output) { 805 // Run |execve()| with the current environment and store "unlimited" data. 806 return GetAppOutputInternal(cl, NULL, output, 807 std::numeric_limits<std::size_t>::max(), true); 808} 809 810// TODO(viettrungluu): Conceivably, we should have a timeout as well, so we 811// don't hang if what we're calling hangs. 812bool GetAppOutputRestricted(const CommandLine& cl, 813 std::string* output, size_t max_output) { 814 // Run |execve()| with the empty environment. 815 char* const empty_environ = NULL; 816 return GetAppOutputInternal(cl, &empty_environ, output, max_output, false); 817} 818 819bool WaitForProcessesToExit(const std::wstring& executable_name, 820 int64 wait_milliseconds, 821 const ProcessFilter* filter) { 822 bool result = false; 823 824 // TODO(port): This is inefficient, but works if there are multiple procs. 825 // TODO(port): use waitpid to avoid leaving zombies around 826 827 base::Time end_time = base::Time::Now() + 828 base::TimeDelta::FromMilliseconds(wait_milliseconds); 829 do { 830 NamedProcessIterator iter(executable_name, filter); 831 if (!iter.NextProcessEntry()) { 832 result = true; 833 break; 834 } 835 PlatformThread::Sleep(100); 836 } while ((base::Time::Now() - end_time) > base::TimeDelta()); 837 838 return result; 839} 840 841bool CleanupProcesses(const std::wstring& executable_name, 842 int64 wait_milliseconds, 843 int exit_code, 844 const ProcessFilter* filter) { 845 bool exited_cleanly = 846 WaitForProcessesToExit(executable_name, wait_milliseconds, 847 filter); 848 if (!exited_cleanly) 849 KillProcesses(executable_name, exit_code, filter); 850 return exited_cleanly; 851} 852 853} // namespace base 854