diff --git a/adb/adb.c b/adb/adb.c index e35c33425..6dbd562bc 100644 --- a/adb/adb.c +++ b/adb/adb.c @@ -299,6 +299,13 @@ void parse_banner(char *banner, atransport *t) return; } + if(!strcmp(type, "sideload")) { + D("setting connection_state to CS_SIDELOAD\n"); + t->connection_state = CS_SIDELOAD; + update_transports(); + return; + } + t->connection_state = CS_HOST; } diff --git a/adb/adb.h b/adb/adb.h index ac31f11cc..f7667c22a 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -434,6 +434,7 @@ int connection_state(atransport *t); #define CS_HOST 3 #define CS_RECOVERY 4 #define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */ +#define CS_SIDELOAD 6 extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; diff --git a/adb/commandline.c b/adb/commandline.c index ffce883cc..5b2aa8849 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -367,6 +367,83 @@ static void format_host_command(char* buffer, size_t buflen, const char* comman } } +int adb_download_buffer(const char *service, const void* data, int sz, + unsigned progress) +{ + char buf[4096]; + unsigned total; + int fd; + const unsigned char *ptr; + + sprintf(buf,"%s:%d", service, sz); + fd = adb_connect(buf); + if(fd < 0) { + fprintf(stderr,"error: %s\n", adb_error()); + return -1; + } + + int opt = CHUNK_SIZE; + opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)); + + total = sz; + ptr = data; + + if(progress) { + char *x = strrchr(service, ':'); + if(x) service = x + 1; + } + + while(sz > 0) { + unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz; + if(writex(fd, ptr, xfer)) { + adb_status(fd); + fprintf(stderr,"* failed to write data '%s' *\n", adb_error()); + return -1; + } + sz -= xfer; + ptr += xfer; + if(progress) { + printf("sending: '%s' %4d%% \r", service, (int)(100LL - ((100LL * sz) / (total)))); + fflush(stdout); + } + } + if(progress) { + printf("\n"); + } + + if(readx(fd, buf, 4)){ + fprintf(stderr,"* error reading response *\n"); + adb_close(fd); + return -1; + } + if(memcmp(buf, "OKAY", 4)) { + buf[4] = 0; + fprintf(stderr,"* error response '%s' *\n", buf); + adb_close(fd); + return -1; + } + + adb_close(fd); + return 0; +} + + +int adb_download(const char *service, const char *fn, unsigned progress) +{ + void *data; + unsigned sz; + + data = load_file(fn, &sz); + if(data == 0) { + fprintf(stderr,"* cannot read '%s' *\n", service); + return -1; + } + + int status = adb_download_buffer(service, data, sz, progress); + free(data); + return status; +} + static void status_window(transport_type ttype, const char* serial) { char command[4096]; @@ -1063,6 +1140,15 @@ top: return 0; } + if(!strcmp(argv[0], "sideload")) { + if(argc != 2) return usage(); + if(adb_download("sideload", argv[1], 1)) { + return 1; + } else { + return 0; + } + } + if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") || !strcmp(argv[0], "reboot-bootloader") || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") diff --git a/adb/transport.c b/adb/transport.c index 83a349a95..2f7bd2784 100644 --- a/adb/transport.c +++ b/adb/transport.c @@ -831,6 +831,7 @@ static const char *statename(atransport *t) case CS_DEVICE: return "device"; case CS_HOST: return "host"; case CS_RECOVERY: return "recovery"; + case CS_SIDELOAD: return "sideload"; case CS_NOPERM: return "no permissions"; default: return "unknown"; }