diff --git a/adb/Android.mk b/adb/Android.mk index 50e28a616..80427b8e6 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -102,7 +102,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ adb.c \ - backup_service.c \ fdevent.c \ transport.c \ transport_local.c \ diff --git a/adb/adb.h b/adb/adb.h index 2504f9926..4704abbb6 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -326,11 +326,6 @@ int create_jdwp_connection_fd(int jdwp_pid); int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd); #if !ADB_HOST -typedef enum { - BACKUP, - RESTORE -} BackupOperation; -int backup_service(BackupOperation operation, char* args); void framebuffer_service(int fd, void *cookie); void remount_service(int fd, void *cookie); #endif @@ -418,7 +413,7 @@ void adb_qemu_trace(const char* fmt, ...); # define D(...) ((void)0) # define DR(...) ((void)0) # define ADB_TRACING 0 -#endif +#endif /* ADB_TRACE */ #if !DEBUG_PACKETS @@ -476,6 +471,11 @@ int connection_state(atransport *t); extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; +typedef enum { + SUBPROC_PTY = 0, + SUBPROC_RAW = 1, +} subproc_mode; + #define CHUNK_SIZE (64*1024) #if !ADB_HOST diff --git a/adb/backup_service.c b/adb/backup_service.c deleted file mode 100644 index 654e0f32d..000000000 --- a/adb/backup_service.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "sysdeps.h" - -#define TRACE_TAG TRACE_ADB -#include "adb.h" - -typedef struct { - pid_t pid; - int fd; -} backup_harvest_params; - -// socketpair but do *not* mark as close_on_exec -static int backup_socketpair(int sv[2]) { - int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv ); - if (rc < 0) - return -1; - - return 0; -} - -// harvest the child process then close the read end of the socketpair -static void* backup_child_waiter(void* args) { - int status; - backup_harvest_params* params = (backup_harvest_params*) args; - - waitpid(params->pid, &status, 0); - adb_close(params->fd); - free(params); - return NULL; -} - -/* returns the data socket passing the backup data here for forwarding */ -int backup_service(BackupOperation op, char* args) { - pid_t pid; - int s[2]; - char* operation; - - // Command string depends on our invocation - if (op == BACKUP) { - operation = "backup"; - } else { - operation = "restore"; - } - - D("backup_service(%s, %s)\n", operation, args); - - // set up the pipe from the subprocess to here - // parent will read s[0]; child will write s[1] - if (backup_socketpair(s)) { - D("can't create backup/restore socketpair\n"); - fprintf(stderr, "unable to create backup/restore socketpair\n"); - return -1; - } - - D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]); - close_on_exec(s[0]); // only the side we hold on to - - // spin off the child process to run the backup command - pid = fork(); - if (pid < 0) { - // failure - D("can't fork for %s\n", operation); - fprintf(stderr, "unable to fork for %s\n", operation); - adb_close(s[0]); - adb_close(s[1]); - return -1; - } - - // Great, we're off and running. - if (pid == 0) { - // child -- actually run the backup here - char* p; - int argc; - char portnum[16]; - char** bu_args; - - // fixed args: [0] is 'bu', [1] is the port number, [2] is the 'operation' string - argc = 3; - for (p = (char*)args; p && *p; ) { - argc++; - while (*p && *p != ':') p++; - if (*p == ':') p++; - } - - bu_args = (char**) alloca(argc*sizeof(char*) + 1); - - // run through again to build the argv array - argc = 0; - bu_args[argc++] = "bu"; - snprintf(portnum, sizeof(portnum), "%d", s[1]); - bu_args[argc++] = portnum; - bu_args[argc++] = operation; - for (p = (char*)args; p && *p; ) { - bu_args[argc++] = p; - while (*p && *p != ':') p++; - if (*p == ':') { - *p = 0; - p++; - } - } - bu_args[argc] = NULL; - - // Close the half of the socket that we don't care about, route 'bu's console - // to the output socket, and off we go - adb_close(s[0]); - - // off we go - execvp("/system/bin/bu", (char * const *)bu_args); - // oops error - close up shop and go home - fprintf(stderr, "Unable to exec 'bu', bailing\n"); - exit(-1); - } else { - adb_thread_t t; - backup_harvest_params* params; - - // parent, i.e. adbd -- close the sending half of the socket - D("fork() returned pid %d\n", pid); - adb_close(s[1]); - - // spin a thread to harvest the child process - params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params)); - params->pid = pid; - params->fd = s[0]; - if (adb_thread_create(&t, backup_child_waiter, params)) { - adb_close(s[0]); - free(params); - D("Unable to create child harvester\n"); - return -1; - } - } - - // we'll be reading from s[0] as the data is sent by the child process - return s[0]; -} diff --git a/adb/commandline.c b/adb/commandline.c index 18dc6e0fa..1ba60499c 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -110,9 +110,10 @@ void help() " adb push [-p] \n" " - copy file/dir to device\n" " ('-p' to display the transfer progress)\n" - " adb pull [-p] []\n" + " adb pull [-p] [-a] []\n" " - copy file/dir from device\n" " ('-p' to display the transfer progress)\n" + " ('-a' means copy timestamp and mode)\n" " adb sync [ ] - copy host->device only if changed\n" " (-l means list but don't copy)\n" " (see 'adb help all')\n" @@ -285,8 +286,17 @@ static void copy_to_file(int inFd, int outFd) { 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; @@ -299,9 +309,19 @@ static void copy_to_file(int inFd, int outFd) { 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); } @@ -938,13 +958,19 @@ static const char *find_product_out_path(const char *hint) return path_buf; } - -static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2, - int* show_progress) { +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; + *copy_attrs = 0; - if ((narg > 0) && !strcmp(*arg, "-p")) { - *show_progress = 1; + while (narg > 0) { + if (!strcmp(*arg, "-p")) { + *show_progress = 1; + } else if (!strcmp(*arg, "-a")) { + *copy_attrs = 1; + } else { + break; + } ++arg; --narg; } @@ -968,7 +994,6 @@ int adb_commandline(int argc, char **argv) int is_server = 0; int persist = 0; int r; - int quote; transport_type ttype = kTransportAny; char* serial = NULL; char* server_port_str = NULL; @@ -1189,19 +1214,14 @@ top: 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(;;) { @@ -1233,6 +1253,36 @@ top: } } + 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"); @@ -1415,9 +1465,10 @@ top: if(!strcmp(argv[0], "push")) { int show_progress = 0; + int copy_attrs = 0; // unused const char* lpath = NULL, *rpath = NULL; - parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress); + parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, ©_attrs); if ((lpath != NULL) && (rpath != NULL)) { return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress); @@ -1428,12 +1479,13 @@ top: if(!strcmp(argv[0], "pull")) { int show_progress = 0; + int copy_attrs = 0; const char* rpath = NULL, *lpath = "."; - parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress); + parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, ©_attrs); if (rpath != NULL) { - return do_sync_pull(rpath, lpath, show_progress); + return do_sync_pull(rpath, lpath, show_progress, copy_attrs); } return usage(); diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index dc4e77fbc..3f540c14b 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -139,7 +139,8 @@ struct syncsendbuf { static syncsendbuf send_buffer; -int sync_readtime(int fd, const char *path, unsigned *timestamp) +int sync_readtime(int fd, const char *path, unsigned int *timestamp, + unsigned int *mode) { syncmsg msg; int len = strlen(path); @@ -161,6 +162,7 @@ int sync_readtime(int fd, const char *path, unsigned *timestamp) } *timestamp = ltohl(msg.stat.time); + *mode = ltohl(msg.stat.mode); return 0; } @@ -237,7 +239,7 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show if (show_progress) { // Determine local file size. struct stat st; - if (lstat(path, &st)) { + if (fstat(lfd, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); return -1; } @@ -931,8 +933,21 @@ static int remote_build_list(int syncfd, copyinfo **filelist, return 0; } +static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode) +{ + struct timeval times[2] = { {time, 0}, {time, 0} }; + int r1 = utimes(lpath, times); + + /* use umask for permissions */ + mode_t mask=umask(0000); + umask(mask); + int r2 = chmod(lpath, mode & ~mask); + + return r1 ? : r2; +} + static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, - int checktimestamps) + int copy_attrs) { copyinfo *filelist = 0; copyinfo *ci, *next; @@ -962,26 +977,6 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, return -1; } -#if 0 - if (checktimestamps) { - for (ci = filelist; ci != 0; ci = ci->next) { - if (sync_start_readtime(fd, ci->dst)) { - return 1; - } - } - for (ci = filelist; ci != 0; ci = ci->next) { - unsigned int timestamp, mode, size; - if (sync_finish_readtime(fd, ×tamp, &mode, &size)) - return 1; - if (size == ci->size) { - /* for links, we cannot update the atime/mtime */ - if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) || - (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) - ci->flag = 1; - } - } - } -#endif for (ci = filelist; ci != 0; ci = next) { next = ci->next; if (ci->flag == 0) { @@ -989,6 +984,10 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { return 1; } + + if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) { + return 1; + } pulled++; } else { skipped++; @@ -1003,9 +1002,9 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, return 0; } -int do_sync_pull(const char *rpath, const char *lpath, int show_progress) +int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs) { - unsigned mode; + unsigned mode, time; struct stat st; int fd; @@ -1016,7 +1015,7 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress) return 1; } - if(sync_readmode(fd, rpath, &mode)) { + if(sync_readtime(fd, rpath, &time, &mode)) { return 1; } if(mode == 0) { @@ -1047,13 +1046,15 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress) if (sync_recv(fd, rpath, lpath, show_progress)) { return 1; } else { + if (copy_attrs && set_time_and_mode(lpath, time, mode)) + return 1; END(); sync_quit(fd); return 0; } } else if(S_ISDIR(mode)) { BEGIN(); - if (copy_remote_dir_local(fd, rpath, lpath, 0)) { + if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) { return 1; } else { END(); diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h index 3e7e096c1..8ea239ec0 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -80,7 +80,7 @@ void file_sync_service(int fd, void *cookie); int do_sync_ls(const char *path); int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress); int do_sync_sync(const char *lpath, const char *rpath, int listonly); -int do_sync_pull(const char *rpath, const char *lpath, int show_progress); +int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime); #define SYNC_DATA_MAX (64*1024) diff --git a/adb/services.c b/adb/services.c index 7b809da94..e48e4603e 100644 --- a/adb/services.c +++ b/adb/services.c @@ -184,11 +184,26 @@ static int create_service_thread(void (*func)(int, void *), void *cookie) } #if !ADB_HOST -static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) + +static void init_subproc_child() { + setsid(); + + // Set OOM score adjustment to prevent killing + int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY); + if (fd >= 0) { + adb_write(fd, "0", 1); + adb_close(fd); + } else { + D("adb: unable to update oom_score_adj\n"); + } +} + +static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) +{ + D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); #ifdef HAVE_WIN32_PROC - D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); - fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); + fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); return -1; #else /* !HAVE_WIN32_PROC */ char *devname; @@ -215,47 +230,74 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1 return -1; } - if(*pid == 0){ - int pts; + if (*pid == 0) { + init_subproc_child(); - setsid(); - - pts = unix_open(devname, O_RDWR); - if(pts < 0) { + int pts = unix_open(devname, O_RDWR); + if (pts < 0) { fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname); exit(-1); } - dup2(pts, 0); - dup2(pts, 1); - dup2(pts, 2); + dup2(pts, STDIN_FILENO); + dup2(pts, STDOUT_FILENO); + dup2(pts, STDERR_FILENO); adb_close(pts); adb_close(ptm); - // set OOM adjustment to zero - char text[64]; - snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid()); - int fd = adb_open(text, O_WRONLY); - if (fd >= 0) { - adb_write(fd, "0", 1); - adb_close(fd); - } else { - D("adb: unable to open %s\n", text); - } execl(cmd, cmd, arg0, arg1, NULL); fprintf(stderr, "- exec '%s' failed: %s (%d) -\n", cmd, strerror(errno), errno); exit(-1); } else { - // Don't set child's OOM adjustment to zero. - // Let the child do it itself, as sometimes the parent starts - // running before the child has a /proc/pid/oom_adj. - // """adb: unable to open /proc/644/oom_adj""" seen in some logs. return ptm; } #endif /* !HAVE_WIN32_PROC */ } + +static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid) +{ + D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1); +#ifdef HAVE_WIN32_PROC + fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1); + return -1; +#else /* !HAVE_WIN32_PROC */ + + // 0 is parent socket, 1 is child socket + int sv[2]; + if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { + printf("[ cannot create socket pair - %s ]\n", strerror(errno)); + return -1; + } + + *pid = fork(); + if (*pid < 0) { + printf("- fork failed: %s -\n", strerror(errno)); + adb_close(sv[0]); + adb_close(sv[1]); + return -1; + } + + if (*pid == 0) { + adb_close(sv[0]); + init_subproc_child(); + + // Only hook up stdin/stdout; drop stderr + dup2(sv[1], STDIN_FILENO); + dup2(sv[1], STDOUT_FILENO); + adb_close(sv[1]); + + execl(cmd, cmd, arg0, arg1, NULL); + fprintf(stderr, "- exec '%s' failed: %s (%d) -\n", + cmd, strerror(errno), errno); + exit(-1); + } else { + adb_close(sv[1]); + return sv[0]; + } +#endif /* !HAVE_WIN32_PROC */ +} #endif /* !ABD_HOST */ #if ADB_HOST @@ -296,18 +338,32 @@ static void subproc_waiter_service(int fd, void *cookie) } } -static int create_subproc_thread(const char *name) +static int create_subproc_thread(const char *name, const subproc_mode mode) { stinfo *sti; adb_thread_t t; int ret_fd; - pid_t pid; - if(name) { - ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid); + pid_t pid = -1; + + const char *arg0, *arg1; + if (name == 0 || *name == 0) { + arg0 = "-"; arg1 = 0; } else { - ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid); + arg0 = "-c"; arg1 = name; } - D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid); + + switch (mode) { + case SUBPROC_PTY: + ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid); + break; + case SUBPROC_RAW: + ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid); + break; + default: + fprintf(stderr, "invalid subproc_mode %d\n", mode); + return -1; + } + D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid); sti = malloc(sizeof(stinfo)); if(sti == 0) fatal("cannot allocate stinfo"); @@ -315,14 +371,14 @@ static int create_subproc_thread(const char *name) sti->cookie = (void*) (uintptr_t) pid; sti->fd = ret_fd; - if(adb_thread_create( &t, service_bootstrap_func, sti)){ + if (adb_thread_create(&t, service_bootstrap_func, sti)) { free(sti); adb_close(ret_fd); - printf("cannot create service thread\n"); + fprintf(stderr, "cannot create service thread\n"); return -1; } - D("service thread started, fd=%d pid=%d\n",ret_fd, pid); + D("service thread started, fd=%d pid=%d\n", ret_fd, pid); return ret_fd; } #endif @@ -367,27 +423,35 @@ int service_to_fd(const char *name) } else if (!strncmp(name, "jdwp:", 5)) { ret = create_jdwp_connection_fd(atoi(name+5)); } else if(!HOST && !strncmp(name, "shell:", 6)) { - if(name[6]) { - ret = create_subproc_thread(name + 6); - } else { - ret = create_subproc_thread(0); - } + ret = create_subproc_thread(name + 6, SUBPROC_PTY); + } else if(!HOST && !strncmp(name, "exec:", 5)) { + ret = create_subproc_thread(name + 5, SUBPROC_RAW); } else if(!strncmp(name, "sync:", 5)) { ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); } else if(!strncmp(name, "reboot:", 7)) { void* arg = strdup(name + 7); - if(arg == 0) return -1; + if (arg == NULL) return -1; ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); } else if(!strncmp(name, "backup:", 7)) { - char* arg = strdup(name+7); + char* arg = strdup(name + 7); if (arg == NULL) return -1; - ret = backup_service(BACKUP, arg); + char* c = arg; + for (; *c != '\0'; c++) { + if (*c == ':') + *c = ' '; + } + char* cmd; + if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) { + ret = create_subproc_thread(cmd, SUBPROC_RAW); + free(cmd); + } + free(arg); } else if(!strncmp(name, "restore:", 8)) { - ret = backup_service(RESTORE, NULL); + ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW); } else if(!strncmp(name, "tcpip:", 6)) { int port; if (sscanf(name + 6, "%d", &port) == 0) {