diff --git a/Android.mk b/Android.mk index 2cdf3ac07..9b66f549d 100644 --- a/Android.mk +++ b/Android.mk @@ -1,3 +1,5 @@ +ifneq ($(WITH_SIMPLE_RECOVERY),true) + LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) @@ -13,14 +15,16 @@ LOCAL_SRC_FILES := \ mounts.c \ extendedcommands.c \ nandroid.c \ - ../../system/core/toolbox/reboot.c \ + reboot.c \ ../../system/core/toolbox/dynarray.c \ + ../../system/core/toolbox/newfs_msdos.c \ firmware.c \ edifyscripting.c \ prop.c \ default_recovery_ui.c \ adb_install.c \ - verifier.c + verifier.c \ + ../../system/vold/vdc.c ADDITIONAL_RECOVERY_FILES := $(shell echo $$ADDITIONAL_RECOVERY_FILES) LOCAL_SRC_FILES += $(ADDITIONAL_RECOVERY_FILES) @@ -29,6 +33,8 @@ LOCAL_MODULE := recovery LOCAL_FORCE_STATIC_EXECUTABLE := true +RECOVERY_FSTAB_VERSION := 2 + ifdef I_AM_KOUSH RECOVERY_NAME := ClockworkMod Recovery LOCAL_CFLAGS += -DI_AM_KOUSH @@ -38,7 +44,7 @@ RECOVERY_NAME := CWM-based Recovery endif endif -RECOVERY_VERSION := $(RECOVERY_NAME) v6.0.3.2 +RECOVERY_VERSION := $(RECOVERY_NAME) v6.0.4.4 LOCAL_CFLAGS += -DRECOVERY_VERSION="$(RECOVERY_VERSION)" RECOVERY_API_VERSION := 2 @@ -54,12 +60,18 @@ ifeq ($(BOARD_USE_CUSTOM_RECOVERY_FONT),) BOARD_USE_CUSTOM_RECOVERY_FONT := \"font_10x18.h\" endif +ifeq ($(ENABLE_LOKI_RECOVERY),true) + LOCAL_CFLAGS += -DENABLE_LOKI + LOCAL_SRC_FILES += \ + compact_loki.c +endif + BOARD_RECOVERY_CHAR_WIDTH := $(shell echo $(BOARD_USE_CUSTOM_RECOVERY_FONT) | cut -d _ -f 2 | cut -d . -f 1 | cut -d x -f 1) BOARD_RECOVERY_CHAR_HEIGHT := $(shell echo $(BOARD_USE_CUSTOM_RECOVERY_FONT) | cut -d _ -f 2 | cut -d . -f 1 | cut -d x -f 2) LOCAL_CFLAGS += -DBOARD_RECOVERY_CHAR_WIDTH=$(BOARD_RECOVERY_CHAR_WIDTH) -DBOARD_RECOVERY_CHAR_HEIGHT=$(BOARD_RECOVERY_CHAR_HEIGHT) -BOARD_RECOVERY_DEFINES := BOARD_HAS_NO_SELECT_BUTTON BOARD_UMS_LUNFILE BOARD_RECOVERY_ALWAYS_WIPES BOARD_RECOVERY_HANDLES_MOUNT BOARD_TOUCH_RECOVERY RECOVERY_EXTEND_NANDROID_MENU TARGET_USE_CUSTOM_LUN_FILE_PATH TARGET_DEVICE +BOARD_RECOVERY_DEFINES := BOARD_RECOVERY_SWIPE BOARD_HAS_NO_SELECT_BUTTON BOARD_UMS_LUNFILE BOARD_RECOVERY_ALWAYS_WIPES BOARD_RECOVERY_HANDLES_MOUNT BOARD_TOUCH_RECOVERY RECOVERY_EXTEND_NANDROID_MENU TARGET_USE_CUSTOM_LUN_FILE_PATH TARGET_DEVICE TARGET_RECOVERY_FSTAB $(foreach board_define,$(BOARD_RECOVERY_DEFINES), \ $(if $($(board_define)), \ @@ -69,8 +81,10 @@ $(foreach board_define,$(BOARD_RECOVERY_DEFINES), \ LOCAL_STATIC_LIBRARIES := -LOCAL_CFLAGS += -DUSE_EXT4 -LOCAL_C_INCLUDES += system/extras/ext4_utils +LOCAL_CFLAGS += -DUSE_EXT4 -DMINIVOLD +LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include external/fsck_msdos +LOCAL_C_INCLUDES += system/vold + LOCAL_STATIC_LIBRARIES += libext4_utils_static libz libsparse_static # This binary is in the recovery ramdisk, which is otherwise a copy of root. @@ -86,27 +100,37 @@ else LOCAL_SRC_FILES += $(BOARD_CUSTOM_RECOVERY_KEYMAPPING) endif +LOCAL_STATIC_LIBRARIES += libvoldclient libsdcard libminipigz libfsck_msdos LOCAL_STATIC_LIBRARIES += libmake_ext4fs libext4_utils_static libz libsparse_static + +ifeq ($(TARGET_USERIMAGES_USE_F2FS), true) +LOCAL_CFLAGS += -DUSE_F2FS +LOCAL_STATIC_LIBRARIES += libmake_f2fs libfsck_f2fs libfibmap_f2fs +endif + LOCAL_STATIC_LIBRARIES += libminzip libunz libmincrypt LOCAL_STATIC_LIBRARIES += libminizip libminadbd libedify libbusybox libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image +LOCAL_LDFLAGS += -Wl,--no-fatal-warnings -LOCAL_STATIC_LIBRARIES += libdedupe libcrypto_static libcrecovery libflashutils libmtdutils libmmcutils libbmlutils +LOCAL_STATIC_LIBRARIES += libfs_mgr libdedupe libcrypto_static libcrecovery libflashutils libmtdutils libmmcutils libbmlutils ifeq ($(BOARD_USES_BML_OVER_MTD),true) LOCAL_STATIC_LIBRARIES += libbml_over_mtd endif -LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils +LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils liblog LOCAL_STATIC_LIBRARIES += libstdc++ libc LOCAL_STATIC_LIBRARIES += libselinux -LOCAL_C_INCLUDES += system/extras/ext4_utils - include $(BUILD_EXECUTABLE) -RECOVERY_LINKS := bu make_ext4fs edify busybox flash_image dump_image mkyaffs2image unyaffs erase_image nandroid reboot volume setprop getprop dedupe minizip +RECOVERY_LINKS := bu make_ext4fs edify busybox flash_image dump_image mkyaffs2image unyaffs erase_image nandroid reboot volume setprop getprop start stop dedupe minizip setup_adbd fsck_msdos newfs_msdos vdc sdcard pigz + +ifeq ($(TARGET_USERIMAGES_USE_F2FS), true) +RECOVERY_LINKS += mkfs.f2fs fsck.f2fs fibmap.f2fs +endif # nc is provided by external/netcat RECOVERY_SYMLINKS := $(addprefix $(TARGET_RECOVERY_ROOT_OUT)/sbin/,$(RECOVERY_LINKS)) @@ -152,6 +176,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := verifier_test.c verifier.c +LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include + LOCAL_MODULE := verifier_test LOCAL_FORCE_STATIC_EXECUTABLE := true @@ -178,4 +204,7 @@ include $(commands_recovery_local_path)/updater/Android.mk include $(commands_recovery_local_path)/applypatch/Android.mk include $(commands_recovery_local_path)/utilities/Android.mk include $(commands_recovery_local_path)/su/Android.mk +include $(commands_recovery_local_path)/voldclient/Android.mk commands_recovery_local_path := + +endif diff --git a/CleanSpec.mk b/CleanSpec.mk index b84e1b65e..eefcc0402 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -47,3 +47,33 @@ # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/recovery_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/dump_image_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/flash_image_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/erase_image_intermediates) + +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libflashutils_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libmmcutils_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libmtdutils_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbmlutils_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libcrecovery_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libvoldclient_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libminui_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libdedupe_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libedify_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libdump_image_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/liberase_image_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libflash_image_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libminizip_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libminadbd_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libmkyaffs2image_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libunyaffs_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libminelf_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbml_over_mtd_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libmake_ext4fs_intermediates) + +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libminui_intermediates) + +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/RECOVERY_EXECUTABLES) + +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/updater_intermediates) diff --git a/README.md b/README.md new file mode 100755 index 000000000..cea2824c5 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +merge git@github.com:CyanogenMod/android_bootable_recovery.git cm-11.0 branch + +bunch version to 6.0.4.4 + +# sndnvaps diff --git a/adb_install.c b/adb_install.c index b073e6811..23064acaa 100644 --- a/adb_install.c +++ b/adb_install.c @@ -99,7 +99,9 @@ void *adb_sideload_thread(void* v) { int apply_from_adb() { - +#ifdef ENABLE_LOKI + int loki_support; +#endif stop_adbd(); set_usb_driver(1); @@ -115,7 +117,7 @@ apply_from_adb() { pthread_t sideload_thread; pthread_create(&sideload_thread, NULL, &adb_sideload_thread, &data); - static char* headers[] = { "ADB Sideload", + static const char* headers[] = { "ADB Sideload", "", NULL }; @@ -153,6 +155,14 @@ apply_from_adb() { } remove(ADB_SIDELOAD_FILENAME); - +#ifdef ENABLE_LOKI + if(loki_support_enabled) { + ui_print("Checking if loki-fying is needed"); + int result; + if(result = loki_check()) { + return result; + } + } +#endif return install_status; } diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c index 7b8a010e3..4eccc0563 100644 --- a/applypatch/applypatch.c +++ b/applypatch/applypatch.c @@ -101,7 +101,7 @@ int LoadFileContents(const char* filename, FileContents* file, } } - SHA(file->data, file->size, file->sha1); + SHA_hash(file->data, file->size, file->sha1); return 0; } @@ -421,18 +421,111 @@ int WriteToPartition(unsigned char* data, size_t len, break; case EMMC: - ; - FILE* f = fopen(partition, "wb"); - if (fwrite(data, 1, len, f) != len) { - printf("short write writing to %s (%s)\n", - partition, strerror(errno)); + { + size_t start = 0; + int success = 0; + int fd = open(partition, O_RDWR); + if (fd < 0) { + printf("failed to open %s: %s\n", partition, strerror(errno)); return -1; } - if (fclose(f) != 0) { + int attempt; + + for (attempt = 0; attempt < 10; ++attempt) { + size_t next_sync = start + (1<<20); + printf("raw write %s attempt %d start at %d\n", partition, attempt+1, start); + lseek(fd, start, SEEK_SET); + while (start < len) { + size_t to_write = len - start; + if (to_write > 4096) to_write = 4096; + + ssize_t written = write(fd, data+start, to_write); + if (written < 0) { + if (errno == EINTR) { + written = 0; + } else { + printf("failed write writing to %s (%s)\n", + partition, strerror(errno)); + return -1; + } + } + start += written; + if (start >= next_sync) { + fsync(fd); + next_sync = start + (1<<20); + } + } + fsync(fd); + + // drop caches so our subsequent verification read + // won't just be reading the cache. + sync(); + int dc = open("/proc/sys/vm/drop_caches", O_WRONLY); + write(dc, "3\n", 2); + close(dc); + sleep(1); + printf(" caches dropped\n"); + + // verify + lseek(fd, 0, SEEK_SET); + unsigned char buffer[4096]; + start = len; + size_t p; + for (p = 0; p < len; p += sizeof(buffer)) { + size_t to_read = len - p; + if (to_read > sizeof(buffer)) to_read = sizeof(buffer); + + size_t so_far = 0; + while (so_far < to_read) { + ssize_t read_count = read(fd, buffer+so_far, to_read-so_far); + if (read_count < 0) { + if (errno == EINTR) { + read_count = 0; + } else { + printf("verify read error %s at %d: %s\n", + partition, p, strerror(errno)); + return -1; + } + } + if ((size_t)read_count < to_read) { + printf("short verify read %s at %d: %d %d %s\n", + partition, p, read_count, to_read, strerror(errno)); + } + so_far += read_count; + } + + if (memcmp(buffer, data+p, to_read)) { + printf("verification failed starting at %d\n", p); + start = p; + break; + } + } + + if (start == len) { + printf("verification read succeeded (attempt %d)\n", attempt+1); + success = true; + break; + } + + sleep(2); + } + + if (!success) { + printf("failed to verify after all attempts\n"); + return -1; + } + + if (close(fd) != 0) { printf("error closing %s (%s)\n", partition, strerror(errno)); return -1; } + // hack: sync and sleep after closing in hopes of getting + // the data actually onto flash. + printf("sleeping after close\n"); + sync(); + sleep(5); break; + } } free(copy); @@ -473,7 +566,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, const char** patch_sha1_str, +int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int num_patches) { int i; uint8_t patch_sha1[SHA_DIGEST_SIZE]; diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h index d1a023293..f1f13a100 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -65,7 +65,7 @@ int LoadFileContents(const char* filename, FileContents* file, int retouch_flag); int SaveFileContents(const char* filename, const FileContents* file); void FreeFileContents(FileContents* file); -int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str, +int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int num_patches); // bsdiff.c diff --git a/bmlutils/bmlutils.c b/bmlutils/bmlutils.c index 609ab8674..fdf9ad0a3 100644 --- a/bmlutils/bmlutils.c +++ b/bmlutils/bmlutils.c @@ -90,7 +90,7 @@ int cmd_bml_restore_raw_partition(const char *partition, const char *filename) int cmd_bml_backup_raw_partition(const char *partition, const char *out_file) { - char* bml; + const char* bml; if (strcmp("boot", partition) == 0) bml = BOARD_BML_BOOT; else if (strcmp("recovery", partition) == 0) @@ -112,9 +112,8 @@ int cmd_bml_backup_raw_partition(const char *partition, const char *out_file) unsigned sz = 0; unsigned i; int ret = -1; - char *in_file = bml; - in = fopen ( in_file, "r" ); + in = fopen ( bml, "r" ); if (in == NULL) goto ERROR3; @@ -142,7 +141,7 @@ int cmd_bml_backup_raw_partition(const char *partition, const char *out_file) } } - fsync(out); + fsync(fileno(out)); ret = 0; ERROR1: fclose ( out ); diff --git a/bootloader.c b/bootloader.c index e88160d8c..588ea5560 100644 --- a/bootloader.c +++ b/bootloader.c @@ -71,22 +71,22 @@ static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v) { size_t write_size; mtd_scan_partitions(); - const MtdPartition *part = mtd_find_partition_by_name(v->device); + const MtdPartition *part = mtd_find_partition_by_name(v->blk_device); if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { - LOGE("Can't find %s\n", v->device); + LOGE("Can't find %s\n", v->blk_device); return -1; } MtdReadContext *read = mtd_read_partition(part); if (read == NULL) { - LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } const ssize_t size = write_size * MISC_PAGES; char data[size]; ssize_t r = mtd_read_data(read, data, size); - if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno)); + if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno)); mtd_read_close(read); if (r != size) return -1; @@ -97,22 +97,22 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v) { size_t write_size; mtd_scan_partitions(); - const MtdPartition *part = mtd_find_partition_by_name(v->device); + const MtdPartition *part = mtd_find_partition_by_name(v->blk_device); if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { - LOGE("Can't find %s\n", v->device); + LOGE("Can't find %s\n", v->blk_device); return -1; } MtdReadContext *read = mtd_read_partition(part); if (read == NULL) { - LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } ssize_t size = write_size * MISC_PAGES; char data[size]; ssize_t r = mtd_read_data(read, data, size); - if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno)); + if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno)); mtd_read_close(read); if (r != size) return -1; @@ -120,16 +120,16 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in, MtdWriteContext *write = mtd_write_partition(part); if (write == NULL) { - LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } if (mtd_write_data(write, data, size) != size) { - LOGE("Can't write %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno)); mtd_write_close(write); return -1; } if (mtd_write_close(write)) { - LOGE("Can't finish %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } @@ -161,20 +161,20 @@ static void wait_for_device(const char* fn) { static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v) { - wait_for_device(v->device); - FILE* f = fopen(v->device, "rb"); + wait_for_device(v->blk_device); + FILE* f = fopen(v->blk_device, "rb"); if (f == NULL) { - LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } struct bootloader_message temp; int count = fread(&temp, sizeof(temp), 1, f); if (count != 1) { - LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } if (fclose(f) != 0) { - LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } memcpy(out, &temp, sizeof(temp)); @@ -183,19 +183,19 @@ static int get_bootloader_message_block(struct bootloader_message *out, static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v) { - wait_for_device(v->device); - FILE* f = fopen(v->device, "wb"); + wait_for_device(v->blk_device); + FILE* f = fopen(v->blk_device, "wb"); if (f == NULL) { - LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } int count = fwrite(in, sizeof(*in), 1, f); if (count != 1) { - LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } if (fclose(f) != 0) { - LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno)); + LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno)); return -1; } return 0; diff --git a/common.h b/common.h old mode 100644 new mode 100755 index 36d51b2bb..3c5e263c8 --- a/common.h +++ b/common.h @@ -19,19 +19,21 @@ #include #include - +#include //#define MENU_TEXT_COLOR 255, 160, 49, 255 #define MENU_TEXT_COLOR 0, 191, 255, 255 #define MENU_TEXT_COLOR_RED 255, 0, 0, 255 #define NORMAL_TEXT_COLOR 200, 200, 200, 255 #define HEADER_TEXT_COLOR NORMAL_TEXT_COLOR + // Initialize the graphics system. void ui_init(); // Use KEY_* codes from or KEY_DREAM_* from "minui/minui.h". void ui_cancel_wait_key(); int ui_wait_key(); // waits for a key/button press, returns the code +int ui_wait_key_with_repeat(); int ui_key_pressed(int key); // returns >0 if the code is currently pressed int ui_text_visible(); // returns >0 if text log is currently visible int ui_text_ever_visible(); // returns >0 if text log was ever visible @@ -53,10 +55,15 @@ int ui_get_text_cols(); void ui_increment_frame(); void ui_setMenuTextColor(int r, int g, int b, int a); +#ifdef ENABLE_LOKI +// Toggle for loki support +extern int loki_support_enabled; +#endif + // Display some header text followed by a menu of items, which appears // at the top of the screen (in place of any scrolling ui_print() // output, if necessary). -int ui_start_menu(char** headers, char** items, int initial_selection); +int ui_start_menu(const char** headers, char** items, int initial_selection); // Set the menu highlight to the given index, and return it (capped to // the range [0..numitems). int ui_menu_select(int sel); @@ -67,12 +74,20 @@ void ui_end_menu(); int ui_get_showing_back_button(); void ui_set_showing_back_button(int showBackButton); +void ui_set_log_stdout(int enabled); +int ui_should_log_stdout(); + +int ui_get_rainbow_mode(); +void ui_rainbow_mode(); +void ui_set_rainbow_mode(int rainbowMode); + // Set the icon (normally the only thing visible besides the progress bar). enum { BACKGROUND_ICON_NONE, BACKGROUND_ICON_INSTALLING, BACKGROUND_ICON_ERROR, BACKGROUND_ICON_CLOCKWORK, + BACKGROUND_ICON_CID, BACKGROUND_ICON_FIRMWARE_INSTALLING, BACKGROUND_ICON_FIRMWARE_ERROR, NUM_BACKGROUND_ICONS @@ -117,35 +132,8 @@ void ui_reset_progress(); #define STRINGIFY(x) #x #define EXPAND(x) STRINGIFY(x) -typedef struct { - const char* mount_point; // eg. "/cache". must live in the root directory. - - const char* fs_type; // "yaffs2" or "ext4" or "vfat" - - const char* device; // MTD partition name if fs_type == "yaffs" - // block device if fs_type == "ext4" or "vfat" - - const char* device2; // alternative device to try if fs_type - // == "ext4" or "vfat" and mounting - // 'device' fails - - long long length; // (ext4 partition only) when - // formatting, size to use for the - // partition. 0 or negative number - // means to format all but the last - // (that much). - - const char* fs_type2; - - const char* fs_options; - - const char* fs_options2; - - const char* lun; // (/sdcard, /emmc, /external_sd only) LUN file to - // use when mounting via USB mass storage +typedef struct fstab_rec Volume; - struct stat stat; -} Volume; typedef struct { // number of frames in indeterminate progress bar animation diff --git a/compact_loki.c b/compact_loki.c new file mode 100644 index 000000000..533c655c9 --- /dev/null +++ b/compact_loki.c @@ -0,0 +1,651 @@ +/* + * loki_patch + * + * A utility to patch unsigned boot and recovery images to make + * them suitable for booting on the AT&T/Verizon Samsung + * Galaxy S4, Galaxy Stellar, and various locked LG devices + * + * by Dan Rosenberg (@djrbliss) + * modified for use in recovery by Seth Shelnutt + * + */ +#include +#include +#include +#include +#include +#include +#include +#include "compact_loki.h" +#include "common.h" + +#define VERSION "2.0" + +#define BOOT_MAGIC_SIZE 8 +#define BOOT_NAME_SIZE 16 +#define BOOT_ARGS_SIZE 512 + +struct boot_img_hdr { + unsigned char magic[BOOT_MAGIC_SIZE]; + unsigned kernel_size; /* size in bytes */ + unsigned kernel_addr; /* physical load addr */ + unsigned ramdisk_size; /* size in bytes */ + unsigned ramdisk_addr; /* physical load addr */ + unsigned second_size; /* size in bytes */ + unsigned second_addr; /* physical load addr */ + unsigned tags_addr; /* physical addr for kernel tags */ + unsigned page_size; /* flash page size we assume */ + unsigned dt_size; /* device_tree in bytes */ + unsigned unused; /* future expansion: should be 0 */ + unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ + unsigned char cmdline[BOOT_ARGS_SIZE]; + unsigned id[8]; /* timestamp / checksum / sha1 / etc */ +}; + +struct loki_hdr { + unsigned char magic[4]; /* 0x494b4f4c */ + unsigned int recovery; /* 0 = boot.img, 1 = recovery.img */ + unsigned char build[128]; /* Build number */ + unsigned int orig_kernel_size; + unsigned int orig_ramdisk_size; + unsigned int ramdisk_addr; +}; + +struct target { + char *vendor; + char *device; + char *build; + unsigned long check_sigs; + unsigned long hdr; + int lg; +}; + +struct target targets[] = { + { + .vendor = "AT&T", + .device = "Samsung Galaxy S4", + .build = "JDQ39.I337UCUAMDB or JDQ39.I337UCUAMDL", + .check_sigs = 0x88e0ff98, + .hdr = 0x88f3bafc, + .lg = 0, + }, + { + .vendor = "Verizon", + .device = "Samsung Galaxy S4", + .build = "JDQ39.I545VRUAMDK", + .check_sigs = 0x88e0fe98, + .hdr = 0x88f372fc, + .lg = 0, + }, + { + .vendor = "DoCoMo", + .device = "Samsung Galaxy S4", + .build = "JDQ39.SC04EOMUAMDI", + .check_sigs = 0x88e0fcd8, + .hdr = 0x88f0b2fc, + .lg = 0, + }, + { + .vendor = "Verizon", + .device = "Samsung Galaxy Stellar", + .build = "IMM76D.I200VRALH2", + .check_sigs = 0x88e0f5c0, + .hdr = 0x88ed32e0, + .lg = 0, + }, + { + .vendor = "Verizon", + .device = "Samsung Galaxy Stellar", + .build = "JZO54K.I200VRBMA1", + .check_sigs = 0x88e101ac, + .hdr = 0x88ed72e0, + .lg = 0, + }, + { + .vendor = "DoCoMo", + .device = "LG Optimus G", + .build = "L01E20b", + .check_sigs = 0x88F10E48, + .hdr = 0x88F54418, + .lg = 1, + }, + { + .vendor = "AT&T or HK", + .device = "LG Optimus G Pro", + .build = "E98010g or E98810b", + .check_sigs = 0x88f11084, + .hdr = 0x88f54418, + .lg = 1, + }, + { + .vendor = "KT, LGU, or SKT", + .device = "LG Optimus G Pro", + .build = "F240K10o, F240L10v, or F240S10w", + .check_sigs = 0x88f110b8, + .hdr = 0x88f54418, + .lg = 1, + }, + { + .vendor = "KT, LGU, or SKT", + .device = "LG Optimus LTE 2", + .build = "F160K20g, F160L20f, F160LV20d, or F160S20f", + .check_sigs = 0x88f10864, + .hdr = 0x88f802b8, + .lg = 1, + }, + { + .vendor = "MetroPCS", + .device = "LG Spirit", + .build = "MS87010a_05", + .check_sigs = 0x88f0e634, + .hdr = 0x88f68194, + .lg = 1, + }, + { + .vendor = "MetroPCS", + .device = "LG Motion", + .build = "MS77010f_01", + .check_sigs = 0x88f1015c, + .hdr = 0x88f58194, + .lg = 1, + }, + { + .vendor = "Verizon", + .device = "LG Lucid 2", + .build = "VS87010B_12", + .check_sigs = 0x88f10adc, + .hdr = 0x88f702bc, + .lg = 1, + }, + { + .vendor = "Verizon", + .device = "LG Spectrum 2", + .build = "VS93021B_05", + .check_sigs = 0x88f10c10, + .hdr = 0x88f84514, + .lg = 1, + }, + { + .vendor = "Boost Mobile", + .device = "LG Optimus F7", + .build = "LG870ZV4_06", + .check_sigs = 0x88f11714, + .hdr = 0x88f842ac, + .lg = 1, + }, + { + .vendor = "Virgin Mobile", + .device = "LG Optimus F3", + .build = "LS720ZV5", + .check_sigs = 0x88f108f0, + .hdr = 0x88f854f4, + .lg = 1, + }, +}; + +#define PATTERN1 "\xf0\xb5\x8f\xb0\x06\x46\xf0\xf7" +#define PATTERN2 "\xf0\xb5\x8f\xb0\x07\x46\xf0\xf7" +#define PATTERN3 "\x2d\xe9\xf0\x41\x86\xb0\xf1\xf7" +#define PATTERN4 "\x2d\xe9\xf0\x4f\xad\xf5\xc6\x6d" +#define PATTERN5 "\x2d\xe9\xf0\x4f\xad\xf5\x21\x7d" +#define PATTERN6 "\x2d\xe9\xf0\x4f\xf3\xb0\x05\x46" + +#define ABOOT_BASE_SAMSUNG 0x88dfffd8 +#define ABOOT_BASE_LG 0x88efffd8 +#define ABOOT_BASE_G2 0xf7fffd8 + +unsigned char patch[] = +"\xfe\xb5" +"\x0b\x4d" +"\xa8\x6a" +"\xab\x68" +"\x98\x42" +"\x0e\xd0" +"\xee\x69" +"\x09\x4c" +"\xef\x6a" +"\x07\xf5\x80\x57" +"\x0f\xce" +"\x0f\xc4" +"\x10\x3f" +"\xfb\xdc" +"\xa8\x6a" +"\x04\x49" +"\xea\x6a" +"\xa8\x60" +"\x69\x61" +"\x2a\x61" +"\x00\x20" +"\xfe\xbd" +"\x00\x00" +"\xff\xff\xff\xff" /* Replace with header address */ +"\x00\x00\x20\x82"; + +int loki_patch_shellcode(unsigned int addr) +{ + + unsigned int i; + unsigned int *ptr; + + for (i = 0; i < sizeof(patch); i++) { + ptr = (unsigned int *)&patch[i]; + if (*ptr == 0xffffffff) { + *ptr = addr; + return 0; + } + else if (*ptr == addr) { + return 0; + } + } + + return -1; +} + +int loki_patch(char *partition, char *partitionPath) +{ + + int ifd, ofd, aboot_fd, pos, i, recovery, offset, fake_size; + unsigned int orig_ramdisk_size, orig_kernel_size, page_kernel_size, page_ramdisk_size, page_size, page_mask; + unsigned long target, aboot_base; + void *orig, *aboot, *ptr; + struct target *tgt; + struct stat st; + struct boot_img_hdr *hdr; + struct loki_hdr *loki_hdr; + char *buf; + + if (!strcmp(partition, "boot")) { + recovery = 0; + } else if (!strcmp(partition, "recovery")) { + recovery = 1; + } else { + ui_print("[+] First argument must be \"boot\" or \"recovery\".\n"); + return 1; + } + + /* Open input files */ + aboot_fd = open("/dev/block/platform/msm_sdcc.1/by-name/aboot", O_RDONLY); + if (aboot_fd < 0) { + ui_print("[-] Failed to open %s for reading.\n", "/dev/block/platform/msm_sdcc.1/by-name/aboot"); + return 1; + } + + ifd = open(partitionPath, O_RDONLY); + if (ifd < 0) { + ui_print("[-] Failed to open %s for reading.\n", partitionPath); + return 1; + } + + ofd = open(Loki_Image, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (ofd < 0) { + ui_print("[-] Failed to open %s for writing.\n", Loki_Image); + return 1; + } + + /* Find the signature checking function via pattern matching */ + if (fstat(aboot_fd, &st)) { + ui_print("[-] fstat() failed.\n"); + return 1; + } + + /* Verify the to-be-patched address matches the known code pattern */ + aboot = mmap(0, (524288 + 0xfff) & ~0xfff, PROT_READ, MAP_PRIVATE, aboot_fd, 0); + if (aboot == MAP_FAILED) { + printf("[-] Failed to mmap aboot.\n"); + return 1; + } + + target = 0; + + for (ptr = aboot; ptr < aboot + 524288 - 0x1000; ptr++) { + if (!memcmp(ptr, PATTERN1, 8) || + !memcmp(ptr, PATTERN2, 8) || + !memcmp(ptr, PATTERN3, 8)) { + + aboot_base = ABOOT_BASE_SAMSUNG; + target = (unsigned long)ptr - (unsigned long)aboot + aboot_base; + break; + } + + if (!memcmp(ptr, PATTERN4, 8)) { + + aboot_base = ABOOT_BASE_LG; + target = (unsigned long)ptr - (unsigned long)aboot + aboot_base; + break; + } + } + + if (!target) { + ui_print("[-] Failed to find function to patch.\n"); + return 1; + } + + tgt = NULL; + + for (i = 0; i < (sizeof(targets)/sizeof(targets[0])); i++) { + if (targets[i].check_sigs == target) { + tgt = &targets[i]; + break; + } + } + + if (!tgt) { + ui_print("[-] Unsupported aboot image.\n"); + return 1; + } + + if (loki_patch_shellcode(tgt->hdr) < 0) { + ui_print("[-] Failed to patch shellcode.\n"); + return 1; + } + + /* Map the original boot/recovery image */ + if (fstat(ifd, &st)) { + ui_print("[-] fstat() failed.\n"); + return 1; + } + + orig = mmap(0, (25165824 + 0x2000 + 0xfff) & ~0xfff, PROT_READ|PROT_WRITE, MAP_PRIVATE, ifd, 0); + if (orig == MAP_FAILED) { + ui_print("[-] Failed to mmap input file.\n"); + return 1; + } + + hdr = orig; + loki_hdr = orig + 0x400; + + if (!memcmp(loki_hdr->magic, "LOKI", 4)) { + ui_print("[-] Input file is already a Loki image.\n"); + + /* Copy the entire file to the output transparently */ + if (write(ofd, orig, 25165824) != 25165824) { + ui_print("[-] Failed to copy Loki image.\n"); + return 1; + } + + ui_print("[+] Copied Loki image to %s.\n", Loki_Image); + + return 0; + } + + /* Set the Loki header */ + memcpy(loki_hdr->magic, "LOKI", 4); + loki_hdr->recovery = recovery; + strncpy(loki_hdr->build, tgt->build, sizeof(loki_hdr->build) - 1); + + page_size = hdr->page_size; + page_mask = hdr->page_size - 1; + + orig_kernel_size = hdr->kernel_size; + orig_ramdisk_size = hdr->ramdisk_size; + + /* Store the original values in uses fields of the header */ + hdr->dt_size = orig_kernel_size; + hdr->unused = orig_ramdisk_size; + hdr->second_addr = hdr->kernel_addr + ((hdr->kernel_size + page_mask) & ~page_mask); + + /* Ramdisk must be aligned to a page boundary */ + hdr->kernel_size = ((hdr->kernel_size + page_mask) & ~page_mask) + hdr->ramdisk_size; + + /* Guarantee 16-byte alignment */ + offset = tgt->check_sigs & 0xf; + + hdr->ramdisk_addr = tgt->check_sigs - offset; + + if (tgt->lg) { + fake_size = page_size; + hdr->ramdisk_size = page_size; + } + else { + fake_size = 0x200; + hdr->ramdisk_size = 0; + } + + /* Write the image header */ + if (write(ofd, orig, page_size) != page_size) { + ui_print("[-] Failed to write header to output file.\n"); + return 1; + } + + page_kernel_size = (orig_kernel_size + page_mask) & ~page_mask; + + /* Write the kernel */ + if (write(ofd, orig + page_size, page_kernel_size) != page_kernel_size) { + ui_print("[-] Failed to write kernel to output file.\n"); + return 1; + } + + page_ramdisk_size = (orig_ramdisk_size + page_mask) & ~page_mask; + + /* Write the ramdisk */ + if (write(ofd, orig + page_size + page_kernel_size, page_ramdisk_size) != page_ramdisk_size) { + ui_print("[-] Failed to write ramdisk to output file.\n"); + return 1; + } + + /* Write fake_size bytes of original code to the output */ + buf = malloc(fake_size); + if (!buf) { + ui_print("[-] Out of memory.\n"); + return 1; + } + + lseek(aboot_fd, tgt->check_sigs - aboot_base - offset, SEEK_SET); + read(aboot_fd, buf, fake_size); + + if (write(ofd, buf, fake_size) != fake_size) { + ui_print("[-] Failed to write original aboot code to output file.\n"); + return 1; + } + + pos = lseek(ofd, 0, SEEK_CUR); + lseek(ofd, pos - (fake_size - offset), SEEK_SET); + + /* Write the patch */ + if (write(ofd, patch, sizeof(patch)) != sizeof(patch)) { + ui_print("[-] Failed to write patch to output file.\n"); + return 1; + } + + close(ifd); + close(ofd); + close(aboot_fd); + + return 0; +} + +int loki_check(){ + if(loki_check_partition(BOOT_PARTITION)){ + if(loki_patch("boot","/dev/block/platform/msm_sdcc.1/by-name/boot")){ + ui_set_background(BACKGROUND_ICON_ERROR); + ui_print("Error loki-ifying the boot image.\n"); + return 1; + } + if(loki_flash("/dev/block/platform/msm_sdcc.1/by-name/boot")){ + ui_set_background(BACKGROUND_ICON_ERROR); + ui_print("Error loki-flashing the boot image.\n"); + return 1; + } + } + if(loki_check_partition(RECOVERY_PARTITION)){ + if(loki_patch("recovery","/dev/block/platform/msm_sdcc.1/by-name/recovery")){ + ui_set_background(BACKGROUND_ICON_ERROR); + ui_print("Error loki-ifying the recovery image.\n"); + return 1; + } + if(loki_flash("/dev/block/platform/msm_sdcc.1/by-name/recovery")){ + ui_set_background(BACKGROUND_ICON_ERROR); + ui_print("Error loki-flashing the recovery image.\n"); + return 1; + } + } + + return 0; +} + +int loki_check_partition(char *partition) +{ + int ifd; + void *orig; + struct stat st; + struct boot_img_hdr *hdr; + struct loki_hdr *loki_hdr; + char *buf; + + ifd = open(partition, O_RDONLY); + if (ifd < 0) { + ui_print("[-] Failed to open %s for reading.\n", partition); + return 1; + } + + /* Map the image to be flashed */ + if (fstat(ifd, &st)) { + ui_print("[-] fstat() failed.\n"); + return 1; + } + + orig = mmap(0, (25165824 + 0x2000 + 0xfff) & ~0xfff, PROT_READ, MAP_PRIVATE, ifd, 0); + if (orig == MAP_FAILED) { + ui_print("[-] Failed to mmap Loki image.\n"); + return 1; + } + + hdr = orig; + loki_hdr = orig + 0x400; + + /* Verify this is a Loki image */ + if (memcmp(loki_hdr->magic, "LOKI", 4)) { + ui_print("%s needs lokifying.\n", partition); + return 1; + } + else { + return 0; + } +} + +int loki_flash(char *partition) +{ + + int ifd, aboot_fd, ofd, recovery, offs, match; + void *orig, *aboot, *patch; + struct stat st; + struct boot_img_hdr *hdr; + struct loki_hdr *loki_hdr; + char prop[256], outfile[1024], buf[4096]; + + + if (!strcmp(partition, "/dev/block/platform/msm_sdcc.1/by-name/boot")) { + recovery = 0; + } else if (!strcmp(partition, "/dev/block/platform/msm_sdcc.1/by-name/recovery")) { + recovery = 1; + } else { + ui_print("[+] First argument must be \"boot\" or \"recovery\".\n"); + return 1; + } + + /* Verify input file */ + aboot_fd = open("/dev/block/platform/msm_sdcc.1/by-name/aboot", O_RDONLY); + if (aboot_fd < 0) { + ui_print("[-] Failed to open aboot for reading.\n"); + return 1; + } + + ifd = open(Loki_Image, O_RDONLY); + if (ifd < 0) { + ui_print("[-] Failed to open %s for reading.\n", Loki_Image); + return 1; + } + + /* Map the image to be flashed */ + if (fstat(ifd, &st)) { + ui_print("[-] fstat() failed.\n"); + return 1; + } + + orig = mmap(0, (25165824 + 0x2000 + 0xfff) & ~0xfff, PROT_READ, MAP_PRIVATE, ifd, 0); + if (orig == MAP_FAILED) { + ui_print("[-] Failed to mmap Loki image.\n"); + return 1; + } + + hdr = orig; + loki_hdr = orig + 0x400; + + /* Verify this is a Loki image */ + if (memcmp(loki_hdr->magic, "LOKI", 4)) { + ui_print("[-] Input file is not a Loki image.\n"); + return 1; + } + + /* Verify this is the right type of image */ + if (loki_hdr->recovery != recovery) { + ui_print("[-] Loki image is not a %s image.\n", recovery ? "recovery" : "boot"); + return 1; + } + + /* Verify the to-be-patched address matches the known code pattern */ + aboot = mmap(0, 0x40000, PROT_READ, MAP_PRIVATE, aboot_fd, 0); + if (aboot == MAP_FAILED) { + ui_print("[-] Failed to mmap aboot.\n"); + return 1; + } + + match = 0; + + for (offs = 0; offs < 0x10; offs += 0x4) { + + if (hdr->ramdisk_addr < ABOOT_BASE_SAMSUNG) + patch = hdr->ramdisk_addr - ABOOT_BASE_G2 + aboot + offs; + else if (hdr->ramdisk_addr < ABOOT_BASE_LG) + patch = hdr->ramdisk_addr - ABOOT_BASE_SAMSUNG + aboot + offs; + else + patch = hdr->ramdisk_addr - ABOOT_BASE_LG + aboot + offs; + + if (patch < aboot || patch > aboot + 0x40000 - 8) { + ui_print("[-] Invalid .lok file.\n"); + return 1; + } + + if (!memcmp(patch, PATTERN1, 8) || + !memcmp(patch, PATTERN2, 8) || + !memcmp(patch, PATTERN3, 8) || + !memcmp(patch, PATTERN4, 8) || + !memcmp(patch, PATTERN5, 8) || + !memcmp(patch, PATTERN6, 8)) { + + match = 1; + break; + } + } + + if (!match) { + ui_print("[-] Loki aboot version does not match device.\n"); + return 1; + } + + ui_print("[+] Loki validation passed, flashing image.\n"); + + snprintf(outfile, sizeof(outfile), + "/dev/block/platform/msm_sdcc.1/by-name/%s", + recovery ? "recovery" : "boot"); + + ofd = open(outfile, O_WRONLY); + if (ofd < 0) { + ui_print("[-] Failed to open output block device.\n"); + return 1; + } + + if (write(ofd, orig, st.st_size) != st.st_size) { + ui_print("[-] Failed to write to block device.\n"); + return 1; + } + + ui_print("[+] Loki flashing complete!\n"); + + close(ifd); + close(aboot_fd); + close(ofd); + + return 0; +} + diff --git a/compact_loki.h b/compact_loki.h new file mode 100644 index 000000000..9ddf836e9 --- /dev/null +++ b/compact_loki.h @@ -0,0 +1,29 @@ +/* + * By Seth Shelnutt + * + * 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. + */ + +#define Loki_Image "/tmp/loki_image" +#define BOOT_PARTITION "/dev/block/platform/msm_sdcc.1/by-name/boot" +#define RECOVERY_PARTITION "/dev/block/platform/msm_sdcc.1/by-name/recovery" + +int loki_patch_shellcode(unsigned int addr); + +int loki_patch(char *partition, char *partitionPath); + +int loki_flash(char *partition); + +int loki_check_partition(char *partition); + +int loki_check(); diff --git a/default_recovery_ui.c b/default_recovery_ui.c index 1f801f193..032c1b304 100644 --- a/default_recovery_ui.c +++ b/default_recovery_ui.c @@ -23,8 +23,7 @@ char* MENU_HEADERS[] = { NULL }; char* MENU_ITEMS[] = { "reboot system now", - "install zip from sdcard", - "install zip from sideload", + "install zip", "wipe data/factory reset", "wipe cache partition", "backup and restore", diff --git a/edifyscripting.c b/edifyscripting.c index 6c4482bb5..9c7aa388e 100644 --- a/edifyscripting.c +++ b/edifyscripting.c @@ -153,7 +153,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { free(path); return StringValue(strdup("")); } - if (0 != format_volume("/sdcard/.android_secure")) { + if (0 != format_volume(get_android_secure_path())) { free(path); return StringValue(strdup("")); } @@ -318,6 +318,7 @@ void remove_extendedcommand() int run_and_remove_extendedcommand() { + char* primary_path = get_primary_storage_path(); char tmp[PATH_MAX]; sprintf(tmp, "cp %s /tmp/%s", EXTENDEDCOMMAND_SCRIPT, basename(EXTENDEDCOMMAND_SCRIPT)); __system(tmp); @@ -325,7 +326,7 @@ int run_and_remove_extendedcommand() int i = 0; for (i = 20; i > 0; i--) { ui_print("Waiting for SD Card to mount (%ds)\n", i); - if (ensure_path_mounted("/sdcard") == 0) { + if (ensure_path_mounted(primary_path) == 0) { ui_print("SD Card mounted...\n"); break; } @@ -342,14 +343,14 @@ int run_and_remove_extendedcommand() ui_print("SD Card marker not found...\n"); if (volume_for_path("/emmc") != NULL) { ui_print("Checking Internal SD Card marker...\n"); - ensure_path_unmounted("/sdcard"); - if (ensure_path_mounted_at_mount_point("/emmc", "/sdcard") != 0) { + ensure_path_unmounted(primary_path); + if (ensure_path_mounted_at_mount_point("/emmc", primary_path) != 0) { ui_print("Internal SD Card marker not found... continuing anyways.\n"); // unmount everything, and remount as normal ensure_path_unmounted("/emmc"); - ensure_path_unmounted("/sdcard"); + ensure_path_unmounted(primary_path); - ensure_path_mounted("/sdcard"); + ensure_path_mounted(primary_path); } } } diff --git a/etc/init.rc b/etc/init.rc index 241c29219..0cffd9177 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -2,6 +2,7 @@ import /init.recovery.${ro.hardware}.rc on early-init start ueventd + start healthd on init export PATH /sbin @@ -27,6 +28,26 @@ on init chown root shell /tmp chmod 0775 /tmp + mkdir /mnt 0775 root system + mkdir /storage 0050 root sdcard_r + mount tmpfs tmpfs /storage mode=0050,uid=0,gid=1028 + + # See storage config details at http://source.android.com/tech/storage/ + mkdir /mnt/shell 0700 shell shell + + # Directory for putting things only root should see. + mkdir /mnt/secure 0700 root root + + # Create private mountpoint so we can MS_MOVE from staging + mount tmpfs tmpfs /mnt/secure mode=0700,uid=0,gid=0 + + # Directory for staging bindmounts + mkdir /mnt/secure/staging 0700 root root + + # Fuse public mount points. + mkdir /mnt/fuse 0700 root system + mount tmpfs tmpfs /mnt/fuse mode=0775,gid=1000 + write /sys/class/android_usb/android0/enable 0 write /sys/class/android_usb/android0/idVendor 18D1 write /sys/class/android_usb/android0/idProduct D001 @@ -47,15 +68,34 @@ on boot service ueventd /sbin/ueventd critical +service healthd /sbin/healthd -n + critical + service recovery /sbin/recovery +service setup_adbd /sbin/setup_adbd + oneshot + service adbd /sbin/adbd recovery disabled + socket adbd stream 660 system system -# Recovery will start adb once it has checked the keys +service vold /sbin/minivold + socket vold stream 0660 root mount + ioprio be 2 -# Restart adbd so it can run as root +# setup_adbd will start adb once it has checked the keys on property:service.adb.root=1 write /sys/class/android_usb/android0/enable 0 restart adbd write /sys/class/android_usb/android0/enable 1 + +on property:sys.storage.ums_enabled=1 + write /sys/class/android_usb/android0/enable 0 + write /sys/class/android_usb/android0/functions adb,mass_storage + write /sys/class/android_usb/android0/enable 1 + +on property:sys.storage.ums_enabled=0 + write /sys/class/android_usb/android0/enable 0 + write /sys/class/android_usb/android0/functions adb + write /sys/class/android_usb/android0/enable ${service.adb.root} diff --git a/extendedcommands.c b/extendedcommands.c old mode 100644 new mode 100755 index 9e724b89b..485294ee4 --- a/extendedcommands.c +++ b/extendedcommands.c @@ -40,14 +40,23 @@ #include "mtdutils/mtdutils.h" #include "bmlutils/bmlutils.h" #include "cutils/android_reboot.h" +#include "mmcutils/mmcutils.h" +#include "voldclient/voldclient.h" +#include "adb_install.h" + +#ifdef ENABLE_LOKI +#include "compact_loki.h" +#endif int signature_check_enabled = 1; +#ifdef ENABLE_LOKI +int loki_support_enabled = 1; +#endif int script_assert_enabled = 1; -static const char *SDCARD_UPDATE_FILE = "/sdcard/update.zip"; int -get_filtered_menu_selection(char** headers, char** items, int menu_only, int initial_selection, int items_count) { +get_filtered_menu_selection(const char** headers, char** items, int menu_only, int initial_selection, int items_count) { int index; int offset = 0; int* translate_table = (int*)malloc(sizeof(int) * items_count); @@ -91,10 +100,13 @@ void write_string_to_file(const char* filename, const char* string) { } void write_recovery_version() { - if ( is_data_media() ) { - write_string_to_file("/sdcard/0/clockworkmod/.recovery_version",EXPAND(RECOVERY_VERSION) "\n" EXPAND(TARGET_DEVICE)); - } - write_string_to_file("/sdcard/clockworkmod/.recovery_version",EXPAND(RECOVERY_VERSION) "\n" EXPAND(TARGET_DEVICE)); + char path[PATH_MAX]; + sprintf(path, "%s%sclockworkmod/.recovery_version", get_primary_storage_path(), (is_data_media() ? "/0/" : "/")); + write_string_to_file(path,EXPAND(RECOVERY_VERSION) "\n" EXPAND(TARGET_DEVICE)); + // force unmount /data on /data/media devices as we call this on recovery start + ignore_data_media_workaround(1); + ensure_path_unmounted(path); + ignore_data_media_workaround(0); } void @@ -104,6 +116,15 @@ toggle_signature_check() ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled"); } +#ifdef ENABLE_LOKI +void +toggle_loki_support() +{ + loki_support_enabled = !loki_support_enabled; + ui_print("Loki Support: %s\n", loki_support_enabled ? "Enabled" : "Disabled"); +} +#endif + int install_zip(const char* packagefilepath) { // updater_script will not be able to mount /data so do it now otherwise files will land on ramdisk @@ -121,42 +142,58 @@ int install_zip(const char* packagefilepath) ui_print("Installation aborted.\n"); return 1; } +#ifdef ENABLE_LOKI + if(loki_support_enabled) { + ui_print("Checking if loki-fying is needed"); + if (loki_check() != 0) { + return 1; + } + } +#endif ui_set_background(BACKGROUND_ICON_NONE); ui_print("\nInstall from sdcard complete.\n"); return 0; } #define ITEM_CHOOSE_ZIP 0 -#define ITEM_APPLY_SDCARD 1 +#define ITEM_APPLY_SIDELOAD 1 #define ITEM_SIG_CHECK 2 #define ITEM_CHOOSE_ZIP_INT 3 -void show_install_update_menu() +int show_install_update_menu() { - static char* headers[] = { "Apply update from .zip file on SD card", + char buf[100]; + int i = 0, chosen_item = 0; + static char* install_menu_items[MAX_NUM_MANAGED_VOLUMES + 3]; + + char* primary_path = get_primary_storage_path(); + char** extra_paths = get_extra_storage_paths(); + int num_extra_volumes = get_num_extra_volumes(); + + memset(install_menu_items, 0, MAX_NUM_MANAGED_VOLUMES + 3); + + static const char* headers[] = { "Install update from zip file", "", NULL }; - - char* install_menu_items[] = { "choose zip from sdcard", - "apply /sdcard/update.zip", - "toggle signature verification", - NULL, - NULL }; - char *other_sd = NULL; - if (volume_for_path("/emmc") != NULL) { - other_sd = "/emmc/"; - install_menu_items[3] = "choose zip from internal sdcard"; - } - else if (volume_for_path("/external_sd") != NULL) { - other_sd = "/external_sd/"; - install_menu_items[3] = "choose zip from external sdcard"; + sprintf(buf, "choose zip from %s", primary_path); + install_menu_items[0] = strdup(buf); + + install_menu_items[1] = "install zip from sideload"; + + install_menu_items[2] = "toggle signature verification"; + + install_menu_items[3 + num_extra_volumes] = NULL; + + for (i = 0; i < num_extra_volumes; i++) { + sprintf(buf, "choose zip from %s", extra_paths[i]); + install_menu_items[3 + i] = strdup(buf); } - + for (;;) { - int chosen_item = get_menu_selection(headers, install_menu_items, 0, 0); + chosen_item = get_menu_selection(headers, install_menu_items, 0, 0); switch (chosen_item) { case ITEM_SIG_CHECK: @@ -183,18 +220,27 @@ void show_install_update_menu() break; } case ITEM_CHOOSE_ZIP: - show_choose_zip_menu("/sdcard/"); - write_recovery_version(); + show_choose_zip_menu(primary_path); break; - case ITEM_CHOOSE_ZIP_INT: - if (other_sd != NULL) - show_choose_zip_menu(other_sd); + case ITEM_APPLY_SIDELOAD: + apply_from_adb(); break; default: - return; + if (chosen_item >= ITEM_CHOOSE_ZIP_INT) { + show_choose_zip_menu(extra_paths[chosen_item - 3]); + } else { + goto out; + } } - } +out: + // free all the dynamic items + free(install_menu_items[0]); + if (extra_paths != NULL) { + for (i = 0; i < num_extra_volumes; i++) + free(install_menu_items[3 + i]); + } + return chosen_item; } void free_string_array(char** array) @@ -229,7 +275,7 @@ char** gather_files(const char* directory, const char* fileExtensionOrDirectory, return NULL; } - int extension_length = 0; + unsigned int extension_length = 0; if (fileExtensionOrDirectory != NULL) extension_length = strlen(fileExtensionOrDirectory); @@ -287,7 +333,7 @@ char** gather_files(const char* directory, const char* fileExtensionOrDirectory, } if(closedir(dir) < 0) { - LOGE("Failed to close directory."); + LOGE("Failed to close directory.\n"); } if (total==0) { @@ -313,8 +359,9 @@ char** gather_files(const char* directory, const char* fileExtensionOrDirectory, } // pass in NULL for fileExtensionOrDirectory and you will get a directory chooser -char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[]) +char* choose_file_menu(const char* basedir, const char* fileExtensionOrDirectory, const char* headers[]) { + static const char* fixed_headers[20]; char path[PATH_MAX] = ""; DIR *dir; struct dirent *de; @@ -322,13 +369,21 @@ char* choose_file_menu(const char* directory, const char* fileExtensionOrDirecto int numDirs = 0; int i; char* return_value = NULL; - int dir_len = strlen(directory); + char directory[PATH_MAX]; + int dir_len = strlen(basedir); + + strcpy(directory, basedir); + + // Append a traiing slash if necessary + if (directory[dir_len - 1] != '/') { + strcat(directory, "/"); + dir_len++; + } i = 0; while (headers[i]) { i++; } - const char** fixed_headers = (const char*)malloc((i + 3) * sizeof(char*)); i = 0; while (headers[i]) { fixed_headers[i] = headers[i]; @@ -366,7 +421,7 @@ char* choose_file_menu(const char* directory, const char* fileExtensionOrDirecto for (;;) { int chosen_item = get_menu_selection(fixed_headers, list, 0, 0); - if (chosen_item == GO_BACK) + if (chosen_item == GO_BACK || chosen_item == REFRESH) break; static char ret[PATH_MAX]; if (chosen_item < numDirs) @@ -389,7 +444,6 @@ char* choose_file_menu(const char* directory, const char* fileExtensionOrDirecto free_string_array(files); free_string_array(dirs); - free(fixed_headers); return return_value; } @@ -400,7 +454,7 @@ void show_choose_zip_menu(const char *mount_point) return; } - static char* headers[] = { "Choose a zip to apply", + static const char* headers[] = { "Choose a zip to apply", "", NULL }; @@ -439,7 +493,7 @@ void show_nandroid_restore_menu(const char* path) return; } - static char* headers[] = { "Choose an image to restore", + static const char* headers[] = { "Choose an image to restore", "", NULL }; @@ -502,7 +556,7 @@ void show_nandroid_delete_menu(const char* path) return; } - static char* headers[] = { "Choose an image to delete", + static const char* headers[] = { "Choose an image to delete", "", NULL }; @@ -520,147 +574,33 @@ void show_nandroid_delete_menu(const char* path) } } -#define MAX_NUM_USB_VOLUMES 3 -#define LUN_FILE_EXPANDS 2 - -struct lun_node { - const char *lun_file; - struct lun_node *next; -}; - -static struct lun_node *lun_head = NULL; -static struct lun_node *lun_tail = NULL; - -int control_usb_storage_set_lun(Volume* vol, bool enable, const char *lun_file) { - const char *vol_device = enable ? vol->device : ""; - int fd; - struct lun_node *node; - - // Verify that we have not already used this LUN file - for(node = lun_head; node; node = node->next) { - if (!strcmp(node->lun_file, lun_file)) { - // Skip any LUN files that are already in use - return -1; - } - } - - // Open a handle to the LUN file - LOGI("Trying %s on LUN file %s\n", vol->device, lun_file); - if ((fd = open(lun_file, O_WRONLY)) < 0) { - LOGW("Unable to open ums lunfile %s (%s)\n", lun_file, strerror(errno)); - return -1; - } - - // Write the volume path to the LUN file - if ((write(fd, vol_device, strlen(vol_device) + 1) < 0) && - (!enable || !vol->device2 || (write(fd, vol->device2, strlen(vol->device2)) < 0))) { - LOGW("Unable to write to ums lunfile %s (%s)\n", lun_file, strerror(errno)); - close(fd); - return -1; - } else { - // Volume path to LUN association succeeded - close(fd); - - // Save off a record of this lun_file being in use now - node = (struct lun_node *)malloc(sizeof(struct lun_node)); - node->lun_file = strdup(lun_file); - node->next = NULL; - if (lun_head == NULL) - lun_head = lun_tail = node; - else { - lun_tail->next = node; - lun_tail = node; - } - - LOGI("Successfully %sshared %s on LUN file %s\n", enable ? "" : "un", vol->device, lun_file); - return 0; - } -} - -int control_usb_storage_for_lun(Volume* vol, bool enable) { - static const char* lun_files[] = { -#ifdef BOARD_UMS_LUNFILE - BOARD_UMS_LUNFILE, -#endif -#ifdef TARGET_USE_CUSTOM_LUN_FILE_PATH - TARGET_USE_CUSTOM_LUN_FILE_PATH, -#endif - "/sys/devices/platform/usb_mass_storage/lun%d/file", - "/sys/class/android_usb/android0/f_mass_storage/lun/file", - "/sys/class/android_usb/android0/f_mass_storage/lun_ex/file", - NULL - }; - - // If recovery.fstab specifies a LUN file, use it - if (vol->lun) { - return control_usb_storage_set_lun(vol, enable, vol->lun); - } - - // Try to find a LUN for this volume - // - iterate through the lun file paths - // - expand any %d by LUN_FILE_EXPANDS - int lun_num = 0; - int i; - for(i = 0; lun_files[i]; i++) { - const char *lun_file = lun_files[i]; - for(lun_num = 0; lun_num < LUN_FILE_EXPANDS; lun_num++) { - char formatted_lun_file[255]; - - // Replace %d with the LUN number - bzero(formatted_lun_file, 255); - snprintf(formatted_lun_file, 254, lun_file, lun_num); - - // Attempt to use the LUN file - if (control_usb_storage_set_lun(vol, enable, formatted_lun_file) == 0) { - return 0; +static int control_usb_storage(bool on) +{ + int i = 0; + int num = 0; + + for (i = 0; i < get_num_volumes(); i++) { + Volume *v = get_device_volumes() + i; + if (fs_mgr_is_voldmanaged(v) && vold_is_volume_available(v->mount_point)) { + if (on) { + vold_share_volume(v->mount_point); + } else { + vold_unshare_volume(v->mount_point, 1); } + property_set("sys.storage.ums_enabled", on ? "1" : "0"); + num++; } } - - // All LUNs were exhausted and none worked - LOGW("Could not %sable %s on LUN %d\n", enable ? "en" : "dis", vol->device, lun_num); - - return -1; // -1 failure, 0 success -} - -int control_usb_storage(Volume **volumes, bool enable) { - int res = -1; - int i; - for(i = 0; i < MAX_NUM_USB_VOLUMES; i++) { - Volume *volume = volumes[i]; - if (volume) { - int vol_res = control_usb_storage_for_lun(volume, enable); - if (vol_res == 0) res = 0; // if any one path succeeds, we return success - } - } - - // Release memory used by the LUN file linked list - struct lun_node *node = lun_head; - while(node) { - struct lun_node *next = node->next; - free((void *)node->lun_file); - free(node); - node = next; - } - lun_head = lun_tail = NULL; - - return res; // -1 failure, 0 success + return num; } void show_mount_usb_storage_menu() { - // Build a list of Volume objects; some or all may not be valid - Volume* volumes[MAX_NUM_USB_VOLUMES] = { - volume_for_path("/sdcard"), - volume_for_path("/emmc"), - volume_for_path("/external_sd") - }; - - // Enable USB storage - if (control_usb_storage(volumes, 1)) + // Enable USB storage using vold + if (!control_usb_storage(true)) return; - static char* headers[] = { "USB Mass Storage device", + static const char* headers[] = { "USB Mass Storage device", "Leaving this menu unmounts", "your SD card from your PC.", "", @@ -677,28 +617,21 @@ void show_mount_usb_storage_menu() } // Disable USB storage - control_usb_storage(volumes, 0); + control_usb_storage(false); } int confirm_selection(const char* title, const char* confirm) { struct stat info; + int ret = 0; + if (0 == stat("/sdcard/clockworkmod/.no_confirm", &info)) return 1; - char* confirm_headers[] = { title, " THIS CAN NOT BE UNDONE.", "", NULL }; - int one_confirm = 0 == stat("/sdcard/clockworkmod/.one_confirm", &info); -#ifdef BOARD_TOUCH_RECOVERY - one_confirm = 1; -#endif - if (one_confirm) { - char* items[] = { "No", - confirm, //" Yes -- wipe partition", // [1] - NULL }; - int chosen_item = get_menu_selection(confirm_headers, items, 0, 0); - return chosen_item == 1; - } - else { + char* confirm_str = strdup(confirm); + const char* confirm_headers[] = { title, " THIS CAN NOT BE UNDONE.", "", NULL }; + int many_confirm = 0 == stat("/sdcard/clockworkmod/.many_confirm", &info); + if (many_confirm) { char* items[] = { "No", "No", "No", @@ -706,19 +639,29 @@ int confirm_selection(const char* title, const char* confirm) "No", "No", "No", - confirm, //" Yes -- wipe partition", // [7] + confirm_str, //" Yes -- wipe partition", // [7] "No", "No", "No", NULL }; int chosen_item = get_menu_selection(confirm_headers, items, 0, 0); - return chosen_item == 7; + ret = (chosen_item == 7); } + else { + char* items[] = { "No", + confirm_str, //" Yes -- wipe partition", // [1] + NULL }; + int chosen_item = get_menu_selection(confirm_headers, items, 0, 0); + ret = (chosen_item == 1); } + free(confirm_str); + return ret; +} #define MKE2FS_BIN "/sbin/mke2fs" #define TUNE2FS_BIN "/sbin/tune2fs" #define E2FSCK_BIN "/sbin/e2fsck" +extern void reset_ext4fs_info(); extern struct selabel_handle *sehandle; int format_device(const char *device, const char *path, const char *fs_type) { @@ -758,7 +701,7 @@ int format_device(const char *device, const char *path, const char *fs_type) { } if (strcmp(v->mount_point, path) != 0) { - return format_unknown_device(v->device, path, NULL); + return format_unknown_device(v->blk_device, path, NULL); } if (ensure_path_unmounted(path) != 0) { @@ -798,12 +741,22 @@ int format_device(const char *device, const char *path, const char *fs_type) { reset_ext4fs_info(); int result = make_ext4fs(device, length, v->mount_point, sehandle); if (result != 0) { - LOGE("format_volume: make_extf4fs failed on %s\n", device); + LOGE("format_volume: make_ext4fs failed on %s\n", device); return -1; } return 0; } +#ifdef USE_F2FS + if (strcmp(fs_type, "f2fs") == 0) { + int result = make_f2fs_main(device, v->mount_point); + if (result != 0) { + LOGE("format_volume: mkfs.f2f2 failed on %s\n", device); + return -1; + } + return 0; + } +#endif return format_unknown_device(device, path, fs_type); } @@ -819,9 +772,9 @@ int format_unknown_device(const char *device, const char* path, const char *fs_t { struct stat st; Volume *vol = volume_for_path("/sd-ext"); - if (vol == NULL || 0 != stat(vol->device, &st)) + if (vol == NULL || 0 != stat(vol->blk_device, &st)) { - ui_print("No app2sd partition found. Skipping format of /sd-ext.\n"); + LOGI("No app2sd partition found. Skipping format of /sd-ext.\n"); return 0; } } @@ -893,12 +846,13 @@ int format_unknown_device(const char *device, const char* path, const char *fs_t typedef struct { char mount[255]; char unmount[255]; - Volume* v; + char path[PATH_MAX]; } MountMenuEntry; typedef struct { char txt[255]; - Volume* v; + char path[PATH_MAX]; + char type[255]; } FormatMenuEntry; int is_safe_to_format(char* name) @@ -918,29 +872,29 @@ int is_safe_to_format(char* name) return 1; } -void show_partition_menu() +int show_partition_menu() { - static char* headers[] = { "Mounts and Storage Menu", + static const char* headers[] = { "Mounts and Storage Menu", "", NULL }; + static char* confirm_format = "Confirm format?"; + static char* confirm = "Yes - Format"; + char confirm_string[255]; + static MountMenuEntry* mount_menu = NULL; static FormatMenuEntry* format_menu = NULL; - - typedef char* string; + static char* list[256]; int i, mountable_volumes, formatable_volumes; int num_volumes; - Volume* device_volumes; + int chosen_item = 0; num_volumes = get_num_volumes(); - device_volumes = get_device_volumes(); - - string options[255]; - if(!device_volumes) - return; + if(!num_volumes) + return 0; mountable_volumes = 0; formatable_volumes = 0; @@ -948,8 +902,13 @@ void show_partition_menu() mount_menu = malloc(num_volumes * sizeof(MountMenuEntry)); format_menu = malloc(num_volumes * sizeof(FormatMenuEntry)); - for (i = 0; i < num_volumes; ++i) { - Volume* v = &device_volumes[i]; + for (i = 0; i < num_volumes; i++) { + Volume* v = get_device_volumes() + i; + + if (fs_mgr_is_voldmanaged(v) && !vold_is_volume_available(v->mount_point)) { + continue; + } + if(strcmp("ramdisk", v->fs_type) != 0 && strcmp("mtd", v->fs_type) != 0 && strcmp("emmc", v->fs_type) != 0 && strcmp("bml", v->fs_type) != 0) { int systemNumber = -1, dataNumber = -1; @@ -979,24 +938,23 @@ void show_partition_menu() } mount_menu[mountable_volumes].v = &device_volumes[i]; ++mountable_volumes; + if (is_safe_to_format(v->mount_point)) { - sprintf(&format_menu[formatable_volumes].txt, "format %s", v->mount_point); - format_menu[formatable_volumes].v = &device_volumes[i]; + sprintf(format_menu[formatable_volumes].txt, "format %s", v->mount_point); + sprintf(format_menu[formatable_volumes].path, "%s", v->mount_point); + sprintf(format_menu[formatable_volumes].type, "%s", v->fs_type); ++formatable_volumes; } } else if (strcmp("ramdisk", v->fs_type) != 0 && strcmp("mtd", v->fs_type) == 0 && is_safe_to_format(v->mount_point)) { - sprintf(&format_menu[formatable_volumes].txt, "format %s", v->mount_point); - format_menu[formatable_volumes].v = &device_volumes[i]; + sprintf(format_menu[formatable_volumes].txt, "format %s", v->mount_point); + sprintf(format_menu[formatable_volumes].path, "%s", v->mount_point); + sprintf(format_menu[formatable_volumes].type, "%s", v->fs_type); ++formatable_volumes; } } - static char* confirm_format = "Confirm format?"; - static char* confirm = "Yes - Format"; - char confirm_string[255]; - for (;;) { for (i = 0; i < mountable_volumes; i++) @@ -1055,27 +1013,26 @@ void show_partition_menu() if(is_path_mounted(v->mount_point)) options[i] = e->unmount; else - options[i] = e->mount; + list[i] = e->mount; } for (i = 0; i < formatable_volumes; i++) { FormatMenuEntry* e = &format_menu[i]; - - options[mountable_volumes+i] = e->txt; + list[mountable_volumes+i] = e->txt; } if (!is_data_media()) { - options[mountable_volumes + formatable_volumes] = "mount USB storage"; - options[mountable_volumes + formatable_volumes + 1] = NULL; - } - else { - options[mountable_volumes + formatable_volumes] = "format /data and /data/media (/sdcard)"; - options[mountable_volumes + formatable_volumes + 1] = NULL; + list[mountable_volumes + formatable_volumes] = "mount USB storage"; + list[mountable_volumes + formatable_volumes + 1] = '\0'; + } else { + list[mountable_volumes + formatable_volumes] = "format /data and /data/media (/sdcard)"; + list[mountable_volumes + formatable_volumes + 1] = "mount USB storage"; + list[mountable_volumes + formatable_volumes + 2] = '\0'; } - int chosen_item = get_menu_selection(headers, &options, 0, 0); - if (chosen_item == GO_BACK) + chosen_item = get_menu_selection(headers, list, 0, 0); + if (chosen_item == GO_BACK || chosen_item == REFRESH) break; if (chosen_item == (mountable_volumes+formatable_volumes)) { if (!is_data_media()) { @@ -1084,18 +1041,20 @@ void show_partition_menu() else { if (!confirm_selection("format /data and /data/media (/sdcard)", confirm)) continue; - handle_data_media_format(1); + ignore_data_media_workaround(1); ui_print("Formatting /data...\n"); if (0 != format_volume("/data")) ui_print("Error formatting /data!\n"); else ui_print("Done.\n"); - handle_data_media_format(0); + ignore_data_media_workaround(0); } } + else if (is_data_media() && chosen_item == (mountable_volumes+formatable_volumes+1)) { + show_mount_usb_storage_menu(); + } else if (chosen_item < mountable_volumes) { MountMenuEntry* e = &mount_menu[chosen_item]; - Volume* v = e->v; if(is_dualsystem()) { int systemNumber = -1, dataNumber = -1; @@ -1135,20 +1094,19 @@ void show_partition_menu() if (is_path_mounted(v->mount_point)) { - if (0 != ensure_path_unmounted(v->mount_point)) - ui_print("Error unmounting %s!\n", v->mount_point); + if (0 != ensure_path_unmounted(e->path)) + ui_print("Error unmounting %s!\n", e->path); } else { - if (0 != ensure_path_mounted(v->mount_point)) - ui_print("Error mounting %s!\n", v->mount_point); + if (0 != ensure_path_mounted(e->path)) + ui_print("Error mounting %s!\n", e->path); } } else if (chosen_item < (mountable_volumes + formatable_volumes)) { chosen_item = chosen_item - mountable_volumes; FormatMenuEntry* e = &format_menu[chosen_item]; - Volume* v = e->v; if(is_dualsystem() && set_active_system(DUALBOOT_ITEM_BOTH)!=0) { continue; @@ -1158,9 +1116,9 @@ void show_partition_menu() if (!confirm_selection(confirm_string, confirm)) continue; - ui_print("Formatting %s...\n", v->mount_point); - if (0 != format_volume(v->mount_point)) - ui_print("Error formatting %s!\n", v->mount_point); + ui_print("Formatting %s...\n", e->path); + if (0 != format_volume(e->path)) + ui_print("Error formatting %s!\n", e->path); else ui_print("Done.\n"); } @@ -1168,6 +1126,7 @@ void show_partition_menu() free(mount_menu); free(format_menu); + return chosen_item; } void show_nandroid_advanced_restore_menu(const char* path) @@ -1177,7 +1136,7 @@ void show_nandroid_advanced_restore_menu(const char* path) return; } - static char* advancedheaders[] = { "Choose an image to restore", + static const char* advancedheaders[] = { "Choose an image to restore", "", "Choose an image to restore", "first. The next menu will", @@ -1193,7 +1152,7 @@ void show_nandroid_advanced_restore_menu(const char* path) if (file == NULL) return; - static char* headers[] = { "Advanced Restore", + static const char* headers[] = { "Advanced Restore", "", NULL }; @@ -1304,35 +1263,54 @@ void show_nandroid_advanced_restore_menu(const char* path) } } -static void run_dedupe_gc(const char* other_sd) { - ensure_path_mounted("/sdcard"); - nandroid_dedupe_gc("/sdcard/clockworkmod/blobs"); - if (other_sd) { - ensure_path_mounted(other_sd); - char tmp[PATH_MAX]; - sprintf(tmp, "%s/clockworkmod/blobs", other_sd); - nandroid_dedupe_gc(tmp); +static void run_dedupe_gc() { + char path[PATH_MAX]; + char* fmt = "%s/clockworkmod/blobs"; + char* primary_path = get_primary_storage_path(); + char** extra_paths = get_extra_storage_paths(); + int i = 0; + + sprintf(path, fmt, primary_path); + ensure_path_mounted(primary_path); + nandroid_dedupe_gc(path); + + if (extra_paths != NULL) { + for (i = 0; i < get_num_extra_volumes(); i++) { + ensure_path_mounted(extra_paths[i]); + sprintf(path, fmt, extra_paths[i]); + nandroid_dedupe_gc(path); + } } } static void choose_default_backup_format() { - static char* headers[] = { "Default Backup Format", + static const char* headers[] = { "Default Backup Format", "", NULL }; + int fmt = nandroid_get_default_backup_format(); + char **list; char* list_tar_default[] = { "tar (default)", "dup", + "tar + gzip", NULL }; char* list_dup_default[] = { "tar", "dup (default)", + "tar + gzip", NULL }; - - if (nandroid_get_default_backup_format() == NANDROID_BACKUP_FORMAT_DUP) { + char* list_tgz_default[] = { "tar", + "dup", + "tar + gzip (default)", + NULL + }; + if (fmt == NANDROID_BACKUP_FORMAT_DUP) { list = list_dup_default; + } else if (fmt == NANDROID_BACKUP_FORMAT_TGZ) { + list = list_tgz_default; } else { list = list_tar_default; } @@ -1347,56 +1325,84 @@ static void choose_default_backup_format() { write_string_to_file(NANDROID_BACKUP_FORMAT_FILE, "dup"); ui_print("Default backup format set to dedupe.\n"); break; + case 2: + write_string_to_file(NANDROID_BACKUP_FORMAT_FILE, "tgz"); + ui_print("Default backup format set to tar + gzip.\n"); + break; } } -void show_nandroid_menu() +static void add_nandroid_options_for_volume(char** menu, char* path, int offset) { - static char* headers[] = { "Backup and Restore", - "", - NULL - }; + char buf[100]; - char* list[] = { "backup", - "restore", - "delete", - "advanced restore", - "free unused backup data", - "choose default backup format", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL + sprintf(buf, "backup to %s", path); + menu[offset] = strdup(buf); + + sprintf(buf, "restore from %s", path); + menu[offset + 1] = strdup(buf); + + sprintf(buf, "delete from %s", path); + menu[offset + 2] = strdup(buf); + + sprintf(buf, "advanced restore from %s", path); + menu[offset + 3] = strdup(buf); +} + +int show_nandroid_menu() +{ + char* primary_path = get_primary_storage_path(); + char** extra_paths = get_extra_storage_paths(); + int num_extra_volumes = get_num_extra_volumes(); + int i = 0, offset = 0, chosen_item = 0; + char* chosen_path = NULL; + int max_backup_index = (num_extra_volumes + 1) * 4; + + static const char* headers[] = { "Backup and Restore", + "", + NULL }; - char *other_sd = NULL; - if (volume_for_path("/emmc") != NULL) { - other_sd = "/emmc"; - list[6] = "backup to internal sdcard"; - list[7] = "restore from internal sdcard"; - list[8] = "advanced restore from internal sdcard"; - list[9] = "delete from internal sdcard"; - } - else if (volume_for_path("/external_sd") != NULL) { - other_sd = "/external_sd"; - list[6] = "backup to external sdcard"; - list[7] = "restore from external sdcard"; - list[8] = "advanced restore from external sdcard"; - list[9] = "delete from external sdcard"; + static char* list[((MAX_NUM_MANAGED_VOLUMES + 1) * 4) + 2]; + + add_nandroid_options_for_volume(list, primary_path, offset); + offset += 4; + + if (extra_paths != NULL) { + for (i = 0; i < num_extra_volumes; i++) { + add_nandroid_options_for_volume(list, extra_paths[i], offset); + offset += 4; + } } + + list[offset] = "free unused backup data"; + offset++; + list[offset] = "choose default backup format"; + offset++; + #ifdef RECOVERY_EXTEND_NANDROID_MENU - extend_nandroid_menu(list, 10, sizeof(list) / sizeof(char*)); + extend_nandroid_menu(list, offset, sizeof(list) / sizeof(char*)); + offset++; #endif + list[offset] = NULL; + for (;;) { - int chosen_item = get_filtered_menu_selection(headers, list, 0, 0, sizeof(list) / sizeof(char*)); - if (chosen_item == GO_BACK) + chosen_item = get_filtered_menu_selection(headers, list, 0, 0, offset); + if (chosen_item == GO_BACK || chosen_item == REFRESH) break; - switch (chosen_item) - { + int chosen_subitem = chosen_item % 4; + if (chosen_item == max_backup_index) { + run_dedupe_gc(); + } else if (chosen_item == (max_backup_index + 1)) { + choose_default_backup_format(); + } else if (chosen_item < max_backup_index){ + if (chosen_item < 4) { + chosen_path = primary_path; + } else if (extra_paths != NULL) { + chosen_path = extra_paths[(chosen_item / 4) -1]; + } + switch (chosen_subitem) { case 0: { char backup_path[PATH_MAX]; @@ -1406,88 +1412,118 @@ void show_nandroid_menu() { struct timeval tp; gettimeofday(&tp, NULL); - sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec); + sprintf(backup_path, "%s/clockworkmod/backup/%ld", chosen_path, tp.tv_sec); } else { - strftime(backup_path, sizeof(backup_path), "/sdcard/clockworkmod/backup/%F.%H.%M.%S", tmp); + char path_fmt[PATH_MAX]; + strftime(path_fmt, sizeof(path_fmt), "clockworkmod/backup/%F.%H.%M.%S", tmp); + // this sprintf results in: + // /emmc/clockworkmod/backup/%F.%H.%M.%S (time values are populated too) + sprintf(backup_path, "%s/%s", chosen_path, path_fmt); } nandroid_backup(backup_path); - write_recovery_version(); } break; case 1: - show_nandroid_restore_menu("/sdcard"); - write_recovery_version(); + show_nandroid_restore_menu(chosen_path); break; case 2: - show_nandroid_delete_menu("/sdcard"); - write_recovery_version(); + show_nandroid_delete_menu(chosen_path); break; case 3: - show_nandroid_advanced_restore_menu("/sdcard"); - write_recovery_version(); - break; - case 4: - run_dedupe_gc(other_sd); - break; - case 5: - choose_default_backup_format(); - break; - case 6: - { - char backup_path[PATH_MAX]; - time_t t = time(NULL); - struct tm *timeptr = localtime(&t); - if (timeptr == NULL) - { - struct timeval tp; - gettimeofday(&tp, NULL); - if (other_sd != NULL) { - sprintf(backup_path, "%s/clockworkmod/backup/%d", other_sd, tp.tv_sec); - } - else { - break; - } - } - else - { - if (other_sd != NULL) { - char tmp[PATH_MAX]; - strftime(tmp, sizeof(tmp), "clockworkmod/backup/%F.%H.%M.%S", timeptr); - // this sprintf results in: - // /emmc/clockworkmod/backup/%F.%H.%M.%S (time values are populated too) - sprintf(backup_path, "%s/%s", other_sd, tmp); - } - else { - break; - } - } - nandroid_backup(backup_path); - } - break; - case 7: - if (other_sd != NULL) { - show_nandroid_restore_menu(other_sd); - } - break; - case 8: - if (other_sd != NULL) { - show_nandroid_advanced_restore_menu(other_sd); - } - break; - case 9: - if (other_sd != NULL) { - show_nandroid_delete_menu(other_sd); - } + show_nandroid_advanced_restore_menu(chosen_path); break; default: + break; + } + } else { #ifdef RECOVERY_EXTEND_NANDROID_MENU handle_nandroid_menu(10, chosen_item); #endif - break; + goto out; } } +out: + for (i = 0; i < max_backup_index; i++) + free(list[i]); + return chosen_item; +} + +void format_sdcard(const char* volume) { + if (is_data_media_volume_path(volume)) + return; + + Volume *vol = volume_for_path(volume); + if (vol == NULL || strcmp(vol->fs_type, "auto") != 0) + return; + if (!fs_mgr_is_voldmanaged(vol) && !can_partition(volume)) + return; + + char* headers[] = {"Format device:", volume, "", NULL }; + + static char* list[] = { "default", + "vfat", + "exfat", + "ntfs", + "ext4", + "ext3", + "ext2", + NULL + }; + + int ret = -1; + char cmd[PATH_MAX]; + int chosen_item = get_menu_selection(headers, list, 0, 0); + if (chosen_item < 0) // REFRESH or GO_BACK + return; + if (!confirm_selection( "Confirm formatting?", "Yes - Format device")) + return; + + Volume *v = volume_for_path(volume); + if (ensure_path_unmounted(v->mount_point) != 0) + return; + + switch (chosen_item) + { + case 0: + ret = format_volume(v->mount_point); + break; + case 1: + case 2: + case 3: + case 4: + if (fs_mgr_is_voldmanaged(v)) { + ret = vold_custom_format_volume(v->mount_point, list[chosen_item], 1) == CommandOkay ? 0 : -1; + } else if (strcmp(list[chosen_item], "vfat") == 0) { + sprintf(cmd, "/sbin/newfs_msdos -F 32 -O android -c 8 %s", v->blk_device); + ret = __system(cmd); + } else if (strcmp(list[chosen_item], "exfat") == 0) { + sprintf(cmd, "/sbin/mkfs.exfat %s", v->blk_device); + ret = __system(cmd); + } else if (strcmp(list[chosen_item], "ntfs") == 0) { + sprintf(cmd, "/sbin/mkntfs -f %s", v->blk_device); + ret = __system(cmd); + } else if (strcmp(list[chosen_item], "ext4") == 0) { + ret = make_ext4fs(v->blk_device, v->length, volume, sehandle); + } + break; + case 5: + case 6: + { + // workaround for new vold managed volumes that cannot be recognized by prebuilt ext2/ext3 bins + const char *device = v->blk_device2; + if (device == NULL) + device = v->blk_device; + ret = format_unknown_device(device, v->mount_point, list[chosen_item]); + break; + } + } + + if (ret) + ui_print("Could not format %s (%s)\n", volume, list[chosen_item]); + else + ui_print("Done formatting %s (%s)\n", volume, list[chosen_item]); } static void partition_sdcard(const char* volume) { @@ -1511,25 +1547,40 @@ static void partition_sdcard(const char* volume) { "256M", NULL }; - static char* ext_headers[] = { "Ext Size", "", NULL }; - static char* swap_headers[] = { "Swap Size", "", NULL }; + static char* partition_types[] = { "ext3", + "ext4", + NULL + }; + + static const char* ext_headers[] = { "Ext Size", "", NULL }; + static const char* swap_headers[] = { "Swap Size", "", NULL }; + static const char* fstype_headers[] = {"Partition Type", "", NULL }; int ext_size = get_menu_selection(ext_headers, ext_sizes, 0, 0); - if (ext_size == GO_BACK) + if (ext_size < 0) return; int swap_size = get_menu_selection(swap_headers, swap_sizes, 0, 0); - if (swap_size == GO_BACK) + if (swap_size < 0) + return; + + int partition_type = get_menu_selection(fstype_headers, partition_types, 0, 0); + if (partition_type < 0) return; char sddevice[256]; Volume *vol = volume_for_path(volume); - strcpy(sddevice, vol->device); + + // can_partition() ensured either blk_device or blk_device2 has /dev/block/mmcblk format + if (strstr(vol->blk_device, "/dev/block/mmcblk") != NULL) + strcpy(sddevice, vol->blk_device); + else strcpy(sddevice, vol->blk_device2); + // we only want the mmcblk, not the partition - sddevice[strlen("/dev/block/mmcblkX")] = NULL; + sddevice[strlen("/dev/block/mmcblkX")] = '\0'; char cmd[PATH_MAX]; setenv("SDPATH", sddevice, 1); - sprintf(cmd, "sdparted -es %s -ss %s -efs ext3 -s", ext_sizes[ext_size], swap_sizes[swap_size]); + sprintf(cmd, "sdparted -es %s -ss %s -efs %s -s", ext_sizes[ext_size], swap_sizes[swap_size], partition_types[partition_type]); ui_print("Partitioning SD Card... please wait...\n"); if (0 == __system(cmd)) ui_print("Done!\n"); @@ -1538,30 +1589,60 @@ static void partition_sdcard(const char* volume) { } int can_partition(const char* volume) { + if (is_data_media_volume_path(volume)) + return 0; + Volume *vol = volume_for_path(volume); if (vol == NULL) { LOGI("Can't format unknown volume: %s\n", volume); return 0; } + if (strcmp(vol->fs_type, "auto") != 0) { + LOGI("Can't partition non-vfat: %s (%s)\n", volume, vol->fs_type); + return 0; + } - int vol_len = strlen(vol->device); // do not allow partitioning of a device that isn't mmcblkX or mmcblkXp1 - if (vol->device[vol_len - 2] == 'p' && vol->device[vol_len - 1] != '1') { - LOGI("Can't partition unsafe device: %s\n", vol->device); + // needed with new vold managed volumes and virtual device path links + int vol_len; + char *device = NULL; + if (strstr(vol->blk_device, "/dev/block/mmcblk") != NULL) { + device = vol->blk_device; + } else if (vol->blk_device2 != NULL && strstr(vol->blk_device2, "/dev/block/mmcblk") != NULL) { + device = vol->blk_device2; + } else { + LOGI("Can't partition non mmcblk device: %s\n", vol->blk_device); return 0; } - - if (strcmp(vol->fs_type, "vfat") != 0) { - LOGI("Can't partition non-vfat: %s\n", vol->fs_type); + + vol_len = strlen(device); + if (device[vol_len - 2] == 'p' && device[vol_len - 1] != '1') { + LOGI("Can't partition unsafe device: %s\n", device); return 0; } return 1; } -void show_advanced_menu() + +#ifdef ENABLE_LOKI + #define FIXED_ADVANCED_ENTRIES 8 +#else + #define FIXED_ADVANCED_ENTRIES 7 +#endif + +int show_advanced_menu() { - static char* headers[] = { "Advanced Menu", + char buf[80]; + int i = 0, j = 0, chosen_item = 0; + /* Default number of entries if no compile-time extras are added */ + static char* list[MAX_NUM_MANAGED_VOLUMES + FIXED_ADVANCED_ENTRIES + 1]; + + char* primary_path = get_primary_storage_path(); + char** extra_paths = get_extra_storage_paths(); + int num_extra_volumes = get_num_extra_volumes(); + + static const char* headers[] = { "Advanced Menu", "", NULL }; @@ -1612,8 +1693,11 @@ void show_advanced_menu() switch (chosen_item) { case 0: - android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); + { + ui_print("Rebooting recovery...\n"); + reboot_main_system(ANDROID_RB_RESTART2, 0, "recovery"); break; + } case 1: if(is_dualsystem() && isTrueDualbootEnabled()) { int system = select_system("Choose system to wipe dalvik-cache:"); @@ -1676,14 +1760,17 @@ void show_advanced_menu() __system("fix_permissions"); ui_print("Done!\n"); break; + case 6: - partition_sdcard("/sdcard"); + ui_printlogtail(12); break; +#ifdef ENABLE_LOKI case 7: - partition_sdcard("/external_sd"); + toggle_loki_support(); break; - case 8: - partition_sdcard("/emmc"); +#endif + default: + partition_sdcard(list[chosen_item] + strlen(list_prefix)); break; case 9: system = select_system("Set bootmode:"); @@ -1697,6 +1784,11 @@ void show_advanced_menu() break; } } + + for (; j > 0; --j) { + free(list[FIXED_ADVANCED_ENTRIES + j - 1]); + } + return chosen_item; } void write_fstab_root(char *path, FILE *file) @@ -1708,10 +1800,10 @@ void write_fstab_root(char *path, FILE *file) } char device[200]; - if (vol->device[0] != '/') - get_partition_device(vol->device, device); + if (vol->blk_device[0] != '/') + get_partition_device(vol->blk_device, device); else - strcpy(device, vol->device); + strcpy(device, vol->blk_device); fprintf(file, "%s ", device); fprintf(file, "%s ", path); @@ -1759,7 +1851,7 @@ int bml_check_volume(const char *path) { ui_print("%s may be rfs. Checking...\n", path); char tmp[PATH_MAX]; - sprintf(tmp, "mount -t rfs %s %s", vol->device, path); + sprintf(tmp, "mount -t rfs %s %s", vol->blk_device, path); int ret = __system(tmp); printf("%d\n", ret); return ret == 0 ? 1 : 0; @@ -1796,8 +1888,8 @@ void process_volumes() { char backup_name[PATH_MAX]; struct timeval tp; gettimeofday(&tp, NULL); - sprintf(backup_name, "before-ext4-convert-%d", tp.tv_sec); - sprintf(backup_path, "/sdcard/clockworkmod/backup/%s", backup_name); + sprintf(backup_name, "before-ext4-convert-%ld", tp.tv_sec); + sprintf(backup_path, "%s/clockworkmod/backup/%s", get_primary_storage_path(), backup_name); ui_set_show_text(1); ui_print("Filesystems need to be converted to ext4.\n"); @@ -1815,14 +1907,14 @@ void handle_failure(int ret) { if (ret == 0) return; - if (0 != ensure_path_mounted("/sdcard")) + if (0 != ensure_path_mounted(get_primary_storage_path())) return; mkdir("/sdcard/clockworkmod", S_IRWXU | S_IRWXG | S_IRWXO); __system("cp /tmp/recovery.log /sdcard/clockworkmod/recovery.log"); ui_print("/tmp/recovery.log was copied to /sdcard/clockworkmod/recovery.log. Please open ROM Manager to report the issue.\n"); } -int is_path_mounted(const char* path) { +static int is_path_mounted(const char* path) { Volume* v = volume_for_path(path); if (v == NULL) { return 0; @@ -1832,12 +1924,8 @@ int is_path_mounted(const char* path) { return 1; } - int result; - result = scan_mounted_volumes(); - if (result < 0) { - LOGE("failed to scan mounted volumes\n"); + if (scan_mounted_volumes() < 0) return 0; - } const MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point); @@ -1884,6 +1972,7 @@ int verify_root_and_recovery(int system_number) { } } + int exists = 0; if (0 == lstat("/system/bin/su", &st)) { exists = 1; @@ -1921,9 +2010,7 @@ int verify_root_and_recovery(int system_number) { ui_show_text(1); ret = 1; if (confirm_selection("Root access is missing. Root device?", "Yes - Root device (/system/xbin/su)")) { - __system("cp /sbin/su.recovery /system/xbin/su"); - __system("chmod 6755 /system/xbin/su"); - __system("ln -sf /system/xbin/su /system/bin/su"); + __system("/sbin/install-su.sh"); } } diff --git a/extendedcommands.h b/extendedcommands.h old mode 100644 new mode 100755 index 34a79f302..649ba3d82 --- a/extendedcommands.h +++ b/extendedcommands.h @@ -1,9 +1,6 @@ extern int signature_check_enabled; extern int script_assert_enabled; -void -write_recovery_version(); - void toggle_signature_check(); @@ -22,28 +19,24 @@ show_nandroid_restore_menu(const char* path); void show_nandroid_advanced_restore_menu(const char* path); -void +int show_nandroid_menu(); -void +int show_partition_menu(); -void -show_choose_zip_menu(); - int install_zip(const char* packagefilepath); int __system(const char *command); -void +int show_advanced_menu(); -int format_unknown_device(const char *device, const char* path, const char *fs_type); +int format_device(const char *device, const char *path, const char *fs_type); -void -wipe_battery_stats(); +int format_unknown_device(const char *device, const char* path, const char *fs_type); void create_fstab(); @@ -55,7 +48,7 @@ void process_volumes(); int extendedcommand_file_exists(); -void show_install_update_menu(); +int show_install_update_menu(); int confirm_selection(const char* title, const char* confirm); @@ -81,6 +74,14 @@ int isTrueDualbootEnabled(); int enableTrueDualboot(int enable); +void free_string_array(char** array); + +int can_partition(const char* volume); + +static int is_path_mounted(const char* path); + +int volume_main(int argc, char **argv); + #ifdef RECOVERY_EXTEND_NANDROID_MENU void extend_nandroid_menu(char** items, int item_count, int max_items); void handle_nandroid_menu(int item_count, int selected); @@ -97,3 +98,4 @@ void handle_nandroid_menu(int item_count, int selected); #define DUALBOOT_PATH_DATAROOT "/data_root" #define DUALBOOT_PATH_USERDATA0 DUALBOOT_PATH_DATAROOT "/system0" #define DUALBOOT_PATH_USERDATA1 DUALBOOT_PATH_DATAROOT "/system1" + diff --git a/flashutils/flashutils.c b/flashutils/flashutils.c index de45e87b8..860945e82 100644 --- a/flashutils/flashutils.c +++ b/flashutils/flashutils.c @@ -90,7 +90,7 @@ int backup_raw_partition(const char* partitionType, const char *partition, const case BML: return cmd_bml_backup_raw_partition(partition, filename); default: - printf("unable to detect device type"); + printf("unable to detect device type\n"); return -1; } } diff --git a/install.c b/install.c index 8b07b168f..62145fdb6 100644 --- a/install.c +++ b/install.c @@ -257,109 +257,37 @@ try_update_binary(const char *path, ZipArchive *zip) { mzCloseZipArchive(zip); return ret; } + mzCloseZipArchive(zip); return INSTALL_SUCCESS; } -// Reads a file containing one or more public keys as produced by -// DumpPublicKey: this is an RSAPublicKey struct as it would appear -// as a C source literal, eg: -// -// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}" -// -// (Note that the braces and commas in this example are actual -// characters the parser expects to find in the file; the ellipses -// indicate more numbers omitted from this example.) -// -// The file may contain multiple keys in this format, separated by -// commas. The last key must not be followed by a comma. -// -// Returns NULL if the file failed to parse, or if it contain zero keys. -static RSAPublicKey* -load_keys(const char* filename, int* numKeys) { - RSAPublicKey* out = NULL; - *numKeys = 0; - - FILE* f = fopen(filename, "r"); - if (f == NULL) { - LOGE("opening %s: %s\n", filename, strerror(errno)); - goto exit; - } - - { - int i; - bool done = false; - while (!done) { - ++*numKeys; - out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey)); - RSAPublicKey* key = out + (*numKeys - 1); - - char start_char; - if (fscanf(f, " %c", &start_char) != 1) goto exit; - if (start_char == '{') { - // a version 1 key has no version specifier. - key->exponent = 3; - } else if (start_char == 'v') { - int version; - if (fscanf(f, "%d {", &version) != 1) goto exit; - if (version == 2) { - key->exponent = 65537; - } else { - goto exit; - } - } - - if (fscanf(f, " %i , 0x%x , { %u", - &(key->len), &(key->n0inv), &(key->n[0])) != 3) { - goto exit; - } - if (key->len != RSANUMWORDS) { - LOGE("key length (%d) does not match expected size\n", key->len); - goto exit; - } - for (i = 1; i < key->len; ++i) { - if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit; - } - if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit; - for (i = 1; i < key->len; ++i) { - if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit; - } - fscanf(f, " } } "); - - // if the line ends in a comma, this file has more keys. - switch (fgetc(f)) { - case ',': - // more keys to come. - break; - - case EOF: - done = true; - break; - - default: - LOGE("unexpected character between keys\n"); - goto exit; - } - - LOGI("read key e=%d\n", key->exponent); - } - } - - fclose(f); - return out; - -exit: - if (f) fclose(f); - free(out); - *numKeys = 0; - return NULL; -} - static int really_install_package(const char *path) { ui_set_background(BACKGROUND_ICON_INSTALLING); ui_print("Finding update package...\n"); ui_show_indeterminate_progress(); + + // Resolve symlink in case legacy /sdcard path is used + // Requires: symlink uses absolute path + char new_path[PATH_MAX]; + if (strlen(path) > 1) { + char *rest = strchr(path + 1, '/'); + if (rest != NULL) { + int readlink_length; + int root_length = rest - path; + char *root = malloc(root_length + 1); + strncpy(root, path, root_length); + root[root_length] = 0; + readlink_length = readlink(root, new_path, PATH_MAX); + if (readlink_length > 0) { + strncpy(new_path + readlink_length, rest, PATH_MAX - readlink_length); + path = new_path; + } + free(root); + } + } + LOGI("Update location: %s\n", path); if (ensure_path_mounted(path) != 0) { @@ -373,7 +301,7 @@ really_install_package(const char *path) if (signature_check_enabled) { int numKeys; - RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); + Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); if (loadedKeys == NULL) { LOGE("Failed to load keys\n"); return INSTALL_CORRUPT; diff --git a/loki_license.txt b/loki_license.txt new file mode 100644 index 000000000..bc2a91404 --- /dev/null +++ b/loki_license.txt @@ -0,0 +1,25 @@ +Copyright (c) 2013 Dan Rosenberg. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INFRAE OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/minadbd/Android.mk b/minadbd/Android.mk index 5a4de6828..5734f875c 100644 --- a/minadbd/Android.mk +++ b/minadbd/Android.mk @@ -25,6 +25,8 @@ LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE LOCAL_MODULE := libminadbd +LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include + LOCAL_STATIC_LIBRARIES := libcutils libc include $(BUILD_STATIC_LIBRARY) diff --git a/minui/Android.mk b/minui/Android.mk index 7a327f5b4..97ac87759 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -35,4 +35,14 @@ ifneq ($(BOARD_USE_CUSTOM_RECOVERY_FONT),) LOCAL_CFLAGS += -DBOARD_USE_CUSTOM_RECOVERY_FONT=$(BOARD_USE_CUSTOM_RECOVERY_FONT) endif +ifneq ($(TARGET_RECOVERY_LCD_BACKLIGHT_PATH),) + LOCAL_CFLAGS += -DRECOVERY_LCD_BACKLIGHT_PATH=$(TARGET_RECOVERY_LCD_BACKLIGHT_PATH) +endif + +# Some devices need kernel headers for graphics +ifeq ($(TARGET_PREBUILT_KERNEL),) + LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +endif + include $(BUILD_STATIC_LIBRARY) diff --git a/minui/events.c b/minui/events.c index a619df6af..eb4497e10 100644 --- a/minui/events.c +++ b/minui/events.c @@ -81,7 +81,7 @@ int ev_init(ev_callback input_cb, void *data) ev_fdinfo[ev_count].data = data; ev_count++; ev_dev_count++; - if(ev_dev_count == MAX_DEVICES) break; + if(ev_dev_count == (MAX_DEVICES + MAX_MISC_FDS)) break; } } diff --git a/minui/graphics.c b/minui/graphics.c index d4195982d..e9ac7247a 100644 --- a/minui/graphics.c +++ b/minui/graphics.c @@ -229,7 +229,7 @@ void gr_font_size(int *x, int *y) *y = gr_font->cheight; } -int gr_text(int x, int y, const char *s) +int gr_text(int x, int y, const char *s, int bold) { GGLContext *gl = gr_context; GRFont *font = gr_font; @@ -426,9 +426,21 @@ gr_pixel *gr_fb_data(void) void gr_fb_blank(bool blank) { +#ifdef RECOVERY_LCD_BACKLIGHT_PATH + int fd; + + fd = open(RECOVERY_LCD_BACKLIGHT_PATH, O_RDWR); + if (fd < 0) { + perror("cannot open LCD backlight"); + return; + } + write(fd, blank ? "000" : "127", 3); + close(fd); +#else int ret; ret = ioctl(gr_fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); if (ret < 0) perror("ioctl(): blank"); +#endif } diff --git a/minui/minui.h b/minui/minui.h index b28189880..e0f97cd9c 100644 --- a/minui/minui.h +++ b/minui/minui.h @@ -33,7 +33,7 @@ void gr_fb_blank(bool blank); void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void gr_fill(int x1, int y1, int x2, int y2); -int gr_text(int x, int y, const char *s); +int gr_text(int x, int y, const char *s, int bold); int gr_measure(const char *s); void gr_font_size(int *x, int *y); diff --git a/mounts.c b/mounts.c index e8b69e832..5dc5a1749 100644 --- a/mounts.c +++ b/mounts.c @@ -106,10 +106,10 @@ scan_mounted_volumes() */ bufp = buf; while (nbytes > 0) { - char device[64]; - char mount_point[64]; + char device[PATH_MAX]; + char mount_point[PATH_MAX]; char filesystem[64]; - char flags[128]; + char flags[256]; int matches; /* %as is a gnu extension that malloc()s a string for each field. diff --git a/nandroid.c b/nandroid.c index 77b348472..2052c4ead 100644 --- a/nandroid.c +++ b/nandroid.c @@ -20,6 +20,8 @@ #include #include +#include "libcrecovery/common.h" + #include "bootloader.h" #include "common.h" #include "cutils/properties.h" @@ -39,7 +41,7 @@ #include "flashutils/flashutils.h" #include -void nandroid_generate_timestamp_path(const char* backup_path) +void nandroid_generate_timestamp_path(char* backup_path) { time_t t = time(NULL); struct tm *tmp = localtime(&t); @@ -47,7 +49,7 @@ void nandroid_generate_timestamp_path(const char* backup_path) { struct timeval tp; gettimeofday(&tp, NULL); - sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec); + sprintf(backup_path, "/sdcard/clockworkmod/backup/%ld", tp.tv_sec); } else { @@ -62,7 +64,7 @@ static void ensure_directory(const char* dir) { } static int print_and_error(const char* message) { - ui_print("%s", message); + ui_print("%s\n", message); return 1; } @@ -78,7 +80,7 @@ static void nandroid_callback(const char* filename) char tmp[PATH_MAX]; strcpy(tmp, justfile); if (tmp[strlen(tmp) - 1] == '\n') - tmp[strlen(tmp) - 1] = NULL; + tmp[strlen(tmp) - 1] = '\0'; tmp[ui_get_text_cols() - 1] = '\0'; nandroid_files_count++; ui_increment_frame(); @@ -118,7 +120,7 @@ static int mkyaffs2image_wrapper(const char* backup_path, const char* backup_fil } while (fgets(tmp, PATH_MAX, fp) != NULL) { - tmp[PATH_MAX - 1] = NULL; + tmp[PATH_MAX - 1] = '\0'; if (callback) nandroid_callback(tmp); } @@ -126,25 +128,38 @@ static int mkyaffs2image_wrapper(const char* backup_path, const char* backup_fil return __pclose(fp); } -static int tar_compress_wrapper(const char* backup_path, const char* backup_file_image, int callback) { - char tmp[PATH_MAX]; - sprintf(tmp, "cd $(dirname %s) ; touch %s.tar ; (tar cv --exclude=data/data/com.google.android.music/files/* %s $(basename %s) | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.) 2> /proc/self/fd/1 ; exit $?", backup_path, backup_file_image, strcmp(backup_path, "/data") == 0 && is_data_media() ? "--exclude 'media'" : "", backup_path, backup_file_image); +static int do_tar_compress(char* command, int callback) { + char buf[PATH_MAX]; - FILE *fp = __popen(tmp, "r"); + FILE *fp = __popen(command, "r"); if (fp == NULL) { - ui_print("Unable to execute tar.\n"); + ui_print("Unable to execute tar command!\n"); return -1; } - while (fgets(tmp, PATH_MAX, fp) != NULL) { - tmp[PATH_MAX - 1] = NULL; + while (fgets(buf, PATH_MAX, fp) != NULL) { + buf[PATH_MAX - 1] = '\0'; if (callback) - nandroid_callback(tmp); + nandroid_callback(buf); } return __pclose(fp); } +static int tar_compress_wrapper(const char* backup_path, const char* backup_file_image, int callback) { + char tmp[PATH_MAX]; + sprintf(tmp, "cd $(dirname %s) ; touch %s.tar ; (tar cv --exclude=data/data/com.google.android.music/files/* %s $(basename %s) | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.) 2> /proc/self/fd/1 ; exit $?", backup_path, backup_file_image, strcmp(backup_path, "/data") == 0 && is_data_media() ? "--exclude 'media'" : "", backup_path, backup_file_image); + + return do_tar_compress(tmp, callback); +} + +static int tar_gzip_compress_wrapper(const char* backup_path, const char* backup_file_image, int callback) { + char tmp[PATH_MAX]; + sprintf(tmp, "cd $(dirname %s) ; touch %s.tar.gz ; (tar cv --exclude=data/data/com.google.android.music/files/* %s $(basename %s) | pigz -c | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.gz.) 2> /proc/self/fd/1 ; exit $?", backup_path, backup_file_image, strcmp(backup_path, "/data") == 0 && is_data_media() ? "--exclude 'media'" : "", backup_path, backup_file_image); + + return do_tar_compress(tmp, callback); +} + static int tar_dump_wrapper(const char* backup_path, const char* backup_file_image, int callback) { char tmp[PATH_MAX]; sprintf(tmp, "cd $(dirname %s); tar cv --exclude=data/data/com.google.android.music/files/* %s $(basename %s) 2> /dev/null | cat", backup_path, strcmp(backup_path, "/data") == 0 && is_data_media() ? "--exclude 'media'" : "", backup_path); @@ -192,7 +207,7 @@ static int dedupe_compress_wrapper(const char* backup_path, const char* backup_f } while (fgets(tmp, PATH_MAX, fp) != NULL) { - tmp[PATH_MAX - 1] = NULL; + tmp[PATH_MAX - 1] = '\0'; if (callback) nandroid_callback(tmp); } @@ -211,7 +226,7 @@ static void refresh_default_backup_handler() { strcpy(fmt, forced_backup_format); } else { - ensure_path_mounted("/sdcard"); + ensure_path_mounted(get_primary_storage_path()); FILE* f = fopen(NANDROID_BACKUP_FORMAT_FILE, "r"); if (NULL == f) { default_backup_handler = tar_compress_wrapper; @@ -220,9 +235,13 @@ static void refresh_default_backup_handler() { fread(fmt, 1, sizeof(fmt), f); fclose(f); } - fmt[3] = NULL; + fmt[3] = '\0'; if (0 == strcmp(fmt, "dup")) default_backup_handler = dedupe_compress_wrapper; + else if (0 == strcmp(fmt, "tgz")) + default_backup_handler = tar_gzip_compress_wrapper; + else if (0 == strcmp(fmt, "tar")) + default_backup_handler = tar_compress_wrapper; else default_backup_handler = tar_compress_wrapper; } @@ -231,6 +250,8 @@ unsigned nandroid_get_default_backup_format() { refresh_default_backup_handler(); if (default_backup_handler == dedupe_compress_wrapper) { return NANDROID_BACKUP_FORMAT_DUP; + } else if (default_backup_handler == tar_gzip_compress_wrapper) { + return NANDROID_BACKUP_FORMAT_TGZ; } else { return NANDROID_BACKUP_FORMAT_TAR; } @@ -242,7 +263,7 @@ static nandroid_backup_handler get_backup_handler(const char *backup_path) { ui_print("Unable to find volume.\n"); return NULL; } - MountedVolume *mv = find_mounted_volume_by_mount_point(v->mount_point); + const MountedVolume *mv = find_mounted_volume_by_mount_point(v->mount_point); if (mv == NULL) { ui_print("Unable to find mounted volume: %s\n", v->mount_point); return NULL; @@ -267,6 +288,7 @@ int nandroid_backup_partition_extended(const char* backup_path, const char* moun int ret = 0; char name[PATH_MAX]; + char tmp[PATH_MAX]; strcpy(name, basename(mount_point)); struct stat file_info; @@ -278,10 +300,9 @@ int nandroid_backup_partition_extended(const char* backup_path, const char* moun return ret; } compute_directory_stats(mount_point); - char tmp[PATH_MAX]; scan_mounted_volumes(); Volume *v = volume_for_path(mount_point); - MountedVolume *mv = NULL; + const MountedVolume *mv = NULL; if (v != NULL) mv = find_mounted_volume_by_mount_point(v->mount_point); @@ -326,9 +347,9 @@ int nandroid_backup_partition(const char* backup_path, const char* root) { strcpy(tmp, "/proc/self/fd/1"); else sprintf(tmp, "%s/%s.img", backup_path, name); - ui_print("Backing up %s image...\n", name); - if (0 != (ret = backup_raw_partition(vol->fs_type, vol->device, tmp))) { + ui_print("Backing up %s image...\n", name); + if (0 != (ret = backup_raw_partition(vol->fs_type, vol->blk_device, tmp))) { ui_print("Error while backing up %s image!", name); return ret; } @@ -361,18 +382,21 @@ int nandroid_backup(const char* backup_path) return print_and_error("Can't mount backup path.\n"); } - Volume* volume = volume_for_path(backup_path); + Volume* volume; + if (is_data_media_volume_path(backup_path)) + volume = volume_for_path("/data"); + else + volume = volume_for_path(backup_path); if (NULL == volume) return print_and_error("Unable to find volume for backup path.\n"); - if (is_data_media_volume_path(volume->mount_point)) - volume = volume_for_path("/data"); int ret; - struct statfs s; + struct statfs sfs; + struct stat s; if (NULL != volume) { - if (0 != (ret = statfs(volume->mount_point, &s))) + if (0 != (ret = statfs(volume->mount_point, &sfs))) return print_and_error("Unable to stat backup path.\n"); - uint64_t bavail = s.f_bavail; - uint64_t bsize = s.f_bsize; + uint64_t bavail = sfs.f_bavail; + uint64_t bsize = sfs.f_bsize; uint64_t sdcard_free = bavail * bsize; uint64_t sdcard_free_mb = sdcard_free / (uint64_t)(1024 * 1024); ui_print("SD Card space free: %lluMB\n", sdcard_free_mb); @@ -392,14 +416,14 @@ int nandroid_backup(const char* backup_path) return ret; Volume *vol = volume_for_path("/wimax"); - if (vol != NULL && 0 == stat(vol->device, &s)) + if (vol != NULL && 0 == stat(vol->blk_device, &s)) { char serialno[PROPERTY_VALUE_MAX]; ui_print("Backing up WiMAX...\n"); serialno[0] = 0; property_get("ro.serialno", serialno, ""); sprintf(tmp, "%s/wimax.%s.img", backup_path, serialno); - ret = backup_raw_partition(vol->fs_type, vol->device, tmp); + ret = backup_raw_partition(vol->fs_type, vol->blk_device, tmp); if (0 != ret) return print_and_error("Error while dumping WiMAX image!\n"); } @@ -423,11 +447,11 @@ int nandroid_backup(const char* backup_path) return ret; } - if (is_data_media() || 0 != stat("/sdcard/.android_secure", &s)) { - ui_print("No /sdcard/.android_secure found. Skipping backup of applications on external storage.\n"); + if (is_data_media() || 0 != stat(get_android_secure_path(), &s)) { + ui_print("No .android_secure found. Skipping backup of applications on external storage.\n"); } else { - if (0 != (ret = nandroid_backup_partition_extended(backup_path, "/sdcard/.android_secure", 0))) + if (0 != (ret = nandroid_backup_partition_extended(backup_path, get_android_secure_path(), 0))) return ret; } @@ -435,14 +459,14 @@ int nandroid_backup(const char* backup_path) return ret; vol = volume_for_path("/sd-ext"); - if (vol == NULL || 0 != stat(vol->device, &s)) + if (vol == NULL || 0 != stat(vol->blk_device, &s)) { - ui_print("No sd-ext found. Skipping backup of sd-ext.\n"); + LOGI("No sd-ext found. Skipping backup of sd-ext.\n"); } else { if (0 != ensure_path_mounted("/sd-ext")) - ui_print("Could not mount sd-ext. sd-ext backup may not be supported on this device. Skipping backup of sd-ext.\n"); + LOGI("Could not mount sd-ext. sd-ext backup may not be supported on this device. Skipping backup of sd-ext.\n"); else if (0 != (ret = nandroid_backup_partition(backup_path, "/sd-ext"))) return ret; } @@ -507,7 +531,7 @@ static int unyaffs_wrapper(const char* backup_file_image, const char* backup_pat } while (fgets(tmp, PATH_MAX, fp) != NULL) { - tmp[PATH_MAX - 1] = NULL; + tmp[PATH_MAX - 1] = '\0'; if (callback) nandroid_callback(tmp); } @@ -515,24 +539,38 @@ static int unyaffs_wrapper(const char* backup_file_image, const char* backup_pat return __pclose(fp); } -static int tar_extract_wrapper(const char* backup_file_image, const char* backup_path, int callback) { - char tmp[PATH_MAX]; - sprintf(tmp, "cd $(dirname %s) ; cat %s* | tar xv ; exit $?", backup_path, backup_file_image); - FILE *fp = __popen(tmp, "r"); +static int do_tar_extract(char* command, int callback) { + char buf[PATH_MAX]; + + FILE *fp = __popen(command, "r"); if (fp == NULL) { - ui_print("Unable to execute tar.\n"); + ui_print("Unable to execute tar command.\n"); return -1; } - while (fgets(tmp, PATH_MAX, fp) != NULL) { - tmp[PATH_MAX - 1] = NULL; + while (fgets(buf, PATH_MAX, fp) != NULL) { + buf[PATH_MAX - 1] = '\0'; if (callback) - nandroid_callback(tmp); + nandroid_callback(buf); } return __pclose(fp); } +static int tar_gzip_extract_wrapper(const char* backup_file_image, const char* backup_path, int callback) { + char tmp[PATH_MAX]; + sprintf(tmp, "cd $(dirname %s) ; cat %s* | pigz -d -c | tar xv ; exit $?", backup_path, backup_file_image); + + return do_tar_extract(tmp, callback); +} + +static int tar_extract_wrapper(const char* backup_file_image, const char* backup_path, int callback) { + char tmp[PATH_MAX]; + sprintf(tmp, "cd $(dirname %s) ; cat %s* | tar xv ; exit $?", backup_path, backup_file_image); + + return do_tar_extract(tmp, callback); +} + static int dedupe_extract_wrapper(const char* backup_file_image, const char* backup_path, int callback) { char tmp[PATH_MAX]; char blob_dir[PATH_MAX]; @@ -573,7 +611,7 @@ static nandroid_restore_handler get_restore_handler(const char *backup_path) { return NULL; } scan_mounted_volumes(); - MountedVolume *mv = find_mounted_volume_by_mount_point(v->mount_point); + const MountedVolume *mv = find_mounted_volume_by_mount_point(v->mount_point); if (mv == NULL) { ui_print("Unable to find mounted volume: %s\n", v->mount_point); return NULL; @@ -603,12 +641,12 @@ int nandroid_restore_partition_extended(const char* backup_path, const char* mou char* name = basename(mount_point); nandroid_restore_handler restore_handler = NULL; - const char *filesystems[] = { "yaffs2", "ext2", "ext3", "ext4", "vfat", "rfs", NULL }; + const char *filesystems[] = { "yaffs2", "ext2", "ext3", "ext4", "vfat", "rfs", "f2fs", NULL }; const char* backup_filesystem = NULL; Volume *vol = volume_for_path(mount_point); const char *device = NULL; if (vol != NULL) - device = vol->device; + device = vol->blk_device; char tmp[PATH_MAX]; sprintf(tmp, "%s/%s.img", backup_path, name); @@ -619,27 +657,33 @@ int nandroid_restore_partition_extended(const char* backup_path, const char* mou restore_handler = tar_extract_wrapper; strcpy(tmp, "/proc/self/fd/0"); } - else if (0 != (ret = statfs(tmp, &file_info))) { + else if (0 != (ret = stat(tmp, &file_info))) { // can't find the backup, it may be the new backup format? // iterate through the backup types printf("couldn't find default\n"); - char *filesystem; + const char *filesystem; int i = 0; while ((filesystem = filesystems[i]) != NULL) { sprintf(tmp, "%s/%s.%s.img", backup_path, name, filesystem); - if (0 == (ret = statfs(tmp, &file_info))) { + if (0 == (ret = stat(tmp, &file_info))) { backup_filesystem = filesystem; restore_handler = unyaffs_wrapper; break; } sprintf(tmp, "%s/%s.%s.tar", backup_path, name, filesystem); - if (0 == (ret = statfs(tmp, &file_info))) { + if (0 == (ret = stat(tmp, &file_info))) { backup_filesystem = filesystem; restore_handler = tar_extract_wrapper; break; } + sprintf(tmp, "%s/%s.%s.tar.gz", backup_path, name, filesystem); + if (0 == (ret = stat(tmp, &file_info))) { + backup_filesystem = filesystem; + restore_handler = tar_gzip_extract_wrapper; + break; + } sprintf(tmp, "%s/%s.%s.dup", backup_path, name, filesystem); - if (0 == (ret = statfs(tmp, &file_info))) { + if (0 == (ret = stat(tmp, &file_info))) { backup_filesystem = filesystem; restore_handler = dedupe_extract_wrapper; break; @@ -742,8 +786,8 @@ int nandroid_restore_partition(const char* backup_path, const char* root) { sprintf(tmp, "%s%s.img", backup_path, root); ui_print("Restoring %s image...\n", name); - if (0 != (ret = restore_raw_partition(vol->fs_type, vol->device, tmp))) { - ui_print("Error while flashing %s image!", name); + if (0 != (ret = restore_raw_partition(vol->fs_type, vol->blk_device, tmp))) { + ui_print("Error while flashing %s image!\n", name); return ret; } return 0; @@ -777,7 +821,7 @@ int nandroid_restore(const char* backup_path, int restore_boot, int restore_syst struct stat s; Volume *vol = volume_for_path("/wimax"); - if (restore_wimax && vol != NULL && 0 == stat(vol->device, &s)) + if (restore_wimax && vol != NULL && 0 == stat(vol->blk_device, &s)) { char serialno[PROPERTY_VALUE_MAX]; @@ -799,7 +843,7 @@ int nandroid_restore(const char* backup_path, int restore_boot, int restore_syst if (0 != (ret = format_volume("/wimax"))) return print_and_error("Error while formatting wimax!\n"); ui_print("Restoring WiMAX image...\n"); - if (0 != (ret = restore_raw_partition(vol->fs_type, vol->device, tmp))) + if (0 != (ret = restore_raw_partition(vol->fs_type, vol->blk_device, tmp))) return ret; } } @@ -821,7 +865,7 @@ int nandroid_restore(const char* backup_path, int restore_boot, int restore_syst return ret; } - if (restore_data && 0 != (ret = nandroid_restore_partition_extended(backup_path, "/sdcard/.android_secure", 0))) + if (restore_data && 0 != (ret = nandroid_restore_partition_extended(backup_path, get_android_secure_path(), 0))) return ret; if (restore_cache && 0 != (ret = nandroid_restore_partition_extended(backup_path, "/cache", 0))) @@ -899,7 +943,9 @@ int bu_main(int argc, char** argv) { } // fprintf(stderr, "%d %d %s\n", fd, STDOUT_FILENO, argv[3]); - return nandroid_dump(partition); + int ret = nandroid_dump(partition); + sleep(10); + return ret; } else if (strcmp(argv[2], "restore") == 0) { if (argc != 3) { @@ -926,6 +972,7 @@ int bu_main(int argc, char** argv) { int nandroid_main(int argc, char** argv) { load_volume_table(); + char backup_path[PATH_MAX]; if (argc > 3 || argc < 2) return nandroid_usage(); @@ -935,7 +982,6 @@ int nandroid_main(int argc, char** argv) if (argc != 2) return nandroid_usage(); - char backup_path[PATH_MAX]; nandroid_generate_timestamp_path(backup_path); return nandroid_backup(backup_path); } @@ -946,7 +992,7 @@ int nandroid_main(int argc, char** argv) return nandroid_usage(); return nandroid_restore(argv[2], 1, 1, 1, 1, 1, 0, 0, 0, 0); } - + if (strcmp("dump", argv[1]) == 0) { if (argc != 3) diff --git a/nandroid.h b/nandroid.h index 0882f46f3..01a6e61d3 100644 --- a/nandroid.h +++ b/nandroid.h @@ -14,5 +14,6 @@ unsigned nandroid_get_default_backup_format(); #define NANDROID_BACKUP_FORMAT_FILE "/sdcard/clockworkmod/.default_backup_format" #define NANDROID_BACKUP_FORMAT_TAR 0 #define NANDROID_BACKUP_FORMAT_DUP 1 +#define NANDROID_BACKUP_FORMAT_TGZ 2 #endif diff --git a/reboot.c b/reboot.c new file mode 100644 index 000000000..374907d28 --- /dev/null +++ b/reboot.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 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 +#include +#include +#include + +int reboot_main(int argc, char *argv[]) +{ + int ret; + size_t prop_len; + char property_val[PROPERTY_VALUE_MAX]; + const char *cmd = "reboot"; + char *optarg = ""; + + opterr = 0; + do { + int c; + + c = getopt(argc, argv, "p"); + + if (c == EOF) { + break; + } + + switch (c) { + case 'p': + cmd = "shutdown"; + break; + case '?': + fprintf(stderr, "usage: %s [-p] [rebootcommand]\n", argv[0]); + exit(EXIT_FAILURE); + } + } while (1); + + if(argc > optind + 1) { + fprintf(stderr, "%s: too many arguments\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (argc > optind) + optarg = argv[optind]; + + prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg); + if (prop_len >= sizeof(property_val)) { + fprintf(stderr, "reboot command too long: %s\n", optarg); + exit(EXIT_FAILURE); + } + + ret = property_set(ANDROID_RB_PROPERTY, property_val); + if(ret < 0) { + perror("reboot"); + exit(EXIT_FAILURE); + } + fprintf(stderr, "Done\n"); + return 0; +} diff --git a/recovery.c b/recovery.c old mode 100644 new mode 100755 index 7fb6eb94c..3ade4fb41 --- a/recovery.c +++ b/recovery.c @@ -41,18 +41,25 @@ #include "roots.h" #include "recovery_ui.h" +#include "voldclient/voldclient.h" + #include "adb_install.h" #include "minadbd/adb.h" +#include "firmware.h" #include "extendedcommands.h" #include "flashutils/flashutils.h" #include "dedupe/dedupe.h" +#include "voldclient/voldclient.h" + +#include "recovery_cmds.h" struct selabel_handle *sehandle = NULL; static const struct option OPTIONS[] = { { "send_intent", required_argument, NULL, 's' }, { "update_package", required_argument, NULL, 'u' }, + { "headless", no_argument, NULL, 'h' }, { "wipe_data", no_argument, NULL, 'w' }, { "wipe_cache", no_argument, NULL, 'c' }, { "show_text", no_argument, NULL, 't' }, @@ -60,16 +67,19 @@ static const struct option OPTIONS[] = { { NULL, 0, NULL, 0 }, }; +#define LAST_LOG_FILE "/cache/recovery/last_log" + +static const char *CACHE_LOG_DIR = "/cache/recovery"; static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *INTENT_FILE = "/cache/recovery/intent"; static const char *LOG_FILE = "/cache/recovery/log"; -static const char *LAST_LOG_FILE = "/cache/recovery/last_log"; +static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install"; static const char *CACHE_ROOT = "/cache"; static const char *SDCARD_ROOT = "/sdcard"; static int allow_display_toggle = 0; static int poweroff = 0; -static const char *SDCARD_PACKAGE_FILE = "/sdcard/update.zip"; static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; +static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install"; static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; extern UIParameters ui_parameters; // from ui.c @@ -203,6 +213,7 @@ get_args(int *argc, char ***argv) { if (*argc <= 1) { FILE *fp = fopen_path(COMMAND_FILE, "r"); if (fp != NULL) { + char *token; char *argv0 = (*argv)[0]; *argv = (char **) malloc(sizeof(char *) * MAX_ARGS); (*argv)[0] = argv0; // use the same program name @@ -210,7 +221,12 @@ get_args(int *argc, char ***argv) { char buf[MAX_ARG_LENGTH]; for (*argc = 1; *argc < MAX_ARGS; ++*argc) { if (!fgets(buf, sizeof(buf), fp)) break; - (*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline. + token = strtok(buf, "\r\n"); + if (token != NULL) { + (*argv)[*argc] = strdup(token); // Strip newline. + } else { + --*argc; + } } check_and_fclose(fp, COMMAND_FILE); @@ -243,15 +259,13 @@ set_sdcard_update_bootloader_message() { static long tmplog_offset = 0; static void -copy_log_file(const char* destination, int append) { +copy_log_file(const char* source, const char* destination, int append) { FILE *log = fopen_path(destination, append ? "a" : "w"); if (log == NULL) { LOGE("Can't open %s\n", destination); } else { - FILE *tmplog = fopen(TEMPORARY_LOG_FILE, "r"); - if (tmplog == NULL) { - LOGE("Can't open %s\n", TEMPORARY_LOG_FILE); - } else { + FILE *tmplog = fopen(source, "r"); + if (tmplog != NULL) { if (append) { fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write } @@ -260,12 +274,40 @@ copy_log_file(const char* destination, int append) { if (append) { tmplog_offset = ftell(tmplog); } - check_and_fclose(tmplog, TEMPORARY_LOG_FILE); + check_and_fclose(tmplog, source); } check_and_fclose(log, destination); } } +// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max +// Overwrites any existing last_log.$max. +static void +rotate_last_logs(int max) { + char oldfn[256]; + char newfn[256]; + + int i; + for (i = max-1; i >= 0; --i) { + snprintf(oldfn, sizeof(oldfn), (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i); + snprintf(newfn, sizeof(newfn), LAST_LOG_FILE ".%d", i+1); + // ignore errors + rename(oldfn, newfn); + } +} + +static void +copy_logs() { + // Copy logs to cache so the system can find out what happened. + copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); + copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); + copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); + chmod(LOG_FILE, 0600); + chown(LOG_FILE, 1000, 1000); // system user + chmod(LAST_LOG_FILE, 0640); + chmod(LAST_INSTALL_FILE, 0644); + sync(); +} // clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and @@ -284,10 +326,7 @@ finish_recovery(const char *send_intent) { } } - // Copy logs to cache so the system can find out what happened. - copy_log_file(LOG_FILE, true); - copy_log_file(LAST_LOG_FILE, false); - chmod(LAST_LOG_FILE, 0640); + copy_logs(); // Reset to normal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; @@ -303,20 +342,95 @@ finish_recovery(const char *send_intent) { sync(); // For good measure. } +typedef struct _saved_log_file { + char* name; + struct stat st; + unsigned char* data; + struct _saved_log_file* next; +} saved_log_file; + static int erase_volume(const char *volume) { + bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); + ui_set_background(BACKGROUND_ICON_INSTALLING); ui_show_indeterminate_progress(); + + saved_log_file* head = NULL; + + if (is_cache) { + // If we're reformatting /cache, we load any + // "/cache/recovery/last*" files into memory, so we can restore + // them after the reformat. + + ensure_path_mounted(volume); + + DIR* d; + struct dirent* de; + d = opendir(CACHE_LOG_DIR); + if (d) { + char path[PATH_MAX]; + strcpy(path, CACHE_LOG_DIR); + strcat(path, "/"); + int path_len = strlen(path); + while ((de = readdir(d)) != NULL) { + if (strncmp(de->d_name, "last", 4) == 0) { + saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file)); + strcpy(path+path_len, de->d_name); + p->name = strdup(path); + if (stat(path, &(p->st)) == 0) { + // truncate files to 512kb + if (p->st.st_size > (1 << 19)) { + p->st.st_size = 1 << 19; + } + p->data = (unsigned char*) malloc(p->st.st_size); + FILE* f = fopen(path, "rb"); + fread(p->data, 1, p->st.st_size, f); + fclose(f); + p->next = head; + head = p; + } else { + free(p); + } + } + } + closedir(d); + } else { + if (errno != ENOENT) { + printf("opendir failed: %s\n", strerror(errno)); + } + } + } + ui_print("Formatting %s...\n", volume); - if (strcmp(volume, "/cache") == 0) { + ensure_path_unmounted(volume); + int result = format_volume(volume); + + if (is_cache) { + while (head) { + FILE* f = fopen_path(head->name, "wb"); + if (f) { + fwrite(head->data, 1, head->st.st_size, f); + fclose(f); + chmod(head->name, head->st.st_mode); + chown(head->name, head->st.st_uid, head->st.st_gid); + } + free(head->name); + free(head->data); + saved_log_file* temp = head->next; + free(head); + head = temp; + } + // Any part of the log we'd copied to cache is now gone. // Reset the pointer so we copy from the beginning of the temp // log. tmplog_offset = 0; + copy_logs(); } - return format_volume(volume); + return result; } static char* @@ -409,21 +523,21 @@ copy_sideloaded_package(const char* original_path) { return strdup(copy_path); } -static char** -prepend_title(char** headers) { - char* title[] = { EXPAND(RECOVERY_VERSION), +static const char** +prepend_title(const char** headers) { + const char* title[] = { EXPAND(RECOVERY_VERSION), "", NULL }; // count the number of lines in our title, plus the // caller-provided headers. int count = 0; - char** p; + const char** p; for (p = title; *p; ++p, ++count); for (p = headers; *p; ++p, ++count); - char** new_headers = malloc((count+1) * sizeof(char*)); - char** h = new_headers; + const char** new_headers = malloc((count+1) * sizeof(const char*)); + const char** h = new_headers; for (p = title; *p; ++p, ++h) *h = *p; for (p = headers; *p; ++p, ++h) *h = *p; *h = NULL; @@ -432,7 +546,7 @@ prepend_title(char** headers) { } int -get_menu_selection(char** headers, char** items, int menu_only, +get_menu_selection(const char** headers, char** items, int menu_only, int initial_selection) { // throw away keys pressed previously, so user doesn't // accidentally trigger menu items. @@ -440,7 +554,8 @@ get_menu_selection(char** headers, char** items, int menu_only, int item_count = ui_start_menu(headers, items, initial_selection); int selected = initial_selection; - int chosen_item = -1; + int chosen_item = -1; // NO_ACTION + int wrap_count = 0; while (chosen_item < 0 && chosen_item != GO_BACK) { int key = ui_wait_key(); @@ -455,9 +570,12 @@ get_menu_selection(char** headers, char** items, int menu_only, return ITEM_REBOOT; } } - else if (key == -2) { + else if (key == -2) { // we are returning from ui_cancel_wait_key(): trigger a GO_BACK return GO_BACK; } + else if (key == -3) { // an USB device was plugged in (returning from ui_wait_key()) + return REFRESH; + } int action = ui_handle_key(key, visible); @@ -491,6 +609,21 @@ get_menu_selection(char** headers, char** items, int menu_only, } else if (!menu_only) { chosen_item = action; } + + if (abs(selected - old_selected) > 1) { + wrap_count++; + if (wrap_count == 5) { + wrap_count = 0; + if (ui_get_rainbow_mode()) { + ui_set_rainbow_mode(0); + ui_print("Rainbow mode disabled\n"); + } + else { + ui_set_rainbow_mode(1); + ui_print("Rainbow mode enabled!\n"); + } + } + } } ui_end_menu(); @@ -521,7 +654,7 @@ update_directory(const char* path, const char* unmount_when_done) { return 0; } - char** headers = prepend_title(MENU_HEADERS); + const char** headers = prepend_title(MENU_HEADERS); int d_size = 0; int d_alloc = 10; @@ -681,15 +814,24 @@ wipe_data(int confirm) { erase_volume("/datadata"); } erase_volume("/sd-ext"); - erase_volume("/sdcard/.android_secure"); + erase_volume(get_android_secure_path()); ui_print("Data wipe complete.\n"); } +static void headless_wait() { + ui_show_text(0); + const char** headers = prepend_title((const char**)MENU_HEADERS); + for(;;) { + finish_recovery(NULL); + get_menu_selection(headers, MENU_ITEMS, 0, 0); + } +} + int ui_menu_level = 1; int ui_root_menu = 0; static void prompt_and_wait() { - char** headers = prepend_title((const char**)MENU_HEADERS); + const char** headers = prepend_title((const char**)MENU_HEADERS); for (;;) { finish_recovery(NULL); @@ -710,29 +852,13 @@ prompt_and_wait() { chosen_item = device_perform_action(chosen_item); int status; - switch (chosen_item) { - case ITEM_REBOOT: - poweroff=0; - return; + int ret = 0; - case ITEM_WIPE_DATA: - wipe_data(ui_text_visible()); - if (!ui_text_visible()) return; - break; - - case ITEM_WIPE_CACHE: - if (confirm_selection("Confirm wipe?", "Yes - Wipe Cache")) - { - ui_print("\n-- Wiping cache...\n"); - erase_volume("/cache"); - ui_print("Cache wipe complete.\n"); - if (!ui_text_visible()) return; - } - break; - - case ITEM_APPLY_SDCARD: - show_install_update_menu(); - break; + for (;;) { + switch (chosen_item) { + case ITEM_REBOOT: + poweroff = 0; + return; case ITEM_APPLY_SIDELOAD: if(is_dualsystem()) { @@ -746,21 +872,37 @@ prompt_and_wait() { else apply_from_adb(); break; - case ITEM_NANDROID: - show_nandroid_menu(); - break; + case ITEM_WIPE_CACHE: + if (confirm_selection("Confirm wipe?", "Yes - Wipe Cache")) + { + ui_print("\n-- Wiping cache...\n"); + erase_volume("/cache"); + ui_print("Cache wipe complete.\n"); + if (!ui_text_visible()) return; + } + break; - case ITEM_PARTITION: - show_partition_menu(); - break; + case ITEM_APPLY_ZIP: + ret = show_install_update_menu(); + break; - case ITEM_ADVANCED: - show_advanced_menu(); - break; + case ITEM_NANDROID: + ret = show_nandroid_menu(); + break; - case ITEM_POWEROFF: - poweroff = 1; - return; + case ITEM_PARTITION: + ret = show_partition_menu(); + break; + + case ITEM_ADVANCED: + ret = show_advanced_menu(); + break; + } + if (ret == REFRESH) { + ret = 0; + continue; + } + break; } } } @@ -797,12 +939,61 @@ setup_adbd() { check_and_fclose(file_src, key_src); } } + ignore_data_media_workaround(1); ensure_path_unmounted("/data"); + ignore_data_media_workaround(0); // Trigger (re)start of adb daemon property_set("service.adb.root", "1"); } +// call a clean reboot +void reboot_main_system(int cmd, int flags, char *arg) { + verify_root_and_recovery(); + finish_recovery(NULL); // sync() in here + vold_unmount_all(); + android_reboot(cmd, flags, arg); +} + +static int v_changed = 0; +int volumes_changed() { + int ret = v_changed; + if (v_changed == 1) + v_changed = 0; + return ret; +} + +static int handle_volume_hotswap(char* label, char* path) { + v_changed = 1; + return 0; +} + +static int handle_volume_state_changed(char* label, char* path, int state) { + int log = -1; + if (state == State_Checking || state == State_Mounted || state == State_Idle) { + // do not ever log to screen mount/unmount events for sdcards + if (strncmp(path, "/storage/sdcard", 15) == 0) + log = 0; + else log = 1; + } + else if (state == State_Formatting || state == State_Shared) { + log = 1; + } + + if (log == 0) + LOGI("%s: %s\n", path, volume_state_to_string(state)); + else if (log == 1) + ui_print("%s: %s\n", path, volume_state_to_string(state)); + + return 0; +} + +static struct vold_callbacks v_callbacks = { + .state_changed = handle_volume_state_changed, + .disk_added = handle_volume_hotswap, + .disk_removed = handle_volume_hotswap, +}; + int main(int argc, char **argv) { @@ -815,48 +1006,37 @@ main(int argc, char **argv) { // set by init umask(0); - if (strcmp(basename(argv[0]), "recovery") != 0) + char* command = argv[0]; + char* stripped = strrchr(argv[0], '/'); + if (stripped) + command = stripped + 1; + + if (strcmp(command, "recovery") != 0) { - if (strstr(argv[0], "minizip") != NULL) - return minizip_main(argc, argv); - if (strstr(argv[0], "dedupe") != NULL) - return dedupe_main(argc, argv); - if (strstr(argv[0], "flash_image") != NULL) - return flash_image_main(argc, argv); - if (strstr(argv[0], "volume") != NULL) - return volume_main(argc, argv); - if (strstr(argv[0], "edify") != NULL) - return edify_main(argc, argv); - if (strstr(argv[0], "dump_image") != NULL) - return dump_image_main(argc, argv); - if (strstr(argv[0], "erase_image") != NULL) - return erase_image_main(argc, argv); - if (strstr(argv[0], "mkyaffs2image") != NULL) - return mkyaffs2image_main(argc, argv); - if (strstr(argv[0], "make_ext4fs") != NULL) - return make_ext4fs_main(argc, argv); - if (strstr(argv[0], "unyaffs") != NULL) - return unyaffs_main(argc, argv); - if (strstr(argv[0], "nandroid")) - return nandroid_main(argc, argv); - if (strstr(argv[0], "bu") == argv[0] + strlen(argv[0]) - 2) - return bu_main(argc, argv); - if (strstr(argv[0], "reboot")) - return reboot_main(argc, argv); + struct recovery_cmd cmd = get_command(command); + if (cmd.name) + return cmd.main_func(argc, argv); + #ifdef BOARD_RECOVERY_HANDLES_MOUNT - if (strstr(argv[0], "mount") && argc == 2 && !strstr(argv[0], "umount")) + if (!strcmp(command, "mount") && argc == 2) { load_volume_table(); return ensure_path_mounted(argv[1]); } #endif - if (strstr(argv[0], "poweroff")){ - return reboot_main(argc, argv); + if (!strcmp(command, "setup_adbd")) { + load_volume_table(); + setup_adbd(); + return 0; + } + if (!strcmp(command, "start")) { + property_set("ctl.start", argv[1]); + return 0; + } + if (!strcmp(command, "stop")) { + property_set("ctl.stop", argv[1]); + return 0; } - if (strstr(argv[0], "setprop")) - return setprop_main(argc, argv); - if (strstr(argv[0], "getprop")) - return getprop_main(argc, argv); return busybox_driver(argc, argv); } __system("/sbin/postrecoveryboot.sh"); @@ -867,14 +1047,29 @@ main(int argc, char **argv) { // If these fail, there's not really anywhere to complain... freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL); freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL); - printf("Starting recovery on %s", ctime(&start)); + printf("Starting recovery on %s\n", ctime(&start)); device_ui_init(&ui_parameters); ui_init(); ui_print(EXPAND(RECOVERY_VERSION)"\n"); + +#ifdef BOARD_RECOVERY_SWIPE +#ifndef BOARD_TOUCH_RECOVERY + //display directions for swipe controls + ui_print("Swipe up/down to change selections.\n"); + ui_print("Swipe to the right for enter.\n"); + ui_print("Swipe to the left for back.\n"); +#endif +#endif + load_volume_table(); process_volumes(); + vold_client_start(&v_callbacks, 0); + vold_set_automount(1); + setup_legacy_storage_paths(); LOGI("Processing arguments.\n"); + ensure_path_mounted(LAST_LOG_FILE); + rotate_last_logs(10); get_args(&argc, &argv); int previous_runs = 0; @@ -882,6 +1077,7 @@ main(int argc, char **argv) { const char *update_package = NULL; int wipe_data = 0, wipe_cache = 0; int sideload = 0; + int headless = 0; LOGI("Checking arguments.\n"); int arg; @@ -895,6 +1091,11 @@ main(int argc, char **argv) { wipe_data = wipe_cache = 1; #endif break; + case 'h': + ui_set_background(BACKGROUND_ICON_CID); + ui_show_text(0); + headless = 1; + break; case 'c': wipe_cache = 1; break; case 't': ui_show_text(1); break; case 'l': sideload = 1; break; @@ -912,7 +1113,7 @@ main(int argc, char **argv) { if (!sehandle) { fprintf(stderr, "Warning: No file_contexts\n"); - // ui_print("Warning: No file_contexts\n"); + ui_print("Warning: No file_contexts\n"); } LOGI("device_recovery_start()\n"); @@ -947,22 +1148,26 @@ main(int argc, char **argv) { if (update_package != NULL) { status = install_package(update_package); - if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); + if (status != INSTALL_SUCCESS) { + copy_logs(); + ui_print("Installation aborted.\n"); + } } else if (wipe_data) { if (device_wipe_data()) status = INSTALL_ERROR; + ignore_data_media_workaround(1); if (erase_volume("/data")) status = INSTALL_ERROR; + ignore_data_media_workaround(0); if (has_datadata() && erase_volume("/datadata")) status = INSTALL_ERROR; if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; - if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n"); + if (status != INSTALL_SUCCESS) { + copy_logs(); + ui_print("Data wipe failed.\n"); + } } else if (wipe_cache) { if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; - if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n"); - } else if (sideload) { - signature_check_enabled = 0; - ui_set_show_text(1); - if (0 == apply_from_adb()) { - status = INSTALL_SUCCESS; - ui_set_show_text(0); + if (status != INSTALL_SUCCESS) { + copy_logs(); + ui_print("Cache wipe failed.\n"); } } else { LOGI("Checking for extendedcommand...\n"); @@ -972,9 +1177,11 @@ main(int argc, char **argv) { signature_check_enabled = 0; script_assert_enabled = 0; is_user_initiated_recovery = 1; - ui_set_show_text(1); - ui_set_background(BACKGROUND_ICON_CLOCKWORK); - + if (!headless) { + ui_set_show_text(1); + ui_set_background(BACKGROUND_ICON_CLOCKWORK); + } + if (extendedcommand_file_exists()) { LOGI("Running extendedcommand...\n"); int dualsystem_error = 0; @@ -1013,13 +1220,24 @@ main(int argc, char **argv) { } } - setup_adbd(); + if (sideload) { + signature_check_enabled = 0; + if (!headless) + ui_set_show_text(1); + if (0 == apply_from_adb()) { + status = INSTALL_SUCCESS; + ui_set_show_text(0); + } + } + if (headless) { + headless_wait(); + } if (status != INSTALL_SUCCESS && !is_user_initiated_recovery) { ui_set_show_text(1); ui_set_background(BACKGROUND_ICON_ERROR); } - if (status != INSTALL_SUCCESS || ui_text_visible()) { + else if (status != INSTALL_SUCCESS || ui_text_visible()) { prompt_and_wait(); } @@ -1032,6 +1250,8 @@ main(int argc, char **argv) { // Otherwise, get ready to boot the main system... finish_recovery(send_intent); + vold_unmount_all(); + sync(); if(!poweroff) { ui_print("Rebooting...\n"); diff --git a/recovery_cmds.h b/recovery_cmds.h new file mode 100644 index 000000000..3d1d1fad4 --- /dev/null +++ b/recovery_cmds.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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. + */ + +#ifndef _RECOVERY_CMDS_H +#define _RECOVERY_CMDS_H + +#include +#include + +#include "extendedcommands.h" +#include "nandroid.h" +#include "dedupe/dedupe.h" + +extern int minizip_main(int argc, char **argv); +extern int flash_image_main(int argc, char **argv); +extern int edify_main(int argc, char **argv); +extern int dump_image_main(int argc, char **argv); +extern int erase_image_main(int argc, char **argv); +extern int mkyaffs2image_main(int argc, char **argv); +extern int unyaffs_main(int argc, char **argv); +extern int make_ext4fs_main(int argc, char **argv); +extern int reboot_main(int argc, char **argv); +extern int poweroff_main(int argc, char **argv); +extern int setprop_main(int argc, char **argv); +extern int getprop_main(int argc, char **argv); +extern int fsck_msdos_main(int argc, char **argv); +extern int newfs_msdos_main(int argc, char **argv); +extern int vdc_main(int argc, char **argv); +extern int pigz_main(int argc, char **argv); +extern int sdcard_main(int argc, char **argv); +#ifdef USE_F2FS +extern int make_f2fs_main(int argc, char **argv); +extern int fsck_f2fs_main(int argc, char **argv); +extern int fibmap_main(int argc, char **argv); +#endif + +extern int busybox_driver(int argc, char **argv); + +struct recovery_cmd { + const char *name; + int (*main_func)(int argc, char **argv); +}; + +static const struct recovery_cmd recovery_cmds[] = { + { "minizip", minizip_main }, + { "dedupe", dedupe_main }, + { "flash_image", flash_image_main }, + { "volume", volume_main }, + { "edify", edify_main }, + { "dump_image", dump_image_main }, + { "erase_image", erase_image_main }, + { "mkyaffs2image", mkyaffs2image_main }, + { "unyaffs", unyaffs_main }, + { "make_ext4fs", make_ext4fs_main }, + { "nandroid", nandroid_main }, + { "bu", bu_main }, + { "reboot", reboot_main }, + { "poweroff", reboot_main }, + { "setprop", setprop_main }, + { "getprop", getprop_main }, + { "fsck_msdos", fsck_msdos_main }, + { "newfs_msdos", newfs_msdos_main }, + { "vdc", vdc_main }, + { "pigz", pigz_main }, + { "sdcard", sdcard_main }, +#ifdef USE_F2FS + { "mkfs.f2fs", make_f2fs_main }, + { "fsck.f2fs", fsck_f2fs_main }, + { "fibmap.f2fs", fibmap_main }, +#endif + { NULL, NULL }, +}; + +inline struct recovery_cmd get_command(char* command) { + int i; + + for (i = 0; recovery_cmds[i].name; i++) { + if (strcmp(command, recovery_cmds[i].name) == 0) + break; + } + + return recovery_cmds[i]; +} +#endif diff --git a/recovery_ui.h b/recovery_ui.h index 101e6be0d..3141a948e 100644 --- a/recovery_ui.h +++ b/recovery_ui.h @@ -65,6 +65,14 @@ extern int device_perform_action(int which); // are erased after this returns (whether it returns success or not). int device_wipe_data(); +// ui_wait_key() special return codes +/* +#define REBOOT -1 // ui_wait_key() timeout to reboot +#define CANCEL -2 // ui_cancel_wait_key() +*/ +#define REFRESH -3 + +// return actions by ui_handle_key() for get_menu_selection() #define NO_ACTION -1 #define HIGHLIGHT_UP -2 @@ -72,18 +80,18 @@ int device_wipe_data(); #define SELECT_ITEM -4 #define GO_BACK -5 +// main menu items for prompt_and_wait() #define ITEM_REBOOT 0 #define ITEM_APPLY_EXT 1 #define ITEM_APPLY_SDCARD 1 // historical synonym for ITEM_APPLY_EXT -#define ITEM_APPLY_SIDELOAD 2 -#define ITEM_WIPE_DATA 3 -#define ITEM_WIPE_CACHE 4 +#define ITEM_APPLY_ZIP 1 // used for installing an update from a zip +#define ITEM_WIPE_DATA 2 +#define ITEM_WIPE_CACHE 3 // unused in cwr #define ITEM_APPLY_CACHE 4 -#define ITEM_NANDROID 5 -#define ITEM_PARTITION 6 -#define ITEM_ADVANCED 7 -#define ITEM_POWEROFF 8 +#define ITEM_NANDROID 4 +#define ITEM_PARTITION 5 +#define ITEM_ADVANCED 6 // Header text to display above the main menu. extern char* MENU_HEADERS[]; @@ -95,11 +103,14 @@ extern char* MENU_ITEMS[]; extern int ui_root_menu; int -get_menu_selection(char** headers, char** items, int menu_only, int initial_selection); +get_menu_selection(const char** headers, char** items, int menu_only, int initial_selection); void set_sdcard_update_bootloader_message(); extern int ui_handle_key(int key, int visible); +// call a clean reboot +void reboot_main_system(int cmd, int flags, char *arg); + #endif diff --git a/res/images/icon_cid.png b/res/images/icon_cid.png new file mode 100644 index 000000000..fbc15f85f Binary files /dev/null and b/res/images/icon_cid.png differ diff --git a/roots.c b/roots.c old mode 100644 new mode 100755 index 972ca371e..841123fb8 --- a/roots.c +++ b/roots.c @@ -31,196 +31,115 @@ #include "common.h" #include "make_ext4fs.h" +#include +#include #include "flashutils/flashutils.h" #include "extendedcommands.h" -int num_volumes; -Volume* device_volumes; +#include "voldclient/voldclient.h" + +static struct fstab *fstab = NULL; int get_num_volumes() { - return num_volumes; + return fstab->num_entries; } Volume* get_device_volumes() { - return device_volumes; -} - -static int is_null(const char* sz) { - if (sz == NULL) - return 1; - if (strcmp("NULL", sz) == 0) - return 1; - return 0; + return fstab->recs; } -static char* dupe_string(const char* sz) { - if (is_null(sz)) - return NULL; - return strdup(sz); -} +void load_volume_table() { + int i; + int ret; -static int parse_options(char* options, Volume* volume) { - char* option; - while (option = strtok(options, ",")) { - options = NULL; - - if (strncmp(option, "length=", 7) == 0) { - volume->length = strtoll(option+7, NULL, 10); - } else if (strncmp(option, "fstype2=", 8) == 0) { - volume->fs_type2 = volume->fs_type; - volume->fs_type = strdup(option + 8); - } else if (strncmp(option, "fs_options=", 11) == 0) { - volume->fs_options = strdup(option + 11); - } else if (strncmp(option, "fs_options2=", 12) == 0) { - volume->fs_options2 = strdup(option + 12); - } else if (strncmp(option, "lun=", 4) == 0) { - volume->lun = strdup(option + 4); - } else { - LOGE("bad option \"%s\"\n", option); - return -1; - } + fstab = fs_mgr_read_fstab("/etc/recovery.fstab"); + if (!fstab) { + LOGE("failed to read /etc/recovery.fstab\n"); + return; } - return 0; -} -void load_volume_table() { - int alloc = 2; - device_volumes = malloc(alloc * sizeof(Volume)); - - // Insert an entry for /tmp, which is the ramdisk and is always mounted. - device_volumes[0].mount_point = "/tmp"; - device_volumes[0].fs_type = "ramdisk"; - device_volumes[0].device = NULL; - device_volumes[0].device2 = NULL; - device_volumes[0].fs_type2 = NULL; - device_volumes[0].fs_options = NULL; - device_volumes[0].fs_options2 = NULL; - device_volumes[0].lun = NULL; - device_volumes[0].length = 0; - num_volumes = 1; - - FILE* fstab = fopen("/etc/recovery.fstab", "r"); - if (fstab == NULL) { - LOGE("failed to open /etc/recovery.fstab (%s)\n", strerror(errno)); + ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk", 0); + if (ret < 0 ) { + LOGE("failed to add /tmp entry to fstab\n"); + fs_mgr_free_fstab(fstab); + fstab = NULL; return; } - char buffer[1024]; - int i; - while (fgets(buffer, sizeof(buffer)-1, fstab)) { - for (i = 0; buffer[i] && isspace(buffer[i]); ++i); - if (buffer[i] == '\0' || buffer[i] == '#') continue; - - char* original = strdup(buffer); - - char* mount_point = strtok(buffer+i, " \t\n"); - char* fs_type = strtok(NULL, " \t\n"); - char* device = strtok(NULL, " \t\n"); - // lines may optionally have a second device, to use if - // mounting the first one fails. - char* options = NULL; - char* device2 = strtok(NULL, " \t\n"); - if (device2) { - if (device2[0] == '/') { - options = strtok(NULL, " \t\n"); - } else { - options = device2; - device2 = NULL; - } - } + fprintf(stderr, "recovery filesystem table\n"); + fprintf(stderr, "=========================\n"); + for (i = 0; i < fstab->num_entries; ++i) { + Volume* v = &fstab->recs[i]; + fprintf(stderr, " %d %s %s %s %lld\n", i, v->mount_point, v->fs_type, + v->blk_device, v->length); + } + fprintf(stderr, "\n"); +} - if (mount_point && fs_type && device) { - while (num_volumes >= alloc) { - alloc *= 2; - device_volumes = realloc(device_volumes, alloc*sizeof(Volume)); - } +Volume* volume_for_path(const char* path) { + return fs_mgr_get_entry_for_mount_point(fstab, path); +} + +int is_primary_storage_voldmanaged() { + Volume* v; + v = volume_for_path("/storage/sdcard0"); + return fs_mgr_is_voldmanaged(v); +} - if(is_dualsystem() && strcmp(mount_point, "/data")==0) { - char resolved_path[PATH_MAX]; - ssize_t len; +static char* primary_storage_path = NULL; +char* get_primary_storage_path() { + if (primary_storage_path == NULL) { + if (volume_for_path("/storage/sdcard0")) + primary_storage_path = "/storage/sdcard0"; + else + primary_storage_path = "/sdcard"; + } + return primary_storage_path; +} - // resolve symlink - if((len = readlink(device, resolved_path, sizeof(resolved_path)-1)) != -1) - resolved_path[len] = '\0'; - else sprintf(resolved_path, "%s", device); +int get_num_extra_volumes() { + int num = 0; + int i; - // delete node - if(rename(resolved_path, "/dev/userdata_moved")!=0) - LOGE("could not move %s to %s!\n", resolved_path, "/dev/userdata_moved"); + for (i = 0; i < get_num_volumes(); i++) { + Volume* v = get_device_volumes() + i; + if ((strcmp("/external_sd", v->mount_point) == 0) || + ((strcmp(get_primary_storage_path(), v->mount_point) != 0) && + fs_mgr_is_voldmanaged(v) && vold_is_volume_available(v->mount_point))) + num++; + } + return num; +} - device = "/dev/userdata_moved"; +char** get_extra_storage_paths() { + int i = 0, j = 0; + static char* paths[MAX_NUM_MANAGED_VOLUMES]; + int num_extra_volumes = get_num_extra_volumes(); - } + if (num_extra_volumes == 0) + return NULL; - device_volumes[num_volumes].mount_point = strdup(mount_point); - device_volumes[num_volumes].fs_type = strdup(fs_type); - device_volumes[num_volumes].device = strdup(device); - device_volumes[num_volumes].device2 = - device2 ? strdup(device2) : NULL; - - device_volumes[num_volumes].length = 0; - - device_volumes[num_volumes].fs_type2 = NULL; - device_volumes[num_volumes].fs_options = NULL; - device_volumes[num_volumes].fs_options2 = NULL; - device_volumes[num_volumes].lun = NULL; - - int code; - if(code=stat(device, &device_volumes[num_volumes].stat)!=0) - LOGE("stat: Error %d on file %s\n", code, device); - - if (parse_options(options, device_volumes + num_volumes) != 0) { - LOGE("skipping malformed recovery.fstab line: %s\n", original); - } else { - ++num_volumes; - - if(is_dualsystem() && mount_point!=NULL && strcmp(mount_point, "/data")==0) { - while (num_volumes >= alloc) { - alloc *= 2; - device_volumes = realloc(device_volumes, alloc*sizeof(Volume)); - } - - device_volumes[num_volumes].mount_point = "/data1"; - device_volumes[num_volumes].fs_type = "bind"; - device_volumes[num_volumes].device = NULL; - device_volumes[num_volumes].device2 = NULL; - device_volumes[num_volumes].fs_type2 = NULL; - device_volumes[num_volumes].fs_options = NULL; - device_volumes[num_volumes].fs_options2 = NULL; - device_volumes[num_volumes].lun = NULL; - device_volumes[num_volumes].length = 0; - ++num_volumes; - } - } - } else { - LOGE("skipping malformed recovery.fstab line: %s\n", original); + for (i = 0; i < get_num_volumes(); i++) { + Volume* v = get_device_volumes() + i; + if ((strcmp("/external_sd", v->mount_point) == 0) || + ((strcmp(get_primary_storage_path(), v->mount_point) != 0) && + fs_mgr_is_voldmanaged(v) && vold_is_volume_available(v->mount_point))) { + paths[j] = v->mount_point; + j++; } - free(original); } + paths[j] = NULL; - fclose(fstab); - - fprintf(stderr, "recovery filesystem table\n"); - fprintf(stderr, "=========================\n"); - for (i = 0; i < num_volumes; ++i) { - Volume* v = &device_volumes[i]; - fprintf(stderr, " %d %s %s %s %s %lld\n", i, v->mount_point, v->fs_type, - v->device, v->device2, v->length); - } - fprintf(stderr,"\n"); + return paths; } -Volume* volume_for_path(const char* path) { - int i; - for (i = 0; i < num_volumes; ++i) { - Volume* v = device_volumes+i; - int len = strlen(v->mount_point); - if (strncmp(path, v->mount_point, len) == 0 && - (path[len] == '\0' || path[len] == '/')) { - return v; - } +static char* android_secure_path = NULL; +char* get_android_secure_path() { + if (android_secure_path == NULL) { + android_secure_path = malloc(sizeof("/.android_secure") + strlen(get_primary_storage_path()) + 1); + sprintf(android_secure_path, "%s/.android_secure", primary_storage_path); } - return NULL; + return android_secure_path; } int try_mount(const char* device, const char* mount_point, const char* fs_type, const char* fs_options) { @@ -343,30 +262,45 @@ int is_dualsystem() { int is_data_media() { int i; - for (i = 0; i < num_volumes; i++) { - Volume* vol = device_volumes + i; + int has_sdcard = 0; + for (i = 0; i < get_num_volumes(); i++) { + Volume* vol = get_device_volumes() + i; if (strcmp(vol->fs_type, "datamedia") == 0) return 1; + if (strcmp(vol->mount_point, "/sdcard") == 0) + has_sdcard = 1; + if (fs_mgr_is_voldmanaged(vol) && + (strcmp(vol->mount_point, "/storage/sdcard0") == 0)) + has_sdcard = 1; } - return 0; + return !has_sdcard; } void setup_data_media() { int i; - for (i = 0; i < num_volumes; i++) { - Volume* vol = device_volumes + i; + char* mount_point = "/sdcard"; + for (i = 0; i < get_num_volumes(); i++) { + Volume* vol = get_device_volumes() + i; if (strcmp(vol->fs_type, "datamedia") == 0) { - rmdir(vol->mount_point); - mkdir("/data/media", 0755); - symlink("/data/media", vol->mount_point); - return; + mount_point = vol->mount_point; + break; } } + rmdir(mount_point); + mkdir("/data/media", 0755); + symlink("/data/media", mount_point); } int is_data_media_volume_path(const char* path) { Volume* v = volume_for_path(path); - return strcmp(v->fs_type, "datamedia") == 0; + if (v != NULL) + return strcmp(v->fs_type, "datamedia") == 0; + + if (!is_data_media()) { + return 0; + } + + return strcmp(path, "/sdcard") == 0 || path == strstr(path, "/sdcard/"); } int ensure_path_mounted(const char* path) { @@ -379,11 +313,6 @@ int getLastDataSubfolder() { } int ensure_path_mounted_at_mount_point(const char* path, const char* mount_point) { - Volume* v = volume_for_path(path); - if (v == NULL) { - LOGE("unknown volume for path [%s]\n", path); - return -1; - } if (is_data_media_volume_path(path)) { if (ui_should_log_stdout()) { LOGI("using /data/media for %s.\n", path); @@ -394,6 +323,11 @@ int ensure_path_mounted_at_mount_point(const char* path, const char* mount_point setup_data_media(); return 0; } + Volume* v = volume_for_path(path); + if (v == NULL) { + LOGE("unknown volume for path [%s]\n", path); + return -1; + } if (strcmp(v->fs_type, "ramdisk") == 0) { // the ramdisk is always mounted. return 0; @@ -495,14 +429,17 @@ int ensure_path_mounted_at_mount_point(const char* path, const char* mount_point mkdir(mount_point, 0755); // in case it doesn't already exist - if (strcmp(v->fs_type, "yaffs2") == 0) { + if (fs_mgr_is_voldmanaged(v)) { + return vold_mount_volume(mount_point, 1) == CommandOkay ? 0 : -1; + + } else if (strcmp(v->fs_type, "yaffs2") == 0) { // mount an MTD partition as a YAFFS2 filesystem. mtd_scan_partitions(); const MtdPartition* partition; - partition = mtd_find_partition_by_name(v->device); + partition = mtd_find_partition_by_name(v->blk_device); if (partition == NULL) { LOGE("failed to find \"%s\" partition to mount at \"%s\"\n", - v->device, mount_point); + v->blk_device, mount_point); return -1; } return mtd_mount_partition(partition, mount_point, v->fs_type, 0); @@ -510,29 +447,31 @@ int ensure_path_mounted_at_mount_point(const char* path, const char* mount_point strcmp(v->fs_type, "ext3") == 0 || strcmp(v->fs_type, "rfs") == 0 || strcmp(v->fs_type, "vfat") == 0) { - if ((result = try_mount(v->device, mount_point, v->fs_type, v->fs_options)) == 0) - return 0; - if ((result = try_mount(v->device2, mount_point, v->fs_type, v->fs_options)) == 0) + if ((result = try_mount(v->blk_device, mount_point, v->fs_type, v->fs_options)) == 0) return 0; - if ((result = try_mount(v->device, mount_point, v->fs_type2, v->fs_options2)) == 0) + if ((result = try_mount(v->blk_device, mount_point, v->fs_type2, v->fs_options2)) == 0) return 0; - if ((result = try_mount(v->device2, mount_point, v->fs_type2, v->fs_options2)) == 0) + if ((result = try_mount(v->blk_device2, mount_point, v->fs_type2, v->fs_options2)) == 0) return 0; return result; } else { // let's try mounting with the mount binary and hope for the best. char mount_cmd[PATH_MAX]; - sprintf(mount_cmd, "mount %s", path); + sprintf(mount_cmd, "mount %s", mount_point); return __system(mount_cmd); } - LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, mount_point); return -1; } static int handle_truedualsystem = 0; +static int ignore_data_media = 0; + int ensure_path_unmounted(const char* path) { // if we are using /data/media, do not ever unmount volumes /data or /sdcard - if (strstr(path, "/data") == path && is_data_media()) { + if (is_data_media_volume_path(path)) { + return ensure_path_unmounted("/data"); + } + if (strstr(path, "/data") == path && is_data_media() && !ignore_data_media) { return 0; } // if we are using TrueDualBoot do not ever unmount volume /data_root @@ -545,9 +484,7 @@ int ensure_path_unmounted(const char* path) { LOGE("unknown volume for path [%s]\n", path); return -1; } - if (is_data_media_volume_path(path)) { - return ensure_path_unmounted("/data"); - } + if (strcmp(v->fs_type, "ramdisk") == 0) { // the ramdisk is always mounted; you can't unmount it. return -1; @@ -576,32 +513,52 @@ int ensure_path_unmounted(const char* path) { return 0; } + if (fs_mgr_is_voldmanaged(volume_for_path(v->mount_point))) + return vold_unmount_volume(v->mount_point, 0, 1) == CommandOkay ? 0 : -1; + return unmount_mounted_volume(mv); } extern struct selabel_handle *sehandle; -static int handle_data_media = 0; int format_volume(const char* volume) { - Volume* v = volume_for_path(volume); - if (v == NULL) { - // silent failure for sd-ext - if (strcmp(volume, "/sd-ext") == 0) - return -1; - LOGE("unknown volume \"%s\"\n", volume); - return -1; - } if (is_data_media_volume_path(volume)) { return format_unknown_device(NULL, volume, NULL); } // check to see if /data is being formatted, and if it is /data/media // Note: the /sdcard check is redundant probably, just being safe. - if (strstr(volume, "/data") == volume && is_data_media() && !handle_data_media) { + if (strstr(volume, "/data") == volume && is_data_media() && !ignore_data_media) { return format_unknown_device(NULL, volume, NULL); } if (strstr(volume, "/data") == volume && is_dualsystem() && isTrueDualbootEnabled() && !handle_truedualsystem) { return format_unknown_device(NULL, volume, NULL); } + + Volume* v = volume_for_path(volume); + if (v == NULL) { + // silent failure for sd-ext + if (strcmp(volume, "/sd-ext") != 0) + LOGE("unknown volume '%s'\n", volume); + return -1; + } + // silent failure to format non existing sd-ext when defined in recovery.fstab + if (strcmp(volume, "/sd-ext") == 0) { + struct stat s; + if (0 != stat(v->blk_device, &s)) { + LOGI("Skipping format of sd-ext\n"); + return -1; + } + } + + // Only use vold format for exact matches otherwise /sdcard will be + // formatted instead of /storage/sdcard0/.android_secure + if (fs_mgr_is_voldmanaged(v) && strcmp(volume, v->mount_point) == 0) { + if (ensure_path_unmounted(volume) != 0) { + LOGE("format_volume failed to unmount %s", v->mount_point); + } + return vold_format_volume(v->mount_point, 1) == CommandOkay ? 0 : -1; + } + if (strcmp(v->fs_type, "ramdisk") == 0) { // you can't format the ramdisk. LOGE("can't format_volume \"%s\"", volume); @@ -612,7 +569,7 @@ int format_volume(const char* volume) { LOGE("can't give path \"%s\" to format_volume\n", volume); return -1; #endif - return format_unknown_device(v->device, volume, NULL); + return format_unknown_device(v->blk_device, volume, NULL); } if (ensure_path_unmounted(volume) != 0) { @@ -622,45 +579,65 @@ int format_volume(const char* volume) { if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) { mtd_scan_partitions(); - const MtdPartition* partition = mtd_find_partition_by_name(v->device); + const MtdPartition* partition = mtd_find_partition_by_name(v->blk_device); if (partition == NULL) { - LOGE("format_volume: no MTD partition \"%s\"\n", v->device); + LOGE("format_volume: no MTD partition \"%s\"\n", v->blk_device); return -1; } MtdWriteContext *write = mtd_write_partition(partition); if (write == NULL) { - LOGW("format_volume: can't open MTD \"%s\"\n", v->device); + LOGW("format_volume: can't open MTD \"%s\"\n", v->blk_device); return -1; } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { - LOGW("format_volume: can't erase MTD \"%s\"\n", v->device); + LOGW("format_volume: can't erase MTD \"%s\"\n", v->blk_device); mtd_write_close(write); return -1; } else if (mtd_write_close(write)) { - LOGW("format_volume: can't close MTD \"%s\"\n", v->device); + LOGW("format_volume: can't close MTD \"%s\"\n", v->blk_device); return -1; } return 0; } if (strcmp(v->fs_type, "ext4") == 0) { - int result = make_ext4fs(v->device, v->length, volume, sehandle); + int result = make_ext4fs(v->blk_device, v->length, volume, sehandle); + if (result != 0) { + LOGE("format_volume: make_extf4fs failed on %s\n", v->blk_device); + return -1; + } + return 0; + } + +#ifdef USE_F2FS + if (strcmp(v->fs_type, "f2fs") == 0) { + int result = make_f2fs_main(v->blk_device, v->mount_point); if (result != 0) { - LOGE("format_volume: make_extf4fs failed on %s\n", v->device); + LOGE("format_volume: mkfs.f2f2 failed on %s\n", v->blk_device); return -1; } return 0; } +#endif #if 0 LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; #endif - return format_unknown_device(v->device, volume, v->fs_type); + return format_unknown_device(v->blk_device, volume, v->fs_type); +} + +void ignore_data_media_workaround(int ignore) { + ignore_data_media = ignore; } -void handle_data_media_format(int handle) { - handle_data_media = handle; +void setup_legacy_storage_paths() { + char* primary_path = get_primary_storage_path(); + + if (!is_data_media_volume_path(primary_path)) { + rmdir("/sdcard"); + symlink(primary_path, "/sdcard"); + } } void handle_truedualsystem_format(int handle) { diff --git a/roots.h b/roots.h old mode 100644 new mode 100755 index 51d7935db..a57aa1137 --- a/roots.h +++ b/roots.h @@ -41,6 +41,11 @@ int ensure_path_unmounted(const char* path); // it is mounted. int format_volume(const char* volume); +char* get_primary_storage_path(); +char** get_extra_storage_paths(); +char* get_android_secure_path(); +void setup_legacy_storage_paths(); +int get_num_extra_volumes(); int get_num_volumes(); Volume* get_device_volumes(); @@ -50,5 +55,9 @@ void setup_data_media(); int is_data_media_volume_path(const char* path); void handle_data_media_format(int handle); void handle_truedualsystem_format(int handle); +void ignore_data_media_workaround(int ignore); + +#define MAX_NUM_MANAGED_VOLUMES 10 + #endif // RECOVERY_ROOTS_H_ diff --git a/su/Android.mk b/su/Android.mk index 6458e8e5d..0b78644ae 100644 --- a/su/Android.mk +++ b/su/Android.mk @@ -6,9 +6,9 @@ include $(CLEAR_VARS) LOCAL_MODULE := su.recovery LOCAL_MODULE_TAGS := eng debug LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_STATIC_LIBRARIES := libc +LOCAL_STATIC_LIBRARIES := libc liblog libcutils LOCAL_C_INCLUDES := external/sqlite/dist -LOCAL_SRC_FILES := ../../../external/koush/Superuser/Superuser/jni/su/su.c ../../../external/koush/Superuser/Superuser/jni/su/activity.c ../../../external/koush/Superuser/Superuser/jni/su/utils.c dbstub.c +LOCAL_SRC_FILES := ../../../external/koush/Superuser/Superuser/jni/su/su.c ../../../external/koush/Superuser/Superuser/jni/su/daemon.c ../../../external/koush/Superuser/Superuser/jni/su/activity.c ../../../external/koush/Superuser/Superuser/jni/su/utils.c dbstub.c LOCAL_CFLAGS := -DSQLITE_OMIT_LOAD_EXTENSION -DREQUESTOR=\"$(SUPERUSER_PACKAGE)\" ifdef SUPERUSER_PACKAGE_PREFIX LOCAL_CFLAGS += -DREQUESTOR_PREFIX=\"$(SUPERUSER_PACKAGE_PREFIX)\" @@ -17,3 +17,18 @@ LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin include $(BUILD_EXECUTABLE) +include $(CLEAR_VARS) +LOCAL_MODULE := install-su.sh +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin +LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := run-su-daemon.sh +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin +LOCAL_SRC_FILES := ../../../external/koush/Superuser/Superuser/assets/install-recovery.sh +include $(BUILD_PREBUILT) diff --git a/su/install-su.sh b/su/install-su.sh new file mode 100644 index 000000000..136b09e3d --- /dev/null +++ b/su/install-su.sh @@ -0,0 +1,26 @@ +#!/sbin/sh +cp /sbin/su.recovery /system/xbin/su +chmod 6755 /system/xbin/su +ln -sf /system/xbin/su /system/bin/su + +# if the system is at least 4.3, and there is no su daemon built in, +# let's try to install it using install-recovery.sh +BUILD_RELEASE_VERSION=$(cat /system/build.prop | grep ro\\.build\\.version\\.release) +IS_43=$(echo $BUILD_RELEASE_VERSION | grep 4\\.3) +if [ ! -z "$IS_43" ] +then + if [ -o "$IS_43" \> "4.3" -o "$IS_43" == "4.3" ] + then + # check for rom su daemon before clobbering install-recovery.sh + if [ ! -f "/system/etc/.has_su_daemon" ] + then + chattr -i /system/etc/install-recovery.sh + cp /sbin/run-su-daemon.sh /system/etc/install-recovery.sh + chmod 755 /system/etc/install-recovery.sh + # note that an post install su daemon was installed + # so recovery doesn't freak out and recommend you disable + # the install-recovery.sh execute bit. + touch /system/etc/.installed_su_daemon + fi + fi +fi diff --git a/swipe.c b/swipe.c new file mode 100644 index 000000000..cee276a69 --- /dev/null +++ b/swipe.c @@ -0,0 +1,84 @@ +static int in_touch = 0; // 1 = in a touch +static int slide_right = 0; +static int slide_left = 0; +static int touch_x = 0; +static int touch_y = 0; +static int old_x = 0; +static int old_y = 0; +static int diff_x = 0; +static int diff_y = 0; + +static void reset_gestures() { + diff_x = 0; + diff_y = 0; + old_x = 0; + old_y = 0; + touch_x = 0; + touch_y = 0; + + ui_clear_key_queue(); +} + +void swipe_handle_input(int fd, struct input_event *ev) { + int abs_store[6] = {0}; + int k; + + ioctl(fd, EVIOCGABS(ABS_MT_POSITION_X), abs_store); + int max_x_touch = abs_store[2]; + + ioctl(fd, EVIOCGABS(ABS_MT_POSITION_Y), abs_store); + int max_y_touch = abs_store[2]; + + if(ev->type == EV_ABS && ev->code == ABS_MT_TRACKING_ID) { + if(in_touch == 0) { + in_touch = 1; + reset_gestures(); + } else { // finger lifted + ev->type = EV_KEY; + int keywidth = gr_fb_width() / 4; + if(slide_right == 1) { + ev->code = KEY_POWER; + slide_right = 0; + } else if(slide_left == 1) { + ev->code = KEY_BACK; + slide_left = 0; + } + + ev->value = 1; + in_touch = 0; + reset_gestures(); + } + } else if(ev->type == EV_ABS && ev->code == ABS_MT_POSITION_X) { + old_x = touch_x; + float touch_x_rel = (float)ev->value / (float)max_x_touch; + touch_x = touch_x_rel * gr_fb_width(); + + if(old_x != 0) diff_x += touch_x - old_x; + + if(diff_x > 100) { + slide_right = 1; + reset_gestures(); + } else if(diff_x < -100) { + slide_left = 1; + reset_gestures(); + } + } else if(ev->type == EV_ABS && ev->code == ABS_MT_POSITION_Y) { + old_y = touch_y; + float touch_y_rel = (float)ev->value / (float)max_y_touch; + touch_y = touch_y_rel * gr_fb_height(); + + if(old_y != 0) diff_y += touch_y - old_y; + + if(diff_y > 80) { + ev->code = KEY_VOLUMEDOWN; + ev->type = EV_KEY; + reset_gestures(); + } else if(diff_y < -80) { + ev->code = KEY_VOLUMEUP; + ev->type = EV_KEY; + reset_gestures(); + } + } + + return; +} diff --git a/testdata/otasigned_f4_sha256.zip b/testdata/otasigned_f4_sha256.zip new file mode 100644 index 000000000..3af408c40 Binary files /dev/null and b/testdata/otasigned_f4_sha256.zip differ diff --git a/testdata/otasigned_sha256.zip b/testdata/otasigned_sha256.zip new file mode 100644 index 000000000..0ed4409b3 Binary files /dev/null and b/testdata/otasigned_sha256.zip differ diff --git a/testdata/test_f4_sha256.x509.pem b/testdata/test_f4_sha256.x509.pem new file mode 100644 index 000000000..9d5376b45 --- /dev/null +++ b/testdata/test_f4_sha256.x509.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIJAKhkCO1dDYMaMA0GCSqGSIb3DQEBCwUAMG8xCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW +aWV3MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMT +B1Rlc3QxMjMwHhcNMTMwNDEwMTcyMzUyWhcNMTMwNTEwMTcyMzUyWjBvMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQD +EwdUZXN0MTIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu8WwMN9x +4Mz7YgkG2qy9g8/kl5ZoYrUM0ApHhaITAcL7RXLZaNipCf0w/YjYTQgj+75MK30x +TsnPeWNOEwA62gkHrZyyWfxBRO6kBYuIuI4roGDBJOmKQ1OEaDeIRKu7q5V8v3Cs +0wQDAQWTbhpxBZr9UYFgJUg8XWBfPrGJLVwsoiy4xrMhoTlNZKHfwOMMqVtSHkZX +qydYrcIzyjh+TO0e/xSNQ8MMRRbtqWgCHN6Rzhog3IHZu0RaPoukariopjXM/s0V +gTm3rHDHCOpna2pNblyiFlvbkoCs769mtNmx/yrDShO30jg/xaG8RypKDvTChzOT +oWW/XQ5VEXjbHwIDAQABo4HUMIHRMB0GA1UdDgQWBBRlT2dEZJY1tmUM8mZ0xnhS +GdD9TTCBoQYDVR0jBIGZMIGWgBRlT2dEZJY1tmUM8mZ0xnhSGdD9TaFzpHEwbzEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50 +YWluIFZpZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4G +A1UEAxMHVGVzdDEyM4IJAKhkCO1dDYMaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN +AQELBQADggEBAKWWQ9S0V9wWjrMJe8exj1gklwD1Ysi0vi+h2tfixahelrpsNkWi +EFjoUSHEkW9ThLmtui646uAlwSiWtSn1XkGGmIJ3s+gmAFUcMc0CaK0dgoq/M9zn +fQ0Vkzc1tK4MLsf+CbPDywPycb6+T3dBkerbWn9GUpjGl1ANWlciXZZ3657m61sL +HhwUOBxbZZ6sYP4ed2SVCf45GgMyJ0VoUg5yI2JzPAgOkGfeEIPVXE1M94edJY4G +8eHYvXovJZwXvKFI+ZyS0KBPx8cpfw89RB9qmkxqNBIm8qWb3qBiuBEIPj+NF/7w +sC/Fv8NNXkVquy0xa0qdyJBABzWE18zGcXs= +-----END CERTIFICATE----- diff --git a/testdata/testkey.pk8 b/testdata/testkey.pk8 new file mode 100644 index 000000000..586c1bd5c Binary files /dev/null and b/testdata/testkey.pk8 differ diff --git a/testdata/testkey.x509.pem b/testdata/testkey.x509.pem new file mode 100644 index 000000000..e242d83e2 --- /dev/null +++ b/testdata/testkey.x509.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE +AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G +A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI +hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM +qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 +wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy +4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU +RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s +zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw +HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ +AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE +CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH +QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG +CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa +J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y +LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe ++ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX +31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr +sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0= +-----END CERTIFICATE----- diff --git a/testdata/testkey_sha256.x509.pem b/testdata/testkey_sha256.x509.pem new file mode 100644 index 000000000..002ce8968 --- /dev/null +++ b/testdata/testkey_sha256.x509.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE +AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xMzA0MTAxODA1MzZaFw0xMzA1MTAxODA1MzZaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G +A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI +hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM +qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 +wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy +4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU +RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s +zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw +HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ +AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE +CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH +QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG +CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKRVj9hOaozH1W8Wb4CNj7sCWixh +UMMZJXkxUtvUVHZGefp6MdtYiD/ZM7YRwZphm9aNhkykbHJdZ3lPzeL2csCa+sDQ +8sIzGu0/aD6p4zgIKQZmz0mZHqPGbHoLWOmA9EexRCFZ7vO/kO56ZbyhfFz2DI3S +Yez65CabErOFhNX6WukSPbV3zfsHRDD5JUStb/ko6t99HXsvIO0Ax9poj60PpCC1 +SiFzHZUY9mOnUfJFs+3NWCwKtP9nho3mZ3pJ1i+SeF6JiqbE3KHl4CDBeVGcu3CK +fiUZ8e8iXVN471Cgc5GD6Ud1pS7ifNZJsKhbETQ63KmvHCLRPi4NmP67uDE= +-----END CERTIFICATE----- diff --git a/ui.c b/ui.c index 9ed2fc930..53fc57b5b 100644 --- a/ui.c +++ b/ui.c @@ -33,6 +33,7 @@ #include #include "minui/minui.h" #include "recovery_ui.h" +#include "voldclient/voldclient.h" extern int __system(const char *command); @@ -81,6 +82,7 @@ static const struct { gr_surface* surface; const char *name; } BITMAPS[] = { { &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" }, { &gBackgroundIcon[BACKGROUND_ICON_ERROR], "icon_error" }, { &gBackgroundIcon[BACKGROUND_ICON_CLOCKWORK], "icon_clockwork" }, + { &gBackgroundIcon[BACKGROUND_ICON_CID], "icon_cid" }, { &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_INSTALLING], "icon_firmware_install" }, { &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_ERROR], "icon_firmware_error" }, { &gProgressBarEmpty, "progress_empty" }, @@ -118,6 +120,9 @@ static int menu_top = 0, menu_items = 0, menu_sel = 0; static int menu_show_start = 0; // this is line which menu display is starting at static int max_menu_rows; +static int cur_rainbow_color = 0; +static int gRainbowMode = 0; + // Key event input queue static pthread_mutex_t key_queue_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t key_queue_cond = PTHREAD_COND_INITIALIZER; @@ -129,6 +134,10 @@ static void update_screen_locked(void); #ifdef BOARD_TOUCH_RECOVERY #include "../../vendor/koush/recovery/touch.c" +#else +#ifdef BOARD_RECOVERY_SWIPE +#include "swipe.c" +#endif #endif // Return the current time as a double (including fractions of a second). @@ -228,7 +237,8 @@ static void draw_progress_locked() static void draw_text_line(int row, const char* t) { if (t[0] != '\0') { - gr_text(0, (row+1)*CHAR_HEIGHT-1, t); + if (ui_get_rainbow_mode()) ui_rainbow_mode(); + gr_text(0, (row+1)*CHAR_HEIGHT-1, t, 0); } } @@ -400,7 +410,11 @@ static int input_callback(int fd, short revents, void *data) #ifdef BOARD_TOUCH_RECOVERY if (touch_handle_input(fd, ev)) - return 0; + return 0; +#else +#ifdef BOARD_RECOVERY_SWIPE + swipe_handle_input(fd, &ev); +#endif #endif if (ev.type == EV_SYN) { @@ -469,7 +483,7 @@ static int input_callback(int fd, short revents, void *data) } if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) { - android_reboot(ANDROID_RB_RESTART, 0, 0); + reboot_main_system(ANDROID_RB_RESTART, 0, 0); } return 0; @@ -746,7 +760,7 @@ void ui_printlogtail(int nb_lines) { #define MENU_ITEM_HEADER " - " #define MENU_ITEM_HEADER_LENGTH strlen(MENU_ITEM_HEADER) -int ui_start_menu(char** headers, char** items, int initial_selection) { +int ui_start_menu(const char** headers, char** items, int initial_selection) { int i; pthread_mutex_lock(&gUpdateMutex); if (text_rows > 0 && text_cols > 0) { @@ -869,27 +883,37 @@ void ui_cancel_wait_key() { pthread_mutex_unlock(&key_queue_mutex); } +extern int volumes_changed(); + +// delay in seconds to refresh clock and USB plugged volumes +#define REFRESH_TIME_USB_INTERVAL 5 int ui_wait_key() { if (boardEnableKeyRepeat) return ui_wait_key_with_repeat(); pthread_mutex_lock(&key_queue_mutex); + int timeouts = UI_WAIT_KEY_TIMEOUT_SEC; - // Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is - // plugged in. + // Time out after REFRESH_TIME_USB_INTERVAL seconds to catch volume changes, and loop for + // UI_WAIT_KEY_TIMEOUT_SEC to restart a device not connected to USB do { struct timeval now; struct timespec timeout; gettimeofday(&now, NULL); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = now.tv_usec * 1000; - timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC; + timeout.tv_sec += REFRESH_TIME_USB_INTERVAL; int rc = 0; while (key_queue_len == 0 && rc != ETIMEDOUT) { rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, &timeout); + if (volumes_changed()) { + pthread_mutex_unlock(&key_queue_mutex); + return REFRESH; + } } - } while (usb_connected() && key_queue_len == 0); + timeouts -= REFRESH_TIME_USB_INTERVAL; + } while ((timeouts > 0 || usb_connected()) && key_queue_len == 0); int key = -1; if (key_queue_len > 0) { @@ -919,20 +943,30 @@ int ui_wait_key_with_repeat() // Loop to wait for more keys. do { + int timeouts = UI_WAIT_KEY_TIMEOUT_SEC; + int rc = 0; struct timeval now; struct timespec timeout; - gettimeofday(&now, NULL); - timeout.tv_sec = now.tv_sec; - timeout.tv_nsec = now.tv_usec * 1000; - timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC; - - int rc = 0; pthread_mutex_lock(&key_queue_mutex); - while (key_queue_len == 0 && rc != ETIMEDOUT) { - rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, - &timeout); + while (key_queue_len == 0 && timeouts > 0) { + gettimeofday(&now, NULL); + timeout.tv_sec = now.tv_sec; + timeout.tv_nsec = now.tv_usec * 1000; + timeout.tv_sec += REFRESH_TIME_USB_INTERVAL; + + rc = 0; + while (key_queue_len == 0 && rc != ETIMEDOUT) { + rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, + &timeout); + if (volumes_changed()) { + pthread_mutex_unlock(&key_queue_mutex); + return REFRESH; + } + } + timeouts -= REFRESH_TIME_USB_INTERVAL; } pthread_mutex_unlock(&key_queue_mutex); + if (rc == ETIMEDOUT && !usb_connected()) { return -1; } @@ -1056,3 +1090,29 @@ void ui_increment_frame() { gInstallingFrame = (gInstallingFrame + 1) % ui_parameters.installing_frames; } + +int ui_get_rainbow_mode() { + return gRainbowMode; +} + +void ui_rainbow_mode() { + static int colors[] = { 255, 0, 0, // red + 255, 127, 0, // orange + 255, 255, 0, // yellow + 0, 255, 0, // green + 60, 80, 255, // blue + 143, 0, 255 }; // violet + + gr_color(colors[cur_rainbow_color], colors[cur_rainbow_color+1], colors[cur_rainbow_color+2], 255); + cur_rainbow_color += 3; + if (cur_rainbow_color >= sizeof(colors)/sizeof(colors[0])) cur_rainbow_color = 0; +} + +void ui_set_rainbow_mode(int rainbowMode) { + gRainbowMode = rainbowMode; + + pthread_mutex_lock(&gUpdateMutex); + update_screen_locked(); + pthread_mutex_unlock(&gUpdateMutex); +} + diff --git a/updater/install.c b/updater/install.c index c1e0a6346..c1f55dcf0 100644 --- a/updater/install.c +++ b/updater/install.c @@ -27,6 +27,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "cutils/misc.h" #include "cutils/properties.h" @@ -600,6 +606,264 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(result); } +struct perm_parsed_args { + bool has_uid; + uid_t uid; + bool has_gid; + gid_t gid; + bool has_mode; + mode_t mode; + bool has_fmode; + mode_t fmode; + bool has_dmode; + mode_t dmode; + bool has_selabel; + char* selabel; + bool has_capabilities; + uint64_t capabilities; +}; + +static struct perm_parsed_args ParsePermArgs(int argc, char** args) { + int i; + struct perm_parsed_args parsed; + int bad = 0; + static int max_warnings = 20; + + memset(&parsed, 0, sizeof(parsed)); + + for (i = 1; i < argc; i += 2) { + if (strcmp("uid", args[i]) == 0) { + int64_t uid; + if (sscanf(args[i+1], "%" SCNd64, &uid) == 1) { + parsed.uid = uid; + parsed.has_uid = true; + } else { + printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("gid", args[i]) == 0) { + int64_t gid; + if (sscanf(args[i+1], "%" SCNd64, &gid) == 1) { + parsed.gid = gid; + parsed.has_gid = true; + } else { + printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("mode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.mode = mode; + parsed.has_mode = true; + } else { + printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("dmode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.dmode = mode; + parsed.has_dmode = true; + } else { + printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("fmode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.fmode = mode; + parsed.has_fmode = true; + } else { + printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("capabilities", args[i]) == 0) { + int64_t capabilities; + if (sscanf(args[i+1], "%" SCNi64, &capabilities) == 1) { + parsed.capabilities = capabilities; + parsed.has_capabilities = true; + } else { + printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("selabel", args[i]) == 0) { + if (args[i+1][0] != '\0') { + parsed.selabel = args[i+1]; + parsed.has_selabel = true; + } else { + printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (max_warnings != 0) { + printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i]); + max_warnings--; + if (max_warnings == 0) { + printf("ParsedPermArgs: suppressing further warnings\n"); + } + } + } + return parsed; +} + +static int ApplyParsedPerms( + const char* filename, + const struct stat *statptr, + struct perm_parsed_args parsed) +{ + int bad = 0; + + /* ignore symlinks */ + if (S_ISLNK(statptr->st_mode)) { + return 0; + } + + if (parsed.has_uid) { + if (chown(filename, parsed.uid, -1) < 0) { + printf("ApplyParsedPerms: chown of %s to %d failed: %s\n", + filename, parsed.uid, strerror(errno)); + bad++; + } + } + + if (parsed.has_gid) { + if (chown(filename, -1, parsed.gid) < 0) { + printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n", + filename, parsed.gid, strerror(errno)); + bad++; + } + } + + if (parsed.has_mode) { + if (chmod(filename, parsed.mode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.mode, strerror(errno)); + bad++; + } + } + + if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { + if (chmod(filename, parsed.dmode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.dmode, strerror(errno)); + bad++; + } + } + + if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { + if (chmod(filename, parsed.fmode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.fmode, strerror(errno)); + bad++; + } + } + + if (parsed.has_selabel) { + // TODO: Don't silently ignore ENOTSUP + if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) { + printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", + filename, parsed.selabel, strerror(errno)); + bad++; + } + } + + if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { + if (parsed.capabilities == 0) { + if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { + // Report failure unless it's ENODATA (attribute not set) + printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", + filename, parsed.capabilities, strerror(errno)); + bad++; + } + } else { + struct vfs_cap_data cap_data; + memset(&cap_data, 0, sizeof(cap_data)); + cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; + cap_data.data[0].permitted = (uint32_t) (parsed.capabilities & 0xffffffff); + cap_data.data[0].inheritable = 0; + cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32); + cap_data.data[1].inheritable = 0; + if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { + printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", + filename, parsed.capabilities, strerror(errno)); + bad++; + } + } + } + + return bad; +} + +// nftw doesn't allow us to pass along context, so we need to use +// global variables. *sigh* +static struct perm_parsed_args recursive_parsed_args; + +static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr, + int fileflags, struct FTW *pfwt) { + return ApplyParsedPerms(filename, statptr, recursive_parsed_args); +} + +static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { + int i; + int bad = 0; + static int nwarnings = 0; + struct stat sb; + Value* result = NULL; + + bool recursive = (strcmp(name, "set_metadata_recursive") == 0); + + if ((argc % 2) != 1) { + return ErrorAbort(state, "%s() expects an odd number of arguments, got %d", + name, argc); + } + + char** args = ReadVarArgs(state, argc, argv); + if (args == NULL) return NULL; + + if (lstat(args[0], &sb) == -1) { + result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno)); + goto done; + } + + struct perm_parsed_args parsed = ParsePermArgs(argc, args); + + if (recursive) { + recursive_parsed_args = parsed; + bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); + memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); + } else { + bad += ApplyParsedPerms(args[0], &sb, parsed); + } + +done: + for (i = 0; i < argc; ++i) { + free(args[i]); + } + free(args); + + if (result != NULL) { + return result; + } + + if (bad > 0) { + return ErrorAbort(state, "%s: some changes failed", name); + } + + return StringValue(strdup("")); +} Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 1) { @@ -1004,7 +1268,7 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(strdup("")); } uint8_t digest[SHA_DIGEST_SIZE]; - SHA(args[0]->data, args[0]->size, digest); + SHA_hash(args[0]->data, args[0]->size, digest); FreeValue(args[0]); if (argc == 1) { @@ -1080,9 +1344,24 @@ void RegisterInstallFunctions() { RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_file", PackageExtractFileFn); RegisterFunction("symlink", SymlinkFn); + + // Maybe, at some future point, we can delete these functions? They have been + // replaced by perm_set and perm_set_recursive. RegisterFunction("set_perm", SetPermFn); RegisterFunction("set_perm_recursive", SetPermFn); + // Usage: + // set_metadata("filename", "key1", "value1", "key2", "value2", ...) + // Example: + // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); + RegisterFunction("set_metadata", SetMetadataFn); + + // Usage: + // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) + // Example: + // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); + RegisterFunction("set_metadata_recursive", SetMetadataFn); + RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); RegisterFunction("write_raw_image", WriteRawImageFn); diff --git a/utilities/Android.mk b/utilities/Android.mk index 37866af0c..49174fee8 100755 --- a/utilities/Android.mk +++ b/utilities/Android.mk @@ -1,13 +1,5 @@ LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) -LOCAL_MODULE := fix_permissions -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES -LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin -LOCAL_SRC_FILES := $(LOCAL_MODULE) -include $(BUILD_PREBUILT) - include $(CLEAR_VARS) LOCAL_MODULE := parted LOCAL_MODULE_TAGS := optional @@ -47,7 +39,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libminizip LOCAL_CFLAGS := -Dmain=minizip_main -D__ANDROID__ -DIOAPI_NO_64 LOCAL_C_INCLUDES := external/zlib -LOCAL_SRC_FILES := ../../../external/zlib/contrib/minizip/minizip.c ../../../external/zlib/contrib/minizip/zip.c ../../../external/zlib/contrib/minizip/ioapi.c +LOCAL_SRC_FILES := ../../../external/zlib/src/contrib/minizip/minizip.c ../../../external/zlib/src/contrib/minizip/zip.c ../../../external/zlib/src/contrib/minizip/ioapi.c include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) diff --git a/utilities/fix_permissions b/utilities/fix_permissions deleted file mode 100755 index a6db51469..000000000 --- a/utilities/fix_permissions +++ /dev/null @@ -1,484 +0,0 @@ -#! /system/bin/sh -# -# Warning: if you want to run this script in cm-recovery change the above to #!/sbin/sh -# -# fix_permissions - fixes permissions on Android data directories after upgrade -# shade@chemlab.org -# -# original concept: http://blog.elsdoerfer.name/2009/05/25/android-fix-package-uid-mismatches/ -# implementation by: Cyanogen -# improved by: ankn, smeat, thenefield, farmatito, rikupw, Kastro -# -# v1.1-v1.31r3 - many improvements and concepts from XDA developers. -# v1.34 through v2.00 - A lot of frustration [by Kastro] -# v2.01 - Completely rewrote the script for SPEED, thanks for the input farmatito -# /data/data depth recursion is tweaked; -# fixed single mode; -# functions created for modularity; -# logging can be disabled via CLI for more speed; -# runtime computation added to end (Runtime: mins secs); -# progress (current # of total) added to screen; -# fixed CLI argument parsing, now you can have more than one option!; -# debug cli option; -# verbosity can be disabled via CLI option for less noise;; -# [by Kastro, (XDA: k4str0), twitter;mattcarver] -# v2.02 - ignore com.htc.resources.apk if it exists and minor code cleanups, -# fix help text, implement simulated run (-s) [farmatito] -# v2.03 - fixed chown group ownership output [Kastro] -# v2.04 - replaced /system/sd with $SD_EXT_DIRECTORY [Firerat] -VERSION="2.04" - -# Defaults -DEBUG=0 # Debug off by default -LOGGING=1 # Logging on by default -VERBOSE=1 # Verbose on by default - -# Messages -UID_MSG="Changing user ownership for:" -GID_MSG="Changing group ownership for:" -PERM_MSG="Changing permissions for:" - -# Programs needed -ECHO="busybox echo" -GREP="busybox grep" -EGREP="busybox egrep" -CAT="busybox cat" -CHOWN="busybox chown" -CHMOD="busybox chmod" -MOUNT="busybox mount" -UMOUNT="busybox umount" -CUT="busybox cut" -FIND="busybox find" -LS="busybox ls" -TR="busybox tr" -TEE="busybox tee" -TEST="busybox test" -SED="busybox sed" -RM="busybox rm" -WC="busybox wc" -EXPR="busybox expr" -DATE="busybox date" - -# Initialise vars -CODEPATH="" -UID="" -GID="" -PACKAGE="" -REMOVE=0 -NOSYSTEM=0 -ONLY_ONE="" -SIMULATE=0 -SYSREMOUNT=0 -SYSMOUNT=0 -DATAMOUNT=0 -SYSSDMOUNT=0 -FP_STARTTIME=$( $DATE +"%m-%d-%Y %H:%M:%S" ) -FP_STARTEPOCH=$( $DATE +%s ) -if $TEST "$SD_EXT_DIRECTORY" = ""; then - #check for mount point, /system/sd included in tests for backward compatibility - for MP in /sd-ext /system/sd;do - if $TEST -d $MP; then - SD_EXT_DIRECTORY=$MP - break - fi - done -fi -fp_usage() -{ - $ECHO "Usage $0 [OPTIONS] [APK_PATH]" - $ECHO " -d turn on debug" - $ECHO " -f fix only package APK_PATH" - $ECHO " -l disable logging for this run (faster)" - $ECHO " -r remove stale data directories" - $ECHO " of uninstalled packages while fixing permissions" - $ECHO " -s simulate only" - $ECHO " -u check only non-system directories" - $ECHO " -v disable verbosity for this run (less output)" - $ECHO " -V print version" - $ECHO " -h this help" -} - -fp_parseargs() -{ - # Parse options - while $TEST $# -ne 0; do - case "$1" in - -d) - DEBUG=1 - ;; - -f) - if $TEST $# -lt 2; then - $ECHO "$0: missing argument for option $1" - exit 1 - else - if $TEST $( $ECHO $2 | $CUT -c1 ) != "-"; then - ONLY_ONE=$2 - shift; - else - $ECHO "$0: missing argument for option $1" - exit 1 - fi - fi - ;; - -r) - REMOVE=1 - ;; - -s) - SIMULATE=1 - ;; - -l) - if $TEST $LOGGING -eq 0; then - LOGGING=1 - else - LOGGING=0 - fi - ;; - -v) - if $TEST $VERBOSE -eq 0; then - VERBOSE=1 - else - VERBOSE=0 - fi - ;; - -u) - NOSYSTEM=1 - ;; - -V) - $ECHO "$0 $VERSION" - exit 0 - ;; - -h) - fp_usage - exit 0 - ;; - -*) - $ECHO "$0: unknown option $1" - $ECHO - fp_usage - exit 1 - ;; - esac - shift; - done -} - -fp_print() -{ - MSG=$@ - if $TEST $LOGGING -eq 1; then - $ECHO $MSG | $TEE -a $LOG_FILE - else - $ECHO $MSG - fi -} - -fp_start() -{ - if $TEST $SIMULATE -eq 0 ; then - if $TEST $( $GREP -c " /system " "/proc/mounts" ) -ne 0; then - DEVICE=$( $GREP " /system " "/proc/mounts" | $CUT -d ' ' -f1 ) - if $TEST $DEBUG -eq 1; then - fp_print "/system mounted on $DEVICE" - fi - if $TEST $( $GREP " /system " "/proc/mounts" | $GREP -c " ro " ) -ne 0; then - $MOUNT -o remount,rw $DEVICE /system - SYSREMOUNT=1 - fi - else - $MOUNT /system > /dev/null 2>&1 - SYSMOUNT=1 - fi - - if $TEST $( $GREP -c " /data " "/proc/mounts" ) -eq 0; then - $MOUNT /data > /dev/null 2>&1 - DATAMOUNT=1 - fi - - if $TEST -e /dev/block/mmcblk0p2 && $TEST $( $GREP -c " $SD_EXT_DIRECTORY " "/proc/mounts" ) -eq 0; then - $MOUNT $SD_EXT_DIRECTORY > /dev/null 2>&1 - SYSSDMOUNT=1 - fi - fi - if $TEST $( $MOUNT | $GREP -c /sdcard ) -eq 0; then - LOG_FILE="/data/fix_permissions.log" - else - LOG_FILE="/sdcard/fix_permissions.log" - fi - if $TEST ! -e "$LOG_FILE"; then - > $LOG_FILE - fi - - fp_print "$0 $VERSION started at $FP_STARTTIME" -} - -fp_chown_uid() -{ - FP_OLDUID=$1 - FP_UID=$2 - FP_FILE=$3 - - #if user ownership doesn't equal then change them - if $TEST "$FP_OLDUID" != "$FP_UID"; then - if $TEST $VERBOSE -ne 0; then - fp_print "$UID_MSG $FP_FILE from '$FP_OLDUID' to '$FP_UID'" - fi - if $TEST $SIMULATE -eq 0; then - $CHOWN $FP_UID "$FP_FILE" - fi - fi -} - -fp_chown_gid() -{ - FP_OLDGID=$1 - FP_GID=$2 - FP_FILE=$3 - - #if group ownership doesn't equal then change them - if $TEST "$FP_OLDGID" != "$FP_GID"; then - if $TEST $VERBOSE -ne 0; then - fp_print "$GID_MSG $FP_FILE from '$FP_OLDGID' to '$FP_GID'" - fi - if $TEST $SIMULATE -eq 0; then - $CHOWN :$FP_GID "$FP_FILE" - fi - fi -} - -fp_chmod() -{ - FP_OLDPER=$1 - FP_OLDPER=$( $ECHO $FP_OLDPER | cut -c2-10 ) - FP_PERSTR=$2 - FP_PERNUM=$3 - FP_FILE=$4 - - #if the permissions are not equal - if $TEST "$FP_OLDPER" != "$FP_PERSTR"; then - if $TEST $VERBOSE -ne 0; then - fp_print "$PERM_MSG $FP_FILE from '$FP_OLDPER' to '$FP_PERSTR' ($FP_PERNUM)" - fi - #change the permissions - if $TEST $SIMULATE -eq 0; then - $CHMOD $FP_PERNUM "$FP_FILE" - fi - fi -} - -fp_all() -{ - FP_NUMS=$( $CAT /data/system/packages.xml | $EGREP "^ /dev/null 2>&1 - fi - - if $TEST $SYSSDMOUNT -eq 1; then - $UMOUNT $SD_EXT_DIRECTORY > /dev/null 2>&1 - fi - - if $TEST $SYSMOUNT -eq 1; then - $UMOUNT /system > /dev/null 2>&1 - fi - - if $TEST $DATAMOUNT -eq 1; then - $UMOUNT /data > /dev/null 2>&1 - fi - - FP_ENDTIME=$( $DATE +"%m-%d-%Y %H:%M:%S" ) - FP_ENDEPOCH=$( $DATE +%s ) - - date_diff $FP_STARTEPOCH $FP_ENDEPOCH - - fp_print "$0 $VERSION ended at $FP_ENDTIME (Runtime:${FP_DDM}m${FP_DDS}s)" -} - -#MAIN SCRIPT - -fp_parseargs $@ -fp_start -if $TEST "$ONLY_ONE" != "" -a "$ONLY_ONE" != "0" ; then - fp_single "$ONLY_ONE" -else - fp_all -fi -fp_end diff --git a/verifier.c b/verifier.c index 729e085cf..a63361130 100644 --- a/verifier.c +++ b/verifier.c @@ -19,10 +19,12 @@ #include "mincrypt/rsa.h" #include "mincrypt/sha.h" +#include "mincrypt/sha256.h" #include #include #include +#include // Look for an RSA signature embedded in the .ZIP file comment given // the path to the zip. Verify it matches one of the given public @@ -31,7 +33,7 @@ // Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered // or no key matches the signature). -int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys) { +int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys) { ui_set_progress(0.0); FILE* f = fopen(path, "rb"); @@ -65,6 +67,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey } if (footer[2] != 0xff || footer[3] != 0xff) { + LOGE("footer is wrong\n"); fclose(f); return VERIFY_FAILURE; } @@ -120,7 +123,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey return VERIFY_FAILURE; } - int i; + unsigned int i; for (i = 4; i < eocd_size-3; ++i) { if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b && eocd[i+2] == 0x05 && eocd[i+3] == 0x06) { @@ -136,9 +139,20 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey #define BUFFER_SIZE 4096 - SHA_CTX ctx; - SHA_init(&ctx); - unsigned char* buffer = malloc(BUFFER_SIZE); + bool need_sha1 = false; + bool need_sha256 = false; + for (i = 0; i < numKeys; ++i) { + switch (pKeys[i].hash_len) { + case SHA_DIGEST_SIZE: need_sha1 = true; break; + case SHA256_DIGEST_SIZE: need_sha256 = true; break; + } + } + + SHA_CTX sha1_ctx; + SHA256_CTX sha256_ctx; + SHA_init(&sha1_ctx); + SHA256_init(&sha256_ctx); + unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE); if (buffer == NULL) { LOGE("failed to alloc memory for sha1 buffer\n"); fclose(f); @@ -149,14 +163,15 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey size_t so_far = 0; fseek(f, 0, SEEK_SET); while (so_far < signed_len) { - int size = BUFFER_SIZE; + unsigned int size = BUFFER_SIZE; if (signed_len - so_far < size) size = signed_len - so_far; if (fread(buffer, 1, size, f) != size) { LOGE("failed to read data from %s (%s)\n", path, strerror(errno)); fclose(f); return VERIFY_FAILURE; } - SHA_update(&ctx, buffer, size); + if (need_sha1) SHA_update(&sha1_ctx, buffer, size); + if (need_sha256) SHA256_update(&sha256_ctx, buffer, size); so_far += size; double f = so_far / (double)signed_len; if (f > frac + 0.02 || size == so_far) { @@ -167,18 +182,152 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey fclose(f); free(buffer); - const uint8_t* sha1 = SHA_final(&ctx); + const uint8_t* sha1 = SHA_final(&sha1_ctx); + const uint8_t* sha256 = SHA256_final(&sha256_ctx); + for (i = 0; i < numKeys; ++i) { + const uint8_t* hash; + switch (pKeys[i].hash_len) { + case SHA_DIGEST_SIZE: hash = sha1; break; + case SHA256_DIGEST_SIZE: hash = sha256; break; + default: continue; + } + // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that // the signing tool appends after the signature itself. - if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES, - RSANUMBYTES, sha1)) { + if (RSA_verify(pKeys[i].public_key, eocd + eocd_size - 6 - RSANUMBYTES, + RSANUMBYTES, hash, pKeys[i].hash_len)) { LOGI("whole-file signature verified against key %d\n", i); free(eocd); return VERIFY_SUCCESS; + } else { + LOGI("failed to verify against key %d\n", i); } } free(eocd); LOGE("failed to verify whole-file signature\n"); return VERIFY_FAILURE; } + +// Reads a file containing one or more public keys as produced by +// DumpPublicKey: this is an RSAPublicKey struct as it would appear +// as a C source literal, eg: +// +// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}" +// +// For key versions newer than the original 2048-bit e=3 keys +// supported by Android, the string is preceded by a version +// identifier, eg: +// +// "v2 {64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}" +// +// (Note that the braces and commas in this example are actual +// characters the parser expects to find in the file; the ellipses +// indicate more numbers omitted from this example.) +// +// The file may contain multiple keys in this format, separated by +// commas. The last key must not be followed by a comma. +// +// A Certificate is a pair of an RSAPublicKey and a particular hash +// (we support SHA-1 and SHA-256; we store the hash length to signify +// which is being used). The hash used is implied by the version number. +// +// 1: 2048-bit RSA key with e=3 and SHA-1 hash +// 2: 2048-bit RSA key with e=65537 and SHA-1 hash +// 3: 2048-bit RSA key with e=3 and SHA-256 hash +// 4: 2048-bit RSA key with e=65537 and SHA-256 hash +// +// Returns NULL if the file failed to parse, or if it contain zero keys. +Certificate* +load_keys(const char* filename, int* numKeys) { + Certificate* out = NULL; + *numKeys = 0; + + FILE* f = fopen(filename, "r"); + if (f == NULL) { + LOGE("opening %s: %s\n", filename, strerror(errno)); + goto exit; + } + + { + int i; + bool done = false; + while (!done) { + ++*numKeys; + out = (Certificate*)realloc(out, *numKeys * sizeof(Certificate)); + Certificate* cert = out + (*numKeys - 1); + cert->public_key = (RSAPublicKey*)malloc(sizeof(RSAPublicKey)); + + char start_char; + if (fscanf(f, " %c", &start_char) != 1) goto exit; + if (start_char == '{') { + // a version 1 key has no version specifier. + cert->public_key->exponent = 3; + cert->hash_len = SHA_DIGEST_SIZE; + } else if (start_char == 'v') { + int version; + if (fscanf(f, "%d {", &version) != 1) goto exit; + switch (version) { + case 2: + cert->public_key->exponent = 65537; + cert->hash_len = SHA_DIGEST_SIZE; + break; + case 3: + cert->public_key->exponent = 3; + cert->hash_len = SHA256_DIGEST_SIZE; + break; + case 4: + cert->public_key->exponent = 65537; + cert->hash_len = SHA256_DIGEST_SIZE; + break; + default: + goto exit; + } + } + + RSAPublicKey* key = cert->public_key; + if (fscanf(f, " %i , 0x%x , { %u", + &(key->len), &(key->n0inv), &(key->n[0])) != 3) { + goto exit; + } + if (key->len != RSANUMWORDS) { + LOGE("key length (%d) does not match expected size\n", key->len); + goto exit; + } + for (i = 1; i < key->len; ++i) { + if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit; + } + if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit; + for (i = 1; i < key->len; ++i) { + if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit; + } + fscanf(f, " } } "); + + // if the line ends in a comma, this file has more keys. + switch (fgetc(f)) { + case ',': + // more keys to come. + break; + + case EOF: + done = true; + break; + + default: + LOGE("unexpected character between keys\n"); + goto exit; + } + + LOGI("read key e=%d hash=%d\n", key->exponent, cert->hash_len); + } + } + + fclose(f); + return out; + +exit: + if (f) fclose(f); + free(out); + *numKeys = 0; + return NULL; +} diff --git a/verifier.h b/verifier.h index 1bdfca6dd..6ce1b44d1 100644 --- a/verifier.h +++ b/verifier.h @@ -19,10 +19,17 @@ #include "mincrypt/rsa.h" +typedef struct Certificate { + int hash_len; // SHA_DIGEST_SIZE (SHA-1) or SHA256_DIGEST_SIZE (SHA-256) + RSAPublicKey* public_key; +} Certificate; + /* Look in the file for a signature footer, and verify that it * matches one of the given keys. Return one of the constants below. */ -int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys); +int verify_file(const char* path, const Certificate *pKeys, unsigned int numKeys); + +Certificate* load_keys(const char* filename, int* numKeys); #define VERIFY_SUCCESS 0 #define VERIFY_FAILURE 1 diff --git a/verifier_test.c b/verifier_test.c index 5b6c1f451..ffdb1c098 100644 --- a/verifier_test.c +++ b/verifier_test.c @@ -19,43 +19,83 @@ #include #include "verifier.h" +#include "mincrypt/sha.h" +#include "mincrypt/sha256.h" // This is build/target/product/security/testkey.x509.pem after being // dumped out by dumpkey.jar. RSAPublicKey test_key = { 64, 0xc926ad21, - { 1795090719, 2141396315, 950055447, -1713398866, - -26044131, 1920809988, 546586521, -795969498, - 1776797858, -554906482, 1805317999, 1429410244, - 129622599, 1422441418, 1783893377, 1222374759, - -1731647369, 323993566, 28517732, 609753416, - 1826472888, 215237850, -33324596, -245884705, - -1066504894, 774857746, 154822455, -1797768399, - -1536767878, -1275951968, -1500189652, 87251430, - -1760039318, 120774784, 571297800, -599067824, - -1815042109, -483341846, -893134306, -1900097649, - -1027721089, 950095497, 555058928, 414729973, - 1136544882, -1250377212, 465547824, -236820568, - -1563171242, 1689838846, -404210357, 1048029507, - 895090649, 247140249, 178744550, -747082073, - -1129788053, 109881576, -350362881, 1044303212, - -522594267, -1309816990, -557446364, -695002876}, - { -857949815, -510492167, -1494742324, -1208744608, - 251333580, 2131931323, 512774938, 325948880, - -1637480859, 2102694287, -474399070, 792812816, - 1026422502, 2053275343, -1494078096, -1181380486, - 165549746, -21447327, -229719404, 1902789247, - 772932719, -353118870, -642223187, 216871947, - -1130566647, 1942378755, -298201445, 1055777370, - 964047799, 629391717, -2062222979, -384408304, - 191868569, -1536083459, -612150544, -1297252564, - -1592438046, -724266841, -518093464, -370899750, - -739277751, -1536141862, 1323144535, 61311905, - 1997411085, 376844204, 213777604, -217643712, - 9135381, 1625809335, -1490225159, -1342673351, - 1117190829, -57654514, 1825108855, -1281819325, - 1111251351, -1726129724, 1684324211, -1773988491, - 367251975, 810756730, -1941182952, 1175080310 } + { 0x6afee91fu, 0x7fa31d5bu, 0x38a0b217u, 0x99df9baeu, + 0xfe72991du, 0x727d3c04u, 0x20943f99u, 0xd08e7826u, + 0x69e7c8a2u, 0xdeeccc8eu, 0x6b9af76fu, 0x553311c4u, + 0x07b9e247u, 0x54c8bbcau, 0x6a540d81u, 0x48dbf567u, + 0x98c92877u, 0x134fbfdeu, 0x01b32564u, 0x24581948u, + 0x6cddc3b8u, 0x0cd444dau, 0xfe0381ccu, 0xf15818dfu, + 0xc06e6d42u, 0x2e2f6412u, 0x093a6737u, 0x94d83b31u, + 0xa466c87au, 0xb3f284a0u, 0xa694ec2cu, 0x053359e6u, + 0x9717ee6au, 0x0732e080u, 0x220d5008u, 0xdc4af350u, + 0x93d0a7c3u, 0xe330c9eau, 0xcac3da1eu, 0x8ebecf8fu, + 0xc2be387fu, 0x38a14e89u, 0x211586f0u, 0x18b846f5u, + 0x43be4c72u, 0xb578c204u, 0x1bbfb230u, 0xf1e267a8u, + 0xa2d3e656u, 0x64b8e4feu, 0xe7e83d4bu, 0x3e77a943u, + 0x3559ffd9u, 0x0ebb0f99u, 0x0aa76ce6u, 0xd3786ea7u, + 0xbca8cd6bu, 0x068ca8e8u, 0xeb1de2ffu, 0x3e3ecd6cu, + 0xe0d9d825u, 0xb1edc762u, 0xdec60b24u, 0xd6931904u}, + { 0xccdcb989u, 0xe19281f9u, 0xa6e80accu, 0xb7f40560u, + 0x0efb0bccu, 0x7f12b0bbu, 0x1e90531au, 0x136d95d0u, + 0x9e660665u, 0x7d54918fu, 0xe3b93ea2u, 0x2f415d10u, + 0x3d2df6e6u, 0x7a627ecfu, 0xa6f22d70u, 0xb995907au, + 0x09de16b2u, 0xfeb8bd61u, 0xf24ec294u, 0x716a427fu, + 0x2e12046fu, 0xeaf3d56au, 0xd9b873adu, 0x0ced340bu, + 0xbc9cec09u, 0x73c65903u, 0xee39ce9bu, 0x3eede25au, + 0x397633b7u, 0x2583c165u, 0x8514f97du, 0xe9166510u, + 0x0b6fae99u, 0xa47139fdu, 0xdb8352f0u, 0xb2ad7f2cu, + 0xa11552e2u, 0xd4d490a7u, 0xe11e8568u, 0xe9e484dau, + 0xd3ef8449u, 0xa47055dau, 0x4edd9557u, 0x03a78ba1u, + 0x770e130du, 0x16762facu, 0x0cbdfcc4u, 0xf3070540u, + 0x008b6515u, 0x60e7e1b7u, 0xa72cf7f9u, 0xaff86e39u, + 0x4296faadu, 0xfc90430eu, 0x6cc8f377u, 0xb398fd43u, + 0x423c5997u, 0x991d59c4u, 0x6464bf73u, 0x96431575u, + 0x15e3d207u, 0x30532a7au, 0x8c4be618u, 0x460a4d76u }, + 3 + }; + +RSAPublicKey test_f4_key = + { 64, 0xc9bd1f21, + { 0x1178db1fu, 0xbf5d0e55u, 0x3393a165u, 0x0ef4c287u, + 0xbc472a4au, 0x383fc5a1u, 0x4a13b7d2u, 0xb1ff2ac3u, + 0xaf66b4d9u, 0x9280acefu, 0xa2165bdbu, 0x6a4d6e5cu, + 0x08ea676bu, 0xb7ac70c7u, 0xcd158139u, 0xa635ccfeu, + 0xa46ab8a8u, 0x445a3e8bu, 0xdc81d9bbu, 0x91ce1a20u, + 0x68021cdeu, 0x4516eda9u, 0x8d43c30cu, 0xed1eff14u, + 0xca387e4cu, 0x58adc233u, 0x4657ab27u, 0xa95b521eu, + 0xdfc0e30cu, 0x394d64a1u, 0xc6b321a1u, 0x2ca22cb8u, + 0xb1892d5cu, 0x5d605f3eu, 0x6025483cu, 0x9afd5181u, + 0x6e1a7105u, 0x03010593u, 0x70acd304u, 0xab957cbfu, + 0x8844abbbu, 0x53846837u, 0x24e98a43u, 0x2ba060c1u, + 0x8b88b88eu, 0x44eea405u, 0xb259fc41u, 0x0907ad9cu, + 0x13003adau, 0xcf79634eu, 0x7d314ec9u, 0xfbbe4c2bu, + 0xd84d0823u, 0xfd30fd88u, 0x68d8a909u, 0xfb4572d9u, + 0xa21301c2u, 0xd00a4785u, 0x6862b50cu, 0xcfe49796u, + 0xdaacbd83u, 0xfb620906u, 0xdf71e0ccu, 0xbbc5b030u }, + { 0x69a82189u, 0x1a8b22f4u, 0xcf49207bu, 0x68cc056au, + 0xb206b7d2u, 0x1d449bbdu, 0xe9d342f2u, 0x29daea58u, + 0xb19d011au, 0xc62f15e4u, 0x9452697au, 0xb62bb87eu, + 0x60f95cc2u, 0x279ebb2du, 0x17c1efd8u, 0xec47558bu, + 0xc81334d1u, 0x88fe7601u, 0x79992eb1u, 0xb4555615u, + 0x2022ac8cu, 0xc79a4b8cu, 0xb288b034u, 0xd6b942f0u, + 0x0caa32fbu, 0xa065ba51u, 0x4de9f154u, 0x29f64f6cu, + 0x7910af5eu, 0x3ed4636au, 0xe4c81911u, 0x9183f37du, + 0x5811e1c4u, 0x29c7a58cu, 0x9715d4d3u, 0xc7e2dce3u, + 0x140972ebu, 0xf4c8a69eu, 0xa104d424u, 0x5dabbdfbu, + 0x41cb4c6bu, 0xd7f44717u, 0x61785ff7u, 0x5e0bc273u, + 0x36426c70u, 0x2aa6f08eu, 0x083badbfu, 0x3cab941bu, + 0x8871da23u, 0x1ab3dbaeu, 0x7115a21du, 0xf5aa0965u, + 0xf766f562u, 0x7f110225u, 0x86d96a04u, 0xc50a120eu, + 0x3a751ca3u, 0xc21aa186u, 0xba7359d0u, 0x3ff2b257u, + 0xd116e8bbu, 0xfc1318c0u, 0x070e5b1du, 0x83b759a6u }, + 65537 }; void ui_print(const char* fmt, ...) { @@ -72,17 +112,36 @@ void ui_set_progress(float fraction) { } int main(int argc, char **argv) { - if (argc != 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); + if (argc < 2 || argc > 4) { + fprintf(stderr, "Usage: %s [-sha256] [-f4 | -file ] \n", argv[0]); return 2; } - int result = verify_file(argv[1], &test_key, 1); + Certificate default_cert; + Certificate* cert = &default_cert; + cert->public_key = &test_key; + cert->hash_len = SHA_DIGEST_SIZE; + int num_keys = 1; + ++argv; + if (strcmp(argv[0], "-sha256") == 0) { + ++argv; + cert->hash_len = SHA256_DIGEST_SIZE; + } + if (strcmp(argv[0], "-f4") == 0) { + ++argv; + cert->public_key = &test_f4_key; + } else if (strcmp(argv[0], "-file") == 0) { + ++argv; + cert = load_keys(argv[0], &num_keys); + ++argv; + } + + int result = verify_file(*argv, cert, num_keys); if (result == VERIFY_SUCCESS) { - printf("SUCCESS\n"); + printf("VERIFIED\n"); return 0; } else if (result == VERIFY_FAILURE) { - printf("FAILURE\n"); + printf("NOT VERIFIED\n"); return 1; } else { printf("bad return value\n"); diff --git a/verifier_test.sh b/verifier_test.sh index 6350e80d3..65f77f401 100755 --- a/verifier_test.sh +++ b/verifier_test.sh @@ -1,11 +1,7 @@ #!/bin/bash # -# A test suite for applypatch. Run in a client where you have done -# envsetup, choosecombo, etc. -# -# DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your -# system partition. -# +# A test suite for recovery's package signature verifier. Run in a +# client where you have done envsetup, lunch, etc. # # TODO: find some way to get this run regularly along with the rest of # the tests. @@ -68,18 +64,39 @@ $ADB push $ANDROID_PRODUCT_OUT/system/bin/verifier_test \ expect_succeed() { testname "$1 (should succeed)" $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip - run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip || fail + shift + run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip || fail } expect_fail() { testname "$1 (should fail)" $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip - run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip && fail + shift + run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip && fail } +# not signed at all expect_fail unsigned.zip +# signed in the pre-donut way expect_fail jarsigned.zip + +# success cases expect_succeed otasigned.zip +expect_succeed otasigned_f4.zip -f4 +expect_succeed otasigned_sha256.zip -sha256 +expect_succeed otasigned_f4_sha256.zip -sha256 -f4 + +# verified against different key +expect_fail otasigned.zip -f4 +expect_fail otasigned_f4.zip + +# verified against right key but wrong hash algorithm +expect_fail otasigned.zip -sha256 +expect_fail otasigned_f4.zip -sha256 -f4 +expect_fail otasigned_sha256.zip +expect_fail otasigned_f4_sha256.zip -f4 + +# various other cases expect_fail random.zip expect_fail fake-eocd.zip expect_fail alter-metadata.zip diff --git a/voldclient/Android.mk b/voldclient/Android.mk new file mode 100644 index 000000000..b76d7bea3 --- /dev/null +++ b/voldclient/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := libvoldclient +LOCAL_SRC_FILES := commands.c dispatcher.c event_loop.c +LOCAL_CFLAGS := -DMINIVOLD -Werror +LOCAL_C_INCLUDES := \ + bootable/recovery \ + system/core/fs_mgr/include \ + system/core/include \ + system/core/libcutils \ + system/vold +LOCAL_MODULE_TAGS := optional +include $(BUILD_STATIC_LIBRARY) diff --git a/voldclient/commands.c b/voldclient/commands.c new file mode 100644 index 000000000..0287ad233 --- /dev/null +++ b/voldclient/commands.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2013 The CyanogenMod 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 "voldclient.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +int vold_update_volumes() { + + const char *cmd[2] = {"volume", "list"}; + return vold_command(2, cmd, 1); +} + +int vold_mount_volume(const char* path, int wait) { + + const char *cmd[3] = { "volume", "mount", path }; + int state = vold_get_volume_state(path); + + if (state == State_Mounted) { + LOGI("Volume %s already mounted\n", path); + return 0; + } + + if (state != State_Idle) { + LOGI("Volume %s is not idle, current state is %d\n", path, state); + return -1; + } + + if (access(path, R_OK) != 0) { + mkdir(path, 0000); + chown(path, 1000, 1000); + } + return vold_command(3, cmd, wait); +} + +int vold_unmount_volume(const char* path, int force, int wait) { + + const char *cmd[4] = { "volume", "unmount", path, "force" }; + int state = vold_get_volume_state(path); + + if (state <= State_Idle) { + LOGI("Volume %s is not mounted\n", path); + return 0; + } + + if (state != State_Mounted) { + LOGI("Volume %s cannot be unmounted in state %d\n", path, state); + return -1; + } + + return vold_command(force ? 4: 3, cmd, wait); +} + +int vold_share_volume(const char* path) { + + const char *cmd[4] = { "volume", "share", path, "ums" }; + int state = vold_get_volume_state(path); + + if (state == State_Mounted) + vold_unmount_volume(path, 0, 1); + + return vold_command(4, cmd, 1); +} + +int vold_unshare_volume(const char* path, int mount) { + + const char *cmd[4] = { "volume", "unshare", path, "ums" }; + int state = vold_get_volume_state(path); + int ret = 0; + + if (state != State_Shared) { + LOGE("Volume %s is not shared - state=%d\n", path, state); + return 0; + } + + ret = vold_command(4, cmd, 1); + + if (mount) + vold_mount_volume(path, 1); + + return ret; +} + +int vold_format_volume(const char* path, int wait) { + + const char* cmd[3] = { "volume", "format", path }; + return vold_command(3, cmd, wait); +} + +int vold_custom_format_volume(const char* path, const char* fstype, int wait) { + const char* cmd[4] = { "volume", "format", path, fstype }; + return vold_command(4, cmd, wait); +} + +const char* volume_state_to_string(int state) { + if (state == State_Init) + return "Initializing"; + else if (state == State_NoMedia) + return "No-Media"; + else if (state == State_Idle) + return "Idle-Unmounted"; + else if (state == State_Pending) + return "Pending"; + else if (state == State_Mounted) + return "Mounted"; + else if (state == State_Unmounting) + return "Unmounting"; + else if (state == State_Checking) + return "Checking"; + else if (state == State_Formatting) + return "Formatting"; + else if (state == State_Shared) + return "Shared-Unmounted"; + else if (state == State_SharedMnt) + return "Shared-Mounted"; + else + return "Unknown-Error"; +} + diff --git a/voldclient/dispatcher.c b/voldclient/dispatcher.c new file mode 100644 index 000000000..1bfe96fd2 --- /dev/null +++ b/voldclient/dispatcher.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2013 The CyanogenMod 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 "voldclient.h" + +#include +#include +#include +#include +#include +#include + +#include "ResponseCode.h" + +#include "common.h" + +static struct vold_callbacks* callbacks = NULL; +static int should_automount = 0; + +struct volume_node { + const char *label; + const char *path; + int state; + struct volume_node *next; +}; + +static struct volume_node *volume_head = NULL; +static struct volume_node *volume_tail = NULL; + +static int num_volumes = 0; + +static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; + +void vold_set_callbacks(struct vold_callbacks* ev_callbacks) { + callbacks = ev_callbacks; +} + +void vold_set_automount(int automount) { + should_automount = automount; +} + +void vold_mount_all() { + + struct volume_node *node; + + pthread_rwlock_rdlock(&rwlock); + for (node = volume_head; node; node = node->next) { + if (node->state == State_Idle) { + vold_mount_volume(node->path, 0); + } + } + pthread_rwlock_unlock(&rwlock); +} + +void vold_unmount_all() { + + struct volume_node *node; + + pthread_rwlock_rdlock(&rwlock); + for (node = volume_head; node; node = node->next) { + if (node->state >= State_Shared) { + vold_unshare_volume(node->path, 0); + } + if (node->state == State_Mounted) { + vold_unmount_volume(node->path, 1, 1); + } + } + pthread_rwlock_unlock(&rwlock); +} + +int vold_get_volume_state(const char *path) { + + int ret = 0; + struct volume_node *node; + + pthread_rwlock_rdlock(&rwlock); + for (node = volume_head; node; node = node->next) { + if (strcmp(path, node->path) == 0) { + ret = node->state; + break; + } + } + pthread_rwlock_unlock(&rwlock); + return ret; +} + +int vold_get_num_volumes() { + return num_volumes; +} + +int vold_is_volume_available(const char *path) { + return vold_get_volume_state(path) > 0; +} + +static void free_volume_list_locked() { + + struct volume_node *node; + + node = volume_head; + while (node) { + struct volume_node *next = node->next; + free((void *)node->path); + free((void *)node->label); + free(node); + node = next; + } + volume_head = volume_tail = NULL; +} + +static int is_listing_volumes = 0; + +static void vold_handle_volume_list(const char* label, const char* path, int state) { + + struct volume_node *node; + + pthread_rwlock_wrlock(&rwlock); + if (is_listing_volumes == 0) { + free_volume_list_locked(); + num_volumes = 0; + is_listing_volumes = 1; + } + + node = (struct volume_node *)malloc(sizeof(struct volume_node)); + node->label = strdup(label); + node->path = strdup(path); + node->state = state; + node->next = NULL; + + if (volume_head == NULL) + volume_head = volume_tail = node; + else { + volume_tail->next = node; + volume_tail = node; + } + + num_volumes++; + pthread_rwlock_unlock(&rwlock); +} + +static void vold_handle_volume_list_done() { + + pthread_rwlock_wrlock(&rwlock); + is_listing_volumes = 0; + pthread_rwlock_unlock(&rwlock); +} + +static void set_volume_state(char* path, int state) { + + struct volume_node *node; + + pthread_rwlock_rdlock(&rwlock); + for (node = volume_head; node; node = node->next) { + if (strcmp(node->path, path) == 0) { + node->state = state; + break; + } + } + pthread_rwlock_unlock(&rwlock); +} + +static void vold_handle_volume_state_change(char* label, char* path, int state) { + + set_volume_state(path, state); + + if (callbacks != NULL && callbacks->state_changed != NULL) + callbacks->state_changed(label, path, state); +} + +static void vold_handle_volume_inserted(char* label, char* path) { + + set_volume_state(path, State_Idle); + + if (callbacks != NULL && callbacks->disk_added != NULL) + callbacks->disk_added(label, path); + + if (should_automount) + vold_mount_volume(path, 0); +} + +static void vold_handle_volume_removed(char* label, char* path) { + + set_volume_state(path, State_NoMedia); + + if (callbacks != NULL && callbacks->disk_removed != NULL) + callbacks->disk_removed(label, path); +} + +int vold_dispatch(int code, char** tokens, int len) { + + int i = 0; + int ret = 0; + + if (code == VolumeListResult) { + //