15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/process_proxy/process_proxy.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ioctl.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
15a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/posix/eintr_wrapper.h"
16a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/kill.h"
17a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/launch.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/process_proxy/process_output_watcher.h"
20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "third_party/cros_system_api/switches/chrome_switches.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum PipeEnd {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PIPE_END_READ,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PIPE_END_WRITE
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum PseudoTerminalFd {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PT_MASTER_FD,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PT_SLAVE_FD
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kInvalidFd = -1;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessProxy::ProcessProxy(): process_launched_(false),
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              callback_set_(false),
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              watcher_started_(false) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set pipes to initial, invalid value so we can easily know if a pipe was
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // opened by us.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearAllFdPairs();
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessProxy::Open(const std::string& command, pid_t* pid) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_launched_)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreatePseudoTerminalPair(pt_pair_)) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  process_launched_ = LaunchProcess(command, pt_pair_[PT_SLAVE_FD], &pid_);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_launched_) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We won't need these anymore. These will be used by the launched process.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseFd(&pt_pair_[PT_SLAVE_FD]);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pid = pid_;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Process launched: " << pid_;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseFdPair(pt_pair_);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return process_launched_;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ProcessProxy::StartWatchingOnThread(
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Thread* watch_thread,
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ProcessOutputCallback& callback) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(process_launched_);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (watcher_started_)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pipe(shutdown_pipe_))
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We give ProcessOutputWatcher a copy of master to make life easier during
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // tear down.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(tbarzic): improve fd managment.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int master_copy = HANDLE_EINTR(dup(pt_pair_[PT_MASTER_FD]));
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (master_copy == -1)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_set_ = true;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_ = callback;
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_runner_ = base::MessageLoopProxy::current();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This object will delete itself once watching is stopped.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It also takes ownership of the passed fds.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProcessOutputWatcher* output_watcher =
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ProcessOutputWatcher(master_copy,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               shutdown_pipe_[PIPE_END_READ],
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::Bind(&ProcessProxy::OnProcessOutput,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          this));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Output watcher took ownership of the read end of shutdown pipe.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_pipe_[PIPE_END_READ] = -1;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |watch| thread is blocked by |output_watcher| from now on.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  watch_thread->message_loop()->PostTask(FROM_HERE,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ProcessOutputWatcher::Start,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(output_watcher)));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  watcher_started_ = true;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessProxy::OnProcessOutput(ProcessOutputType type,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const std::string& output) {
1107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!callback_runner_.get())
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_runner_->PostTask(
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&ProcessProxy::CallOnProcessOutputCallback,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this, type, output));
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ProcessProxy::CallOnProcessOutputCallback(ProcessOutputType type,
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               const std::string& output) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We may receive some output even after Close was called (crosh process does
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not have to quit instantly, or there may be some trailing data left in
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // output stream fds). In that case owner of the callback may be gone so we
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't want to send it anything. |callback_set_| is reset when this gets
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // closed.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (callback_set_)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Run(type, output);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessProxy::StopWatching() {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!watcher_started_)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Signal Watcher that we are done. We use self-pipe trick to unblock watcher.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Anything may be written to the pipe.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char message[] = "q";
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return base::WriteFileDescriptor(shutdown_pipe_[PIPE_END_WRITE],
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   message, sizeof(message));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessProxy::Close() {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!process_launched_)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  process_launched_ = false;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_set_ = false;
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_ = ProcessOutputCallback();
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_runner_ = NULL;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::KillProcess(pid_, 0, true /* wait */);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(tbarzic): What if this fails?
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopWatching();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAllFdPairs();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessProxy::Write(const std::string& text) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!process_launched_)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't want to write '\0' to the pipe.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t data_size = text.length() * sizeof(*text.c_str());
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bytes_written =
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::WriteFileDescriptor(pt_pair_[PT_MASTER_FD],
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                text.c_str(), data_size);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (bytes_written == static_cast<int>(data_size));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessProxy::OnTerminalResize(int width, int height) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (width < 0 || height < 0)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  winsize ws;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of rows.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ws.ws_row = height;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of columns.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ws.ws_col = width;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (HANDLE_EINTR(ioctl(pt_pair_[PT_MASTER_FD], TIOCSWINSZ, &ws)) != -1);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessProxy::~ProcessProxy() {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In case watcher did not started, we may get deleted without calling Close.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In that case we have to clean up created pipes. If watcher had been
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // started, there will be a callback with our reference owned by
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // process_output_watcher until Close is called, so we know Close has been
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // called  by now (and pipes have been cleaned).
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!watcher_started_)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseAllFdPairs();
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessProxy::CreatePseudoTerminalPair(int *pt_pair) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearFdPair(pt_pair);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open Master.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pt_pair[PT_MASTER_FD] = HANDLE_EINTR(posix_openpt(O_RDWR | O_NOCTTY));
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pt_pair[PT_MASTER_FD] == -1)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (grantpt(pt_pair_[PT_MASTER_FD]) != 0 ||
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unlockpt(pt_pair_[PT_MASTER_FD]) != 0) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseFd(&pt_pair[PT_MASTER_FD]);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* slave_name = NULL;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Per man page, slave_name must not be freed.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  slave_name = ptsname(pt_pair_[PT_MASTER_FD]);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (slave_name)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pt_pair_[PT_SLAVE_FD] = HANDLE_EINTR(open(slave_name, O_RDWR | O_NOCTTY));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pt_pair_[PT_SLAVE_FD] == -1) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseFdPair(pt_pair);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessProxy::LaunchProcess(const std::string& command, int slave_fd,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 pid_t* pid) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Redirect crosh  process' output and input so we can read it.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FileHandleMappingVector fds_mapping;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fds_mapping.push_back(std::make_pair(slave_fd, STDIN_FILENO));
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fds_mapping.push_back(std::make_pair(slave_fd, STDOUT_FILENO));
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fds_mapping.push_back(std::make_pair(slave_fd, STDERR_FILENO));
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::LaunchOptions options;
227a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Do not set NO_NEW_PRIVS on processes if the system is in dev-mode. This
228a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // permits sudo in the crosh shell when in developer mode.
229a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  options.allow_new_privs = base::CommandLine::ForCurrentProcess()->
230a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      HasSwitch(chromeos::switches::kSystemInDevMode);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options.fds_to_remap = &fds_mapping;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options.ctrl_terminal_fd = slave_fd;
23358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  options.environ["TERM"] = "xterm";
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Launch the process.
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::LaunchProcess(CommandLine(base::FilePath(command)), options,
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             pid);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessProxy::CloseAllFdPairs() {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseFdPair(pt_pair_);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseFdPair(shutdown_pipe_);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessProxy::CloseFdPair(int* pipe) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseFd(&(pipe[PIPE_END_READ]));
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseFd(&(pipe[PIPE_END_WRITE]));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessProxy::CloseFd(int* fd) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*fd != kInvalidFd) {
252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IGNORE_EINTR(close(*fd)) != 0)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(WARNING) << "close fd failed.";
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *fd = kInvalidFd;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessProxy::ClearAllFdPairs() {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearFdPair(pt_pair_);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearFdPair(shutdown_pipe_);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessProxy::ClearFdPair(int* pipe) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pipe[PIPE_END_READ] = kInvalidFd;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pipe[PIPE_END_WRITE] = kInvalidFd;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
269