diff options
-rw-r--r-- | Android.mk | 4 | ||||
-rw-r--r-- | applypatch/applypatch.c | 64 | ||||
-rw-r--r-- | applypatch/applypatch.h | 4 | ||||
-rw-r--r-- | etc/init.rc | 9 | ||||
-rw-r--r-- | minadbd/README.txt | 14 | ||||
-rw-r--r-- | minadbd/adb.c | 757 | ||||
-rw-r--r-- | minadbd/adb.h | 27 | ||||
-rw-r--r-- | minadbd/services.c | 1 | ||||
-rw-r--r-- | minadbd/sockets.c | 100 | ||||
-rw-r--r-- | minadbd/sysdeps.h | 25 | ||||
-rw-r--r-- | minadbd/transport.c | 257 | ||||
-rw-r--r-- | minadbd/transport_usb.c | 27 | ||||
-rw-r--r-- | minelf/Retouch.c | 210 | ||||
-rw-r--r-- | minelf/Retouch.h | 6 | ||||
-rw-r--r-- | mtdutils/flash_image.c | 10 | ||||
-rw-r--r-- | recovery.cpp | 4 | ||||
-rw-r--r-- | updater/install.c | 118 |
17 files changed, 101 insertions, 1536 deletions
diff --git a/Android.mk b/Android.mk index 7e48e7f64..036da9ee3 100644 --- a/Android.mk +++ b/Android.mk @@ -40,8 +40,8 @@ ifeq ($(TARGET_RECOVERY_UI_LIB),) else LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB) endif -LOCAL_STATIC_LIBRARIES += libext4_utils libz -LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt libminadbd +LOCAL_STATIC_LIBRARIES += libext4_utils +LOCAL_STATIC_LIBRARIES += libminzip libz libmtdutils libmincrypt libminadbd LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils LOCAL_STATIC_LIBRARIES += libstdc++ libc diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c index 106091386..00004e9a8 100644 --- a/applypatch/applypatch.c +++ b/applypatch/applypatch.c @@ -30,10 +30,16 @@ #include "mtdutils/mtdutils.h" #include "edify/expr.h" -int SaveFileContents(const char* filename, FileContents file); static int LoadPartitionContents(const char* filename, FileContents* file); -int ParseSha1(const char* str, uint8_t* digest); static ssize_t FileSink(unsigned char* data, ssize_t len, void* token); +static int GenerateTarget(FileContents* source_file, + const Value* source_patch_value, + FileContents* copy_file, + const Value* copy_patch_value, + const char* source_filename, + const char* target_filename, + const uint8_t target_sha1[SHA_DIGEST_SIZE], + size_t target_size); static int mtd_partitions_scanned = 0; @@ -113,11 +119,6 @@ static int compare_size_indices(const void* a, const void* b) { } } -void FreeFileContents(FileContents* file) { - if (file) free(file->data); - free(file); -} - // Load the contents of an MTD or EMMC partition into the provided // FileContents. filename should be a string of the form // "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:..." (or @@ -322,7 +323,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { // Save the contents of the given FileContents object under the given // filename. Return 0 on success. -int SaveFileContents(const char* filename, FileContents file) { +int SaveFileContents(const char* filename, const FileContents* file) { int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC); if (fd < 0) { printf("failed to open \"%s\" for write: %s\n", @@ -330,10 +331,10 @@ int SaveFileContents(const char* filename, FileContents file) { return -1; } - ssize_t bytes_written = FileSink(file.data, file.size, &fd); - if (bytes_written != file.size) { + ssize_t bytes_written = FileSink(file->data, file->size, &fd); + if (bytes_written != file->size) { printf("short write of \"%s\" (%ld bytes of %ld) (%s)\n", - filename, (long)bytes_written, (long)file.size, + filename, (long)bytes_written, (long)file->size, strerror(errno)); close(fd); return -1; @@ -341,11 +342,11 @@ int SaveFileContents(const char* filename, FileContents file) { fsync(fd); close(fd); - if (chmod(filename, file.st.st_mode) != 0) { + if (chmod(filename, file->st.st_mode) != 0) { printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (chown(filename, file.st.st_uid, file.st.st_gid) != 0) { + if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) { printf("chown of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -471,7 +472,7 @@ int ParseSha1(const char* str, uint8_t* digest) { // Search an array of sha1 strings for one matching the given sha1. // Return the index of the match on success, or -1 if no match is // found. -int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str, +int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str, int num_patches) { int i; uint8_t patch_sha1[SHA_DIGEST_SIZE]; @@ -503,6 +504,7 @@ int applypatch_check(const char* filename, "sha1 sums; checking cache\n", filename); free(file.data); + file.data = NULL; // If the source file is missing or corrupted, it might be because // we were killed in the middle of patching it. A copy of it @@ -631,9 +633,10 @@ int applypatch(const char* source_filename, FileContents copy_file; FileContents source_file; + copy_file.data = NULL; + source_file.data = NULL; const Value* source_patch_value = NULL; const Value* copy_patch_value = NULL; - int made_copy = 0; // We try to load the target file into the source_file object. if (LoadFileContents(target_filename, &source_file, @@ -643,6 +646,7 @@ int applypatch(const char* source_filename, // has the desired hash, nothing for us to do. printf("\"%s\" is already target; no patch needed\n", target_filename); + free(source_file.data); return 0; } } @@ -653,6 +657,7 @@ int applypatch(const char* source_filename, // Need to load the source file: either we failed to load the // target file, or we did but it's different from the source file. free(source_file.data); + source_file.data = NULL; LoadFileContents(source_filename, &source_file, RETOUCH_DO_MASK); } @@ -667,6 +672,7 @@ int applypatch(const char* source_filename, if (source_patch_value == NULL) { free(source_file.data); + source_file.data = NULL; printf("source file is bad; trying copy\n"); if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file, @@ -685,16 +691,36 @@ int applypatch(const char* source_filename, if (copy_patch_value == NULL) { // fail. printf("copy file doesn't match source SHA-1s either\n"); + free(copy_file.data); return 1; } } + int result = GenerateTarget(&source_file, source_patch_value, + ©_file, copy_patch_value, + source_filename, target_filename, + target_sha1, target_size); + free(source_file.data); + free(copy_file.data); + + return result; +} + +static int GenerateTarget(FileContents* source_file, + const Value* source_patch_value, + FileContents* copy_file, + const Value* copy_patch_value, + const char* source_filename, + const char* target_filename, + const uint8_t target_sha1[SHA_DIGEST_SIZE], + size_t target_size) { int retry = 1; SHA_CTX ctx; int output; MemorySinkInfo msi; FileContents* source_to_use; char* outname; + int made_copy = 0; // assume that target_filename (eg "/system/app/Foo.apk") is located // on the same filesystem as its top-level directory ("/system"). @@ -723,7 +749,7 @@ int applypatch(const char* source_filename, // We still write the original source to cache, in case // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file.size) < 0) { + if (MakeFreeSpaceOnCache(source_file->size) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -763,7 +789,7 @@ int applypatch(const char* source_filename, return 1; } - if (MakeFreeSpaceOnCache(source_file.size) < 0) { + if (MakeFreeSpaceOnCache(source_file->size) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -782,10 +808,10 @@ int applypatch(const char* source_filename, const Value* patch; if (source_patch_value != NULL) { - source_to_use = &source_file; + source_to_use = source_file; patch = source_patch_value; } else { - source_to_use = ©_file; + source_to_use = copy_file; patch = copy_patch_value; } diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h index a78c89bfe..fb58843ba 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -62,9 +62,9 @@ int applypatch_check(const char* filename, int LoadFileContents(const char* filename, FileContents* file, int retouch_flag); -int SaveFileContents(const char* filename, FileContents file); +int SaveFileContents(const char* filename, const FileContents* file); void FreeFileContents(FileContents* file); -int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str, +int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str, int num_patches); // bsdiff.c diff --git a/etc/init.rc b/etc/init.rc index a301779aa..89a161e70 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -15,13 +15,16 @@ on init mkdir /cache mount /tmp /tmp tmpfs + chown root shell /tmp + chmod 0775 /tmp + write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 18D1 write /sys/class/android_usb/android0/idProduct D001 write /sys/class/android_usb/android0/functions adb - write /sys/class/android_usb/android0/iManufacturer $ro.product.manufacturer - write /sys/class/android_usb/android0/iProduct $ro.product.model - write /sys/class/android_usb/android0/iSerial $ro.serialno + write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer} + write /sys/class/android_usb/android0/iProduct ${ro.product.model} + write /sys/class/android_usb/android0/iSerial ${ro.serialno} on boot diff --git a/minadbd/README.txt b/minadbd/README.txt index 0c190d05d..c9df484c3 100644 --- a/minadbd/README.txt +++ b/minadbd/README.txt @@ -4,16 +4,19 @@ the following changes: adb.c - much support for host mode and non-linux OS's stripped out; this version only runs as adbd on the device. - - does not setuid/setgid itself (always stays root) + - always setuid/setgid's itself to the shell user - only uses USB transport - references to JDWP removed - main() removed + - all ADB_HOST and win32 code removed + - removed listeners, logging code, background server (for host) adb.h - minor changes to match adb.c changes sockets.c - references to JDWP removed + - ADB_HOST code removed services.c - all services except echo_service (which is commented out) removed @@ -25,3 +28,12 @@ services.c Android.mk - only builds in adbd mode; builds as static library instead of a standalone executable. + +sysdeps.h + - changes adb_creat() to use O_NOFOLLOW + +transport.c + - removed ADB_HOST code + +transport_usb.c + - removed ADB_HOST code diff --git a/minadbd/adb.c b/minadbd/adb.c index d1e97b31f..0e8fd2a7e 100644 --- a/minadbd/adb.c +++ b/minadbd/adb.c @@ -28,13 +28,9 @@ #include "sysdeps.h" #include "adb.h" -#if !ADB_HOST #include <private/android_filesystem_config.h> #include <linux/capability.h> #include <linux/prctl.h> -#else -#include "usb_vendors.h" -#endif #if ADB_TRACE ADB_MUTEX_DEFINE( D_lock ); @@ -228,29 +224,6 @@ static void send_connect(atransport *t) HOST ? "host" : adb_device_banner); cp->msg.data_length = strlen((char*) cp->data) + 1; send_packet(cp, t); -#if ADB_HOST - /* XXX why sleep here? */ - // allow the device some time to respond to the connect message - adb_sleep_ms(1000); -#endif -} - -static char *connection_state_name(atransport *t) -{ - if (t == NULL) { - return "unknown"; - } - - switch(t->connection_state) { - case CS_BOOTLOADER: - return "bootloader"; - case CS_DEVICE: - return "device"; - case CS_OFFLINE: - return "offline"; - default: - return "unknown"; - } } void parse_banner(char *banner, atransport *t) @@ -400,448 +373,11 @@ void handle_packet(apacket *p, atransport *t) put_apacket(p); } -alistener listener_list = { - .next = &listener_list, - .prev = &listener_list, -}; - -static void ss_listener_event_func(int _fd, unsigned ev, void *_l) -{ - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = adb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - adb_socket_setbufsize(fd, CHUNK_SIZE); - - s = create_local_socket(fd); - if(s) { - connect_to_smartsocket(s); - return; - } - - adb_close(fd); - } -} - -static void listener_event_func(int _fd, unsigned ev, void *_l) -{ - alistener *l = _l; - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = adb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - s = create_local_socket(fd); - if(s) { - s->transport = l->transport; - connect_to_remote(s, l->connect_to); - return; - } - - adb_close(fd); - } -} - -static void free_listener(alistener* l) -{ - if (l->next) { - l->next->prev = l->prev; - l->prev->next = l->next; - l->next = l->prev = l; - } - - // closes the corresponding fd - fdevent_remove(&l->fde); - - if (l->local_name) - free((char*)l->local_name); - - if (l->connect_to) - free((char*)l->connect_to); - - if (l->transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - } - free(l); -} - -static void listener_disconnect(void* _l, atransport* t) -{ - alistener* l = _l; - - free_listener(l); -} - -int local_name_to_fd(const char *name) -{ - int port; - - if(!strncmp("tcp:", name, 4)){ - int ret; - port = atoi(name + 4); - ret = socket_loopback_server(port, SOCK_STREAM); - return ret; - } -#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */ - // It's non-sensical to support the "reserved" space on the adb host side - if(!strncmp(name, "local:", 6)) { - return socket_local_server(name + 6, - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - } else if(!strncmp(name, "localabstract:", 14)) { - return socket_local_server(name + 14, - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - } else if(!strncmp(name, "localfilesystem:", 16)) { - return socket_local_server(name + 16, - ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); - } - -#endif - printf("unknown local portname '%s'\n", name); - return -1; -} - -static int remove_listener(const char *local_name, const char *connect_to, atransport* transport) -{ - alistener *l; - - for (l = listener_list.next; l != &listener_list; l = l->next) { - if (!strcmp(local_name, l->local_name) && - !strcmp(connect_to, l->connect_to) && - l->transport && l->transport == transport) { - - listener_disconnect(l, transport); - return 0; - } - } - - return -1; -} - -static int install_listener(const char *local_name, const char *connect_to, atransport* transport) -{ - alistener *l; - - //printf("install_listener('%s','%s')\n", local_name, connect_to); - - for(l = listener_list.next; l != &listener_list; l = l->next){ - if(strcmp(local_name, l->local_name) == 0) { - char *cto; - - /* can't repurpose a smartsocket */ - if(l->connect_to[0] == '*') { - return -1; - } - - cto = strdup(connect_to); - if(cto == 0) { - return -1; - } - - //printf("rebinding '%s' to '%s'\n", local_name, connect_to); - free((void*) l->connect_to); - l->connect_to = cto; - if (l->transport != transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - l->transport = transport; - add_transport_disconnect(l->transport, &l->disconnect); - } - return 0; - } - } - - if((l = calloc(1, sizeof(alistener))) == 0) goto nomem; - if((l->local_name = strdup(local_name)) == 0) goto nomem; - if((l->connect_to = strdup(connect_to)) == 0) goto nomem; - - - l->fd = local_name_to_fd(local_name); - if(l->fd < 0) { - free((void*) l->local_name); - free((void*) l->connect_to); - free(l); - printf("cannot bind '%s'\n", local_name); - return -2; - } - - close_on_exec(l->fd); - if(!strcmp(l->connect_to, "*smartsocket*")) { - fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); - } else { - fdevent_install(&l->fde, l->fd, listener_event_func, l); - } - fdevent_set(&l->fde, FDE_READ); - - l->next = &listener_list; - l->prev = listener_list.prev; - l->next->prev = l; - l->prev->next = l; - l->transport = transport; - - if (transport) { - l->disconnect.opaque = l; - l->disconnect.func = listener_disconnect; - add_transport_disconnect(transport, &l->disconnect); - } - return 0; - -nomem: - fatal("cannot allocate listener"); - return 0; -} - -#ifdef HAVE_WIN32_PROC -static BOOL WINAPI ctrlc_handler(DWORD type) -{ - exit(STATUS_CONTROL_C_EXIT); - return TRUE; -} -#endif - static void adb_cleanup(void) { usb_cleanup(); } -void start_logging(void) -{ -#ifdef HAVE_WIN32_PROC - char temp[ MAX_PATH ]; - FILE* fnul; - FILE* flog; - - GetTempPath( sizeof(temp) - 8, temp ); - strcat( temp, "adb.log" ); - - /* Win32 specific redirections */ - fnul = fopen( "NUL", "rt" ); - if (fnul != NULL) - stdin[0] = fnul[0]; - - flog = fopen( temp, "at" ); - if (flog == NULL) - flog = fnul; - - setvbuf( flog, NULL, _IONBF, 0 ); - - stdout[0] = flog[0]; - stderr[0] = flog[0]; - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); -#else - int fd; - - fd = unix_open("/dev/null", O_RDONLY); - dup2(fd, 0); - adb_close(fd); - - fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640); - if(fd < 0) { - fd = unix_open("/dev/null", O_WRONLY); - } - dup2(fd, 1); - dup2(fd, 2); - adb_close(fd); - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); -#endif -} - -#if !ADB_HOST -void start_device_log(void) -{ - int fd; - char path[PATH_MAX]; - struct tm now; - time_t t; - char value[PROPERTY_VALUE_MAX]; - - // read the trace mask from persistent property persist.adb.trace_mask - // give up if the property is not set or cannot be parsed - property_get("persist.adb.trace_mask", value, ""); - if (sscanf(value, "%x", &adb_trace_mask) != 1) - return; - - adb_mkdir("/data/adb", 0775); - tzset(); - time(&t); - localtime_r(&t, &now); - strftime(path, sizeof(path), - "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt", - &now); - fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640); - if (fd < 0) - return; - - // redirect stdout and stderr to the log file - dup2(fd, 1); - dup2(fd, 2); - fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid()); - adb_close(fd); - - fd = unix_open("/dev/null", O_RDONLY); - dup2(fd, 0); - adb_close(fd); -} -#endif - -#if ADB_HOST -int launch_server(int server_port) -{ -#ifdef HAVE_WIN32_PROC - /* we need to start the server in the background */ - /* we create a PIPE that will be used to wait for the server's "OK" */ - /* message since the pipe handles must be inheritable, we use a */ - /* security attribute */ - HANDLE pipe_read, pipe_write; - SECURITY_ATTRIBUTES sa; - STARTUPINFO startup; - PROCESS_INFORMATION pinfo; - char program_path[ MAX_PATH ]; - int ret; - - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - - /* create pipe, and ensure its read handle isn't inheritable */ - ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 ); - if (!ret) { - fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() ); - return -1; - } - - SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 ); - - ZeroMemory( &startup, sizeof(startup) ); - startup.cb = sizeof(startup); - startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE ); - startup.hStdOutput = pipe_write; - startup.hStdError = GetStdHandle( STD_ERROR_HANDLE ); - startup.dwFlags = STARTF_USESTDHANDLES; - - ZeroMemory( &pinfo, sizeof(pinfo) ); - - /* get path of current program */ - GetModuleFileName( NULL, program_path, sizeof(program_path) ); - - ret = CreateProcess( - program_path, /* program path */ - "adb fork-server server", - /* the fork-server argument will set the - debug = 2 in the child */ - NULL, /* process handle is not inheritable */ - NULL, /* thread handle is not inheritable */ - TRUE, /* yes, inherit some handles */ - DETACHED_PROCESS, /* the new process doesn't have a console */ - NULL, /* use parent's environment block */ - NULL, /* use parent's starting directory */ - &startup, /* startup info, i.e. std handles */ - &pinfo ); - - CloseHandle( pipe_write ); - - if (!ret) { - fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() ); - CloseHandle( pipe_read ); - return -1; - } - - CloseHandle( pinfo.hProcess ); - CloseHandle( pinfo.hThread ); - - /* wait for the "OK\n" message */ - { - char temp[3]; - DWORD count; - - ret = ReadFile( pipe_read, temp, 3, &count, NULL ); - CloseHandle( pipe_read ); - if ( !ret ) { - fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() ); - return -1; - } - if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { - fprintf(stderr, "ADB server didn't ACK\n" ); - return -1; - } - } -#elif defined(HAVE_FORKEXEC) - char path[PATH_MAX]; - int fd[2]; - - // set up a pipe so the child can tell us when it is ready. - // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child. - if (pipe(fd)) { - fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno); - return -1; - } - get_my_path(path, PATH_MAX); - pid_t pid = fork(); - if(pid < 0) return -1; - - if (pid == 0) { - // child side of the fork - - // redirect stderr to the pipe - // we use stderr instead of stdout due to stdout's buffering behavior. - adb_close(fd[0]); - dup2(fd[1], STDERR_FILENO); - adb_close(fd[1]); - - // child process - int result = execl(path, "adb", "fork-server", "server", NULL); - // this should not return - fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno); - } else { - // parent side of the fork - - char temp[3]; - - temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C'; - // wait for the "OK\n" message - adb_close(fd[1]); - int ret = adb_read(fd[0], temp, 3); - int saved_errno = errno; - adb_close(fd[0]); - if (ret < 0) { - fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno); - return -1; - } - if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') { - fprintf(stderr, "ADB server didn't ACK\n" ); - return -1; - } - - setsid(); - } -#else -#error "cannot implement background server start on this platform" -#endif - return 0; -} -#endif - -/* Constructs a local name of form tcp:port. - * target_str points to the target string, it's content will be overwritten. - * target_size is the capacity of the target string. - * server_port is the port number to use for the local name. - */ -void build_local_name(char* target_str, size_t target_size, int server_port) -{ - snprintf(target_str, target_size, "tcp:%d", server_port); -} - int adb_main() { atexit(adb_cleanup); @@ -858,6 +394,16 @@ int adb_main() usb_init(); } + if (setgid(AID_SHELL) != 0) { + fprintf(stderr, "failed to setgid to shell\n"); + exit(1); + } + if (setuid(AID_SHELL) != 0) { + fprintf(stderr, "failed to setuid to shell\n"); + exit(1); + } + fprintf(stderr, "userid is %d\n", getuid()); + D("Event loop starting\n"); fdevent_loop(); @@ -866,286 +412,3 @@ int adb_main() return 0; } - -#if ADB_HOST -void connect_device(char* host, char* buffer, int buffer_size) -{ - int port, fd; - char* portstr = strchr(host, ':'); - char hostbuf[100]; - char serial[100]; - - strncpy(hostbuf, host, sizeof(hostbuf) - 1); - if (portstr) { - if (portstr - host >= sizeof(hostbuf)) { - snprintf(buffer, buffer_size, "bad host name %s", host); - return; - } - // zero terminate the host at the point we found the colon - hostbuf[portstr - host] = 0; - if (sscanf(portstr + 1, "%d", &port) == 0) { - snprintf(buffer, buffer_size, "bad port number %s", portstr); - return; - } - } else { - port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT; - } - - snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port); - if (find_transport(serial)) { - snprintf(buffer, buffer_size, "already connected to %s", serial); - return; - } - - fd = socket_network_client(hostbuf, port, SOCK_STREAM); - if (fd < 0) { - snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port); - return; - } - - D("client: connected on remote on fd %d\n", fd); - close_on_exec(fd); - disable_tcp_nagle(fd); - register_socket_transport(fd, serial, port, 0); - snprintf(buffer, buffer_size, "connected to %s", serial); -} - -void connect_emulator(char* port_spec, char* buffer, int buffer_size) -{ - char* port_separator = strchr(port_spec, ','); - if (!port_separator) { - snprintf(buffer, buffer_size, - "unable to parse '%s' as <console port>,<adb port>", - port_spec); - return; - } - - // Zero-terminate console port and make port_separator point to 2nd port. - *port_separator++ = 0; - int console_port = strtol(port_spec, NULL, 0); - int adb_port = strtol(port_separator, NULL, 0); - if (!(console_port > 0 && adb_port > 0)) { - *(port_separator - 1) = ','; - snprintf(buffer, buffer_size, - "Invalid port numbers: Expected positive numbers, got '%s'", - port_spec); - return; - } - - /* Check if the emulator is already known. - * Note: There's a small but harmless race condition here: An emulator not - * present just yet could be registered by another invocation right - * after doing this check here. However, local_connect protects - * against double-registration too. From here, a better error message - * can be produced. In the case of the race condition, the very specific - * error message won't be shown, but the data doesn't get corrupted. */ - atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port); - if (known_emulator != NULL) { - snprintf(buffer, buffer_size, - "Emulator on port %d already registered.", adb_port); - return; - } - - /* Check if more emulators can be registered. Similar unproblematic - * race condition as above. */ - int candidate_slot = get_available_local_transport_index(); - if (candidate_slot < 0) { - snprintf(buffer, buffer_size, "Cannot accept more emulators."); - return; - } - - /* Preconditions met, try to connect to the emulator. */ - if (!local_connect_arbitrary_ports(console_port, adb_port)) { - snprintf(buffer, buffer_size, - "Connected to emulator on ports %d,%d", console_port, adb_port); - } else { - snprintf(buffer, buffer_size, - "Could not connect to emulator on ports %d,%d", - console_port, adb_port); - } -} -#endif - -int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) -{ - atransport *transport = NULL; - char buf[4096]; - - if(!strcmp(service, "kill")) { - fprintf(stderr,"adb server killed by remote request\n"); - fflush(stdout); - adb_write(reply_fd, "OKAY", 4); - usb_cleanup(); - exit(0); - } - -#if ADB_HOST - // "transport:" is used for switching transport with a specified serial number - // "transport-usb:" is used for switching transport to the only USB transport - // "transport-local:" is used for switching transport to the only local transport - // "transport-any:" is used for switching transport to the only transport - if (!strncmp(service, "transport", strlen("transport"))) { - char* error_string = "unknown failure"; - transport_type type = kTransportAny; - - if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { - type = kTransportUsb; - } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { - type = kTransportLocal; - } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { - type = kTransportAny; - } else if (!strncmp(service, "transport:", strlen("transport:"))) { - service += strlen("transport:"); - serial = service; - } - - transport = acquire_one_transport(CS_ANY, type, serial, &error_string); - - if (transport) { - s->transport = transport; - adb_write(reply_fd, "OKAY", 4); - } else { - sendfailmsg(reply_fd, error_string); - } - return 1; - } - - // return a list of all connected devices - if (!strcmp(service, "devices")) { - char buffer[4096]; - memset(buf, 0, sizeof(buf)); - memset(buffer, 0, sizeof(buffer)); - D("Getting device list \n"); - list_transports(buffer, sizeof(buffer)); - snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); - D("Wrote device list \n"); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - - // add a new TCP transport, device or emulator - if (!strncmp(service, "connect:", 8)) { - char buffer[4096]; - char* host = service + 8; - if (!strncmp(host, "emu:", 4)) { - connect_emulator(host + 4, buffer, sizeof(buffer)); - } else { - connect_device(host, buffer, sizeof(buffer)); - } - // Send response for emulator and device - snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - - // remove TCP transport - if (!strncmp(service, "disconnect:", 11)) { - char buffer[4096]; - memset(buffer, 0, sizeof(buffer)); - char* serial = service + 11; - if (serial[0] == 0) { - // disconnect from all TCP devices - unregister_all_tcp_transports(); - } else { - char hostbuf[100]; - // assume port 5555 if no port is specified - if (!strchr(serial, ':')) { - snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial); - serial = hostbuf; - } - atransport *t = find_transport(serial); - - if (t) { - unregister_transport(t); - } else { - snprintf(buffer, sizeof(buffer), "No such device %s", serial); - } - } - - snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - - // returns our value for ADB_SERVER_VERSION - if (!strcmp(service, "version")) { - char version[12]; - snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION); - snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - - if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { - char *out = "unknown"; - transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - if (transport && transport->serial) { - out = transport->serial; - } - snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - // indicates a new emulator instance has started - if (!strncmp(service,"emulator:",9)) { - int port = atoi(service+9); - local_connect(port); - /* we don't even need to send a reply */ - return 0; - } -#endif // ADB_HOST - - if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) { - char *local, *remote, *err; - int r; - atransport *transport; - - int createForward = strncmp(service,"kill",4); - - local = service + (createForward ? 8 : 12); - remote = strchr(local,';'); - if(remote == 0) { - sendfailmsg(reply_fd, "malformed forward spec"); - return 0; - } - - *remote++ = 0; - if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){ - sendfailmsg(reply_fd, "malformed forward spec"); - return 0; - } - - transport = acquire_one_transport(CS_ANY, ttype, serial, &err); - if (!transport) { - sendfailmsg(reply_fd, err); - return 0; - } - - if (createForward) { - r = install_listener(local, remote, transport); - } else { - r = remove_listener(local, remote, transport); - } - if(r == 0) { - /* 1st OKAY is connect, 2nd OKAY is status */ - writex(reply_fd, "OKAYOKAY", 8); - return 0; - } - - if (createForward) { - sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket"); - } else { - sendfailmsg(reply_fd, "cannot remove listener"); - } - return 0; - } - - if(!strncmp(service,"get-state",strlen("get-state"))) { - transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - char *state = connection_state_name(transport); - snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - return -1; -} diff --git a/minadbd/adb.h b/minadbd/adb.h index a989eddab..98fa5972e 100644 --- a/minadbd/adb.h +++ b/minadbd/adb.h @@ -41,7 +41,6 @@ typedef struct amessage amessage; typedef struct apacket apacket; typedef struct asocket asocket; -typedef struct alistener alistener; typedef struct aservice aservice; typedef struct atransport atransport; typedef struct adisconnect adisconnect; @@ -134,7 +133,7 @@ struct asocket { /* the adisconnect structure is used to record a callback that ** will be called whenever a transport is disconnected (e.g. by the user) ** this should be used to cleanup objects that depend on the -** transport (e.g. remote sockets, listeners, etc...) +** transport (e.g. remote sockets, etc...) */ struct adisconnect { @@ -194,30 +193,6 @@ struct atransport }; -/* A listener is an entity which binds to a local port -** and, upon receiving a connection on that port, creates -** an asocket to connect the new local connection to a -** specific remote service. -** -** TODO: some listeners read from the new connection to -** determine what exact service to connect to on the far -** side. -*/ -struct alistener -{ - alistener *next; - alistener *prev; - - fdevent fde; - int fd; - - const char *local_name; - const char *connect_to; - atransport *transport; - adisconnect disconnect; -}; - - void print_packet(const char *label, apacket *p); asocket *find_local_socket(unsigned id); diff --git a/minadbd/services.c b/minadbd/services.c index 8fc8b3ccb..aef37f7e4 100644 --- a/minadbd/services.c +++ b/minadbd/services.c @@ -53,6 +53,7 @@ static void sideload_service(int s, void *cookie) fd = adb_creat(ADB_SIDELOAD_FILENAME, 0644); if(fd < 0) { + fprintf(stderr, "failed to create %s\n", ADB_SIDELOAD_FILENAME); adb_close(s); return; } diff --git a/minadbd/sockets.c b/minadbd/sockets.c index 9f4cecb3a..2dd646159 100644 --- a/minadbd/sockets.c +++ b/minadbd/sockets.c @@ -413,22 +413,6 @@ asocket *create_local_service_socket(const char *name) return s; } -#if ADB_HOST -static asocket *create_host_service_socket(const char *name, const char* serial) -{ - asocket *s; - - s = host_service_to_socket(name, serial); - - if (s != NULL) { - D("LS(%d) bound to '%s'\n", s->id, name); - return s; - } - - return s; -} -#endif /* ADB_HOST */ - /* a Remote socket is used to send/receive data to/from a given transport object ** it needs to be closed when the transport is forcibly destroyed by the user */ @@ -612,11 +596,6 @@ char *skip_host_serial(char *service) { static int smart_socket_enqueue(asocket *s, apacket *p) { unsigned len; -#if ADB_HOST - char *service = NULL; - char* serial = NULL; - transport_type ttype = kTransportAny; -#endif D("SS(%d): enqueue %d\n", s->id, p->len); @@ -658,84 +637,6 @@ static int smart_socket_enqueue(asocket *s, apacket *p) D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4)); -#if ADB_HOST - service = (char *)p->data + 4; - if(!strncmp(service, "host-serial:", strlen("host-serial:"))) { - char* serial_end; - service += strlen("host-serial:"); - - // serial number should follow "host:" and could be a host:port string. - serial_end = skip_host_serial(service); - if (serial_end) { - *serial_end = 0; // terminate string - serial = service; - service = serial_end + 1; - } - } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) { - ttype = kTransportUsb; - service += strlen("host-usb:"); - } else if (!strncmp(service, "host-local:", strlen("host-local:"))) { - ttype = kTransportLocal; - service += strlen("host-local:"); - } else if (!strncmp(service, "host:", strlen("host:"))) { - ttype = kTransportAny; - service += strlen("host:"); - } else { - service = NULL; - } - - if (service) { - asocket *s2; - - /* some requests are handled immediately -- in that - ** case the handle_host_request() routine has sent - ** the OKAY or FAIL message and all we have to do - ** is clean up. - */ - if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) { - /* XXX fail message? */ - D( "SS(%d): handled host service '%s'\n", s->id, service ); - goto fail; - } - if (!strncmp(service, "transport", strlen("transport"))) { - D( "SS(%d): okay transport\n", s->id ); - p->len = 0; - return 0; - } - - /* try to find a local service with this name. - ** if no such service exists, we'll fail out - ** and tear down here. - */ - s2 = create_host_service_socket(service, serial); - if(s2 == 0) { - D( "SS(%d): couldn't create host service '%s'\n", s->id, service ); - sendfailmsg(s->peer->fd, "unknown host service"); - goto fail; - } - - /* we've connected to a local host service, - ** so we make our peer back into a regular - ** local socket and bind it to the new local - ** service socket, acknowledge the successful - ** connection, and close this smart socket now - ** that its work is done. - */ - adb_write(s->peer->fd, "OKAY", 4); - - s->peer->ready = local_socket_ready; - s->peer->close = local_socket_close; - s->peer->peer = s2; - s2->peer = s->peer; - s->peer = 0; - D( "SS(%d): okay\n", s->id ); - s->close(s); - - /* initial state is "ready" */ - s2->ready(s2); - return 0; - } -#else /* !ADB_HOST */ if (s->transport == NULL) { char* error_string = "unknown failure"; s->transport = acquire_one_transport (CS_ANY, @@ -746,7 +647,6 @@ static int smart_socket_enqueue(asocket *s, apacket *p) goto fail; } } -#endif if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) { /* if there's no remote we fail the connection diff --git a/minadbd/sysdeps.h b/minadbd/sysdeps.h index b51807615..800ddb753 100644 --- a/minadbd/sysdeps.h +++ b/minadbd/sysdeps.h @@ -324,6 +324,18 @@ static __inline__ int adb_open_mode( const char* pathname, int options, int return open( pathname, options, mode ); } +static __inline__ int adb_creat(const char* path, int mode) +{ + int fd = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, mode); + + if ( fd < 0 ) + return -1; + + close_on_exec(fd); + return fd; +} +#undef creat +#define creat ___xxx_creat static __inline__ int adb_open( const char* pathname, int options ) { @@ -380,19 +392,6 @@ static __inline__ int adb_unlink(const char* path) #undef unlink #define unlink ___xxx_unlink -static __inline__ int adb_creat(const char* path, int mode) -{ - int fd = creat(path, mode); - - if ( fd < 0 ) - return -1; - - close_on_exec(fd); - return fd; -} -#undef creat -#define creat ___xxx_creat - static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { int fd; diff --git a/minadbd/transport.c b/minadbd/transport.c index 2f7bd2784..ff2004932 100644 --- a/minadbd/transport.c +++ b/minadbd/transport.c @@ -363,154 +363,10 @@ static int transport_registration_send = -1; static int transport_registration_recv = -1; static fdevent transport_registration_fde; - -#if ADB_HOST -static int list_transports_msg(char* buffer, size_t bufferlen) -{ - char head[5]; - int len; - - len = list_transports(buffer+4, bufferlen-4); - snprintf(head, sizeof(head), "%04x", len); - memcpy(buffer, head, 4); - len += 4; - return len; -} - -/* this adds support required by the 'track-devices' service. - * this is used to send the content of "list_transport" to any - * number of client connections that want it through a single - * live TCP connection - */ -typedef struct device_tracker device_tracker; -struct device_tracker { - asocket socket; - int update_needed; - device_tracker* next; -}; - -/* linked list of all device trackers */ -static device_tracker* device_tracker_list; - -static void -device_tracker_remove( device_tracker* tracker ) -{ - device_tracker** pnode = &device_tracker_list; - device_tracker* node = *pnode; - - adb_mutex_lock( &transport_lock ); - while (node) { - if (node == tracker) { - *pnode = node->next; - break; - } - pnode = &node->next; - node = *pnode; - } - adb_mutex_unlock( &transport_lock ); -} - -static void -device_tracker_close( asocket* socket ) -{ - device_tracker* tracker = (device_tracker*) socket; - asocket* peer = socket->peer; - - D( "device tracker %p removed\n", tracker); - if (peer) { - peer->peer = NULL; - peer->close(peer); - } - device_tracker_remove(tracker); - free(tracker); -} - -static int -device_tracker_enqueue( asocket* socket, apacket* p ) -{ - /* you can't read from a device tracker, close immediately */ - put_apacket(p); - device_tracker_close(socket); - return -1; -} - -static int -device_tracker_send( device_tracker* tracker, - const char* buffer, - int len ) -{ - apacket* p = get_apacket(); - asocket* peer = tracker->socket.peer; - - memcpy(p->data, buffer, len); - p->len = len; - return peer->enqueue( peer, p ); -} - - -static void -device_tracker_ready( asocket* socket ) -{ - device_tracker* tracker = (device_tracker*) socket; - - /* we want to send the device list when the tracker connects - * for the first time, even if no update occured */ - if (tracker->update_needed > 0) { - char buffer[1024]; - int len; - - tracker->update_needed = 0; - - len = list_transports_msg(buffer, sizeof(buffer)); - device_tracker_send(tracker, buffer, len); - } -} - - -asocket* -create_device_tracker(void) -{ - device_tracker* tracker = calloc(1,sizeof(*tracker)); - - if(tracker == 0) fatal("cannot allocate device tracker"); - - D( "device tracker %p created\n", tracker); - - tracker->socket.enqueue = device_tracker_enqueue; - tracker->socket.ready = device_tracker_ready; - tracker->socket.close = device_tracker_close; - tracker->update_needed = 1; - - tracker->next = device_tracker_list; - device_tracker_list = tracker; - - return &tracker->socket; -} - - -/* call this function each time the transport list has changed */ -void update_transports(void) -{ - char buffer[1024]; - int len; - device_tracker* tracker; - - len = list_transports_msg(buffer, sizeof(buffer)); - - tracker = device_tracker_list; - while (tracker != NULL) { - device_tracker* next = tracker->next; - /* note: this may destroy the tracker if the connection is closed */ - device_tracker_send(tracker, buffer, len); - tracker = next; - } -} -#else void update_transports(void) { // nothing to do on the device side } -#endif // ADB_HOST typedef struct tmsg tmsg; struct tmsg @@ -822,64 +678,6 @@ retry: return result; } -#if ADB_HOST -static const char *statename(atransport *t) -{ - switch(t->connection_state){ - case CS_OFFLINE: return "offline"; - case CS_BOOTLOADER: return "bootloader"; - 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"; - } -} - -int list_transports(char *buf, size_t bufsize) -{ - char* p = buf; - char* end = buf + bufsize; - int len; - atransport *t; - - /* XXX OVERRUN PROBLEMS XXX */ - adb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - const char* serial = t->serial; - if (!serial || !serial[0]) - serial = "????????????"; - len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t)); - - if (p + len >= end) { - /* discard last line if buffer is too short */ - break; - } - p += len; - } - p[0] = 0; - adb_mutex_unlock(&transport_lock); - return p - buf; -} - - -/* hack for osx */ -void close_usb_devices() -{ - atransport *t; - - adb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if ( !t->kicked ) { - t->kicked = 1; - t->kick(t); - } - } - adb_mutex_unlock(&transport_lock); -} -#endif // ADB_HOST - void register_socket_transport(int s, const char *serial, int port, int local) { atransport *t = calloc(1, sizeof(atransport)); @@ -901,61 +699,6 @@ void register_socket_transport(int s, const char *serial, int port, int local) register_transport(t); } -#if ADB_HOST -atransport *find_transport(const char *serial) -{ - atransport *t; - - adb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if (t->serial && !strcmp(serial, t->serial)) { - break; - } - } - adb_mutex_unlock(&transport_lock); - - if (t != &transport_list) - return t; - else - return 0; -} - -void unregister_transport(atransport *t) -{ - adb_mutex_lock(&transport_lock); - t->next->prev = t->prev; - t->prev->next = t->next; - adb_mutex_unlock(&transport_lock); - - kick_transport(t); - transport_unref(t); -} - -// unregisters all non-emulator TCP transports -void unregister_all_tcp_transports() -{ - atransport *t, *next; - adb_mutex_lock(&transport_lock); - for (t = transport_list.next; t != &transport_list; t = next) { - next = t->next; - if (t->type == kTransportLocal && t->adb_port == 0) { - t->next->prev = t->prev; - t->prev->next = next; - // we cannot call kick_transport when holding transport_lock - if (!t->kicked) - { - t->kicked = 1; - t->kick(t); - } - transport_unref_locked(t); - } - } - - adb_mutex_unlock(&transport_lock); -} - -#endif - void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable) { atransport *t = calloc(1, sizeof(atransport)); diff --git a/minadbd/transport_usb.c b/minadbd/transport_usb.c index ee6b637b5..91cbf6151 100644 --- a/minadbd/transport_usb.c +++ b/minadbd/transport_usb.c @@ -23,10 +23,6 @@ #define TRACE_TAG TRACE_TRANSPORT #include "adb.h" -#if ADB_HOST -#include "usb_vendors.h" -#endif - #ifdef HAVE_BIG_ENDIAN #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) static inline void fix_endians(apacket *p) @@ -121,28 +117,5 @@ void init_usb_transport(atransport *t, usb_handle *h, int state) t->type = kTransportUsb; t->usb = h; -#if ADB_HOST - HOST = 1; -#else HOST = 0; -#endif -} - -#if ADB_HOST -int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol) -{ - unsigned i; - for (i = 0; i < vendorIdCount; i++) { - if (vid == vendorIds[i]) { - if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && - usb_protocol == ADB_PROTOCOL) { - return 1; - } - - return 0; - } - } - - return 0; } -#endif diff --git a/minelf/Retouch.c b/minelf/Retouch.c index 33809cd6d..d75eec1e8 100644 --- a/minelf/Retouch.c +++ b/minelf/Retouch.c @@ -194,213 +194,3 @@ int retouch_mask_data(uint8_t *binary_object, if (retouch_offset != NULL) *retouch_offset = offset_candidate; return RETOUCH_DATA_MATCHED; } - -// On success, _override is set to the offset that was actually applied. -// This implies that once we randomize to an offset we stick with it. -// This in turn is necessary in order to guarantee recovery after crash. -bool retouch_one_library(const char *binary_name, - const char *binary_sha1, - int32_t retouch_offset, - int32_t *retouch_offset_override) { - bool success = true; - int result; - - FileContents file; - file.data = NULL; - - char binary_name_atomic[strlen(binary_name)+10]; - strcpy(binary_name_atomic, binary_name); - strcat(binary_name_atomic, ".atomic"); - - // We need a path that exists for calling statfs() later. - // - // Assume that binary_name (eg "/system/app/Foo.apk") is located - // on the same filesystem as its top-level directory ("/system"). - char target_fs[strlen(binary_name)+1]; - char* slash = strchr(binary_name+1, '/'); - if (slash != NULL) { - int count = slash - binary_name; - strncpy(target_fs, binary_name, count); - target_fs[count] = '\0'; - } else { - strcpy(target_fs, binary_name); - } - - result = LoadFileContents(binary_name, &file, RETOUCH_DONT_MASK); - - if (result == 0) { - // Figure out the *apparent* offset to which this file has been - // retouched. If it looks good, we will skip processing (we might - // have crashed and during this recovery pass we don't want to - // overwrite a valuable saved file in /cache---which would happen - // if we blindly retouch everything again). NOTE: This implies - // that we might have to override the supplied retouch offset. We - // can do the override only once though: everything should match - // afterward. - - int32_t inferred_offset; - int retouch_probe_result = retouch_mask_data(file.data, - file.size, - NULL, - &inferred_offset); - - if (retouch_probe_result == RETOUCH_DATA_MATCHED) { - if ((retouch_offset == inferred_offset) || - ((retouch_offset != 0 && inferred_offset != 0) && - (retouch_offset_override != NULL))) { - // This file is OK already and we are allowed to override. - // Let's just return the offset override value. It is critical - // to skip regardless of override: a broken file might need - // recovery down the list and we should not mess up the saved - // copy by doing unnecessary retouching. - // - // NOTE: If retouching was already started with a different - // value, we will not be allowed to override. This happens - // if on the retouch list there is a patched binary (which is - // masked in apply_patch()) before there is a non-patched - // binary. - if (retouch_offset_override != NULL) - *retouch_offset_override = inferred_offset; - success = true; - goto out; - } else { - // Retouch to zero (mask the retouching), to make sure that - // the SHA-1 check will pass below. - int32_t zero = 0; - retouch_mask_data(file.data, file.size, &zero, NULL); - SHA(file.data, file.size, file.sha1); - } - } - - if (retouch_probe_result == RETOUCH_DATA_NOTAPPLICABLE) { - // In the case of not retouchable, fake it. We do not want - // to do the normal processing and overwrite the backup file: - // we might be recovering! - // - // We return a zero override, which tells the caller that we - // simply skipped the file. - if (retouch_offset_override != NULL) - *retouch_offset_override = 0; - success = true; - goto out; - } - - // If we get here, either there was a mismatch in the offset, or - // the file has not been processed yet. Continue with normal - // processing. - } - - if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) { - free(file.data); - printf("Attempting to recover source from '%s' ...\n", - CACHE_TEMP_SOURCE); - result = LoadFileContents(CACHE_TEMP_SOURCE, &file, RETOUCH_DO_MASK); - if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) { - printf(" failed.\n"); - success = false; - goto out; - } - printf(" succeeded.\n"); - } - - // Retouch in-memory before worrying about backing up the original. - // - // Recovery steps will be oblivious to the actual retouch offset used, - // so might as well write out the already-retouched copy. Then, in the - // usual case, we will just swap the file locally, with no more writes - // needed. In the no-free-space case, we will then write the same to the - // original location. - - result = retouch_mask_data(file.data, file.size, &retouch_offset, NULL); - if (result != RETOUCH_DATA_MATCHED) { - success = false; - goto out; - } - if (retouch_offset_override != NULL) - *retouch_offset_override = retouch_offset; - - // How much free space do we need? - bool enough_space = false; - size_t free_space = FreeSpaceForFile(target_fs); - // 50% margin when estimating the space needed. - enough_space = (free_space > (file.size * 3 / 2)); - - // The experts say we have to allow for a retry of the - // whole process to avoid filesystem weirdness. - int retry = 1; - bool made_copy = false; - do { - // First figure out where to store a copy of the original. - // Ideally leave the original itself intact until the - // atomic swap. If no room on the same partition, fall back - // to the cache partition and remove the original. - - if (!enough_space) { - printf("Target is %ldB; free space is %ldB: not enough.\n", - (long)file.size, (long)free_space); - - retry = 0; - if (MakeFreeSpaceOnCache(file.size) < 0) { - printf("Not enough free space on '/cache'.\n"); - success = false; - goto out; - } - if (SaveFileContents(CACHE_TEMP_SOURCE, file) < 0) { - printf("Failed to back up source file.\n"); - success = false; - goto out; - } - made_copy = true; - unlink(binary_name); - - size_t free_space = FreeSpaceForFile(target_fs); - printf("(now %ld bytes free for target)\n", (long)free_space); - } - - result = SaveFileContents(binary_name_atomic, file); - if (result != 0) { - // Maybe the filesystem was optimistic: retry. - enough_space = false; - unlink(binary_name_atomic); - printf("Saving the retouched contents failed; retrying.\n"); - continue; - } - - // Succeeded; no need to retry. - break; - } while (retry-- > 0); - - // Give the .atomic file the same owner, group, and mode of the - // original source file. - if (chmod(binary_name_atomic, file.st.st_mode) != 0) { - printf("chmod of \"%s\" failed: %s\n", - binary_name_atomic, strerror(errno)); - success = false; - goto out; - } - if (chown(binary_name_atomic, file.st.st_uid, file.st.st_gid) != 0) { - printf("chown of \"%s\" failed: %s\n", - binary_name_atomic, - strerror(errno)); - success = false; - goto out; - } - - // Finally, rename the .atomic file to replace the target file. - if (rename(binary_name_atomic, binary_name) != 0) { - printf("rename of .atomic to \"%s\" failed: %s\n", - binary_name, strerror(errno)); - success = false; - goto out; - } - - // If this run created a copy, and we're here, we can delete it. - if (made_copy) unlink(CACHE_TEMP_SOURCE); - - out: - // clean up - free(file.data); - unlink(binary_name_atomic); - - return success; -} diff --git a/minelf/Retouch.h b/minelf/Retouch.h index 048d78e44..13bacd5ad 100644 --- a/minelf/Retouch.h +++ b/minelf/Retouch.h @@ -25,12 +25,6 @@ typedef struct { uint32_t blob_size; /* in bytes, located right before this struct */ } retouch_info_t __attribute__((packed)); -// Retouch a file. Use CACHED_SOURCE_TEMP to store a copy. -bool retouch_one_library(const char *binary_name, - const char *binary_sha1, - int32_t retouch_offset, - int32_t *retouch_offset_override); - #define RETOUCH_DONT_MASK 0 #define RETOUCH_DO_MASK 1 diff --git a/mtdutils/flash_image.c b/mtdutils/flash_image.c index c77687602..a39d60001 100644 --- a/mtdutils/flash_image.c +++ b/mtdutils/flash_image.c @@ -42,7 +42,7 @@ void die(const char *msg, ...) { } fprintf(stderr, "%s\n", buf); - LOGE("%s\n", buf); + ALOGE("%s\n", buf); exit(1); } @@ -74,23 +74,23 @@ int main(int argc, char **argv) { MtdReadContext *in = mtd_read_partition(partition); if (in == NULL) { - LOGW("error opening %s: %s\n", argv[1], strerror(errno)); + ALOGW("error opening %s: %s\n", argv[1], strerror(errno)); // just assume it needs re-writing } else { char check[HEADER_SIZE]; int checklen = mtd_read_data(in, check, sizeof(check)); if (checklen <= 0) { - LOGW("error reading %s: %s\n", argv[1], strerror(errno)); + ALOGW("error reading %s: %s\n", argv[1], strerror(errno)); // just assume it needs re-writing } else if (checklen == headerlen && !memcmp(header, check, headerlen)) { - LOGI("header is the same, not flashing %s\n", argv[1]); + ALOGI("header is the same, not flashing %s\n", argv[1]); return 0; } mtd_read_close(in); } // Skip the header (we'll come back to it), write everything else - LOGI("flashing %s from %s\n", argv[1], argv[2]); + ALOGI("flashing %s from %s\n", argv[1], argv[2]); MtdWriteContext *out = mtd_write_partition(partition); if (out == NULL) die("error writing %s", argv[1]); diff --git a/recovery.cpp b/recovery.cpp index 3f95372c5..726442b84 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -682,6 +682,10 @@ prompt_and_wait(Device* device) { break; case Device::APPLY_EXT: + // Some packages expect /cache to be mounted (eg, + // standard incremental packages expect to use /cache + // as scratch space). + ensure_path_mounted(CACHE_ROOT); status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device); if (status == INSTALL_SUCCESS && wipe_cache) { ui->Print("\n-- Wiping cache (at package request)...\n"); diff --git a/updater/install.c b/updater/install.c index f68bd03c8..c087d4ebe 100644 --- a/updater/install.c +++ b/updater/install.c @@ -33,7 +33,6 @@ #include "edify/expr.h" #include "mincrypt/sha.h" #include "minzip/DirUtil.h" -#include "minelf/Retouch.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" #include "updater.h" @@ -435,121 +434,6 @@ Value* PackageExtractFileFn(const char* name, State* state, } -// retouch_binaries(lib1, lib2, ...) -Value* RetouchBinariesFn(const char* name, State* state, - int argc, Expr* argv[]) { - UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); - - char **retouch_entries = ReadVarArgs(state, argc, argv); - if (retouch_entries == NULL) { - return StringValue(strdup("t")); - } - - // some randomness from the clock - int32_t override_base; - bool override_set = false; - int32_t random_base = time(NULL) % 1024; - // some more randomness from /dev/random - FILE *f_random = fopen("/dev/random", "rb"); - uint16_t random_bits = 0; - if (f_random != NULL) { - fread(&random_bits, 2, 1, f_random); - random_bits = random_bits % 1024; - fclose(f_random); - } - random_base = (random_base + random_bits) % 1024; - fprintf(ui->cmd_pipe, "ui_print Random offset: 0x%x\n", random_base); - fprintf(ui->cmd_pipe, "ui_print\n"); - - // make sure we never randomize to zero; this let's us look at a file - // and know for sure whether it has been processed; important in the - // crash recovery process - if (random_base == 0) random_base = 1; - // make sure our randomization is page-aligned - random_base *= -0x1000; - override_base = random_base; - - int i = 0; - bool success = true; - while (i < (argc - 1)) { - success = success && retouch_one_library(retouch_entries[i], - retouch_entries[i+1], - random_base, - override_set ? - NULL : - &override_base); - if (!success) - ErrorAbort(state, "Failed to retouch '%s'.", retouch_entries[i]); - - free(retouch_entries[i]); - free(retouch_entries[i+1]); - i += 2; - - if (success && override_base != 0) { - random_base = override_base; - override_set = true; - } - } - if (i < argc) { - free(retouch_entries[i]); - success = false; - } - free(retouch_entries); - - if (!success) { - Value* v = malloc(sizeof(Value)); - v->type = VAL_STRING; - v->data = NULL; - v->size = -1; - return v; - } - return StringValue(strdup("t")); -} - - -// undo_retouch_binaries(lib1, lib2, ...) -Value* UndoRetouchBinariesFn(const char* name, State* state, - int argc, Expr* argv[]) { - UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); - - char **retouch_entries = ReadVarArgs(state, argc, argv); - if (retouch_entries == NULL) { - return StringValue(strdup("t")); - } - - int i = 0; - bool success = true; - int32_t override_base; - while (i < (argc-1)) { - success = success && retouch_one_library(retouch_entries[i], - retouch_entries[i+1], - 0 /* undo => offset==0 */, - NULL); - if (!success) - ErrorAbort(state, "Failed to unretouch '%s'.", - retouch_entries[i]); - - free(retouch_entries[i]); - free(retouch_entries[i+1]); - i += 2; - } - if (i < argc) { - free(retouch_entries[i]); - success = false; - } - free(retouch_entries); - - if (!success) { - Value* v = malloc(sizeof(Value)); - v->type = VAL_STRING; - v->data = NULL; - v->size = -1; - return v; - } - return StringValue(strdup("t")); -} - - // symlink target src1 src2 ... // unlinks any previously existing src1, src2, etc before creating symlinks. Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -1190,8 +1074,6 @@ void RegisterInstallFunctions() { RegisterFunction("delete_recursive", DeleteFn); RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_file", PackageExtractFileFn); - RegisterFunction("retouch_binaries", RetouchBinariesFn); - RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn); RegisterFunction("symlink", SymlinkFn); RegisterFunction("set_perm", SetPermFn); RegisterFunction("set_perm_recursive", SetPermFn); |