blob: 6fdbbdb8c6e317fb8123a41905d89f61ac28c703 [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
23#include <pty.h>
24#include <termios.h>
25
26#include <paths.h>
27
28#include "adb.h"
29#include "adb_io.h"
30#include "adb_trace.h"
31#include "sysdeps.h"
32
33namespace {
34
35void init_subproc_child()
36{
37 setsid();
38
39 // Set OOM score adjustment to prevent killing
40 int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
41 if (fd >= 0) {
42 adb_write(fd, "0", 1);
43 adb_close(fd);
44 } else {
45 D("adb: unable to update oom_score_adj");
46 }
47}
48
49int create_subproc_pty(const char* cmd, const char* arg0, const char* arg1,
50 pid_t* pid) {
51 D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)", cmd, arg0, arg1);
52 char pts_name[PATH_MAX];
53 int ptm;
54 *pid = forkpty(&ptm, pts_name, nullptr, nullptr);
55 if (*pid == -1) {
56 printf("- fork failed: %s -\n", strerror(errno));
57 unix_close(ptm);
58 return -1;
59 }
60
61 if (*pid == 0) {
62 init_subproc_child();
63
64 int pts = unix_open(pts_name, O_RDWR | O_CLOEXEC);
65 if (pts == -1) {
66 fprintf(stderr, "child failed to open pseudo-term slave %s: %s\n",
67 pts_name, strerror(errno));
68 unix_close(ptm);
69 exit(-1);
70 }
71
72 // arg0 is "-c" in batch mode and "-" in interactive mode.
73 if (strcmp(arg0, "-c") == 0) {
74 termios tattr;
75 if (tcgetattr(pts, &tattr) == -1) {
76 fprintf(stderr, "tcgetattr failed: %s\n", strerror(errno));
77 unix_close(pts);
78 unix_close(ptm);
79 exit(-1);
80 }
81
82 cfmakeraw(&tattr);
83 if (tcsetattr(pts, TCSADRAIN, &tattr) == -1) {
84 fprintf(stderr, "tcsetattr failed: %s\n", strerror(errno));
85 unix_close(pts);
86 unix_close(ptm);
87 exit(-1);
88 }
89 }
90
91 dup2(pts, STDIN_FILENO);
92 dup2(pts, STDOUT_FILENO);
93 dup2(pts, STDERR_FILENO);
94
95 unix_close(pts);
96 unix_close(ptm);
97
98 execl(cmd, cmd, arg0, arg1, nullptr);
99 fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
100 cmd, strerror(errno), errno);
101 exit(-1);
102 } else {
103 return ptm;
104 }
105}
106
107int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1,
108 pid_t *pid)
109{
110 D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)", cmd, arg0, arg1);
111
112 // 0 is parent socket, 1 is child socket
113 int sv[2];
114 if (adb_socketpair(sv) < 0) {
115 printf("[ cannot create socket pair - %s ]\n", strerror(errno));
116 return -1;
117 }
118 D("socketpair: (%d,%d)", sv[0], sv[1]);
119
120 *pid = fork();
121 if (*pid < 0) {
122 printf("- fork failed: %s -\n", strerror(errno));
123 adb_close(sv[0]);
124 adb_close(sv[1]);
125 return -1;
126 }
127
128 if (*pid == 0) {
129 adb_close(sv[0]);
130 init_subproc_child();
131
132 dup2(sv[1], STDIN_FILENO);
133 dup2(sv[1], STDOUT_FILENO);
134 dup2(sv[1], STDERR_FILENO);
135
136 adb_close(sv[1]);
137
138 execl(cmd, cmd, arg0, arg1, NULL);
139 fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
140 cmd, strerror(errno), errno);
141 exit(-1);
142 } else {
143 adb_close(sv[1]);
144 return sv[0];
145 }
146}
147
148void subproc_waiter_service(int fd, void *cookie)
149{
150 pid_t pid = (pid_t) (uintptr_t) cookie;
151
152 D("entered. fd=%d of pid=%d", fd, pid);
153 while (true) {
154 int status;
155 pid_t p = waitpid(pid, &status, 0);
156 if (p == pid) {
157 D("fd=%d, post waitpid(pid=%d) status=%04x", fd, p, status);
158 if (WIFSIGNALED(status)) {
159 D("*** Killed by signal %d", WTERMSIG(status));
160 break;
161 } else if (!WIFEXITED(status)) {
162 D("*** Didn't exit!!. status %d", status);
163 break;
164 } else if (WEXITSTATUS(status) >= 0) {
165 D("*** Exit code %d", WEXITSTATUS(status));
166 break;
167 }
168 }
169 }
170 D("shell exited fd=%d of pid=%d err=%d", fd, pid, errno);
171 if (SHELL_EXIT_NOTIFY_FD >=0) {
172 int res;
173 res = WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)) ? 0 : -1;
174 D("notified shell exit via fd=%d for pid=%d res=%d errno=%d",
175 SHELL_EXIT_NOTIFY_FD, pid, res, errno);
176 }
177}
178
179} // namespace
180
181// References to things in services.cpp. This is temporary just to make as few
182// modifications as possible while moving functionality into it's own file.
183// TODO(dpursell): remove these in the next CL.
184void *service_bootstrap_func(void *x);
185struct stinfo_duplicate {
186 void (*func)(int fd, void *cookie);
187 int fd;
188 void *cookie;
189};
190
191int StartSubprocess(const char *name, SubprocessType type) {
192 const char *arg0, *arg1;
193 if (*name == '\0') {
194 arg0 = "-";
195 arg1 = nullptr;
196 } else {
197 arg0 = "-c";
198 arg1 = name;
199 }
200
201 pid_t pid = -1;
202 int ret_fd;
203 if (type == SubprocessType::kPty) {
204 ret_fd = create_subproc_pty(_PATH_BSHELL, arg0, arg1, &pid);
205 } else {
206 ret_fd = create_subproc_raw(_PATH_BSHELL, arg0, arg1, &pid);
207 }
208 D("create_subproc ret_fd=%d pid=%d", ret_fd, pid);
209
210 stinfo_duplicate* sti = reinterpret_cast<stinfo_duplicate*>(malloc(sizeof(stinfo_duplicate)));
211 if(sti == 0) fatal("cannot allocate stinfo");
212 sti->func = subproc_waiter_service;
213 sti->cookie = (void*) (uintptr_t) pid;
214 sti->fd = ret_fd;
215
216 if (!adb_thread_create(service_bootstrap_func, sti)) {
217 free(sti);
218 adb_close(ret_fd);
219 fprintf(stderr, "cannot create service thread\n");
220 return -1;
221 }
222
223 D("service thread started, fd=%d pid=%d", ret_fd, pid);
224 return ret_fd;
225}
226
227#endif // !ADB_HOST