shell_service.cpp revision 18ddf5c6a233bd56d20548fd834c0ecbf8216410
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17// Functionality for launching and managing shell subprocesses. 18// 19// There are two types of subprocesses, PTY or raw. PTY is typically used for 20// an interactive session, raw for non-interactive. There are also two methods 21// of communication with the subprocess, passing raw data or using a simple 22// protocol to wrap packets. The protocol allows separating stdout/stderr and 23// passing the exit code back, but is not backwards compatible. 24// ----------------+-------------------------------------- 25// Type Protocol | Exit code? Separate stdout/stderr? 26// ----------------+-------------------------------------- 27// PTY No | No No 28// Raw No | No No 29// PTY Yes | Yes No 30// Raw Yes | Yes Yes 31// ----------------+-------------------------------------- 32// 33// Non-protocol subprocesses work by passing subprocess stdin/out/err through 34// a single pipe which is registered with a local socket in adbd. The local 35// socket uses the fdevent loop to pass raw data between this pipe and the 36// transport, which then passes data back to the adb client. Cleanup is done by 37// waiting in a separate thread for the subprocesses to exit and then signaling 38// a separate fdevent to close out the local socket from the main loop. 39// 40// ------------------+-------------------------+------------------------------ 41// Subprocess | adbd subprocess thread | adbd main fdevent loop 42// ------------------+-------------------------+------------------------------ 43// | | 44// stdin/out/err <-----------------------------> LocalSocket 45// | | | 46// | | Block on exit | 47// | | * | 48// v | * | 49// Exit ---> Unblock | 50// | | | 51// | v | 52// | Notify shell exit FD ---> Close LocalSocket 53// ------------------+-------------------------+------------------------------ 54// 55// The protocol requires the thread to intercept stdin/out/err in order to 56// wrap/unwrap data with shell protocol packets. 57// 58// ------------------+-------------------------+------------------------------ 59// Subprocess | adbd subprocess thread | adbd main fdevent loop 60// ------------------+-------------------------+------------------------------ 61// | | 62// stdin/out <---> Protocol <---> LocalSocket 63// stderr ---> Protocol ---> LocalSocket 64// | | | 65// v | | 66// Exit ---> Exit code protocol ---> LocalSocket 67// | | | 68// | v | 69// | Notify shell exit FD ---> Close LocalSocket 70// ------------------+-------------------------+------------------------------ 71// 72// An alternate approach is to put the protocol wrapping/unwrapping in the main 73// fdevent loop, which has the advantage of being able to re-use the existing 74// select() code for handling data streams. However, implementation turned out 75// to be more complex due to partial reads and non-blocking I/O so this model 76// was chosen instead. 77 78#define TRACE_TAG SHELL 79 80#include "sysdeps.h" 81 82#include "shell_service.h" 83 84#include <errno.h> 85#include <pty.h> 86#include <pwd.h> 87#include <sys/select.h> 88#include <termios.h> 89 90#include <memory> 91 92#include <base/logging.h> 93#include <base/stringprintf.h> 94#include <paths.h> 95 96#include "adb.h" 97#include "adb_io.h" 98#include "adb_trace.h" 99#include "adb_utils.h" 100 101namespace { 102 103void init_subproc_child() 104{ 105 setsid(); 106 107 // Set OOM score adjustment to prevent killing 108 int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC); 109 if (fd >= 0) { 110 adb_write(fd, "0", 1); 111 adb_close(fd); 112 } else { 113 D("adb: unable to update oom_score_adj"); 114 } 115} 116 117// Reads from |fd| until close or failure. 118std::string ReadAll(int fd) { 119 char buffer[512]; 120 std::string received; 121 122 while (1) { 123 int bytes = adb_read(fd, buffer, sizeof(buffer)); 124 if (bytes <= 0) { 125 break; 126 } 127 received.append(buffer, bytes); 128 } 129 130 return received; 131} 132 133// Helper to automatically close an FD when it goes out of scope. 134class ScopedFd { 135 public: 136 ScopedFd() {} 137 ~ScopedFd() { Reset(); } 138 139 void Reset(int fd=-1) { 140 if (fd != fd_) { 141 if (valid()) { 142 adb_close(fd_); 143 } 144 fd_ = fd; 145 } 146 } 147 148 int Release() { 149 int temp = fd_; 150 fd_ = -1; 151 return temp; 152 } 153 154 bool valid() const { return fd_ >= 0; } 155 156 int fd() const { return fd_; } 157 158 private: 159 int fd_ = -1; 160 161 DISALLOW_COPY_AND_ASSIGN(ScopedFd); 162}; 163 164// Creates a socketpair and saves the endpoints to |fd1| and |fd2|. 165bool CreateSocketpair(ScopedFd* fd1, ScopedFd* fd2) { 166 int sockets[2]; 167 if (adb_socketpair(sockets) < 0) { 168 PLOG(ERROR) << "cannot create socket pair"; 169 return false; 170 } 171 fd1->Reset(sockets[0]); 172 fd2->Reset(sockets[1]); 173 return true; 174} 175 176class Subprocess { 177 public: 178 Subprocess(const std::string& command, const char* terminal_type, 179 SubprocessType type, SubprocessProtocol protocol); 180 ~Subprocess(); 181 182 const std::string& command() const { return command_; } 183 bool is_interactive() const { return command_.empty(); } 184 185 int local_socket_fd() const { return local_socket_sfd_.fd(); } 186 187 pid_t pid() const { return pid_; } 188 189 // Sets up FDs, forks a subprocess, starts the subprocess manager thread, 190 // and exec's the child. Returns false on failure. 191 bool ForkAndExec(); 192 193 private: 194 // Opens the file at |pts_name|. 195 int OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd); 196 197 static void* ThreadHandler(void* userdata); 198 void PassDataStreams(); 199 void WaitForExit(); 200 201 ScopedFd* SelectLoop(fd_set* master_read_set_ptr, 202 fd_set* master_write_set_ptr); 203 204 // Input/output stream handlers. Success returns nullptr, failure returns 205 // a pointer to the failed FD. 206 ScopedFd* PassInput(); 207 ScopedFd* PassOutput(ScopedFd* sfd, ShellProtocol::Id id); 208 209 const std::string command_; 210 const std::string terminal_type_; 211 SubprocessType type_; 212 SubprocessProtocol protocol_; 213 pid_t pid_ = -1; 214 ScopedFd local_socket_sfd_; 215 216 // Shell protocol variables. 217 ScopedFd stdinout_sfd_, stderr_sfd_, protocol_sfd_; 218 std::unique_ptr<ShellProtocol> input_, output_; 219 size_t input_bytes_left_ = 0; 220 221 DISALLOW_COPY_AND_ASSIGN(Subprocess); 222}; 223 224Subprocess::Subprocess(const std::string& command, const char* terminal_type, 225 SubprocessType type, SubprocessProtocol protocol) 226 : command_(command), 227 terminal_type_(terminal_type ? terminal_type : ""), 228 type_(type), 229 protocol_(protocol) { 230} 231 232Subprocess::~Subprocess() { 233} 234 235bool Subprocess::ForkAndExec() { 236 ScopedFd child_stdinout_sfd, child_stderr_sfd; 237 ScopedFd parent_error_sfd, child_error_sfd; 238 char pts_name[PATH_MAX]; 239 240 // Create a socketpair for the fork() child to report any errors back to 241 // the parent. Since we use threads, logging directly from the child could 242 // create a race condition. 243 if (!CreateSocketpair(&parent_error_sfd, &child_error_sfd)) { 244 LOG(ERROR) << "failed to create pipe for subprocess error reporting"; 245 } 246 247 if (type_ == SubprocessType::kPty) { 248 int fd; 249 pid_ = forkpty(&fd, pts_name, nullptr, nullptr); 250 stdinout_sfd_.Reset(fd); 251 } else { 252 if (!CreateSocketpair(&stdinout_sfd_, &child_stdinout_sfd)) { 253 return false; 254 } 255 // Raw subprocess + shell protocol allows for splitting stderr. 256 if (protocol_ == SubprocessProtocol::kShell && 257 !CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) { 258 return false; 259 } 260 pid_ = fork(); 261 } 262 263 if (pid_ == -1) { 264 PLOG(ERROR) << "fork failed"; 265 return false; 266 } 267 268 if (pid_ == 0) { 269 // Subprocess child. 270 init_subproc_child(); 271 272 if (type_ == SubprocessType::kPty) { 273 child_stdinout_sfd.Reset(OpenPtyChildFd(pts_name, &child_error_sfd)); 274 } 275 276 dup2(child_stdinout_sfd.fd(), STDIN_FILENO); 277 dup2(child_stdinout_sfd.fd(), STDOUT_FILENO); 278 dup2(child_stderr_sfd.valid() ? child_stderr_sfd.fd() : child_stdinout_sfd.fd(), 279 STDERR_FILENO); 280 281 // exec doesn't trigger destructors, close the FDs manually. 282 stdinout_sfd_.Reset(); 283 stderr_sfd_.Reset(); 284 child_stdinout_sfd.Reset(); 285 child_stderr_sfd.Reset(); 286 parent_error_sfd.Reset(); 287 close_on_exec(child_error_sfd.fd()); 288 289 // TODO: $HOSTNAME? Normally bash automatically sets that, but mksh doesn't. 290 passwd* pw = getpwuid(getuid()); 291 if (pw != nullptr) { 292 setenv("HOME", pw->pw_dir, 1); 293 setenv("LOGNAME", pw->pw_name, 1); 294 setenv("SHELL", pw->pw_shell, 1); 295 setenv("USER", pw->pw_name, 1); 296 } 297 if (!terminal_type_.empty()) { 298 setenv("TERM", terminal_type_.c_str(), 1); 299 } 300 301 if (is_interactive()) { 302 execl(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr); 303 } else { 304 execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr); 305 } 306 WriteFdExactly(child_error_sfd.fd(), "exec '" _PATH_BSHELL "' failed"); 307 child_error_sfd.Reset(); 308 exit(-1); 309 } 310 311 // Subprocess parent. 312 D("subprocess parent: stdin/stdout FD = %d, stderr FD = %d", 313 stdinout_sfd_.fd(), stderr_sfd_.fd()); 314 315 // Wait to make sure the subprocess exec'd without error. 316 child_error_sfd.Reset(); 317 std::string error_message = ReadAll(parent_error_sfd.fd()); 318 if (!error_message.empty()) { 319 LOG(ERROR) << error_message; 320 return false; 321 } 322 323 if (protocol_ == SubprocessProtocol::kNone) { 324 // No protocol: all streams pass through the stdinout FD and hook 325 // directly into the local socket for raw data transfer. 326 local_socket_sfd_.Reset(stdinout_sfd_.Release()); 327 } else { 328 // Shell protocol: create another socketpair to intercept data. 329 if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) { 330 return false; 331 } 332 D("protocol FD = %d", protocol_sfd_.fd()); 333 334 input_.reset(new ShellProtocol(protocol_sfd_.fd())); 335 output_.reset(new ShellProtocol(protocol_sfd_.fd())); 336 if (!input_ || !output_) { 337 LOG(ERROR) << "failed to allocate shell protocol objects"; 338 return false; 339 } 340 341 // Don't let reads/writes to the subprocess block our thread. This isn't 342 // likely but could happen under unusual circumstances, such as if we 343 // write a ton of data to stdin but the subprocess never reads it and 344 // the pipe fills up. 345 for (int fd : {stdinout_sfd_.fd(), stderr_sfd_.fd()}) { 346 if (fd >= 0) { 347 if (!set_file_block_mode(fd, false)) { 348 LOG(ERROR) << "failed to set non-blocking mode for fd " << fd; 349 return false; 350 } 351 } 352 } 353 } 354 355 if (!adb_thread_create(ThreadHandler, this)) { 356 PLOG(ERROR) << "failed to create subprocess thread"; 357 return false; 358 } 359 360 return true; 361} 362 363int Subprocess::OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd) { 364 int child_fd = adb_open(pts_name, O_RDWR | O_CLOEXEC); 365 if (child_fd == -1) { 366 // Don't use WriteFdFmt; since we're in the fork() child we don't want 367 // to allocate any heap memory to avoid race conditions. 368 const char* messages[] = {"child failed to open pseudo-term slave ", 369 pts_name, ": ", strerror(errno)}; 370 for (const char* message : messages) { 371 WriteFdExactly(error_sfd->fd(), message); 372 } 373 exit(-1); 374 } 375 376 if (!is_interactive()) { 377 termios tattr; 378 if (tcgetattr(child_fd, &tattr) == -1) { 379 WriteFdExactly(error_sfd->fd(), "tcgetattr failed"); 380 exit(-1); 381 } 382 383 cfmakeraw(&tattr); 384 if (tcsetattr(child_fd, TCSADRAIN, &tattr) == -1) { 385 WriteFdExactly(error_sfd->fd(), "tcsetattr failed"); 386 exit(-1); 387 } 388 } 389 390 return child_fd; 391} 392 393void* Subprocess::ThreadHandler(void* userdata) { 394 Subprocess* subprocess = reinterpret_cast<Subprocess*>(userdata); 395 396 adb_thread_setname(android::base::StringPrintf( 397 "shell srvc %d", subprocess->local_socket_fd())); 398 399 subprocess->PassDataStreams(); 400 subprocess->WaitForExit(); 401 402 D("deleting Subprocess for PID %d", subprocess->pid()); 403 delete subprocess; 404 405 return nullptr; 406} 407 408void Subprocess::PassDataStreams() { 409 if (!protocol_sfd_.valid()) { 410 return; 411 } 412 413 // Start by trying to read from the protocol FD, stdout, and stderr. 414 fd_set master_read_set, master_write_set; 415 FD_ZERO(&master_read_set); 416 FD_ZERO(&master_write_set); 417 for (ScopedFd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) { 418 if (sfd->valid()) { 419 FD_SET(sfd->fd(), &master_read_set); 420 } 421 } 422 423 // Pass data until the protocol FD or both the subprocess pipes die, at 424 // which point we can't pass any more data. 425 while (protocol_sfd_.valid() && 426 (stdinout_sfd_.valid() || stderr_sfd_.valid())) { 427 ScopedFd* dead_sfd = SelectLoop(&master_read_set, &master_write_set); 428 if (dead_sfd) { 429 D("closing FD %d", dead_sfd->fd()); 430 FD_CLR(dead_sfd->fd(), &master_read_set); 431 FD_CLR(dead_sfd->fd(), &master_write_set); 432 if (dead_sfd == &protocol_sfd_) { 433 // Using SIGHUP is a decent general way to indicate that the 434 // controlling process is going away. If specific signals are 435 // needed (e.g. SIGINT), pass those through the shell protocol 436 // and only fall back on this for unexpected closures. 437 D("protocol FD died, sending SIGHUP to pid %d", pid_); 438 kill(pid_, SIGHUP); 439 } 440 dead_sfd->Reset(); 441 } 442 } 443} 444 445namespace { 446 447inline bool ValidAndInSet(const ScopedFd& sfd, fd_set* set) { 448 return sfd.valid() && FD_ISSET(sfd.fd(), set); 449} 450 451} // namespace 452 453ScopedFd* Subprocess::SelectLoop(fd_set* master_read_set_ptr, 454 fd_set* master_write_set_ptr) { 455 fd_set read_set, write_set; 456 int select_n = std::max(std::max(protocol_sfd_.fd(), stdinout_sfd_.fd()), 457 stderr_sfd_.fd()) + 1; 458 ScopedFd* dead_sfd = nullptr; 459 460 // Keep calling select() and passing data until an FD closes/errors. 461 while (!dead_sfd) { 462 memcpy(&read_set, master_read_set_ptr, sizeof(read_set)); 463 memcpy(&write_set, master_write_set_ptr, sizeof(write_set)); 464 if (select(select_n, &read_set, &write_set, nullptr, nullptr) < 0) { 465 if (errno == EINTR) { 466 continue; 467 } else { 468 PLOG(ERROR) << "select failed, closing subprocess pipes"; 469 stdinout_sfd_.Reset(); 470 stderr_sfd_.Reset(); 471 return nullptr; 472 } 473 } 474 475 // Read stdout, write to protocol FD. 476 if (ValidAndInSet(stdinout_sfd_, &read_set)) { 477 dead_sfd = PassOutput(&stdinout_sfd_, ShellProtocol::kIdStdout); 478 } 479 480 // Read stderr, write to protocol FD. 481 if (!dead_sfd && ValidAndInSet(stderr_sfd_, &read_set)) { 482 dead_sfd = PassOutput(&stderr_sfd_, ShellProtocol::kIdStderr); 483 } 484 485 // Read protocol FD, write to stdin. 486 if (!dead_sfd && ValidAndInSet(protocol_sfd_, &read_set)) { 487 dead_sfd = PassInput(); 488 // If we didn't finish writing, block on stdin write. 489 if (input_bytes_left_) { 490 FD_CLR(protocol_sfd_.fd(), master_read_set_ptr); 491 FD_SET(stdinout_sfd_.fd(), master_write_set_ptr); 492 } 493 } 494 495 // Continue writing to stdin; only happens if a previous write blocked. 496 if (!dead_sfd && ValidAndInSet(stdinout_sfd_, &write_set)) { 497 dead_sfd = PassInput(); 498 // If we finished writing, go back to blocking on protocol read. 499 if (!input_bytes_left_) { 500 FD_SET(protocol_sfd_.fd(), master_read_set_ptr); 501 FD_CLR(stdinout_sfd_.fd(), master_write_set_ptr); 502 } 503 } 504 } // while (!dead_sfd) 505 506 return dead_sfd; 507} 508 509ScopedFd* Subprocess::PassInput() { 510 // Only read a new packet if we've finished writing the last one. 511 if (!input_bytes_left_) { 512 if (!input_->Read()) { 513 // Read() uses ReadFdExactly() which sets errno to 0 on EOF. 514 if (errno != 0) { 515 PLOG(ERROR) << "error reading protocol FD " 516 << protocol_sfd_.fd(); 517 } 518 return &protocol_sfd_; 519 } 520 521 if (stdinout_sfd_.valid()) { 522 switch (input_->id()) { 523 case ShellProtocol::kIdWindowSizeChange: 524 int rows, cols, x_pixels, y_pixels; 525 if (sscanf(input_->data(), "%dx%d,%dx%d", 526 &rows, &cols, &x_pixels, &y_pixels) == 4) { 527 winsize ws; 528 ws.ws_row = rows; 529 ws.ws_col = cols; 530 ws.ws_xpixel = x_pixels; 531 ws.ws_ypixel = y_pixels; 532 ioctl(stdinout_sfd_.fd(), TIOCSWINSZ, &ws); 533 } 534 break; 535 case ShellProtocol::kIdStdin: 536 input_bytes_left_ = input_->data_length(); 537 break; 538 case ShellProtocol::kIdCloseStdin: 539 if (type_ == SubprocessType::kRaw) { 540 if (adb_shutdown(stdinout_sfd_.fd(), SHUT_WR) == 0) { 541 return nullptr; 542 } 543 PLOG(ERROR) << "failed to shutdown writes to FD " 544 << stdinout_sfd_.fd(); 545 return &stdinout_sfd_; 546 } else { 547 // PTYs can't close just input, so rather than close the 548 // FD and risk losing subprocess output, leave it open. 549 // This only happens if the client starts a PTY shell 550 // non-interactively which is rare and unsupported. 551 // If necessary, the client can manually close the shell 552 // with `exit` or by killing the adb client process. 553 D("can't close input for PTY FD %d", stdinout_sfd_.fd()); 554 } 555 break; 556 } 557 } 558 } 559 560 if (input_bytes_left_ > 0) { 561 int index = input_->data_length() - input_bytes_left_; 562 int bytes = adb_write(stdinout_sfd_.fd(), input_->data() + index, 563 input_bytes_left_); 564 if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) { 565 if (bytes < 0) { 566 PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_.fd(); 567 } 568 // stdin is done, mark this packet as finished and we'll just start 569 // dumping any further data received from the protocol FD. 570 input_bytes_left_ = 0; 571 return &stdinout_sfd_; 572 } else if (bytes > 0) { 573 input_bytes_left_ -= bytes; 574 } 575 } 576 577 return nullptr; 578} 579 580ScopedFd* Subprocess::PassOutput(ScopedFd* sfd, ShellProtocol::Id id) { 581 int bytes = adb_read(sfd->fd(), output_->data(), output_->data_capacity()); 582 if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) { 583 // read() returns EIO if a PTY closes; don't report this as an error, 584 // it just means the subprocess completed. 585 if (bytes < 0 && !(type_ == SubprocessType::kPty && errno == EIO)) { 586 PLOG(ERROR) << "error reading output FD " << sfd->fd(); 587 } 588 return sfd; 589 } 590 591 if (bytes > 0 && !output_->Write(id, bytes)) { 592 if (errno != 0) { 593 PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.fd(); 594 } 595 return &protocol_sfd_; 596 } 597 598 return nullptr; 599} 600 601void Subprocess::WaitForExit() { 602 int exit_code = 1; 603 604 D("waiting for pid %d", pid_); 605 while (true) { 606 int status; 607 if (pid_ == waitpid(pid_, &status, 0)) { 608 D("post waitpid (pid=%d) status=%04x", pid_, status); 609 if (WIFSIGNALED(status)) { 610 exit_code = 0x80 | WTERMSIG(status); 611 D("subprocess killed by signal %d", WTERMSIG(status)); 612 break; 613 } else if (!WIFEXITED(status)) { 614 D("subprocess didn't exit"); 615 break; 616 } else if (WEXITSTATUS(status) >= 0) { 617 exit_code = WEXITSTATUS(status); 618 D("subprocess exit code = %d", WEXITSTATUS(status)); 619 break; 620 } 621 } 622 } 623 624 // If we have an open protocol FD send an exit packet. 625 if (protocol_sfd_.valid()) { 626 output_->data()[0] = exit_code; 627 if (output_->Write(ShellProtocol::kIdExit, 1)) { 628 D("wrote the exit code packet: %d", exit_code); 629 } else { 630 PLOG(ERROR) << "failed to write the exit code packet"; 631 } 632 protocol_sfd_.Reset(); 633 } 634 635 // Pass the local socket FD to the shell cleanup fdevent. 636 if (SHELL_EXIT_NOTIFY_FD >= 0) { 637 int fd = local_socket_sfd_.fd(); 638 if (WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd))) { 639 D("passed fd %d to SHELL_EXIT_NOTIFY_FD (%d) for pid %d", 640 fd, SHELL_EXIT_NOTIFY_FD, pid_); 641 // The shell exit fdevent now owns the FD and will close it once 642 // the last bit of data flushes through. 643 local_socket_sfd_.Release(); 644 } else { 645 PLOG(ERROR) << "failed to write fd " << fd 646 << " to SHELL_EXIT_NOTIFY_FD (" << SHELL_EXIT_NOTIFY_FD 647 << ") for pid " << pid_; 648 } 649 } 650} 651 652} // namespace 653 654int StartSubprocess(const char* name, const char* terminal_type, 655 SubprocessType type, SubprocessProtocol protocol) { 656 D("starting %s subprocess (protocol=%s, TERM=%s): '%s'", 657 type == SubprocessType::kRaw ? "raw" : "PTY", 658 protocol == SubprocessProtocol::kNone ? "none" : "shell", 659 terminal_type, name); 660 661 Subprocess* subprocess = new Subprocess(name, terminal_type, type, protocol); 662 if (!subprocess) { 663 LOG(ERROR) << "failed to allocate new subprocess"; 664 return -1; 665 } 666 667 if (!subprocess->ForkAndExec()) { 668 LOG(ERROR) << "failed to start subprocess"; 669 delete subprocess; 670 return -1; 671 } 672 673 D("subprocess creation successful: local_socket_fd=%d, pid=%d", 674 subprocess->local_socket_fd(), subprocess->pid()); 675 return subprocess->local_socket_fd(); 676} 677