summaryrefslogtreecommitdiff
path: root/chromium/base/process/launch_fuchsia.cc
blob: 4ab969afa3853bb8c8fb1c9f23b9a4f5ff1b4dfd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/process/launch.h"

#include <launchpad/launchpad.h>
#include <magenta/process.h>
#include <unistd.h>

#include "base/command_line.h"
#include "base/logging.h"

namespace base {

namespace {

bool GetAppOutputInternal(const std::vector<std::string>& argv,
                          bool include_stderr,
                          std::string* output,
                          int* exit_code) {
  DCHECK(exit_code);

  std::vector<const char*> argv_cstr;
  argv_cstr.reserve(argv.size() + 1);
  for (const auto& arg : argv)
    argv_cstr.push_back(arg.c_str());
  argv_cstr.push_back(nullptr);

  launchpad_t* lp;
  launchpad_create(MX_HANDLE_INVALID, argv_cstr[0], &lp);
  launchpad_load_from_file(lp, argv_cstr[0]);
  launchpad_set_args(lp, argv.size(), argv_cstr.data());
  launchpad_clone(lp, LP_CLONE_MXIO_ROOT | LP_CLONE_MXIO_CWD |
                          LP_CLONE_DEFAULT_JOB | LP_CLONE_ENVIRON);
  launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO);
  int pipe_fd;
  mx_status_t status = launchpad_add_pipe(lp, &pipe_fd, STDOUT_FILENO);
  if (status != NO_ERROR) {
    LOG(ERROR) << "launchpad_add_pipe failed: " << status;
    launchpad_destroy(lp);
    return false;
  }

  if (include_stderr)
    launchpad_clone_fd(lp, pipe_fd, STDERR_FILENO);
  else
    launchpad_clone_fd(lp, STDERR_FILENO, STDERR_FILENO);

  mx_handle_t proc;
  const char* errmsg;
  status = launchpad_go(lp, &proc, &errmsg);
  if (status != NO_ERROR) {
    LOG(ERROR) << "launchpad_go failed: " << errmsg << ", status=" << status;
    return false;
  }

  output->clear();
  for (;;) {
    char buffer[256];
    ssize_t bytes_read = read(pipe_fd, buffer, sizeof(buffer));
    if (bytes_read <= 0)
      break;
    output->append(buffer, bytes_read);
  }
  close(pipe_fd);

  Process process(proc);
  return process.WaitForExit(exit_code);
}

}  // namespace

Process LaunchProcess(const CommandLine& cmdline,
                      const LaunchOptions& options) {
  return LaunchProcess(cmdline.argv(), options);
}

Process LaunchProcess(const std::vector<std::string>& argv,
                      const LaunchOptions& options) {
  std::vector<const char*> argv_cstr;
  argv_cstr.reserve(argv.size() + 1);
  for (const auto& arg : argv)
    argv_cstr.push_back(arg.c_str());
  argv_cstr.push_back(nullptr);

  // Note that per launchpad.h, the intention is that launchpad_ functions are
  // used in a "builder" style. From launchpad_create() to launchpad_go() the
  // status is tracked in the launchpad_t object, and launchpad_go() reports on
  // the final status, and cleans up |lp| (assuming it was even created).
  launchpad_t* lp;
  launchpad_create(options.job_handle, argv_cstr[0], &lp);
  launchpad_load_from_file(lp, argv_cstr[0]);
  launchpad_set_args(lp, argv.size(), argv_cstr.data());

  uint32_t to_clone =
      LP_CLONE_MXIO_ROOT | LP_CLONE_MXIO_CWD | LP_CLONE_DEFAULT_JOB;

  std::unique_ptr<char* []> new_environ;
  char* const empty_environ = nullptr;
  char* const* old_environ = environ;
  if (options.clear_environ)
    old_environ = &empty_environ;
  if (!options.environ.empty())
    new_environ = AlterEnvironment(old_environ, options.environ);
  if (!options.environ.empty() || options.clear_environ)
    launchpad_set_environ(lp, new_environ.get());
  else
    to_clone |= LP_CLONE_ENVIRON;

  if (!options.fds_to_remap)
    to_clone |= LP_CLONE_MXIO_STDIO;
  launchpad_clone(lp, to_clone);

  if (options.fds_to_remap) {
    for (const auto& src_target : *options.fds_to_remap) {
      launchpad_clone_fd(lp, src_target.first, src_target.second);
    }
  }

  mx_handle_t proc;
  const char* errmsg;
  mx_status_t status = launchpad_go(lp, &proc, &errmsg);
  if (status != NO_ERROR) {
    LOG(ERROR) << "launchpad_go failed: " << errmsg << ", status=" << status;
    return Process();
  }

  return Process(proc);
}

bool GetAppOutput(const CommandLine& cl, std::string* output) {
  return GetAppOutput(cl.argv(), output);
}

bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
  int exit_code;
  bool result = GetAppOutputInternal(argv, false, output, &exit_code);
  return result && exit_code == EXIT_SUCCESS;
}

bool GetAppOutputAndError(const CommandLine& cl, std::string* output) {
  return GetAppOutputAndError(cl.argv(), output);
}

bool GetAppOutputAndError(const std::vector<std::string>& argv,
                          std::string* output) {
  int exit_code;
  bool result = GetAppOutputInternal(argv, true, output, &exit_code);
  return result && exit_code == EXIT_SUCCESS;
}

bool GetAppOutputWithExitCode(const CommandLine& cl,
                              std::string* output,
                              int* exit_code) {
  bool result = GetAppOutputInternal(cl.argv(), false, output, exit_code);
  return result && *exit_code == EXIT_SUCCESS;
}

}  // namespace base