blob: 5f80a593e7c3aafae74a9d1f2b7dbc357a7ec236 [file] [log] [blame]
David Pursell80f67022015-08-28 15:08:49 -07001/*
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#define TRACE_TAG TRACE_SHELL
18
19#include "shell_service.h"
20
21#if !ADB_HOST
22
David Pursella9320582015-08-28 18:31:29 -070023#include <errno.h>
David Pursell80f67022015-08-28 15:08:49 -070024#include <pty.h>
25#include <termios.h>
26
David Pursella9320582015-08-28 18:31:29 -070027#include <base/logging.h>
28#include <base/stringprintf.h>
David Pursell80f67022015-08-28 15:08:49 -070029#include <paths.h>
30
31#include "adb.h"
32#include "adb_io.h"
33#include "adb_trace.h"
34#include "sysdeps.h"
35
36namespace {
37
38void init_subproc_child()
39{
40 setsid();
41
42 // Set OOM score adjustment to prevent killing
43 int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
44 if (fd >= 0) {
45 adb_write(fd, "0", 1);
46 adb_close(fd);
47 } else {
48 D("adb: unable to update oom_score_adj");
49 }
50}
51
David Pursella9320582015-08-28 18:31:29 -070052// Reads from |fd| until close or failure.
53std::string ReadAll(int fd) {
54 char buffer[512];
55 std::string received;
56
57 while (1) {
58 int bytes = adb_read(fd, buffer, sizeof(buffer));
59 if (bytes <= 0) {
60 break;
61 }
62 received.append(buffer, bytes);
David Pursell80f67022015-08-28 15:08:49 -070063 }
64
David Pursella9320582015-08-28 18:31:29 -070065 return received;
66}
67
68// Helper to automatically close an FD when it goes out of scope.
69class ScopedFd {
70 public:
71 ScopedFd() {}
72 ~ScopedFd() { Reset(); }
73
74 void Reset(int fd=-1) {
75 if (fd != fd_) {
76 if (valid()) {
77 adb_close(fd_);
78 }
79 fd_ = fd;
80 }
81 }
82
83 int Release() {
84 int temp = fd_;
85 fd_ = -1;
86 return temp;
87 }
88
89 bool valid() const { return fd_ >= 0; }
90
91 int fd() const { return fd_; }
92
93 private:
94 int fd_ = -1;
95
96 DISALLOW_COPY_AND_ASSIGN(ScopedFd);
97};
98
99// Creates a socketpair and saves the endpoints to |fd1| and |fd2|.
100bool CreateSocketpair(ScopedFd* fd1, ScopedFd* fd2) {
101 int sockets[2];
102 if (adb_socketpair(sockets) < 0) {
103 PLOG(ERROR) << "cannot create socket pair";
104 return false;
105 }
106 fd1->Reset(sockets[0]);
107 fd2->Reset(sockets[1]);
108 return true;
109}
110
111class Subprocess {
112 public:
113 Subprocess(const std::string& command, SubprocessType type);
114 ~Subprocess();
115
116 const std::string& command() const { return command_; }
117 bool is_interactive() const { return command_.empty(); }
118
119 int local_socket_fd() const { return local_socket_sfd_.fd(); }
120
121 pid_t pid() const { return pid_; }
122
123 // Sets up FDs, forks a subprocess, starts the subprocess manager thread,
124 // and exec's the child. Returns false on failure.
125 bool ForkAndExec();
126
127 private:
128 // Opens the file at |pts_name|.
129 int OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd);
130
131 static void* ThreadHandler(void* userdata);
132 void WaitForExit();
133
134 const std::string command_;
135 SubprocessType type_;
136
137 pid_t pid_ = -1;
138 ScopedFd local_socket_sfd_;
139
140 DISALLOW_COPY_AND_ASSIGN(Subprocess);
141};
142
143Subprocess::Subprocess(const std::string& command, SubprocessType type)
144 : command_(command), type_(type) {
145}
146
147Subprocess::~Subprocess() {
148}
149
150bool Subprocess::ForkAndExec() {
151 ScopedFd parent_sfd, child_sfd, parent_error_sfd, child_error_sfd;
152 char pts_name[PATH_MAX];
153
154 // Create a socketpair for the fork() child to report any errors back to
155 // the parent. Since we use threads, logging directly from the child could
156 // create a race condition.
157 if (!CreateSocketpair(&parent_error_sfd, &child_error_sfd)) {
158 LOG(ERROR) << "failed to create pipe for subprocess error reporting";
159 }
160
161 if (type_ == SubprocessType::kPty) {
162 int fd;
163 pid_ = forkpty(&fd, pts_name, nullptr, nullptr);
164 parent_sfd.Reset(fd);
165 } else {
166 if (!CreateSocketpair(&parent_sfd, &child_sfd)) {
167 return false;
168 }
169 pid_ = fork();
170 }
171
172 if (pid_ == -1) {
173 PLOG(ERROR) << "fork failed";
174 return false;
175 }
176
177 if (pid_ == 0) {
178 // Subprocess child.
David Pursell80f67022015-08-28 15:08:49 -0700179 init_subproc_child();
180
David Pursella9320582015-08-28 18:31:29 -0700181 if (type_ == SubprocessType::kPty) {
182 child_sfd.Reset(OpenPtyChildFd(pts_name, &child_error_sfd));
183 }
184
185 dup2(child_sfd.fd(), STDIN_FILENO);
186 dup2(child_sfd.fd(), STDOUT_FILENO);
187 dup2(child_sfd.fd(), STDERR_FILENO);
188
189 // exec doesn't trigger destructors, close the FDs manually.
190 parent_sfd.Reset();
191 child_sfd.Reset();
192 parent_error_sfd.Reset();
193 close_on_exec(child_error_sfd.fd());
194
195 if (is_interactive()) {
196 execl(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr);
197 } else {
198 execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr);
199 }
200 WriteFdExactly(child_error_sfd.fd(), "exec '" _PATH_BSHELL "' failed");
201 child_error_sfd.Reset();
202 exit(-1);
203 }
204
205 // Subprocess parent.
206 D("subprocess parent: subprocess FD = %d", parent_sfd.fd());
207
208 // Wait to make sure the subprocess exec'd without error.
209 child_error_sfd.Reset();
210 std::string error_message = ReadAll(parent_error_sfd.fd());
211 if (!error_message.empty()) {
212 LOG(ERROR) << error_message;
213 return false;
214 }
215
216 local_socket_sfd_.Reset(parent_sfd.Release());
217
218 if (!adb_thread_create(ThreadHandler, this)) {
219 PLOG(ERROR) << "failed to create subprocess thread";
220 return false;
221 }
222
223 return true;
224}
225
226int Subprocess::OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd) {
227 int child_fd = adb_open(pts_name, O_RDWR | O_CLOEXEC);
228 if (child_fd == -1) {
229 // Don't use WriteFdFmt; since we're in the fork() child we don't want
230 // to allocate any heap memory to avoid race conditions.
231 const char* messages[] = {"child failed to open pseudo-term slave ",
232 pts_name, ": ", strerror(errno)};
233 for (const char* message : messages) {
234 WriteFdExactly(error_sfd->fd(), message);
235 }
236 exit(-1);
237 }
238
239 if (!is_interactive()) {
240 termios tattr;
241 if (tcgetattr(child_fd, &tattr) == -1) {
242 WriteFdExactly(error_sfd->fd(), "tcgetattr failed");
David Pursell80f67022015-08-28 15:08:49 -0700243 exit(-1);
244 }
245
David Pursella9320582015-08-28 18:31:29 -0700246 cfmakeraw(&tattr);
247 if (tcsetattr(child_fd, TCSADRAIN, &tattr) == -1) {
248 WriteFdExactly(error_sfd->fd(), "tcsetattr failed");
249 exit(-1);
David Pursell80f67022015-08-28 15:08:49 -0700250 }
David Pursell80f67022015-08-28 15:08:49 -0700251 }
David Pursella9320582015-08-28 18:31:29 -0700252
253 return child_fd;
David Pursell80f67022015-08-28 15:08:49 -0700254}
255
David Pursella9320582015-08-28 18:31:29 -0700256void* Subprocess::ThreadHandler(void* userdata) {
257 Subprocess* subprocess = reinterpret_cast<Subprocess*>(userdata);
David Pursell80f67022015-08-28 15:08:49 -0700258
David Pursella9320582015-08-28 18:31:29 -0700259 adb_thread_setname(android::base::StringPrintf(
260 "shell srvc %d", subprocess->local_socket_fd()));
David Pursell80f67022015-08-28 15:08:49 -0700261
David Pursella9320582015-08-28 18:31:29 -0700262 subprocess->WaitForExit();
David Pursell80f67022015-08-28 15:08:49 -0700263
David Pursella9320582015-08-28 18:31:29 -0700264 D("deleting Subprocess");
265 delete subprocess;
David Pursell80f67022015-08-28 15:08:49 -0700266
David Pursella9320582015-08-28 18:31:29 -0700267 return nullptr;
David Pursell80f67022015-08-28 15:08:49 -0700268}
269
David Pursella9320582015-08-28 18:31:29 -0700270void Subprocess::WaitForExit() {
271 D("waiting for pid %d", pid_);
David Pursell80f67022015-08-28 15:08:49 -0700272 while (true) {
273 int status;
David Pursella9320582015-08-28 18:31:29 -0700274 if (pid_ == waitpid(pid_, &status, 0)) {
275 D("post waitpid (pid=%d) status=%04x", pid_, status);
David Pursell80f67022015-08-28 15:08:49 -0700276 if (WIFSIGNALED(status)) {
David Pursella9320582015-08-28 18:31:29 -0700277 D("subprocess killed by signal %d", WTERMSIG(status));
David Pursell80f67022015-08-28 15:08:49 -0700278 break;
279 } else if (!WIFEXITED(status)) {
David Pursella9320582015-08-28 18:31:29 -0700280 D("subprocess didn't exit");
David Pursell80f67022015-08-28 15:08:49 -0700281 break;
282 } else if (WEXITSTATUS(status) >= 0) {
David Pursella9320582015-08-28 18:31:29 -0700283 D("subprocess exit code = %d", WEXITSTATUS(status));
David Pursell80f67022015-08-28 15:08:49 -0700284 break;
285 }
David Pursella9320582015-08-28 18:31:29 -0700286 }
David Pursell80f67022015-08-28 15:08:49 -0700287 }
David Pursella9320582015-08-28 18:31:29 -0700288
289 // Pass the local socket FD to the shell cleanup fdevent.
290 if (SHELL_EXIT_NOTIFY_FD >= 0) {
291 int fd = local_socket_sfd_.fd();
292 if (WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd))) {
293 D("passed fd %d to SHELL_EXIT_NOTIFY_FD (%d) for pid %d",
294 fd, SHELL_EXIT_NOTIFY_FD, pid_);
295 // The shell exit fdevent now owns the FD and will close it once
296 // the last bit of data flushes through.
297 local_socket_sfd_.Release();
298 } else {
299 PLOG(ERROR) << "failed to write fd " << fd
300 << " to SHELL_EXIT_NOTIFY_FD (" << SHELL_EXIT_NOTIFY_FD
301 << ") for pid " << pid_;
302 }
David Pursell80f67022015-08-28 15:08:49 -0700303 }
304}
305
306} // namespace
307
David Pursell80f67022015-08-28 15:08:49 -0700308int StartSubprocess(const char *name, SubprocessType type) {
David Pursella9320582015-08-28 18:31:29 -0700309 D("starting %s subprocess: '%s'",
310 type == SubprocessType::kRaw ? "raw" : "PTY", name);
David Pursell80f67022015-08-28 15:08:49 -0700311
David Pursella9320582015-08-28 18:31:29 -0700312 Subprocess* subprocess = new Subprocess(name, type);
313 if (!subprocess) {
314 LOG(ERROR) << "failed to allocate new subprocess";
David Pursell80f67022015-08-28 15:08:49 -0700315 return -1;
316 }
317
David Pursella9320582015-08-28 18:31:29 -0700318 if (!subprocess->ForkAndExec()) {
319 LOG(ERROR) << "failed to start subprocess";
320 delete subprocess;
321 return -1;
322 }
323
324 D("subprocess creation successful: local_socket_fd=%d, pid=%d",
325 subprocess->local_socket_fd(), subprocess->pid());
326 return subprocess->local_socket_fd();
David Pursell80f67022015-08-28 15:08:49 -0700327}
328
329#endif // !ADB_HOST