Add "exec" service: shell commands with no pty.
To facilitate device scripts that want to read/write binary data from
the host side, this change introduces a new "exec" service that
behaves like "shell" but without creating a pty, which would otherwise
mangle binary data.
After forking, it hooks up stdin/stdout of the child process to
the socket connected through to the host. The adb transport doesn't
support shutdown(), so the host can't half-close the socket and wait
for device termination. Instead, the host side now has two explicit
commands "exec-in" and "exec-out" for either sending or receiving
data.
Teach host side copy_to_file() to deal with stdin/stdout special
cases. Switch device side backup/restore services to use the new
create_subproc_raw under the hood.
Change-Id: I5993049803519d3959761f2363037b02c50920ee
diff --git a/adb/commandline.c b/adb/commandline.c
index a3eaf43..2cadc72 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -274,8 +274,17 @@
long total = 0;
D("copy_to_file(%d -> %d)\n", inFd, outFd);
+#ifdef HAVE_TERMIO_H
+ if (inFd == STDIN_FILENO) {
+ stdin_raw_init(STDIN_FILENO);
+ }
+#endif
for (;;) {
- len = adb_read(inFd, buf, BUFSIZE);
+ if (inFd == STDIN_FILENO) {
+ len = unix_read(inFd, buf, BUFSIZE);
+ } else {
+ len = adb_read(inFd, buf, BUFSIZE);
+ }
if (len == 0) {
D("copy_to_file() : read 0 bytes; exiting\n");
break;
@@ -288,9 +297,19 @@
D("copy_to_file() : error %d\n", errno);
break;
}
- adb_write(outFd, buf, len);
+ if (outFd == STDOUT_FILENO) {
+ fwrite(buf, 1, len, stdout);
+ fflush(stdout);
+ } else {
+ adb_write(outFd, buf, len);
+ }
total += len;
}
+#ifdef HAVE_TERMIO_H
+ if (inFd == STDIN_FILENO) {
+ stdin_raw_restore(STDIN_FILENO);
+ }
+#endif
D("copy_to_file() finished after %lu bytes\n", total);
free(buf);
}
@@ -927,7 +946,6 @@
return path_buf;
}
-
static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
int *show_progress, int *copy_attrs) {
*show_progress = 0;
@@ -964,7 +982,6 @@
int is_server = 0;
int persist = 0;
int r;
- int quote;
transport_type ttype = kTransportAny;
char* serial = NULL;
char* server_port_str = NULL;
@@ -1185,19 +1202,14 @@
return r;
}
- snprintf(buf, sizeof buf, "shell:%s", argv[1]);
+ snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
argc -= 2;
argv += 2;
- while(argc-- > 0) {
- strcat(buf, " ");
-
- /* quote empty strings and strings with spaces */
- quote = (**argv == 0 || strchr(*argv, ' '));
- if (quote)
- strcat(buf, "\"");
- strcat(buf, *argv++);
- if (quote)
- strcat(buf, "\"");
+ while (argc-- > 0) {
+ char *quoted = dupAndQuote(*argv++);
+ strncat(buf, " ", sizeof(buf) - 1);
+ strncat(buf, quoted, sizeof(buf) - 1);
+ free(quoted);
}
for(;;) {
@@ -1229,6 +1241,36 @@
}
}
+ if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
+ int exec_in = !strcmp(argv[0], "exec-in");
+ int fd;
+
+ snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+ argc -= 2;
+ argv += 2;
+ while (argc-- > 0) {
+ char *quoted = dupAndQuote(*argv++);
+ strncat(buf, " ", sizeof(buf) - 1);
+ strncat(buf, quoted, sizeof(buf) - 1);
+ free(quoted);
+ }
+
+ fd = adb_connect(buf);
+ if (fd < 0) {
+ fprintf(stderr, "error: %s\n", adb_error());
+ return -1;
+ }
+
+ if (exec_in) {
+ copy_to_file(STDIN_FILENO, fd);
+ } else {
+ copy_to_file(fd, STDOUT_FILENO);
+ }
+
+ adb_close(fd);
+ return 0;
+ }
+
if(!strcmp(argv[0], "kill-server")) {
int fd;
fd = _adb_connect("host:kill");