Merge from ClockworkMod recovery
Change-Id: Id5b312147173ced559a62d97029acede6c2f8766
diff --git a/Android.mk b/Android.mk
index e6c3547..b0fc158 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,6 +5,7 @@
include $(CLEAR_VARS)
commands_recovery_local_path := $(LOCAL_PATH)
+# LOCAL_CPP_EXTENSION := .c
LOCAL_SRC_FILES := \
recovery.c \
@@ -13,15 +14,30 @@
roots.c \
ui.c \
verifier.c \
- encryptedfs_provisioning.c
+ encryptedfs_provisioning.c \
+ mounts.c \
+ extendedcommands.c \
+ nandroid.c \
+ reboot.c \
+ setprop.c
LOCAL_MODULE := recovery
LOCAL_FORCE_STATIC_EXECUTABLE := true
-RECOVERY_API_VERSION := 3
+RECOVERY_VERSION := ClockworkMod Recovery v2.5.1.8
+LOCAL_CFLAGS += -DRECOVERY_VERSION="$(RECOVERY_VERSION)"
+RECOVERY_API_VERSION := 2
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
+BOARD_RECOVERY_DEFINES := BOARD_HAS_NO_SELECT_BUTTON BOARD_SDCARD_DEVICE_PRIMARY BOARD_SDCARD_DEVICE_SECONDARY BOARD_SDEXT_DEVICE BOARD_SDEXT_FILESYSTEM BOARD_DATA_DEVICE BOARD_DATA_FILESYSTEM BOARD_DATADATA_DEVICE BOARD_DATADATA_FILESYSTEM BOARD_CACHE_DEVICE BOARD_CACHE_FILESYSTEM BOARD_SYSTEM_DEVICE BOARD_SYSTEM_FILESYSTEM BOARD_HAS_DATADATA BOARD_DATA_FILESYSTEM_OPTIONS BOARD_DATADATA_FILESYSTEM_OPTIONS BOARD_CACHE_FILESYSTEM_OPTIONS BOARD_SYSTEM_FILESYSTEM_OPTIONS BOARD_HAS_MTD_CACHE BOARD_USES_BMLUTILS BOARD_USES_MMCUTILS BOARD_HAS_SMALL_RECOVERY BOARD_LDPI_RECOVERY BOARD_RECOVERY_IGNORE_BOOTABLES BOARD_HAS_NO_MISC_PARTITION BOARD_HAS_SDCARD_INTERNAL BOARD_SDCARD_DEVICE_INTERNAL BOARD_HIJACK_RECOVERY_PATH
+
+$(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
+ $(if $($(board_define)), \
+ $(eval LOCAL_CFLAGS += -D$(board_define)=\"$($(board_define))\") \
+ ) \
+ )
+
# This binary is in the recovery ramdisk, which is otherwise a copy of root.
# It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses
# a (redundant) copy of the binary in /system/bin for user builds.
@@ -30,13 +46,18 @@
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES :=
-ifeq ($(TARGET_RECOVERY_UI_LIB),)
+ifeq ($(BOARD_CUSTOM_RECOVERY_KEYMAPPING),)
LOCAL_SRC_FILES += default_recovery_ui.c
else
- LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
+ LOCAL_SRC_FILES += $(BOARD_CUSTOM_RECOVERY_KEYMAPPING)
endif
+
LOCAL_STATIC_LIBRARIES += libext4_utils libz
-LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt
+LOCAL_STATIC_LIBRARIES += libminzip libunz libmincrypt
+
+LOCAL_STATIC_LIBRARIES += libbusybox libclearsilverregex libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image
+LOCAL_STATIC_LIBRARIES += libflashutils libmtdutils libmmcutils libbmlutils
+
LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
LOCAL_STATIC_LIBRARIES += libstdc++ libc
@@ -44,6 +65,46 @@
include $(BUILD_EXECUTABLE)
+RECOVERY_LINKS := edify busybox flash_image dump_image mkyaffs2image unyaffs erase_image nandroid reboot
+
+# nc is provided by external/netcat
+RECOVERY_SYMLINKS := $(addprefix $(TARGET_RECOVERY_ROOT_OUT)/sbin/,$(RECOVERY_LINKS))
+$(RECOVERY_SYMLINKS): RECOVERY_BINARY := $(LOCAL_MODULE)
+$(RECOVERY_SYMLINKS): $(LOCAL_INSTALLED_MODULE)
+ @echo "Symlink: $@ -> $(RECOVERY_BINARY)"
+ @mkdir -p $(dir $@)
+ @rm -rf $@
+ $(hide) ln -sf $(RECOVERY_BINARY) $@
+
+ALL_DEFAULT_INSTALLED_MODULES += $(RECOVERY_SYMLINKS)
+
+# Now let's do recovery symlinks
+BUSYBOX_LINKS := $(shell cat external/busybox/busybox-minimal.links)
+RECOVERY_BUSYBOX_SYMLINKS := $(addprefix $(TARGET_RECOVERY_ROOT_OUT)/sbin/,$(filter-out $(exclude),$(notdir $(BUSYBOX_LINKS))))
+$(RECOVERY_BUSYBOX_SYMLINKS): BUSYBOX_BINARY := busybox
+$(RECOVERY_BUSYBOX_SYMLINKS): $(LOCAL_INSTALLED_MODULE)
+ @echo "Symlink: $@ -> $(BUSYBOX_BINARY)"
+ @mkdir -p $(dir $@)
+ @rm -rf $@
+ $(hide) ln -sf $(BUSYBOX_BINARY) $@
+
+ALL_DEFAULT_INSTALLED_MODULES += $(RECOVERY_BUSYBOX_SYMLINKS)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := nandroid-md5.sh
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := nandroid-md5.sh
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := killrecovery.sh
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := killrecovery.sh
+include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
@@ -60,13 +121,17 @@
include $(BUILD_EXECUTABLE)
+include $(commands_recovery_local_path)/bmlutils/Android.mk
+include $(commands_recovery_local_path)/flashutils/Android.mk
include $(commands_recovery_local_path)/minui/Android.mk
include $(commands_recovery_local_path)/minzip/Android.mk
include $(commands_recovery_local_path)/mtdutils/Android.mk
+include $(commands_recovery_local_path)/mmcutils/Android.mk
include $(commands_recovery_local_path)/tools/Android.mk
include $(commands_recovery_local_path)/edify/Android.mk
include $(commands_recovery_local_path)/updater/Android.mk
include $(commands_recovery_local_path)/applypatch/Android.mk
+include $(commands_recovery_local_path)/utilities/Android.mk
commands_recovery_local_path :=
endif # TARGET_ARCH == arm
diff --git a/bmlutils/Android.mk b/bmlutils/Android.mk
new file mode 100644
index 0000000..e95cb5f
--- /dev/null
+++ b/bmlutils/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DBOARD_BOOT_DEVICE=\"$(BOARD_BOOT_DEVICE)\"
+LOCAL_SRC_FILES := bmlutils.c
+LOCAL_MODULE := libbmlutils
+LOCAL_MODULE_TAGS := eng
+include $(BUILD_STATIC_LIBRARY)
diff --git a/bmlutils/bmlutils.c b/bmlutils/bmlutils.c
new file mode 100644
index 0000000..1cc28b2
--- /dev/null
+++ b/bmlutils/bmlutils.c
@@ -0,0 +1,100 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <linux/input.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/wait.h>
+#include <sys/limits.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <signal.h>
+#include <sys/wait.h>
+
+extern int __system(const char *command);
+#define BML_UNLOCK_ALL 0x8A29 ///< unlock all partition RO -> RW
+
+static int restore_internal(const char* bml, const char* filename)
+{
+ char buf[4096];
+ int dstfd, srcfd, bytes_read, bytes_written, total_read = 0;
+ if (filename == NULL)
+ srcfd = 0;
+ else {
+ srcfd = open(filename, O_RDONLY | O_LARGEFILE);
+ if (srcfd < 0)
+ return 2;
+ }
+ dstfd = open(bml, O_RDWR | O_LARGEFILE);
+ if (dstfd < 0)
+ return 3;
+ if (ioctl(dstfd, BML_UNLOCK_ALL, 0))
+ return 4;
+ do {
+ total_read += bytes_read = read(srcfd, buf, 4096);
+ if (!bytes_read)
+ break;
+ if (bytes_read < 4096)
+ memset(&buf[bytes_read], 0, 4096 - bytes_read);
+ if (write(dstfd, buf, 4096) < 4096)
+ return 5;
+ } while(bytes_read == 4096);
+
+ close(dstfd);
+ close(srcfd);
+
+ return 0;
+}
+
+int cmd_bml_restore_raw_partition(const char *partition, const char *filename)
+{
+ char *bml;
+ if (strcmp(partition, "boot") == 0 || strcmp(partition, "recovery") == 0)
+ bml = "/dev/block/bml7";
+ else
+ return 6;
+
+ int ret = restore_internal("/dev/block/bml7", filename);
+ if (ret != 0)
+ return ret;
+
+ ret = restore_internal("/dev/block/bml8", filename);
+ return ret;
+}
+
+int cmd_bml_backup_raw_partition(const char *partition, const char *filename)
+{
+ char tmp[PATH_MAX];
+ sprintf(tmp, "dd of=%s if=/dev/block/bml7 bs=4096", filename);
+ return __system(tmp);
+}
+
+int cmd_bml_erase_raw_partition(const char *partition)
+{
+ // TODO: implement raw wipe
+ return 0;
+}
+
+int cmd_bml_erase_partition(const char *partition, const char *filesystem)
+{
+ return -1;
+}
+
+int cmd_bml_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
+{
+ return -1;
+}
+
+int cmd_bml_get_partition_device(const char *partition, char *device)
+{
+ return -1;
+}
diff --git a/bootloader.h b/bootloader.h
index 2e749aa..3d4302f 100644
--- a/bootloader.h
+++ b/bootloader.h
@@ -47,4 +47,13 @@
int get_bootloader_message(struct bootloader_message *out);
int set_bootloader_message(const struct bootloader_message *in);
+/* Write an update to the cache partition for update-radio or update-hboot.
+ * Note, this destroys any filesystem on the cache partition!
+ * The expected bitmap format is 240x320, 16bpp (2Bpp), RGB 5:6:5.
+ */
+int write_update_for_bootloader(
+ const char *update, int update_len,
+ int bitmap_width, int bitmap_height, int bitmap_bpp,
+ const char *busy_bitmap, const char *error_bitmap);
+
#endif
diff --git a/common.h b/common.h
index 97e87ee..df26597 100644
--- a/common.h
+++ b/common.h
@@ -34,10 +34,13 @@
// so keep the output short and not too cryptic.
void ui_print(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+void ui_reset_text_col();
+void ui_set_show_text(int value);
+
// 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).
-void ui_start_menu(char** headers, char** items, int initial_selection);
+int ui_start_menu(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);
@@ -45,15 +48,25 @@
// statements will be displayed.
void ui_end_menu();
+int ui_get_showing_back_button();
+void ui_set_showing_back_button(int showBackButton);
+
// Set the icon (normally the only thing visible besides the progress bar).
enum {
BACKGROUND_ICON_NONE,
BACKGROUND_ICON_INSTALLING,
BACKGROUND_ICON_ERROR,
+ BACKGROUND_ICON_FIRMWARE_INSTALLING,
+ BACKGROUND_ICON_FIRMWARE_ERROR,
NUM_BACKGROUND_ICONS
};
void ui_set_background(int icon);
+// Get a malloc'd copy of the screen image showing (only) the specified icon.
+// Also returns the width, height, and bits per pixel of the returned image.
+// TODO: Use some sort of "struct Bitmap" here instead of all these variables?
+char *ui_copy_image(int icon, int *width, int *height, int *bpp);
+
// Show a progress bar and define the scope of the next operation:
// portion - fraction of the progress bar the next operation will use
// seconds - expected time interval (progress bar moves at this minimum rate)
diff --git a/default_recovery_ui.c b/default_recovery_ui.c
index ce12787..9c192a2 100644
--- a/default_recovery_ui.c
+++ b/default_recovery_ui.c
@@ -18,15 +18,18 @@
#include "recovery_ui.h"
#include "common.h"
+#include "extendedcommands.h"
-char* MENU_HEADERS[] = { "Android system recovery utility",
- "",
- NULL };
+char* MENU_HEADERS[] = { NULL };
char* MENU_ITEMS[] = { "reboot system now",
"apply update from sdcard",
"wipe data/factory reset",
"wipe cache partition",
+ "install zip from sdcard",
+ "backup and restore",
+ "mounts and storage",
+ "advanced",
NULL };
int device_recovery_start() {
@@ -34,7 +37,14 @@
}
int device_toggle_display(volatile char* key_pressed, int key_code) {
- return key_code == KEY_HOME;
+ int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT];
+ if (alt && key_code == KEY_L)
+ return 1;
+ // allow toggling of the display if the correct key is pressed, and the display toggle is allowed or the display is currently off
+ if (ui_get_showing_back_button()) {
+ return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_END);
+ }
+ return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_POWER || key_code == KEY_END);
}
int device_reboot_now(volatile char* key_pressed, int key_code) {
@@ -44,16 +54,37 @@
int device_handle_key(int key_code, int visible) {
if (visible) {
switch (key_code) {
+ case KEY_CAPSLOCK:
case KEY_DOWN:
case KEY_VOLUMEDOWN:
return HIGHLIGHT_DOWN;
+ case KEY_LEFTSHIFT:
case KEY_UP:
case KEY_VOLUMEUP:
return HIGHLIGHT_UP;
+ case KEY_POWER:
+ if (ui_get_showing_back_button()) {
+ return SELECT_ITEM;
+ }
+ if (!get_allow_toggle_display())
+ return GO_BACK;
+ break;
+ case KEY_LEFTBRACE:
case KEY_ENTER:
+ case BTN_MOUSE:
+ case KEY_CENTER:
+ case KEY_CAMERA:
+ case KEY_F21:
+ case KEY_SEND:
return SELECT_ITEM;
+
+ case KEY_END:
+ case KEY_BACKSPACE:
+ case KEY_BACK:
+ if (!get_allow_toggle_display())
+ return GO_BACK;
}
}
diff --git a/encryptedfs_provisioning.c b/encryptedfs_provisioning.c
index 601c817..678c09f 100644
--- a/encryptedfs_provisioning.c
+++ b/encryptedfs_provisioning.c
@@ -27,7 +27,7 @@
#include "cutils/properties.h"
#include "common.h"
#include "mtdutils/mtdutils.h"
-#include "mtdutils/mounts.h"
+#include "mounts.h"
#include "roots.h"
const char* encrypted_fs_enabled_property = "persist.security.secfs.enabled";
diff --git a/etc/init.rc b/etc/init.rc
index a675a4b..e6b43e0 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -10,6 +10,7 @@
symlink /system/etc /etc
mkdir /sdcard
+ mkdir /emmc
mkdir /system
mkdir /data
mkdir /cache
diff --git a/extendedcommands.c b/extendedcommands.c
new file mode 100644
index 0000000..df22448
--- /dev/null
+++ b/extendedcommands.c
@@ -0,0 +1,972 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <linux/input.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/wait.h>
+#include <sys/limits.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <signal.h>
+#include <sys/wait.h>
+
+#include "bootloader.h"
+#include "common.h"
+#include "cutils/properties.h"
+#include "firmware.h"
+#include "install.h"
+#include "minui/minui.h"
+#include "minzip/DirUtil.h"
+#include "roots.h"
+#include "recovery_ui.h"
+
+#include "../../external/yaffs2/yaffs2/utils/mkyaffs2image.h"
+#include "../../external/yaffs2/yaffs2/utils/unyaffs.h"
+
+#include "extendedcommands.h"
+#include "nandroid.h"
+#include "mounts.h"
+
+int signature_check_enabled = 1;
+int script_assert_enabled = 1;
+static const char *SDCARD_UPDATE_FILE = "/sdcard/update.zip";
+
+void
+toggle_signature_check()
+{
+ signature_check_enabled = !signature_check_enabled;
+ ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled");
+}
+
+void toggle_script_asserts()
+{
+ script_assert_enabled = !script_assert_enabled;
+ ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled");
+}
+
+int install_zip(const char* packagefilepath)
+{
+ ui_print("\n-- Installing: %s\n", packagefilepath);
+#ifndef BOARD_HAS_NO_MISC_PARTITION
+ set_sdcard_update_bootloader_message();
+#endif
+ int status = install_package(packagefilepath);
+ ui_reset_progress();
+ if (status != INSTALL_SUCCESS) {
+ ui_set_background(BACKGROUND_ICON_ERROR);
+ ui_print("Installation aborted.\n");
+ return 1;
+ }
+ ui_set_background(BACKGROUND_ICON_NONE);
+ ui_print("\nInstall from sdcard complete.\n");
+ return 0;
+}
+
+char* INSTALL_MENU_ITEMS[] = { "apply /sdcard/update.zip",
+ "choose zip from sdcard",
+ "toggle signature verification",
+ "toggle script asserts",
+ NULL };
+#define ITEM_APPLY_SDCARD 0
+#define ITEM_CHOOSE_ZIP 1
+#define ITEM_SIG_CHECK 2
+#define ITEM_ASSERTS 3
+
+void show_install_update_menu()
+{
+ static char* headers[] = { "Apply update from .zip file on SD card",
+ "",
+ NULL
+ };
+ for (;;)
+ {
+ int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0, 0);
+ switch (chosen_item)
+ {
+ case ITEM_ASSERTS:
+ toggle_script_asserts();
+ break;
+ case ITEM_SIG_CHECK:
+ toggle_signature_check();
+ break;
+ case ITEM_APPLY_SDCARD:
+ {
+ if (confirm_selection("Confirm install?", "Yes - Install /sdcard/update.zip"))
+ install_zip(SDCARD_UPDATE_FILE);
+ break;
+ }
+ case ITEM_CHOOSE_ZIP:
+ show_choose_zip_menu();
+ break;
+ default:
+ return;
+ }
+
+ }
+}
+
+void free_string_array(char** array)
+{
+ if (array == NULL)
+ return;
+ char* cursor = array[0];
+ int i = 0;
+ while (cursor != NULL)
+ {
+ free(cursor);
+ cursor = array[++i];
+ }
+ free(array);
+}
+
+char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
+{
+ char path[PATH_MAX] = "";
+ DIR *dir;
+ struct dirent *de;
+ int total = 0;
+ int i;
+ char** files = NULL;
+ int pass;
+ *numFiles = 0;
+ int dirLen = strlen(directory);
+
+ dir = opendir(directory);
+ if (dir == NULL) {
+ ui_print("Couldn't open directory.\n");
+ return NULL;
+ }
+
+ int extension_length = 0;
+ if (fileExtensionOrDirectory != NULL)
+ extension_length = strlen(fileExtensionOrDirectory);
+
+ int isCounting = 1;
+ i = 0;
+ for (pass = 0; pass < 2; pass++) {
+ while ((de=readdir(dir)) != NULL) {
+ // skip hidden files
+ if (de->d_name[0] == '.')
+ continue;
+
+ // NULL means that we are gathering directories, so skip this
+ if (fileExtensionOrDirectory != NULL)
+ {
+ // make sure that we can have the desired extension (prevent seg fault)
+ if (strlen(de->d_name) < extension_length)
+ continue;
+ // compare the extension
+ if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
+ continue;
+ }
+ else
+ {
+ struct stat info;
+ char fullFileName[PATH_MAX];
+ strcpy(fullFileName, directory);
+ strcat(fullFileName, de->d_name);
+ stat(fullFileName, &info);
+ // make sure it is a directory
+ if (!(S_ISDIR(info.st_mode)))
+ continue;
+ }
+
+ if (pass == 0)
+ {
+ total++;
+ continue;
+ }
+
+ files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
+ strcpy(files[i], directory);
+ strcat(files[i], de->d_name);
+ if (fileExtensionOrDirectory == NULL)
+ strcat(files[i], "/");
+ i++;
+ }
+ if (pass == 1)
+ break;
+ if (total == 0)
+ break;
+ rewinddir(dir);
+ *numFiles = total;
+ files = (char**) malloc((total+1)*sizeof(char*));
+ files[total]=NULL;
+ }
+
+ if(closedir(dir) < 0) {
+ LOGE("Failed to close directory.");
+ }
+
+ if (total==0) {
+ return NULL;
+ }
+
+ // sort the result
+ if (files != NULL) {
+ for (i = 0; i < total; i++) {
+ int curMax = -1;
+ int j;
+ for (j = 0; j < total - i; j++) {
+ if (curMax == -1 || strcmp(files[curMax], files[j]) < 0)
+ curMax = j;
+ }
+ char* temp = files[curMax];
+ files[curMax] = files[total - i - 1];
+ files[total - i - 1] = temp;
+ }
+ }
+
+ return files;
+}
+
+// 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 path[PATH_MAX] = "";
+ DIR *dir;
+ struct dirent *de;
+ int numFiles = 0;
+ int numDirs = 0;
+ int i;
+ char* return_value = NULL;
+ int dir_len = strlen(directory);
+
+ char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
+ char** dirs = NULL;
+ if (fileExtensionOrDirectory != NULL)
+ dirs = gather_files(directory, NULL, &numDirs);
+ int total = numDirs + numFiles;
+ if (total == 0)
+ {
+ ui_print("No files found.\n");
+ }
+ else
+ {
+ char** list = (char**) malloc((total + 1) * sizeof(char*));
+ list[total] = NULL;
+
+
+ for (i = 0 ; i < numDirs; i++)
+ {
+ list[i] = strdup(dirs[i] + dir_len);
+ }
+
+ for (i = 0 ; i < numFiles; i++)
+ {
+ list[numDirs + i] = strdup(files[i] + dir_len);
+ }
+
+ for (;;)
+ {
+ int chosen_item = get_menu_selection(headers, list, 0, 0);
+ if (chosen_item == GO_BACK)
+ break;
+ static char ret[PATH_MAX];
+ if (chosen_item < numDirs)
+ {
+ char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
+ if (subret != NULL)
+ {
+ strcpy(ret, subret);
+ return_value = ret;
+ break;
+ }
+ continue;
+ }
+ strcpy(ret, files[chosen_item - numDirs]);
+ return_value = ret;
+ break;
+ }
+ free_string_array(list);
+ }
+
+ free_string_array(files);
+ free_string_array(dirs);
+ return return_value;
+}
+
+void show_choose_zip_menu()
+{
+ if (ensure_path_mounted("/sdcard") != 0) {
+ LOGE ("Can't mount /sdcard\n");
+ return;
+ }
+
+ static char* headers[] = { "Choose a zip to apply",
+ "",
+ NULL
+ };
+
+ char* file = choose_file_menu("/sdcard/", ".zip", headers);
+ if (file == NULL)
+ return;
+ static char* confirm_install = "Confirm install?";
+ static char confirm[PATH_MAX];
+ sprintf(confirm, "Yes - Install %s", basename(file));
+ if (confirm_selection(confirm_install, confirm))
+ install_zip(file);
+}
+
+void show_nandroid_restore_menu()
+{
+ if (ensure_path_mounted("/sdcard") != 0) {
+ LOGE ("Can't mount /sdcard\n");
+ return;
+ }
+
+ static char* headers[] = { "Choose an image to restore",
+ "",
+ NULL
+ };
+
+ char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
+ if (file == NULL)
+ return;
+
+ if (confirm_selection("Confirm restore?", "Yes - Restore"))
+ nandroid_restore(file, 1, 1, 1, 1, 1);
+}
+
+void show_mount_usb_storage_menu()
+{
+ char command[PATH_MAX];
+ Volume *vol = volume_for_path("/sdcard");
+ sprintf(command, "echo %s > /sys/devices/platform/usb_mass_storage/lun0/file", vol->device);
+ __system(command);
+ static char* headers[] = { "USB Mass Storage device",
+ "Leaving this menu unmount",
+ "your SD card from your PC.",
+ "",
+ NULL
+ };
+
+ static char* list[] = { "Unmount", NULL };
+
+ for (;;)
+ {
+ int chosen_item = get_menu_selection(headers, list, 0, 0);
+ if (chosen_item == GO_BACK || chosen_item == 0)
+ break;
+ }
+
+ __system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
+ __system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
+}
+
+int confirm_selection(const char* title, const char* confirm)
+{
+ struct stat info;
+ if (0 == stat("/sdcard/clockworkmod/.no_confirm", &info))
+ return 1;
+
+ char* confirm_headers[] = { title, " THIS CAN NOT BE UNDONE.", "", NULL };
+ char* items[] = { "No",
+ "No",
+ "No",
+ "No",
+ "No",
+ "No",
+ "No",
+ confirm, //" Yes -- wipe partition", // [7
+ "No",
+ "No",
+ "No",
+ NULL };
+
+ int chosen_item = get_menu_selection(confirm_headers, items, 0, 0);
+ return chosen_item == 7;
+}
+
+int format_unknown_device(const char* path)
+{
+ // if this is SDEXT:, don't worry about it.
+ if (0 == strcmp(path, "/sd-ext"))
+ {
+ struct stat st;
+ Volume *vol = volume_for_path("/sd-ext");
+ if (vol == NULL || 0 != stat(vol->device, &st))
+ {
+ ui_print("No app2sd partition found. Skipping format of /sd-ext.\n");
+ return 0;
+ }
+ }
+
+ if (0 != ensure_path_mounted(path))
+ {
+ ui_print("Error mounting %s!\n", path);
+ ui_print("Skipping format...\n");
+ return 0;
+ }
+
+ static char tmp[PATH_MAX];
+ sprintf(tmp, "rm -rf %s/*", path);
+ __system(tmp);
+ sprintf(tmp, "rm -rf %s/.*", path);
+ __system(tmp);
+
+ ensure_path_unmounted(path);
+ return 0;
+}
+
+//#define MOUNTABLE_COUNT 5
+//#define DEVICE_COUNT 4
+//#define MMC_COUNT 2
+
+void show_partition_menu()
+{
+ static char* headers[] = { "Mounts and Storage Menu",
+ "",
+ NULL
+ };
+
+ typedef char* string;
+ string mounts[][3] = {
+ { "mount /system", "unmount /system", "/system" },
+ { "mount /data", "unmount /data", "/data" },
+ { "mount /cache", "unmount /cache", "/cache" },
+ { "mount /sdcard", "unmount /sdcard", "/sdcard:" },
+#ifdef BOARD_HAS_SDCARD_INTERNAL
+ { "mount /emmc", "unmount /emmc", "/emmc" },
+#endif
+ { "mount /sd-ext", "unmount /sd-ext", "/sd-ext" }
+ };
+
+ string devices[][2] = {
+ { "format boot", "boot:" },
+ { "format system", "/system" },
+ { "format data", "/data" },
+ { "format cache", "/cache" },
+ { "format sdcard", "/sdcard" },
+ { "format sd-ext", "/sd-ext" },
+#ifdef BOARD_HAS_SDCARD_INTERNAL
+ { "format internal sdcard", "/emmc" }
+#endif
+ };
+
+ const int MOUNTABLE_COUNT = sizeof(mounts) / sizeof(string) / 3;
+ const int DEVICE_COUNT = sizeof(devices) / sizeof(string) / 2;
+
+ static char* confirm_format = "Confirm format?";
+ static char* confirm = "Yes - Format";
+
+ for (;;)
+ {
+ int ismounted[MOUNTABLE_COUNT];
+ int i;
+ static string options[MOUNTABLE_COUNT + DEVICE_COUNT + 1 + 1]; // mountables, format mtds, format mmcs, usb storage, null
+ for (i = 0; i < MOUNTABLE_COUNT; i++)
+ {
+ ismounted[i] = is_path_mounted(mounts[i][2]);
+ options[i] = ismounted[i] ? mounts[i][1] : mounts[i][0];
+ }
+
+ for (i = 0; i < DEVICE_COUNT; i++)
+ {
+ options[DEVICE_COUNT + i] = devices[i][0];
+ }
+
+ options[MOUNTABLE_COUNT + DEVICE_COUNT] = "mount USB storage";
+ options[MOUNTABLE_COUNT + DEVICE_COUNT + 1] = NULL;
+
+ int chosen_item = get_menu_selection(headers, options, 0, 0);
+ if (chosen_item == GO_BACK)
+ break;
+ if (chosen_item == MOUNTABLE_COUNT + DEVICE_COUNT)
+ {
+ show_mount_usb_storage_menu();
+ }
+ else if (chosen_item < MOUNTABLE_COUNT)
+ {
+ if (ismounted[chosen_item])
+ {
+ if (0 != ensure_path_unmounted(mounts[chosen_item][2]))
+ ui_print("Error unmounting %s!\n", mounts[chosen_item][2]);
+ }
+ else
+ {
+ if (0 != ensure_path_mounted(mounts[chosen_item][2]))
+ ui_print("Error mounting %s!\n", mounts[chosen_item][2]);
+ }
+ }
+ else if (chosen_item < MOUNTABLE_COUNT + DEVICE_COUNT)
+ {
+ chosen_item = chosen_item - MOUNTABLE_COUNT;
+ if (!confirm_selection(confirm_format, confirm))
+ continue;
+ ui_print("Formatting %s...\n", devices[chosen_item][1]);
+ if (0 != format_device(devices[chosen_item][1]))
+ ui_print("Error formatting %s!\n", devices[chosen_item][1]);
+ else
+ ui_print("Done.\n");
+ }
+ }
+}
+
+#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
+
+int extendedcommand_file_exists()
+{
+ struct stat file_info;
+ return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
+}
+
+int run_script_from_buffer(char* script_data, int script_len, char* filename)
+{
+ ui_print("not yet implemented.\n");
+ return -1;
+
+ /*
+ const AmCommandList *commands = parseAmendScript(script_data, script_len);
+ if (commands == NULL) {
+ printf("Syntax error in update script\n");
+ return 1;
+ } else {
+ printf("Parsed %.*s\n", script_len, filename);
+ }
+
+ int ret = execCommandList((ExecContext *)1, commands);
+ if (ret != 0) {
+ int num = ret;
+ char *line = NULL, *next = script_data;
+ while (next != NULL && ret-- > 0) {
+ line = next;
+ next = memchr(line, '\n', script_data + script_len - line);
+ if (next != NULL) *next++ = '\0';
+ }
+ printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
+ return 1;
+ }
+ */
+}
+
+int run_script(char* filename)
+{
+ struct stat file_info;
+ if (0 != stat(filename, &file_info)) {
+ printf("Error executing stat on file: %s\n", filename);
+ return 1;
+ }
+
+ int script_len = file_info.st_size;
+ char* script_data = (char*)malloc(script_len + 1);
+ FILE *file = fopen(filename, "rb");
+ fread(script_data, script_len, 1, file);
+ // supposedly not necessary, but let's be safe.
+ script_data[script_len] = '\0';
+ fclose(file);
+ LOGI("Running script:\n");
+ LOGI("\n%s\n", script_data);
+
+ int ret = run_script_from_buffer(script_data, script_len, filename);
+ free(script_data);
+ return ret;
+}
+
+int run_and_remove_extendedcommand()
+{
+ char tmp[PATH_MAX];
+ sprintf(tmp, "cp %s /tmp/%s", EXTENDEDCOMMAND_SCRIPT, basename(EXTENDEDCOMMAND_SCRIPT));
+ __system(tmp);
+ remove(EXTENDEDCOMMAND_SCRIPT);
+ 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) {
+ ui_print("SD Card mounted...\n");
+ break;
+ }
+ sleep(1);
+ }
+ remove("/sdcard/clockworkmod/.recoverycheckpoint");
+ if (i == 0) {
+ ui_print("Timed out waiting for SD card... continuing anyways.");
+ }
+
+ sprintf(tmp, "/tmp/%s", basename(EXTENDEDCOMMAND_SCRIPT));
+ return run_script(tmp);
+}
+
+void show_nandroid_advanced_restore_menu()
+{
+ if (ensure_path_mounted("/sdcard") != 0) {
+ LOGE ("Can't mount /sdcard\n");
+ return;
+ }
+
+ static char* advancedheaders[] = { "Choose an image to restore",
+ "",
+ "Choose an image to restore",
+ "first. The next menu will",
+ "you more options.",
+ "",
+ NULL
+ };
+
+ char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, advancedheaders);
+ if (file == NULL)
+ return;
+
+ static char* headers[] = { "Nandroid Advanced Restore",
+ "",
+ NULL
+ };
+
+ static char* list[] = { "Restore boot",
+ "Restore system",
+ "Restore data",
+ "Restore cache",
+ "Restore sd-ext",
+ NULL
+ };
+
+
+ static char* confirm_restore = "Confirm restore?";
+
+ int chosen_item = get_menu_selection(headers, list, 0, 0);
+ switch (chosen_item)
+ {
+ case 0:
+ if (confirm_selection(confirm_restore, "Yes - Restore boot"))
+ nandroid_restore(file, 1, 0, 0, 0, 0);
+ break;
+ case 1:
+ if (confirm_selection(confirm_restore, "Yes - Restore system"))
+ nandroid_restore(file, 0, 1, 0, 0, 0);
+ break;
+ case 2:
+ if (confirm_selection(confirm_restore, "Yes - Restore data"))
+ nandroid_restore(file, 0, 0, 1, 0, 0);
+ break;
+ case 3:
+ if (confirm_selection(confirm_restore, "Yes - Restore cache"))
+ nandroid_restore(file, 0, 0, 0, 1, 0);
+ break;
+ case 4:
+ if (confirm_selection(confirm_restore, "Yes - Restore sd-ext"))
+ nandroid_restore(file, 0, 0, 0, 0, 1);
+ break;
+ }
+}
+
+void show_nandroid_menu()
+{
+ static char* headers[] = { "Nandroid",
+ "",
+ NULL
+ };
+
+ static char* list[] = { "Backup",
+ "Restore",
+ "Advanced Restore",
+ NULL
+ };
+
+ int chosen_item = get_menu_selection(headers, list, 0, 0);
+ switch (chosen_item)
+ {
+ case 0:
+ {
+ char backup_path[PATH_MAX];
+ time_t t = time(NULL);
+ struct tm *tmp = localtime(&t);
+ if (tmp == NULL)
+ {
+ struct timeval tp;
+ gettimeofday(&tp, NULL);
+ sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec);
+ }
+ else
+ {
+ strftime(backup_path, sizeof(backup_path), "/sdcard/clockworkmod/backup/%F.%H.%M.%S", tmp);
+ }
+ nandroid_backup(backup_path);
+ }
+ break;
+ case 1:
+ show_nandroid_restore_menu();
+ break;
+ case 2:
+ show_nandroid_advanced_restore_menu();
+ break;
+ }
+}
+
+void wipe_battery_stats()
+{
+ ensure_path_mounted("/data");
+ remove("/data/system/batterystats.bin");
+ ensure_path_unmounted("/data");
+}
+
+void show_advanced_menu()
+{
+ static char* headers[] = { "Advanced and Debugging Menu",
+ "",
+ NULL
+ };
+
+ static char* list[] = { "Reboot Recovery",
+ "Wipe Dalvik Cache",
+ "Wipe Battery Stats",
+ "Report Error",
+ "Key Test",
+#ifndef BOARD_HAS_SMALL_RECOVERY
+ "Partition SD Card",
+ "Fix Permissions",
+#ifdef BOARD_HAS_SDCARD_INTERNAL
+ "Partition Internal SD Card",
+#endif
+#endif
+ NULL
+ };
+
+ for (;;)
+ {
+ int chosen_item = get_menu_selection(headers, list, 0, 0);
+ if (chosen_item == GO_BACK)
+ break;
+ switch (chosen_item)
+ {
+ case 0:
+ __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, "recovery");
+ break;
+ case 1:
+ {
+ if (0 != ensure_path_mounted("/data"))
+ break;
+ ensure_path_mounted("/sd-ext");
+ ensure_path_mounted("/cache");
+ if (confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache")) {
+ __system("rm -r /data/dalvik-cache");
+ __system("rm -r /cache/dalvik-cache");
+ __system("rm -r /sd-ext/dalvik-cache");
+ }
+ ensure_path_unmounted("/data");
+ ui_print("Dalvik Cache wiped.\n");
+ break;
+ }
+ case 2:
+ {
+ if (confirm_selection( "Confirm wipe?", "Yes - Wipe Battery Stats"))
+ wipe_battery_stats();
+ break;
+ }
+ case 3:
+ handle_failure(1);
+ break;
+ case 4:
+ {
+ ui_print("Outputting key codes.\n");
+ ui_print("Go back to end debugging.\n");
+ int key;
+ int action;
+ do
+ {
+ key = ui_wait_key();
+ action = device_handle_key(key, 1);
+ ui_print("Key: %d\n", key);
+ }
+ while (action != GO_BACK);
+ break;
+ }
+ case 5:
+ {
+ static char* ext_sizes[] = { "128M",
+ "256M",
+ "512M",
+ "1024M",
+ "2048M",
+ "4096M",
+ NULL };
+
+ static char* swap_sizes[] = { "0M",
+ "32M",
+ "64M",
+ "128M",
+ "256M",
+ NULL };
+
+ static char* ext_headers[] = { "Ext Size", "", NULL };
+ static char* swap_headers[] = { "Swap Size", "", NULL };
+
+ int ext_size = get_menu_selection(ext_headers, ext_sizes, 0, 0);
+ if (ext_size == GO_BACK)
+ continue;
+
+ int swap_size = get_menu_selection(swap_headers, swap_sizes, 0, 0);
+ if (swap_size == GO_BACK)
+ continue;
+
+ char sddevice[256];
+ Volume *vol = volume_for_path("/sdcard");
+ strcpy(sddevice, vol->device);
+ // we only want the mmcblk, not the partition
+ sddevice[strlen("/dev/block/mmcblkX")] = NULL;
+ 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]);
+ ui_print("Partitioning SD Card... please wait...\n");
+ if (0 == __system(cmd))
+ ui_print("Done!\n");
+ else
+ ui_print("An error occured while partitioning your SD Card. Please see /tmp/recovery.log for more details.\n");
+ break;
+ }
+ case 6:
+ {
+ ensure_path_mounted("/system");
+ ensure_path_mounted("/data");
+ ui_print("Fixing permissions...\n");
+ __system("fix_permissions");
+ ui_print("Done!\n");
+ break;
+ }
+ case 7:
+ {
+ static char* ext_sizes[] = { "128M",
+ "256M",
+ "512M",
+ "1024M",
+ "2048M",
+ "4096M",
+ NULL };
+
+ static char* swap_sizes[] = { "0M",
+ "32M",
+ "64M",
+ "128M",
+ "256M",
+ NULL };
+
+ static char* ext_headers[] = { "Data Size", "", NULL };
+ static char* swap_headers[] = { "Swap Size", "", NULL };
+
+ int ext_size = get_menu_selection(ext_headers, ext_sizes, 0, 0);
+ if (ext_size == GO_BACK)
+ continue;
+
+ int swap_size = 0;
+ if (swap_size == GO_BACK)
+ continue;
+
+ char sddevice[256];
+ Volume *vol = volume_for_path("/emmc");
+ strcpy(sddevice, vol->device);
+ // we only want the mmcblk, not the partition
+ sddevice[strlen("/dev/block/mmcblkX")] = NULL;
+ 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]);
+ ui_print("Partitioning Internal SD Card... please wait...\n");
+ if (0 == __system(cmd))
+ ui_print("Done!\n");
+ else
+ ui_print("An error occured while partitioning your Internal SD Card. Please see /tmp/recovery.log for more details.\n");
+ break;
+ }
+ }
+ }
+}
+
+/*
+void write_fstab_root(char *root_path, FILE *file)
+{
+ RootInfo *info = get_root_info_for_path(root_path);
+ if (info == NULL) {
+ LOGW("Unable to get root info for %s during fstab generation!", root_path);
+ return;
+ }
+ char device[PATH_MAX];
+ int ret = get_root_partition_device(root_path, device);
+ if (ret == 0)
+ {
+ fprintf(file, "%s ", device);
+ }
+ else
+ {
+ fprintf(file, "%s ", info->device);
+ }
+
+ fprintf(file, "%s ", info->mount_point);
+ fprintf(file, "%s %s\n", info->filesystem, info->filesystem_options == NULL ? "rw" : info->filesystem_options);
+}
+
+void create_fstab()
+{
+ __system("touch /etc/mtab");
+ FILE *file = fopen("/etc/fstab", "w");
+ if (file == NULL) {
+ LOGW("Unable to create /etc/fstab!");
+ return;
+ }
+ write_fstab_root("CACHE:", file);
+ write_fstab_root("DATA:", file);
+#ifdef BOARD_HAS_DATADATA
+ write_fstab_root("DATADATA:", file);
+#endif
+ write_fstab_root("SYSTEM:", file);
+ write_fstab_root("SDCARD:", file);
+ write_fstab_root("SDEXT:", file);
+ fclose(file);
+}
+*/
+
+void handle_failure(int ret)
+{
+ if (ret == 0)
+ return;
+ if (0 != ensure_path_mounted("/sdcard"))
+ return;
+ mkdir("/sdcard/clockworkmod", S_IRWXU);
+ __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 format_device(const char* device) {
+ if (device == NULL)
+ return -1;
+ if (device[0] == '/') {
+ Volume *vol = volume_for_path(device);
+ if (vol == NULL)
+ return -1;
+ return erase_partition(device, vol->fs_type);
+ }
+ return erase_raw_partition(device);
+}
+
+int is_path_mounted(const char* path) {
+ Volume* v = volume_for_path(path);
+ if (v == NULL) {
+ return 0;
+ }
+ if (strcmp(v->fs_type, "ramdisk") == 0) {
+ // the ramdisk is always mounted.
+ return 1;
+ }
+
+ int result;
+ result = scan_mounted_volumes();
+ if (result < 0) {
+ LOGE("failed to scan mounted volumes\n");
+ return 0;
+ }
+
+ const MountedVolume* mv =
+ find_mounted_volume_by_mount_point(v->mount_point);
+ if (mv) {
+ // volume is already mounted
+ return 1;
+ }
+ return 0;
+}
diff --git a/extendedcommands.h b/extendedcommands.h
new file mode 100644
index 0000000..650a519
--- /dev/null
+++ b/extendedcommands.h
@@ -0,0 +1,46 @@
+extern int signature_check_enabled;
+extern int script_assert_enabled;
+
+void
+toggle_signature_check();
+
+void
+toggle_script_asserts();
+
+void
+show_choose_zip_menu();
+
+int
+do_nandroid_backup(const char* backup_name);
+
+int
+do_nandroid_restore();
+
+void
+show_nandroid_restore_menu();
+
+void
+show_nandroid_menu();
+
+void
+show_partition_menu();
+
+void
+show_choose_zip_menu();
+
+int
+install_zip(const char* packagefilepath);
+
+int
+__system(const char *command);
+
+void
+show_advanced_menu();
+
+int
+format_unknown_device(const char* root);
+
+void
+wipe_battery_stats();
+
+void create_fstab();
diff --git a/firmware.h b/firmware.h
new file mode 100644
index 0000000..aeb8f97
--- /dev/null
+++ b/firmware.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef _RECOVERY_FIRMWARE_H
+#define _RECOVERY_FIRMWARE_H
+
+/* Save a radio or bootloader update image for later installation.
+ * The type should be one of "hboot" or "radio".
+ * Takes ownership of type and data. Returns nonzero on error.
+ */
+int remember_firmware_update(const char *type, const char *data, int length);
+
+/* Returns true if a firmware update has been saved. */
+int firmware_update_pending();
+
+/* If an update was saved, reboot into the bootloader now to install it.
+ * Returns 0 if no radio image was defined, nonzero on error,
+ * doesn't return at all on success...
+ */
+int maybe_install_firmware_update(const char *send_intent);
+
+#endif
diff --git a/flashutils/Android.mk b/flashutils/Android.mk
new file mode 100644
index 0000000..324480a
--- /dev/null
+++ b/flashutils/Android.mk
@@ -0,0 +1,98 @@
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_ARCH),arm)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := flashutils.c
+LOCAL_MODULE := libflashutils
+LOCAL_MODULE_TAGS := eng
+LOCAL_C_INCLUDES += bootable/recovery
+LOCAL_STATIC_LIBRARIES := libmmcutils libmtdutils libbmlutils
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := flash_image.c
+LOCAL_MODULE := flash_image
+LOCAL_MODULE_TAGS := eng
+#LOCAL_STATIC_LIBRARIES += $(BOARD_FLASH_LIBRARY)
+LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils
+LOCAL_SHARED_LIBRARIES := libcutils libc
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dump_image.c
+LOCAL_MODULE := dump_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils
+LOCAL_SHARED_LIBRARIES := libcutils libc
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := erase_image.c
+LOCAL_MODULE := erase_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils
+LOCAL_SHARED_LIBRARIES := libcutils libc
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := flash_image.c
+LOCAL_MODULE := libflash_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_CFLAGS += -Dmain=flash_image_main
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dump_image.c
+LOCAL_MODULE := libdump_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_CFLAGS += -Dmain=dump_image_main
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := erase_image.c
+LOCAL_MODULE := liberase_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_CFLAGS += -Dmain=erase_image_main
+include $(BUILD_STATIC_LIBRARY)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dump_image.c
+LOCAL_MODULE := utility_dump_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
+LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
+LOCAL_MODULE_STEM := dump_image
+LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils libcutils libc
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := flash_image.c
+LOCAL_MODULE := utility_flash_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
+LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
+LOCAL_MODULE_STEM := flash_image
+LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils libcutils libc
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := erase_image.c
+LOCAL_MODULE := utility_erase_image
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
+LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
+LOCAL_MODULE_STEM := erase_image
+LOCAL_STATIC_LIBRARIES := libflashutils libmtdutils libmmcutils libbmlutils libcutils libc
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+include $(BUILD_EXECUTABLE)
+
+endif # TARGET_ARCH == arm
+endif # !TARGET_SIMULATOR
diff --git a/flashutils/dump_image.c b/flashutils/dump_image.c
new file mode 100644
index 0000000..4db1f74
--- /dev/null
+++ b/flashutils/dump_image.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include "cutils/log.h"
+#include "flashutils.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#if 0
+
+#define LOG_TAG "dump_image"
+
+#define BLOCK_SIZE 2048
+#define SPARE_SIZE (BLOCK_SIZE >> 5)
+
+static int die(const char *msg, ...) {
+ int err = errno;
+ va_list args;
+ va_start(args, msg);
+ char buf[1024];
+ vsnprintf(buf, sizeof(buf), msg, args);
+ va_end(args);
+
+ if (err != 0) {
+ strlcat(buf, ": ", sizeof(buf));
+ strlcat(buf, strerror(err), sizeof(buf));
+ }
+
+ fprintf(stderr, "%s\n", buf);
+ return 1;
+}
+
+/* Read a flash partition and write it to an image file. */
+
+int dump_image(char* partition_name, char* filename, dump_image_callback callback) {
+ MtdReadContext *in;
+ const MtdPartition *partition;
+ char buf[BLOCK_SIZE + SPARE_SIZE];
+ size_t partition_size;
+ size_t read_size;
+ size_t total;
+ int fd;
+ int wrote;
+ int len;
+
+ if (mtd_scan_partitions() <= 0)
+ return die("error scanning partitions");
+
+ partition = mtd_find_partition_by_name(partition_name);
+ if (partition == NULL)
+ return die("can't find %s partition", partition_name);
+
+ if (mtd_partition_info(partition, &partition_size, NULL, NULL)) {
+ return die("can't get info of partition %s", partition_name);
+ }
+
+ if (!strcmp(filename, "-")) {
+ fd = fileno(stdout);
+ }
+ else {
+ fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ }
+
+ if (fd < 0)
+ return die("error opening %s", filename);
+
+ in = mtd_read_partition(partition);
+ if (in == NULL) {
+ close(fd);
+ unlink(filename);
+ return die("error opening %s: %s\n", partition_name, strerror(errno));
+ }
+
+ total = 0;
+ while ((len = mtd_read_data(in, buf, BLOCK_SIZE)) > 0) {
+ wrote = write(fd, buf, len);
+ if (wrote != len) {
+ close(fd);
+ unlink(filename);
+ return die("error writing %s", filename);
+ }
+ total += BLOCK_SIZE;
+ if (callback != NULL)
+ callback(total, partition_size);
+ }
+
+ mtd_read_close(in);
+
+ if (close(fd)) {
+ unlink(filename);
+ return die("error closing %s", filename);
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ ssize_t (*read_func) (MtdReadContext *, char *, size_t);
+ MtdReadContext *in;
+ const MtdPartition *partition;
+ char buf[BLOCK_SIZE + SPARE_SIZE];
+ size_t partition_size;
+ size_t read_size;
+ size_t total;
+ int fd;
+ int wrote;
+ int len;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
+ return 2;
+ }
+
+ return dump_image(argv[1], argv[2], NULL);
+}
+
+#endif
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
+ return 2;
+ }
+
+ return backup_raw_partition(argv[1], argv[2]);
+}
diff --git a/flashutils/erase_image.c b/flashutils/erase_image.c
new file mode 100644
index 0000000..c495255
--- /dev/null
+++ b/flashutils/erase_image.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Portions Copyright (C) 2010 Magnus Eriksson <packetlss@gmail.com>
+ *
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+
+#include "cutils/log.h"
+#include "flashutils.h"
+
+#if 0
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+
+#define LOG_TAG "erase_image"
+
+static int die(const char *msg, ...) {
+ int err = errno;
+ va_list args;
+ va_start(args, msg);
+ char buf[1024];
+ vsnprintf(buf, sizeof(buf), msg, args);
+ va_end(args);
+
+ if (err != 0) {
+ strlcat(buf, ": ", sizeof(buf));
+ strlcat(buf, strerror(err), sizeof(buf));
+ }
+
+ fprintf(stderr, "%s\n", buf);
+ LOGE("%s\n", buf);
+ return 3;
+}
+
+
+int erase_image(char* partition_name) {
+ MtdWriteContext *out;
+ size_t erased;
+ size_t total_size;
+ size_t erase_size;
+
+ if (mtd_scan_partitions() <= 0) die("error scanning partitions");
+ const MtdPartition *partition = mtd_find_partition_by_name(partition_name);
+ if (partition == NULL) return die("can't find %s partition", partition_name);
+
+ out = mtd_write_partition(partition);
+ if (out == NULL) return die("could not estabilish write context for %s", partition_name);
+
+ // do the actual erase, -1 = full partition erase
+ erased = mtd_erase_blocks(out, -1);
+
+ // erased = bytes erased, if zero, something borked
+ if (!erased) return die("error erasing %s", partition_name);
+
+ return 0;
+}
+
+
+/* Erase a mtd partition */
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <partition>\n", argv[0]);
+ return 2;
+ }
+
+ return erase_image(argv[1]);
+}
+
+#endif
+
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s partition\n", argv[0]);
+ return 2;
+ }
+
+ return erase_raw_partition(argv[1]);
+}
diff --git a/mtdutils/flash_image.c b/flashutils/flash_image.c
similarity index 93%
rename from mtdutils/flash_image.c
rename to flashutils/flash_image.c
index c776876..3966c42 100644
--- a/mtdutils/flash_image.c
+++ b/flashutils/flash_image.c
@@ -22,8 +22,8 @@
#include <unistd.h>
#include "cutils/log.h"
-#include "mtdutils.h"
+#if 0
#define LOG_TAG "flash_image"
#define HEADER_SIZE 2048 // size of header to compare for equality
@@ -138,3 +138,17 @@
if (mtd_write_close(out)) die("error closing %s", argv[1]);
return 0;
}
+#endif
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
+ return 2;
+ }
+
+ int ret = restore_raw_partition(argv[1], argv[2]);
+ if (ret != 0)
+ fprintf(stderr, "failed with error: %d\n", ret);
+ return ret;
+}
diff --git a/flashutils/flashutils.c b/flashutils/flashutils.c
new file mode 100644
index 0000000..b71d4fa
--- /dev/null
+++ b/flashutils/flashutils.c
@@ -0,0 +1,160 @@
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "flashutils/flashutils.h"
+
+int the_flash_type = UNKNOWN;
+
+int device_flash_type()
+{
+ if (the_flash_type == UNKNOWN) {
+ if (access("/dev/block/bml1", F_OK) == 0) {
+ the_flash_type = BML;
+ } else if (access("/proc/emmc", F_OK) == 0) {
+ the_flash_type = MMC;
+ } else if (access("/proc/mtd", F_OK) == 0) {
+ the_flash_type = MTD;
+ } else {
+ the_flash_type = UNSUPPORTED;
+ }
+ }
+ return the_flash_type;
+}
+
+char* get_default_filesystem()
+{
+ return device_flash_type() == MMC ? "ext3" : "yaffs2";
+}
+
+// This was pulled from bionic: The default system command always looks
+// for shell in /system/bin/sh. This is bad.
+#define _PATH_BSHELL "/sbin/sh"
+
+extern char **environ;
+int
+__system(const char *command)
+{
+ pid_t pid;
+ sig_t intsave, quitsave;
+ sigset_t mask, omask;
+ int pstat;
+ char *argp[] = {"sh", "-c", NULL, NULL};
+
+ if (!command) /* just checking... */
+ return(1);
+
+ argp[2] = (char *)command;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+ switch (pid = vfork()) {
+ case -1: /* error */
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ return(-1);
+ case 0: /* child */
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ execve(_PATH_BSHELL, argp, environ);
+ _exit(127);
+ }
+
+ intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
+ quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
+ pid = waitpid(pid, (int *)&pstat, 0);
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ (void)bsd_signal(SIGINT, intsave);
+ (void)bsd_signal(SIGQUIT, quitsave);
+ return (pid == -1 ? -1 : pstat);
+}
+
+int restore_raw_partition(const char *partition, const char *filename)
+{
+ int type = device_flash_type();
+ switch (type) {
+ case MTD:
+ return cmd_mtd_restore_raw_partition(partition, filename);
+ case MMC:
+ return cmd_mmc_restore_raw_partition(partition, filename);
+ case BML:
+ return cmd_bml_restore_raw_partition(partition, filename);
+ default:
+ return -1;
+ }
+}
+
+int backup_raw_partition(const char *partition, const char *filename)
+{
+ int type = device_flash_type();
+ switch (type) {
+ case MTD:
+ return cmd_mtd_backup_raw_partition(partition, filename);
+ case MMC:
+ return cmd_mmc_backup_raw_partition(partition, filename);
+ case BML:
+ return cmd_bml_backup_raw_partition(partition, filename);
+ default:
+ return -1;
+ }
+}
+
+int erase_raw_partition(const char *partition)
+{
+ int type = device_flash_type();
+ switch (type) {
+ case MTD:
+ return cmd_mtd_erase_raw_partition(partition);
+ case MMC:
+ return cmd_mmc_erase_raw_partition(partition);
+ case BML:
+ return cmd_bml_erase_raw_partition(partition);
+ default:
+ return -1;
+ }
+}
+
+int erase_partition(const char *partition, const char *filesystem)
+{
+ int type = device_flash_type();
+ switch (type) {
+ case MTD:
+ return cmd_mtd_erase_partition(partition, filesystem);
+ case MMC:
+ return cmd_mmc_erase_partition(partition, filesystem);
+ case BML:
+ return cmd_bml_erase_partition(partition, filesystem);
+ default:
+ return -1;
+ }
+}
+
+int mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
+{
+ int type = device_flash_type();
+ switch (type) {
+ case MTD:
+ return cmd_mtd_mount_partition(partition, mount_point, filesystem, read_only);
+ case MMC:
+ return cmd_mmc_mount_partition(partition, mount_point, filesystem, read_only);
+ case BML:
+ return cmd_bml_mount_partition(partition, mount_point, filesystem, read_only);
+ default:
+ return -1;
+ }
+}
+
+int get_partition_device(const char *partition, char *device)
+{
+ int type = device_flash_type();
+ switch (type) {
+ case MTD:
+ return cmd_mtd_get_partition_device(partition, device);
+ case MMC:
+ return cmd_mmc_get_partition_device(partition, device);
+ case BML:
+ return cmd_bml_get_partition_device(partition, device);
+ default:
+ return -1;
+ }
+}
diff --git a/flashutils/flashutils.h b/flashutils/flashutils.h
new file mode 100644
index 0000000..d5dadcb
--- /dev/null
+++ b/flashutils/flashutils.h
@@ -0,0 +1,51 @@
+#ifndef FLASHUTILS_H
+#define FLASHUTILS_H
+
+int restore_raw_partition(const char *partition, const char *filename);
+int backup_raw_partition(const char *partition, const char *filename);
+int erase_raw_partition(const char *partition);
+int erase_partition(const char *partition, const char *filesystem);
+int mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only);
+int get_partition_device(const char *partition, char *device);
+
+#define FLASH_MTD 0
+#define FLASH_MMC 1
+#define FLASH_BML 2
+
+int is_mtd_device();
+char* get_default_filesystem();
+
+int __system(const char *command);
+
+extern int cmd_mtd_restore_raw_partition(const char *partition, const char *filename);
+extern int cmd_mtd_backup_raw_partition(const char *partition, const char *filename);
+extern int cmd_mtd_erase_raw_partition(const char *partition);
+extern int cmd_mtd_erase_partition(const char *partition, const char *filesystem);
+extern int cmd_mtd_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only);
+extern int cmd_mtd_get_partition_device(const char *partition, char *device);
+
+extern int cmd_mmc_restore_raw_partition(const char *partition, const char *filename);
+extern int cmd_mmc_backup_raw_partition(const char *partition, const char *filename);
+extern int cmd_mmc_erase_raw_partition(const char *partition);
+extern int cmd_mmc_erase_partition(const char *partition, const char *filesystem);
+extern int cmd_mmc_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only);
+extern int cmd_mmc_get_partition_device(const char *partition, char *device);
+
+extern int cmd_bml_restore_raw_partition(const char *partition, const char *filename);
+extern int cmd_bml_backup_raw_partition(const char *partition, const char *filename);
+extern int cmd_bml_erase_raw_partition(const char *partition);
+extern int cmd_bml_erase_partition(const char *partition, const char *filesystem);
+extern int cmd_bml_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only);
+extern int cmd_bml_get_partition_device(const char *partition, char *device);
+
+extern int device_flash_type();
+
+enum flash_type {
+ UNSUPPORTED = -1,
+ UNKNOWN = 0,
+ MTD = 1,
+ MMC = 2,
+ BML = 3
+};
+
+#endif
\ No newline at end of file
diff --git a/install.c b/install.c
index 5bb3a78..2d8a4cd 100644
--- a/install.c
+++ b/install.c
@@ -28,14 +28,74 @@
#include "minui/minui.h"
#include "minzip/SysUtil.h"
#include "minzip/Zip.h"
-#include "mtdutils/mounts.h"
+#include "mounts.h"
#include "mtdutils/mtdutils.h"
#include "roots.h"
#include "verifier.h"
+#include "firmware.h"
+
+#include "extendedcommands.h"
+
+
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
#define PUBLIC_KEYS_FILE "/res/keys"
+// The update binary ask us to install a firmware file on reboot. Set
+// that up. Takes ownership of type and filename.
+static int
+handle_firmware_update(char* type, char* filename, ZipArchive* zip) {
+ unsigned int data_size;
+ const ZipEntry* entry = NULL;
+
+ if (strncmp(filename, "PACKAGE:", 8) == 0) {
+ entry = mzFindZipEntry(zip, filename+8);
+ if (entry == NULL) {
+ LOGE("Failed to find \"%s\" in package", filename+8);
+ return INSTALL_ERROR;
+ }
+ data_size = entry->uncompLen;
+ } else {
+ struct stat st_data;
+ if (stat(filename, &st_data) < 0) {
+ LOGE("Error stat'ing %s: %s\n", filename, strerror(errno));
+ return INSTALL_ERROR;
+ }
+ data_size = st_data.st_size;
+ }
+
+ LOGI("type is %s; size is %d; file is %s\n",
+ type, data_size, filename);
+
+ char* data = malloc(data_size);
+ if (data == NULL) {
+ LOGI("Can't allocate %d bytes for firmware data\n", data_size);
+ return INSTALL_ERROR;
+ }
+
+ if (entry) {
+ if (mzReadZipEntry(zip, entry, data, data_size) == false) {
+ LOGE("Failed to read \"%s\" from package", filename+8);
+ return INSTALL_ERROR;
+ }
+ } else {
+ FILE* f = fopen(filename, "rb");
+ if (f == NULL) {
+ LOGE("Failed to open %s: %s\n", filename, strerror(errno));
+ return INSTALL_ERROR;
+ }
+ if (fread(data, 1, data_size, f) != data_size) {
+ LOGE("Failed to read firmware data: %s\n", strerror(errno));
+ return INSTALL_ERROR;
+ }
+ fclose(f);
+ }
+
+ free(filename);
+
+ return INSTALL_SUCCESS;
+}
+
// If the package contains an update binary, extract it and run it.
static int
try_update_binary(const char *path, ZipArchive *zip) {
@@ -43,7 +103,7 @@
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
if (binary_entry == NULL) {
mzCloseZipArchive(zip);
- return INSTALL_CORRUPT;
+ return INSTALL_UPDATE_BINARY_MISSING;
}
char* binary = "/tmp/update_binary";
@@ -117,6 +177,9 @@
}
close(pipefd[1]);
+ char* firmware_type = NULL;
+ char* firmware_filename = NULL;
+
char buffer[1024];
FILE* from_child = fdopen(pipefd[0], "r");
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
@@ -136,6 +199,18 @@
char* fraction_s = strtok(NULL, " \n");
float fraction = strtof(fraction_s, NULL);
ui_set_progress(fraction);
+ } else if (strcmp(command, "firmware") == 0) {
+ char* type = strtok(NULL, " \n");
+ char* filename = strtok(NULL, " \n");
+
+ if (type != NULL && filename != NULL) {
+ if (firmware_type != NULL) {
+ LOGE("ignoring attempt to do multiple firmware updates");
+ } else {
+ firmware_type = strdup(type);
+ firmware_filename = strdup(filename);
+ }
+ }
} else if (strcmp(command, "ui_print") == 0) {
char* str = strtok(NULL, "\n");
if (str) {
@@ -156,6 +231,11 @@
return INSTALL_ERROR;
}
+ if (firmware_type != NULL) {
+ return handle_firmware_update(firmware_type, firmware_filename, zip);
+ } else {
+ return INSTALL_SUCCESS;
+ }
return INSTALL_SUCCESS;
}
@@ -248,27 +328,30 @@
ui_print("Opening update package...\n");
- int numKeys;
- RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
- if (loadedKeys == NULL) {
- LOGE("Failed to load keys\n");
- return INSTALL_CORRUPT;
- }
- LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
-
- // Give verification half the progress bar...
- ui_print("Verifying update package...\n");
- ui_show_progress(
- VERIFICATION_PROGRESS_FRACTION,
- VERIFICATION_PROGRESS_TIME);
-
int err;
- err = verify_file(path, loadedKeys, numKeys);
- free(loadedKeys);
- LOGI("verify_file returned %d\n", err);
- if (err != VERIFY_SUCCESS) {
- LOGE("signature verification failed\n");
- return INSTALL_CORRUPT;
+
+ if (signature_check_enabled) {
+ int numKeys;
+ RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
+ if (loadedKeys == NULL) {
+ LOGE("Failed to load keys\n");
+ return INSTALL_CORRUPT;
+ }
+ LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
+
+ // Give verification half the progress bar...
+ ui_print("Verifying update package...\n");
+ ui_show_progress(
+ VERIFICATION_PROGRESS_FRACTION,
+ VERIFICATION_PROGRESS_TIME);
+
+ err = verify_file(path, loadedKeys, numKeys);
+ free(loadedKeys);
+ LOGI("verify_file returned %d\n", err);
+ if (err != VERIFY_SUCCESS) {
+ LOGE("signature verification failed\n");
+ return INSTALL_CORRUPT;
+ }
}
/* Try to open the package.
diff --git a/install.h b/install.h
index a7ebc09..ec97d39 100644
--- a/install.h
+++ b/install.h
@@ -19,7 +19,7 @@
#include "common.h"
-enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
+enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_UPDATE_SCRIPT_MISSING, INSTALL_UPDATE_BINARY_MISSING };
int install_package(const char *root_path);
#endif // RECOVERY_INSTALL_H_
diff --git a/killrecovery.sh b/killrecovery.sh
new file mode 100755
index 0000000..352cb4b
--- /dev/null
+++ b/killrecovery.sh
@@ -0,0 +1,22 @@
+#!/sbin/sh
+mkdir -p /sd-ext
+rm /cache/recovery/command
+rm /cache/update.zip
+touch /tmp/.ignorebootmessage
+kill $(ps | grep /sbin/adbd)
+kill $(ps | grep /sbin/recovery)
+
+# On the Galaxy S, the recovery comes test signed, but the
+# recovery is not automatically restarted.
+if [ -f /init.smdkc110.rc ]
+then
+ /sbin/recovery &
+fi
+
+# Droid X
+if [ -f /init.mapphone_cdma.rc ]
+then
+ /sbin/recovery &
+fi
+
+exit 1
diff --git a/minui/Android.mk b/minui/Android.mk
index 91dd939..10f0f3f 100644
--- a/minui/Android.mk
+++ b/minui/Android.mk
@@ -7,6 +7,10 @@
external/libpng\
external/zlib
+ifneq ($(BOARD_LDPI_RECOVERY),)
+ LOCAL_CFLAGS += -DBOARD_LDPI_RECOVERY='"$(BOARD_LDPI_RECOVERY)"'
+endif
+
LOCAL_MODULE := libminui
include $(BUILD_STATIC_LIBRARY)
diff --git a/minui/events.c b/minui/events.c
index 3aed2a8..efdca95 100644
--- a/minui/events.c
+++ b/minui/events.c
@@ -19,16 +19,166 @@
#include <fcntl.h>
#include <dirent.h>
#include <sys/poll.h>
+#include <limits.h>
#include <linux/input.h>
+#include "../common.h"
+
#include "minui.h"
#define MAX_DEVICES 16
+#define VIBRATOR_TIMEOUT_FILE "/sys/class/timed_output/vibrator/enable"
+#define VIBRATOR_TIME_MS 50
+
+#define PRESS_THRESHHOLD 10
+
+#define ABS_MT_POSITION_X 0x35
+#define ABS_MT_POSITION_Y 0x36
+#define ABS_MT_TOUCH_MAJOR 0x30
+#define SYN_MT_REPORT 2
+
+struct virtualkey {
+ int scancode;
+ int centerx, centery;
+ int width, height;
+};
+
+struct position {
+ int x, y;
+ int pressed;
+ struct input_absinfo xi, yi;
+};
+
+struct ev {
+ struct pollfd *fd;
+
+ struct virtualkey *vks;
+ int vk_count;
+
+ struct position p, mt_p;
+ int sent, mt_idx;
+};
+
static struct pollfd ev_fds[MAX_DEVICES];
+static struct ev evs[MAX_DEVICES];
static unsigned ev_count = 0;
+static inline int ABS(int x) {
+ return x<0?-x:x;
+}
+
+int vibrate(int timeout_ms)
+{
+ char str[20];
+ int fd;
+ int ret;
+
+ fd = open(VIBRATOR_TIMEOUT_FILE, O_WRONLY);
+ if (fd < 0)
+ return -1;
+
+ ret = snprintf(str, sizeof(str), "%d", timeout_ms);
+ ret = write(fd, str, ret);
+ close(fd);
+
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+/* Returns empty tokens */
+static char *vk_strtok_r(char *str, const char *delim, char **save_str)
+{
+ if(!str) {
+ if(!*save_str) return NULL;
+ str = (*save_str) + 1;
+ }
+ *save_str = strpbrk(str, delim);
+ if(*save_str) **save_str = '\0';
+ return str;
+}
+
+static int vk_init(struct ev *e)
+{
+ char vk_path[PATH_MAX] = "/sys/board_properties/virtualkeys.";
+ char vks[2048], *ts;
+ ssize_t len;
+ int vk_fd;
+ int i;
+
+ e->vk_count = 0;
+
+ len = strlen(vk_path);
+ len = ioctl(e->fd->fd, EVIOCGNAME(sizeof(vk_path) - len), vk_path + len);
+ if (len <= 0)
+ return -1;
+
+ vk_fd = open(vk_path, O_RDONLY);
+ if (vk_fd < 0)
+ return -1;
+
+ len = read(vk_fd, vks, sizeof(vks)-1);
+ close(vk_fd);
+ if (len <= 0)
+ return -1;
+
+ vks[len] = '\0';
+
+ /* Parse a line like:
+ keytype:keycode:centerx:centery:width:height:keytype2:keycode2:centerx2:...
+ */
+ for (ts = vks, e->vk_count = 1; *ts; ++ts) {
+ if (*ts == ':')
+ ++e->vk_count;
+ }
+
+ if (e->vk_count % 6) {
+ LOGW("minui: %s is %d %% 6\n", vk_path, e->vk_count % 6);
+ }
+ e->vk_count /= 6;
+ if (e->vk_count <= 0)
+ return -1;
+
+ e->sent = 0;
+ e->mt_idx = 0;
+
+ ioctl(e->fd->fd, EVIOCGABS(ABS_X), &e->p.xi);
+ ioctl(e->fd->fd, EVIOCGABS(ABS_Y), &e->p.yi);
+ e->p.pressed = 0;
+
+ ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_X), &e->mt_p.xi);
+ ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_Y), &e->mt_p.yi);
+ e->mt_p.pressed = 0;
+
+ e->vks = malloc(sizeof(*e->vks) * e->vk_count);
+
+ for (i = 0; i < e->vk_count; ++i) {
+ char *token[6];
+ int j;
+
+ for (j = 0; j < 6; ++j) {
+ token[j] = vk_strtok_r((i||j)?NULL:vks, ":", &ts);
+ }
+
+ if (strcmp(token[0], "0x01") != 0) {
+ /* Java does string compare, so we do too. */
+ LOGW("minui: %s: ignoring unknown virtual key type %s\n", vk_path, token[0]);
+ continue;
+ }
+
+ e->vks[i].scancode = strtol(token[1], NULL, 0);
+ e->vks[i].centerx = strtol(token[2], NULL, 0);
+ e->vks[i].centery = strtol(token[3], NULL, 0);
+ e->vks[i].width = strtol(token[4], NULL, 0);
+ e->vks[i].height = strtol(token[5], NULL, 0);
+ }
+
+ return 0;
+}
+
int ev_init(void)
{
DIR *dir;
@@ -45,6 +195,11 @@
ev_fds[ev_count].fd = fd;
ev_fds[ev_count].events = POLLIN;
+ evs[ev_count].fd = &ev_fds[ev_count];
+
+ /* Load virtualkeys if there are any */
+ vk_init(&evs[ev_count]);
+
ev_count++;
if(ev_count == MAX_DEVICES) break;
}
@@ -55,11 +210,135 @@
void ev_exit(void)
{
- while (ev_count > 0) {
- close(ev_fds[--ev_count].fd);
+ while (ev_count-- > 0) {
+ if (evs[ev_count].vk_count) {
+ free(evs[ev_count].vks);
+ evs[ev_count].vk_count = 0;
+ }
+ close(ev_fds[ev_count].fd);
}
}
+static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
+{
+ int screen_pos;
+
+ if (info->minimum == info->maximum)
+ return 0;
+
+ screen_pos = (value - info->minimum) * (screen_size - 1) / (info->maximum - info->minimum);
+ return (screen_pos >= 0 && screen_pos < screen_size);
+}
+
+static int vk_tp_to_screen(struct position *p, int *x, int *y)
+{
+ if (p->xi.minimum == p->xi.maximum || p->yi.minimum == p->yi.maximum)
+ return 0;
+
+ *x = (p->x - p->xi.minimum) * (gr_fb_width() - 1) / (p->xi.maximum - p->xi.minimum);
+ *y = (p->y - p->yi.minimum) * (gr_fb_height() - 1) / (p->yi.maximum - p->yi.minimum);
+
+ if (*x >= 0 && *x < gr_fb_width() &&
+ *y >= 0 && *y < gr_fb_height()) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Translate a virtual key in to a real key event, if needed */
+/* Returns non-zero when the event should be consumed */
+static int vk_modify(struct ev *e, struct input_event *ev)
+{
+ int i;
+ int x, y;
+
+ if (ev->type == EV_KEY) {
+ if (ev->code == BTN_TOUCH)
+ e->p.pressed = ev->value;
+ return 0;
+ }
+
+ if (ev->type == EV_ABS) {
+ switch (ev->code) {
+ case ABS_X:
+ e->p.x = ev->value;
+ return !vk_inside_display(e->p.x, &e->p.xi, gr_fb_width());
+ case ABS_Y:
+ e->p.y = ev->value;
+ return !vk_inside_display(e->p.y, &e->p.yi, gr_fb_height());
+ case ABS_MT_POSITION_X:
+ if (e->mt_idx) return 1;
+ e->mt_p.x = ev->value;
+ return !vk_inside_display(e->mt_p.x, &e->mt_p.xi, gr_fb_width());
+ case ABS_MT_POSITION_Y:
+ if (e->mt_idx) return 1;
+ e->mt_p.y = ev->value;
+ return !vk_inside_display(e->mt_p.y, &e->mt_p.yi, gr_fb_height());
+ case ABS_MT_TOUCH_MAJOR:
+ if (e->mt_idx) return 1;
+ if (e->sent)
+ e->mt_p.pressed = (ev->value > 0);
+ else
+ e->mt_p.pressed = (ev->value > PRESS_THRESHHOLD);
+ return 0;
+ }
+
+ return 0;
+ }
+
+ if (ev->type != EV_SYN)
+ return 0;
+
+ if (ev->code == SYN_MT_REPORT) {
+ /* Ignore the rest of the points */
+ ++e->mt_idx;
+ return 1;
+ }
+ if (ev->code != SYN_REPORT)
+ return 0;
+
+ /* Report complete */
+
+ e->mt_idx = 0;
+
+ if (!e->p.pressed && !e->mt_p.pressed) {
+ /* No touch */
+ e->sent = 0;
+ return 0;
+ }
+
+ if (!(e->p.pressed && vk_tp_to_screen(&e->p, &x, &y)) &&
+ !(e->mt_p.pressed && vk_tp_to_screen(&e->mt_p, &x, &y))) {
+ /* No touch inside vk area */
+ return 0;
+ }
+
+ if (e->sent) {
+ /* We've already sent a fake key for this touch */
+ return 1;
+ }
+
+ /* The screen is being touched on the vk area */
+ e->sent = 1;
+
+ for (i = 0; i < e->vk_count; ++i) {
+ int xd = ABS(e->vks[i].centerx - x);
+ int yd = ABS(e->vks[i].centery - y);
+ if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2) {
+ /* Fake a key event */
+ ev->type = EV_KEY;
+ ev->code = e->vks[i].scancode;
+ ev->value = 1;
+
+ vibrate(VIBRATOR_TIME_MS);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
int ev_get(struct input_event *ev, unsigned dont_wait)
{
int r;
@@ -72,7 +351,10 @@
for(n = 0; n < ev_count; n++) {
if(ev_fds[n].revents & POLLIN) {
r = read(ev_fds[n].fd, ev, sizeof(*ev));
- if(r == sizeof(*ev)) return 0;
+ if(r == sizeof(*ev)) {
+ if (!vk_modify(&evs[n], ev))
+ return 0;
+ }
}
}
}
diff --git a/minui/font_7x16.h b/minui/font_7x16.h
new file mode 100644
index 0000000..31c94fc
--- /dev/null
+++ b/minui/font_7x16.h
@@ -0,0 +1,15 @@
+struct {
+ unsigned width;
+ unsigned height;
+ unsigned cwidth;
+ unsigned cheight;
+ unsigned char rundata[];
+} font = {
+ .width = 668,
+ .height = 16,
+ .cwidth = 7,
+ .cheight = 16,
+ .rundata = {
+0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7e,0x82,0x03,0x82,0x7f,0x7f,0x5f,0x82,0x0b,0x82,0x14,0x81,0x0b,0x81,0x11,0x81,0x0c,0x82,0x09,0x81,0x08,0x81,0x07,0x81,0x03,0x81,0x06,0x83,0x68,0x83,0x04,0x81,0x04,0x83,0x17,0x81,0x05,0x81,0x01,0x81,0x0c,0x81,0x04,0x82,0x07,0x83,0x04,0x81,0x07,0x81,0x05,0x81,0x06,0x81,0x25,0x81,0x02,0x84,0x02,0x83,0x05,0x84,0x03,0x84,0x05,0x82,0x02,0x85,0x04,0x83,0x02,0x86,0x02,0x84,0x03,0x84,0x27,0x83,0x0b,0x82,0x03,0x85,0x04,0x83,0x02,0x84,0x03,0x86,0x01,0x86,0x03,0x83,0x02,0x81,0x04,0x81,0x01,0x85,0x04,0x83,0x02,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x82,0x03,0x81,0x02,0x84,0x02,0x85,0x03,0x84,0x02,0x85,0x03,0x84,0x01,0x87,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x82,0x05,0x81,0x01,0x81,0x04,0x82,0x05,0x81,0x01,0x86,0x03,0x81,0x04,0x81,0x08,0x81,0x05,0x82,0x0e,0x81,0x0a,0x81,0x11,0x81,0x0b,0x81,0x0b,0x81,0x14,0x81,0x08,0x81,0x37,0x81,0x30,0x81,0x06,0x81,0x06,0x81,0x17,0x81,0x05,0x81,0x01,0x81,0x05,0x81,0x01,0x81,0x03,0x83,0x02,0x81,0x02,0x81,0x05,0x81,0x07,0x81,0x07,0x81,0x05,0x81,0x04,0x81,0x01,0x81,0x01,0x81,0x22,0x81,0x03,0x81,0x02,0x81,0x04,0x81,0x04,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x04,0x82,0x02,0x81,0x07,0x81,0x03,0x81,0x05,0x82,0x01,0x81,0x04,0x81,0x01,0x82,0x02,0x81,0x26,0x81,0x03,0x81,0x03,0x83,0x04,0x82,0x03,0x81,0x04,0x81,0x02,0x81,0x03,0x81,0x01,0x81,0x03,0x81,0x02,0x81,0x06,0x81,0x07,0x81,0x03,0x81,0x01,0x81,0x04,0x81,0x03,0x81,0x08,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x06,0x82,0x02,0x82,0x01,0x82,0x03,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x04,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x01,0x81,0x04,0x82,0x02,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x03,0x81,0x06,0x82,0x03,0x81,0x05,0x81,0x07,0x81,0x04,0x81,0x02,0x81,0x18,0x81,0x11,0x81,0x0b,0x81,0x0b,0x81,0x14,0x81,0x08,0x81,0x37,0x81,0x30,0x81,0x06,0x81,0x06,0x81,0x17,0x81,0x05,0x81,0x01,0x81,0x04,0x81,0x02,0x81,0x02,0x81,0x01,0x81,0x01,0x81,0x01,0x81,0x02,0x81,0x05,0x81,0x07,0x81,0x06,0x81,0x07,0x81,0x04,0x83,0x05,0x81,0x1d,0x81,0x02,0x81,0x04,0x81,0x03,0x81,0x09,0x81,0x06,0x81,0x03,0x81,0x01,0x81,0x02,0x81,0x06,0x81,0x0a,0x81,0x02,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x14,0x81,0x08,0x81,0x0b,0x81,0x02,0x81,0x02,0x82,0x03,0x82,0x03,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x06,0x81,0x06,0x81,0x04,0x81,0x03,0x81,0x08,0x81,0x02,0x81,0x02,0x81,0x03,0x81,0x06,0x82,0x02,0x82,0x01,0x81,0x01,0x81,0x02,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x08,0x81,0x04,0x81,0x04,0x81,0x02,0x81,0x02,0x81,0x01,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x03,0x81,0x01,0x81,0x07,0x81,0x04,0x81,0x05,0x81,0x07,0x81,0x03,0x81,0x04,0x81,0x11,0x83,0x03,0x84,0x04,0x83,0x04,0x84,0x03,0x83,0x03,0x85,0x03,0x84,0x02,0x81,0x01,0x82,0x03,0x83,0x05,0x83,0x03,0x81,0x03,0x81,0x04,0x81,0x04,0x85,0x02,0x81,0x01,0x82,0x04,0x83,0x03,0x84,0x04,0x84,0x03,0x84,0x03,0x83,0x03,0x85,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x01,0x81,0x05,0x81,0x01,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x85,0x04,0x81,0x06,0x81,0x06,0x81,0x17,0x81,0x0b,0x86,0x01,0x81,0x01,0x81,0x04,0x82,0x02,0x81,0x03,0x82,0x0d,0x81,0x07,0x81,0x04,0x83,0x05,0x81,0x1c,0x81,0x03,0x81,0x04,0x81,0x03,0x81,0x09,0x81,0x06,0x81,0x02,0x82,0x01,0x81,0x02,0x85,0x02,0x81,0x01,0x83,0x06,0x81,0x02,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x03,0x81,0x06,0x81,0x06,0x83,0x0a,0x83,0x06,0x82,0x02,0x81,0x04,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x06,0x81,0x06,0x81,0x04,0x81,0x03,0x81,0x08,0x81,0x02,0x81,0x01,0x81,0x04,0x81,0x06,0x81,0x01,0x82,0x01,0x81,0x01,0x81,0x01,0x81,0x02,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x01,0x82,0x07,0x81,0x04,0x81,0x04,0x81,0x02,0x81,0x02,0x81,0x01,0x81,0x01,0x81,0x01,0x81,0x01,0x81,0x03,0x82,0x04,0x81,0x01,0x81,0x06,0x81,0x05,0x81,0x06,0x81,0x06,0x81,0x19,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x82,0x05,0x81,0x03,0x81,0x02,0x82,0x02,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x02,0x82,0x02,0x81,0x04,0x81,0x07,0x81,0x03,0x81,0x02,0x81,0x05,0x81,0x04,0x81,0x01,0x81,0x01,0x81,0x02,0x82,0x02,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x03,0x82,0x02,0x81,0x01,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x01,0x81,0x05,0x81,0x02,0x81,0x01,0x81,0x03,0x81,0x03,0x81,0x06,0x81,0x04,0x81,0x06,0x81,0x06,0x81,0x17,0x81,0x0c,0x81,0x01,0x81,0x03,0x83,0x06,0x82,0x04,0x82,0x0d,0x81,0x07,0x81,0x03,0x81,0x01,0x81,0x01,0x81,0x04,0x81,0x1c,0x81,0x03,0x81,0x02,0x81,0x01,0x81,0x03,0x81,0x08,0x81,0x04,0x83,0x03,0x81,0x02,0x81,0x06,0x82,0x01,0x82,0x02,0x82,0x04,0x81,0x04,0x84,0x02,0x81,0x03,0x82,0x03,0x81,0x06,0x81,0x04,0x82,0x05,0x86,0x05,0x82,0x03,0x82,0x03,0x81,0x02,0x83,0x02,0x81,0x02,0x81,0x02,0x85,0x02,0x81,0x06,0x81,0x04,0x81,0x01,0x86,0x01,0x86,0x01,0x81,0x03,0x82,0x01,0x86,0x03,0x81,0x08,0x81,0x02,0x83,0x04,0x81,0x06,0x81,0x01,0x82,0x01,0x81,0x01,0x81,0x01,0x82,0x01,0x81,0x01,0x81,0x04,0x81,0x01,0x85,0x02,0x81,0x04,0x81,0x01,0x85,0x03,0x84,0x04,0x81,0x04,0x81,0x04,0x81,0x02,0x81,0x02,0x81,0x01,0x81,0x01,0x81,0x01,0x81,0x01,0x81,0x03,0x82,0x05,0x81,0x06,0x82,0x05,0x81,0x06,0x81,0x06,0x81,0x1d,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x06,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x04,0x81,0x07,0x81,0x03,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x01,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x03,0x81,0x05,0x81,0x08,0x81,0x04,0x81,0x03,0x81,0x03,0x81,0x01,0x81,0x03,0x81,0x01,0x81,0x01,0x81,0x03,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x03,0x82,0x07,0x81,0x07,0x82,0x02,0x83,0x10,0x81,0x0c,0x81,0x01,0x81,0x05,0x83,0x02,0x82,0x01,0x82,0x02,0x81,0x02,0x81,0x01,0x81,0x0a,0x81,0x07,0x81,0x05,0x81,0x03,0x87,0x09,0x83,0x0c,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x07,0x81,0x08,0x81,0x01,0x81,0x03,0x81,0x07,0x81,0x01,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x04,0x81,0x02,0x83,0x01,0x81,0x0f,0x82,0x10,0x82,0x03,0x81,0x04,0x81,0x01,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x02,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x03,0x81,0x08,0x81,0x02,0x81,0x02,0x81,0x03,0x81,0x06,0x81,0x01,0x82,0x01,0x81,0x01,0x81,0x02,0x81,0x01,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x03,0x81,0x07,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x02,0x81,0x02,0x81,0x01,0x81,0x01,0x81,0x01,0x81,0x01,0x81,0x03,0x82,0x05,0x81,0x06,0x81,0x06,0x81,0x07,0x81,0x05,0x81,0x1a,0x84,0x02,0x81,0x03,0x81,0x02,0x81,0x06,0x81,0x03,0x81,0x02,0x85,0x04,0x81,0x04,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x04,0x81,0x07,0x81,0x03,0x82,0x07,0x81,0x04,0x81,0x01,0x81,0x01,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x03,0x81,0x06,0x83,0x05,0x81,0x04,0x81,0x03,0x81,0x03,0x81,0x01,0x81,0x03,0x81,0x01,0x81,0x01,0x81,0x04,0x81,0x05,0x81,0x01,0x81,0x05,0x81,0x06,0x81,0x06,0x81,0x06,0x81,0x07,0x83,0x18,0x86,0x04,0x81,0x01,0x81,0x04,0x81,0x02,0x81,0x01,0x81,0x02,0x83,0x0a,0x81,0x07,0x81,0x0c,0x81,0x1b,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x06,0x81,0x09,0x81,0x01,0x86,0x06,0x81,0x01,0x81,0x04,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x06,0x81,0x11,0x83,0x02,0x86,0x02,0x83,0x0a,0x81,0x01,0x81,0x02,0x81,0x02,0x84,0x02,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x03,0x81,0x08,0x81,0x02,0x81,0x02,0x82,0x02,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x02,0x81,0x01,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x06,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x03,0x82,0x03,0x82,0x01,0x82,0x03,0x81,0x02,0x81,0x04,0x81,0x05,0x81,0x07,0x81,0x07,0x81,0x05,0x81,0x19,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x06,0x81,0x03,0x81,0x02,0x81,0x08,0x81,0x04,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x04,0x81,0x07,0x81,0x03,0x81,0x01,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x01,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x03,0x81,0x09,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x03,0x81,0x01,0x81,0x03,0x82,0x01,0x82,0x03,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x07,0x81,0x06,0x81,0x06,0x81,0x17,0x81,0x0b,0x81,0x02,0x81,0x03,0x81,0x01,0x81,0x01,0x81,0x04,0x81,0x02,0x81,0x01,0x82,0x02,0x81,0x0c,0x81,0x05,0x81,0x0d,0x81,0x06,0x81,0x0d,0x81,0x05,0x81,0x06,0x81,0x02,0x81,0x04,0x81,0x05,0x81,0x05,0x81,0x04,0x81,0x05,0x81,0x02,0x81,0x03,0x82,0x02,0x81,0x02,0x82,0x03,0x81,0x04,0x81,0x04,0x81,0x01,0x81,0x03,0x81,0x04,0x81,0x06,0x81,0x09,0x81,0x08,0x81,0x08,0x81,0x04,0x81,0x02,0x83,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x02,0x81,0x03,0x81,0x01,0x81,0x03,0x81,0x02,0x81,0x06,0x81,0x07,0x81,0x03,0x81,0x01,0x81,0x04,0x81,0x03,0x81,0x04,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x06,0x81,0x04,0x81,0x01,0x81,0x03,0x82,0x02,0x81,0x02,0x81,0x02,0x81,0x07,0x81,0x02,0x82,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x03,0x82,0x03,0x81,0x03,0x81,0x03,0x81,0x02,0x81,0x04,0x81,0x04,0x82,0x07,0x81,0x08,0x81,0x04,0x81,0x19,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x82,0x05,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x04,0x81,0x07,0x81,0x03,0x81,0x02,0x81,0x05,0x81,0x04,0x81,0x01,0x81,0x01,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x02,0x81,0x03,0x81,0x03,0x81,0x05,0x81,0x03,0x81,0x04,0x81,0x04,0x81,0x03,0x81,0x04,0x81,0x05,0x81,0x01,0x81,0x04,0x81,0x01,0x81,0x04,0x82,0x04,0x81,0x08,0x81,0x06,0x81,0x06,0x81,0x17,0x81,0x0b,0x81,0x01,0x81,0x05,0x83,0x06,0x82,0x03,0x83,0x01,0x81,0x0b,0x81,0x05,0x81,0x0d,0x81,0x06,0x81,0x0d,0x81,0x05,0x81,0x06,0x84,0x02,0x85,0x02,0x86,0x02,0x84,0x06,0x81,0x03,0x84,0x03,0x84,0x03,0x81,0x06,0x84,0x03,0x83,0x05,0x81,0x06,0x81,0x1b,0x81,0x04,0x82,0x05,0x81,0x04,0x81,0x01,0x85,0x04,0x83,0x02,0x84,0x03,0x86,0x01,0x81,0x08,0x83,0x02,0x81,0x04,0x81,0x01,0x85,0x03,0x83,0x03,0x81,0x04,0x81,0x01,0x86,0x01,0x81,0x04,0x81,0x01,0x81,0x03,0x82,0x02,0x84,0x02,0x81,0x07,0x84,0x02,0x81,0x05,0x81,0x01,0x84,0x04,0x81,0x05,0x84,0x04,0x82,0x03,0x81,0x03,0x81,0x02,0x81,0x04,0x81,0x03,0x81,0x04,0x86,0x03,0x81,0x08,0x81,0x04,0x81,0x1a,0x84,0x02,0x84,0x04,0x83,0x04,0x84,0x03,0x83,0x05,0x81,0x05,0x84,0x02,0x81,0x03,0x81,0x02,0x85,0x05,0x81,0x03,0x81,0x03,0x81,0x05,0x82,0x02,0x81,0x01,0x81,0x01,0x81,0x02,0x81,0x03,0x81,0x03,0x83,0x03,0x84,0x04,0x84,0x03,0x81,0x06,0x83,0x05,0x83,0x03,0x84,0x04,0x81,0x05,0x81,0x01,0x81,0x03,0x81,0x03,0x81,0x04,0x81,0x04,0x85,0x04,0x81,0x06,0x81,0x06,0x81,0x2c,0x81,0x1c,0x82,0x03,0x82,0x13,0x81,0x13,0x81,0x54,0x81,0x22,0x81,0x79,0x81,0x43,0x82,0x08,0x81,0x02,0x82,0x47,0x81,0x13,0x81,0x26,0x81,0x0a,0x81,0x35,0x81,0x0d,0x83,0x04,0x81,0x04,0x83,0x2c,0x81,0x7f,0x44,0x83,0x76,0x81,0x7f,0x17,0x81,0x02,0x81,0x13,0x81,0x26,0x81,0x0a,0x81,0x34,0x81,0x15,0x81,0x7f,0x7f,0x7f,0x50,0x87,0x34,0x82,0x12,0x82,0x27,0x81,0x0a,0x81,0x33,0x82,0x7f,0x7f,0x7f,0x7f,0x7f,0x4b,0x00,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x00,0x49,0x44,0x41,0x54,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0x00,0x00,0x00,0x00,0x50,0x4c,0x54,0x45,0x00,0x00,0x00,0x00,0x62,0x4b,0x47,0x44,0x00,0x00,0x00,0x00,0x63,0x48,0x52,0x4d,0x00,0x00,0x00,0x00,0x67,0x41,0x4d,0x41,0x00,0x00,0x00,0x00,0x68,0x49,0x53,0x54,0x00,0x00,0x00,0x00,0x69,0x43,0x43,0x50,0x00,0x00,0x00,0x00,0x69,0x54,0x58,0x74,0x00,0x00,0x00,0x00,0x6f,0x46,0x46,0x73,0x00,0x00,0x00,0x00,0x70,0x43,0x41,0x4c,0x00,0x00,0x00,0x00,0x73,0x43,0x41,0x4c,0x00,0x00,0x00,0x00,0x70,0x48,0x59,0x73,0x00,0x00,0x00,0x00,0x73,0x42,0x49,0x54,0x00,0x00,0x00,0x00,0x73,0x50,0x4c,0x54,0x00,0x00,0x00,0x00,0x73,0x52,0x47,0x42,0x00,0x00,0x00,0x00,0x74,0x45,0x58,0x74,0x00,0x00,0x00,0x00,0x74,0x49,0x4d,0x45,0x00,0x00,0x00,0x00,0x74,0x52,0x4e,0x53,0x00,0x00,0x00,0x00,0x7a,0x54,0x58,0x74,0x00,
+ }
+};
diff --git a/minui/graphics.c b/minui/graphics.c
index 4127c40..a96342f 100644
--- a/minui/graphics.c
+++ b/minui/graphics.c
@@ -29,7 +29,12 @@
#include <pixelflinger/pixelflinger.h>
-#include "font_10x18.h"
+#ifndef BOARD_LDPI_RECOVERY
+ #include "font_10x18.h"
+#else
+ #include "font_7x16.h"
+#endif
+
#include "minui.h"
typedef struct {
@@ -85,7 +90,7 @@
fb->version = sizeof(*fb);
fb->width = vi.xres;
fb->height = vi.yres;
- fb->stride = vi.xres;
+ fb->stride = fi.line_length/2; /* stride is the number of pixels until the data of next row, >= xres */;
fb->data = bits;
fb->format = GGL_PIXEL_FORMAT_RGB_565;
memset(fb->data, 0, vi.yres * vi.xres * 2);
@@ -95,8 +100,8 @@
fb->version = sizeof(*fb);
fb->width = vi.xres;
fb->height = vi.yres;
- fb->stride = vi.xres;
- fb->data = (void*) (((unsigned) bits) + vi.yres * vi.xres * 2);
+ fb->stride = fi.line_length/2;
+ fb->data = (void*) (((unsigned) bits) + vi.yres * fi.line_length / 2);
fb->format = GGL_PIXEL_FORMAT_RGB_565;
memset(fb->data, 0, vi.yres * vi.xres * 2);
diff --git a/minui/resources.c b/minui/resources.c
index 3d2c727..e055e68 100644
--- a/minui/resources.c
+++ b/minui/resources.c
@@ -125,7 +125,7 @@
int y;
if (channels == 3) {
- for (y = 0; y < height; ++y) {
+ for (y = 0; y < (int)height; ++y) {
unsigned char* pRow = pData + y * stride;
png_read_row(png_ptr, pRow, NULL);
@@ -144,7 +144,7 @@
}
}
} else {
- for (y = 0; y < height; ++y) {
+ for (y = 0; y < (int)height; ++y) {
unsigned char* pRow = pData + y * stride;
png_read_row(png_ptr, pRow, NULL);
}
diff --git a/mmcutils/Android.mk b/mmcutils/Android.mk
new file mode 100644
index 0000000..f1fe294
--- /dev/null
+++ b/mmcutils/Android.mk
@@ -0,0 +1,16 @@
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_ARCH),arm)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ mmcutils.c
+
+LOCAL_MODULE := libmmcutils
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif # TARGET_ARCH == arm
+endif # !TARGET_SIMULATOR
diff --git a/mmcutils/mmcutils.c b/mmcutils/mmcutils.c
new file mode 100644
index 0000000..44fdcf2
--- /dev/null
+++ b/mmcutils/mmcutils.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/mount.h> // for _IOW, _IOR, mount()
+
+#include "mmcutils.h"
+
+unsigned ext3_count = 0;
+char *ext3_partitions[] = {"system", "userdata", "cache", "NONE"};
+
+unsigned vfat_count = 0;
+char *vfat_partitions[] = {"modem", "NONE"};
+
+struct MmcPartition {
+ char *device_index;
+ char *filesystem;
+ char *name;
+ unsigned dstatus;
+ unsigned dtype ;
+ unsigned dfirstsec;
+ unsigned dsize;
+};
+
+typedef struct {
+ MmcPartition *partitions;
+ int partitions_allocd;
+ int partition_count;
+} MmcState;
+
+static MmcState g_mmc_state = {
+ NULL, // partitions
+ 0, // partitions_allocd
+ -1 // partition_count
+};
+
+#define MMC_DEVICENAME "/dev/block/mmcblk0"
+
+static void
+mmc_partition_name (MmcPartition *mbr, unsigned int type) {
+ switch(type)
+ {
+ char name[64];
+ case MMC_BOOT_TYPE:
+ sprintf(name,"boot");
+ mbr->name = strdup(name);
+ break;
+ case MMC_RECOVERY_TYPE:
+ sprintf(name,"recovery");
+ mbr->name = strdup(name);
+ break;
+ case MMC_EXT3_TYPE:
+ if (strcmp("NONE", ext3_partitions[ext3_count])) {
+ strcpy((char *)name,(const char *)ext3_partitions[ext3_count]);
+ mbr->name = strdup(name);
+ ext3_count++;
+ }
+ mbr->filesystem = strdup("ext3");
+ break;
+ case MMC_VFAT_TYPE:
+ if (strcmp("NONE", vfat_partitions[vfat_count])) {
+ strcpy((char *)name,(const char *)vfat_partitions[vfat_count]);
+ mbr->name = strdup(name);
+ vfat_count++;
+ }
+ mbr->filesystem = strdup("vfat");
+ break;
+ };
+}
+
+static int
+mmc_read_mbr (const char *device, MmcPartition *mbr) {
+ FILE *fd;
+ unsigned char buffer[512];
+ int idx, i;
+ unsigned mmc_partition_count = 0;
+ unsigned int dtype;
+ unsigned int dfirstsec;
+ unsigned int EBR_first_sec;
+ unsigned int EBR_current_sec;
+ int ret = -1;
+
+ fd = fopen(device, "r");
+ if(fd == NULL)
+ {
+ printf("Can't open device: \"%s\"\n", device);
+ goto ERROR2;
+ }
+ if ((fread(buffer, 512, 1, fd)) != 1)
+ {
+ printf("Can't read device: \"%s\"\n", device);
+ goto ERROR1;
+ }
+ /* Check to see if signature exists */
+ if ((buffer[TABLE_SIGNATURE] != 0x55) || \
+ (buffer[TABLE_SIGNATURE + 1] != 0xAA))
+ {
+ printf("Incorrect mbr signatures!\n");
+ goto ERROR1;
+ }
+ idx = TABLE_ENTRY_0;
+ for (i = 0; i < 4; i++)
+ {
+ char device_index[128];
+
+ mbr[mmc_partition_count].dstatus = \
+ buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
+ mbr[mmc_partition_count].dtype = \
+ buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
+ mbr[mmc_partition_count].dfirstsec = \
+ GET_LWORD_FROM_BYTE(&buffer[idx + \
+ i * TABLE_ENTRY_SIZE + \
+ OFFSET_FIRST_SEC]);
+ mbr[mmc_partition_count].dsize = \
+ GET_LWORD_FROM_BYTE(&buffer[idx + \
+ i * TABLE_ENTRY_SIZE + \
+ OFFSET_SIZE]);
+ dtype = mbr[mmc_partition_count].dtype;
+ dfirstsec = mbr[mmc_partition_count].dfirstsec;
+ mmc_partition_name(&mbr[mmc_partition_count], \
+ mbr[mmc_partition_count].dtype);
+
+ sprintf(device_index, "%sp%d", device, (mmc_partition_count+1));
+ mbr[mmc_partition_count].device_index = strdup(device_index);
+
+ mmc_partition_count++;
+ if (mmc_partition_count == MAX_PARTITIONS)
+ goto SUCCESS;
+ }
+
+ /* See if the last partition is EBR, if not, parsing is done */
+ if (dtype != 0x05)
+ {
+ goto SUCCESS;
+ }
+
+ EBR_first_sec = dfirstsec;
+ EBR_current_sec = dfirstsec;
+
+ fseek (fd, (EBR_first_sec * 512), SEEK_SET);
+ if ((fread(buffer, 512, 1, fd)) != 1)
+ goto ERROR1;
+
+ /* Loop to parse the EBR */
+ for (i = 0;; i++)
+ {
+ char device_index[128];
+
+ if ((buffer[TABLE_SIGNATURE] != 0x55) || (buffer[TABLE_SIGNATURE + 1] != 0xAA))
+ {
+ break;
+ }
+ mbr[mmc_partition_count].dstatus = \
+ buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
+ mbr[mmc_partition_count].dtype = \
+ buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
+ mbr[mmc_partition_count].dfirstsec = \
+ GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
+ OFFSET_FIRST_SEC]) + \
+ EBR_current_sec;
+ mbr[mmc_partition_count].dsize = \
+ GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
+ OFFSET_SIZE]);
+ mmc_partition_name(&mbr[mmc_partition_count], \
+ mbr[mmc_partition_count].dtype);
+
+ sprintf(device_index, "%sp%d", device, (mmc_partition_count+1));
+ mbr[mmc_partition_count].device_index = strdup(device_index);
+
+ mmc_partition_count++;
+ if (mmc_partition_count == MAX_PARTITIONS)
+ goto SUCCESS;
+
+ dfirstsec = GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
+ if(dfirstsec == 0)
+ {
+ /* Getting to the end of the EBR tables */
+ break;
+ }
+ /* More EBR to follow - read in the next EBR sector */
+ fseek (fd, ((EBR_first_sec + dfirstsec) * 512), SEEK_SET);
+ if ((fread(buffer, 512, 1, fd)) != 1)
+ goto ERROR1;
+
+ EBR_current_sec = EBR_first_sec + dfirstsec;
+ }
+
+SUCCESS:
+ ret = mmc_partition_count;
+ERROR1:
+ fclose(fd);
+ERROR2:
+ return ret;
+}
+
+int
+mmc_scan_partitions() {
+ int i;
+ ssize_t nbytes;
+
+ if (g_mmc_state.partitions == NULL) {
+ const int nump = MAX_PARTITIONS;
+ MmcPartition *partitions = malloc(nump * sizeof(*partitions));
+ if (partitions == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ g_mmc_state.partitions = partitions;
+ g_mmc_state.partitions_allocd = nump;
+ memset(partitions, 0, nump * sizeof(*partitions));
+ }
+ g_mmc_state.partition_count = 0;
+ ext3_count = 0;
+ vfat_count = 0;
+
+ /* Initialize all of the entries to make things easier later.
+ * (Lets us handle sparsely-numbered partitions, which
+ * may not even be possible.)
+ */
+ for (i = 0; i < g_mmc_state.partitions_allocd; i++) {
+ MmcPartition *p = &g_mmc_state.partitions[i];
+ if (p->device_index != NULL) {
+ free(p->device_index);
+ p->device_index = NULL;
+ }
+ if (p->name != NULL) {
+ free(p->name);
+ p->name = NULL;
+ }
+ if (p->filesystem != NULL) {
+ free(p->filesystem);
+ p->filesystem = NULL;
+ }
+ }
+
+ g_mmc_state.partition_count = mmc_read_mbr(MMC_DEVICENAME, g_mmc_state.partitions);
+ if(g_mmc_state.partition_count == -1)
+ {
+ printf("Error in reading mbr!\n");
+ // keep "partitions" around so we can free the names on a rescan.
+ g_mmc_state.partition_count = -1;
+ }
+ return g_mmc_state.partition_count;
+}
+
+const MmcPartition *
+mmc_find_partition_by_name(const char *name)
+{
+ if (g_mmc_state.partitions != NULL) {
+ int i;
+ for (i = 0; i < g_mmc_state.partitions_allocd; i++) {
+ MmcPartition *p = &g_mmc_state.partitions[i];
+ if (p->device_index !=NULL && p->name != NULL) {
+ if (strcmp(p->name, name) == 0) {
+ return p;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#define MKE2FS_BIN "/sbin/mke2fs"
+#define TUNE2FS_BIN "/sbin/tune2fs"
+#define E2FSCK_BIN "/sbin/e2fsck"
+
+static int
+run_exec_process ( char **argv) {
+ pid_t pid;
+ int status;
+ pid = fork();
+ if (pid == 0) {
+ execv(argv[0], argv);
+ fprintf(stderr, "E:Can't run (%s)\n",strerror(errno));
+ _exit(-1);
+ }
+
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ return 1;
+ }
+ return 0;
+}
+
+int
+mmc_format_ext3 (MmcPartition *partition) {
+ char device[128];
+ strcpy(device, partition->device_index);
+ // Run mke2fs
+ char *const mke2fs[] = {MKE2FS_BIN, "-j", device, NULL};
+ if(run_exec_process(mke2fs))
+ return -1;
+
+ // Run tune2fs
+ char *const tune2fs[] = {TUNE2FS_BIN, "-j", "-C", "1", device, NULL};
+ if(run_exec_process(tune2fs))
+ return -1;
+
+ // Run e2fsck
+ char *const e2fsck[] = {E2FSCK_BIN, "-fy", device, NULL};
+ if(run_exec_process(e2fsck))
+ return -1;
+
+ return 0;
+}
+
+int
+mmc_mount_partition(const MmcPartition *partition, const char *mount_point,
+ int read_only)
+{
+ const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME;
+ char devname[128];
+ int rv = -1;
+ strcpy(devname, partition->device_index);
+ if (partition->filesystem == NULL) {
+ printf("Null filesystem!\n");
+ return rv;
+ }
+ if (!read_only) {
+ rv = mount(devname, mount_point, partition->filesystem, flags, NULL);
+ }
+ if (read_only || rv < 0) {
+ rv = mount(devname, mount_point, partition->filesystem, flags | MS_RDONLY, 0);
+ if (rv < 0) {
+ printf("Failed to mount %s on %s: %s\n",
+ devname, mount_point, strerror(errno));
+ } else {
+ printf("Mount %s on %s read-only\n", devname, mount_point);
+ }
+ }
+ return rv;
+}
+
+int
+mmc_raw_copy (const MmcPartition *partition, char *in_file) {
+ int ch;
+ FILE *in;
+ FILE *out;
+ int val = 0;
+ char buf[512];
+ unsigned sz = 0;
+ unsigned i;
+ int ret = -1;
+ char *out_file = partition->device_index;
+
+ in = fopen ( in_file, "r" );
+ if (in == NULL)
+ goto ERROR3;
+
+ out = fopen ( out_file, "w" );
+ if (out == NULL)
+ goto ERROR2;
+
+ fseek(in, 0L, SEEK_END);
+ sz = ftell(in);
+ fseek(in, 0L, SEEK_SET);
+
+ if (sz % 512)
+ {
+ while ( ( ch = fgetc ( in ) ) != EOF )
+ fputc ( ch, out );
+ }
+ else
+ {
+ for (i=0; i< (sz/512); i++)
+ {
+ if ((fread(buf, 512, 1, in)) != 1)
+ goto ERROR1;
+ if ((fwrite(buf, 512, 1, out)) != 1)
+ goto ERROR1;
+ }
+ }
+
+ fsync(out);
+ ret = 0;
+ERROR1:
+ fclose ( out );
+ERROR2:
+ fclose ( in );
+ERROR3:
+ return ret;
+
+}
+
+
+// TODO: refactor this to not be a giant copy paste mess
+int
+mmc_raw_dump (const MmcPartition *partition, char *out_file) {
+ int ch;
+ FILE *in;
+ FILE *out;
+ int val = 0;
+ char buf[512];
+ unsigned sz = 0;
+ unsigned i;
+ int ret = -1;
+ char *in_file = partition->device_index;
+
+ in = fopen ( in_file, "r" );
+ if (in == NULL)
+ goto ERROR3;
+
+ out = fopen ( out_file, "w" );
+ if (out == NULL)
+ goto ERROR2;
+
+ fseek(in, 0L, SEEK_END);
+ sz = ftell(in);
+ fseek(in, 0L, SEEK_SET);
+
+ if (sz % 512)
+ {
+ while ( ( ch = fgetc ( in ) ) != EOF )
+ fputc ( ch, out );
+ }
+ else
+ {
+ for (i=0; i< (sz/512); i++)
+ {
+ if ((fread(buf, 512, 1, in)) != 1)
+ goto ERROR1;
+ if ((fwrite(buf, 512, 1, out)) != 1)
+ goto ERROR1;
+ }
+ }
+
+ fsync(out);
+ ret = 0;
+ERROR1:
+ fclose ( out );
+ERROR2:
+ fclose ( in );
+ERROR3:
+ return ret;
+
+}
+
+
+int
+mmc_raw_read (const MmcPartition *partition, char *data, int data_size) {
+ int ch;
+ FILE *in;
+ int val = 0;
+ char buf[512];
+ unsigned sz = 0;
+ unsigned i;
+ int ret = -1;
+ char *in_file = partition->device_index;
+
+ in = fopen ( in_file, "r" );
+ if (in == NULL)
+ goto ERROR3;
+
+ fseek(in, 0L, SEEK_END);
+ sz = ftell(in);
+ fseek(in, 0L, SEEK_SET);
+
+ fread(data, data_size, 1, in);
+
+ ret = 0;
+ERROR1:
+ERROR2:
+ fclose ( in );
+ERROR3:
+ return ret;
+
+}
+
+int
+mmc_raw_write (const MmcPartition *partition, char *data, int data_size) {
+ int ch;
+ FILE *out;
+ int val = 0;
+ char buf[512];
+ unsigned sz = 0;
+ unsigned i;
+ int ret = -1;
+ char *out_file = partition->device_index;
+
+ out = fopen ( out_file, "w" );
+ if (out == NULL)
+ goto ERROR3;
+
+ fwrite(data, data_size, 1, out);
+
+ ret = 0;
+ERROR1:
+ERROR2:
+ fclose ( out );
+ERROR3:
+ return ret;
+
+}
+
+int cmd_mmc_restore_raw_partition(const char *partition, const char *filename)
+{
+ mmc_scan_partitions();
+ const MmcPartition *p;
+ p = mmc_find_partition_by_name(partition);
+ if (p == NULL)
+ return -1;
+ return mmc_raw_copy(p, filename);
+}
+
+int cmd_mmc_backup_raw_partition(const char *partition, const char *filename)
+{
+ mmc_scan_partitions();
+ const MmcPartition *p;
+ p = mmc_find_partition_by_name(partition);
+ if (p == NULL)
+ return -1;
+ return mmc_raw_dump(p, filename);
+}
+
+int cmd_mmc_erase_raw_partition(const char *partition)
+{
+ mmc_scan_partitions();
+ const MmcPartition *p;
+ p = mmc_find_partition_by_name(partition);
+ if (p == NULL)
+ return -1;
+
+ // TODO: implement raw wipe
+ return 0;
+}
+
+int cmd_mmc_erase_partition(const char *partition, const char *filesystem)
+{
+ mmc_scan_partitions();
+ const MmcPartition *p;
+ p = mmc_find_partition_by_name(partition);
+ if (p == NULL)
+ return -1;
+ return mmc_format_ext3 (p);
+}
+
+int cmd_mmc_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
+{
+ mmc_scan_partitions();
+ const MmcPartition *p;
+ p = mmc_find_partition_by_name(partition);
+ if (p == NULL)
+ return -1;
+ return mmc_mount_partition(p, mount_point, read_only);
+}
+
+int cmd_mmc_get_partition_device(const char *partition, char *device)
+{
+ mmc_scan_partitions();
+ const MmcPartition *p;
+ p = mmc_find_partition_by_name(partition);
+ if (p == NULL)
+ return -1;
+ strcpy(device, p->device_index);
+ return 0;
+}
diff --git a/mmcutils/mmcutils.h b/mmcutils/mmcutils.h
new file mode 100644
index 0000000..64e5813
--- /dev/null
+++ b/mmcutils/mmcutils.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
+ */
+
+#ifndef MMCUTILS_H_
+#define MMCUTILS_H_
+
+/* Some useful define used to access the MBR/EBR table */
+#define BLOCK_SIZE 0x200
+#define TABLE_ENTRY_0 0x1BE
+#define TABLE_ENTRY_1 0x1CE
+#define TABLE_ENTRY_2 0x1DE
+#define TABLE_ENTRY_3 0x1EE
+#define TABLE_SIGNATURE 0x1FE
+#define TABLE_ENTRY_SIZE 0x010
+
+#define OFFSET_STATUS 0x00
+#define OFFSET_TYPE 0x04
+#define OFFSET_FIRST_SEC 0x08
+#define OFFSET_SIZE 0x0C
+#define COPYBUFF_SIZE (1024 * 16)
+#define BINARY_IN_TABLE_SIZE (16 * 512)
+#define MAX_FILE_ENTRIES 20
+
+#define MMC_BOOT_TYPE 0x48
+#define MMC_SYSTEM_TYPE 0x82
+#define MMC_USERDATA_TYPE 0x83
+#define MMC_RECOVERY_TYPE 0x71
+
+#define MMC_RCA 2
+
+#define MAX_PARTITIONS 64
+
+#define GET_LWORD_FROM_BYTE(x) ((unsigned)*(x) | \
+ ((unsigned)*((x)+1) << 8) | \
+ ((unsigned)*((x)+2) << 16) | \
+ ((unsigned)*((x)+3) << 24))
+
+#define PUT_LWORD_TO_BYTE(x, y) do{*(x) = (y) & 0xff; \
+ *((x)+1) = ((y) >> 8) & 0xff; \
+ *((x)+2) = ((y) >> 16) & 0xff; \
+ *((x)+3) = ((y) >> 24) & 0xff; }while(0)
+
+#define GET_PAR_NUM_FROM_POS(x) ((((x) & 0x0000FF00) >> 8) + ((x) & 0x000000FF))
+
+#define MMC_BOOT_TYPE 0x48
+#define MMC_EXT3_TYPE 0x83
+#define MMC_VFAT_TYPE 0xC
+typedef struct MmcPartition MmcPartition;
+
+/* Functions */
+int mmc_scan_partitions();
+const MmcPartition *mmc_find_partition_by_name(const char *name);
+int mmc_format_ext3 (MmcPartition *partition);
+int mmc_mount_partition(const MmcPartition *partition, const char *mount_point, \
+ int read_only);
+int mmc_raw_copy (const MmcPartition *partition, char *in_file);
+int mmc_raw_read (const MmcPartition *partition, char *data, int data_size);
+int mmc_raw_write (const MmcPartition *partition, char *data, int data_size);
+
+#endif // MMCUTILS_H_
+
+
diff --git a/mtdutils/mounts.c b/mounts.c
similarity index 100%
rename from mtdutils/mounts.c
rename to mounts.c
diff --git a/mtdutils/mounts.h b/mounts.h
similarity index 100%
rename from mtdutils/mounts.h
rename to mounts.h
diff --git a/mtdutils/Android.mk b/mtdutils/Android.mk
index 57ab579..90e97fd 100644
--- a/mtdutils/Android.mk
+++ b/mtdutils/Android.mk
@@ -5,20 +5,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- mtdutils.c \
- mounts.c
+ mtdutils.c
LOCAL_MODULE := libmtdutils
include $(BUILD_STATIC_LIBRARY)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := flash_image.c
-LOCAL_MODULE := flash_image
-LOCAL_MODULE_TAGS := eng
-LOCAL_STATIC_LIBRARIES := libmtdutils
-LOCAL_SHARED_LIBRARIES := libcutils libc
-include $(BUILD_EXECUTABLE)
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR
diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c
index 198f498..c8dbba4 100644
--- a/mtdutils/mtdutils.c
+++ b/mtdutils/mtdutils.c
@@ -28,13 +28,6 @@
#include "mtdutils.h"
-struct MtdPartition {
- int device_index;
- unsigned int size;
- unsigned int erase_size;
- char *name;
-};
-
struct MtdReadContext {
const MtdPartition *partition;
char *buffer;
@@ -345,7 +338,7 @@
read += ctx->partition->erase_size;
}
- if (read >= len) {
+ if (read >= (int)len) {
return read;
}
@@ -569,3 +562,295 @@
}
return pos;
}
+
+#define BLOCK_SIZE 2048
+#define SPARE_SIZE (BLOCK_SIZE >> 5)
+#define HEADER_SIZE 2048
+
+int cmd_mtd_restore_raw_partition(const char *partition_name, const char *filename)
+{
+ const MtdPartition *ptn;
+ MtdWriteContext *write;
+ void *data;
+ unsigned sz;
+
+ if (mtd_scan_partitions() <= 0)
+ {
+ printf("error scanning partitions");
+ return -1;
+ }
+ const MtdPartition *partition = mtd_find_partition_by_name(partition_name);
+ if (partition == NULL)
+ {
+ printf("can't find %s partition", partition_name);
+ return -1;
+ }
+
+ // If the first part of the file matches the partition, skip writing
+
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ {
+ printf("error opening %s", filename);
+ return -1;
+ }
+
+ char header[HEADER_SIZE];
+ int headerlen = read(fd, header, sizeof(header));
+ if (headerlen <= 0)
+ {
+ printf("error reading %s header", filename);
+ return -1;
+ }
+
+ MtdReadContext *in = mtd_read_partition(partition);
+ if (in == NULL) {
+ printf("error opening %s: %s\n", partition, strerror(errno));
+ // just assume it needs re-writing
+ } else {
+ char check[HEADER_SIZE];
+ int checklen = mtd_read_data(in, check, sizeof(check));
+ if (checklen <= 0) {
+ printf("error reading %s: %s\n", partition_name, strerror(errno));
+ // just assume it needs re-writing
+ } else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
+ printf("header is the same, not flashing %s\n", partition_name);
+ return 0;
+ }
+ mtd_read_close(in);
+ }
+
+ // Skip the header (we'll come back to it), write everything else
+ printf("flashing %s from %s\n", partition_name, filename);
+
+ MtdWriteContext *out = mtd_write_partition(partition);
+ if (out == NULL)
+ {
+ printf("error writing %s", partition_name);
+ return -1;
+ }
+
+ char buf[HEADER_SIZE];
+ memset(buf, 0, headerlen);
+ int wrote = mtd_write_data(out, buf, headerlen);
+ if (wrote != headerlen)
+ {
+ printf("error writing %s", partition_name);
+ return -1;
+ }
+
+ int len;
+ while ((len = read(fd, buf, sizeof(buf))) > 0) {
+ wrote = mtd_write_data(out, buf, len);
+ if (wrote != len)
+ {
+ printf("error writing %s", partition_name);
+ return -1;
+ }
+ }
+ if (len < 0)
+ {
+ printf("error reading %s", filename);
+ return -1;
+ }
+
+ if (mtd_write_close(out))
+ {
+ printf("error closing %s", partition_name);
+ return -1;
+ }
+
+ // Now come back and write the header last
+
+ out = mtd_write_partition(partition);
+ if (out == NULL)
+ {
+ printf("error re-opening %s", partition_name);
+ return -1;
+ }
+
+ wrote = mtd_write_data(out, header, headerlen);
+ if (wrote != headerlen)
+ {
+ printf("error re-writing %s", partition_name);
+ return -1;
+ }
+
+ // Need to write a complete block, so write the rest of the first block
+ size_t block_size;
+ if (mtd_partition_info(partition, NULL, &block_size, NULL))
+ {
+ printf("error getting %s block size", partition_name);
+ return -1;
+ }
+
+ if (lseek(fd, headerlen, SEEK_SET) != headerlen)
+ {
+ printf("error rewinding %s", filename);
+ return -1;
+ }
+
+ int left = block_size - headerlen;
+ while (left < 0) left += block_size;
+ while (left > 0) {
+ len = read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left);
+ if (len <= 0){
+ printf("error reading %s", filename);
+ return -1;
+ }
+ if (mtd_write_data(out, buf, len) != len)
+ {
+ printf("error writing %s", partition_name);
+ return -1;
+ }
+
+ left -= len;
+ }
+
+ if (mtd_write_close(out))
+ {
+ printf("error closing %s", partition_name);
+ return -1;
+ }
+ return 0;
+}
+
+
+int cmd_mtd_backup_raw_partition(const char *partition_name, const char *filename)
+{
+ MtdReadContext *in;
+ const MtdPartition *partition;
+ char buf[BLOCK_SIZE + SPARE_SIZE];
+ size_t partition_size;
+ size_t read_size;
+ size_t total;
+ int fd;
+ int wrote;
+ int len;
+
+ if (mtd_scan_partitions() <= 0)
+ {
+ printf("error scanning partitions");
+ return -1;
+ }
+
+ partition = mtd_find_partition_by_name(partition_name);
+ if (partition == NULL)
+ {
+ printf("can't find %s partition", partition_name);
+ return -1;
+ }
+
+ if (mtd_partition_info(partition, &partition_size, NULL, NULL)) {
+ printf("can't get info of partition %s", partition_name);
+ return -1;
+ }
+
+ if (!strcmp(filename, "-")) {
+ fd = fileno(stdout);
+ }
+ else {
+ fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ }
+
+ if (fd < 0)
+ {
+ printf("error opening %s", filename);
+ return -1;
+ }
+
+ in = mtd_read_partition(partition);
+ if (in == NULL) {
+ close(fd);
+ unlink(filename);
+ printf("error opening %s: %s\n", partition_name, strerror(errno));
+ return -1;
+ }
+
+ total = 0;
+ while ((len = mtd_read_data(in, buf, BLOCK_SIZE)) > 0) {
+ wrote = write(fd, buf, len);
+ if (wrote != len) {
+ close(fd);
+ unlink(filename);
+ printf("error writing %s", filename);
+ return -1;
+ }
+ total += BLOCK_SIZE;
+ }
+
+ mtd_read_close(in);
+
+ if (close(fd)) {
+ unlink(filename);
+ printf("error closing %s", filename);
+ return -1;
+ }
+ return 0;
+}
+
+int cmd_mtd_erase_raw_partition(const char *partition_name)
+{
+ MtdWriteContext *out;
+ size_t erased;
+ size_t total_size;
+ size_t erase_size;
+
+ if (mtd_scan_partitions() <= 0)
+ {
+ printf("error scanning partitions");
+ return -1;
+ }
+ const MtdPartition *p = mtd_find_partition_by_name(partition_name);
+ if (p == NULL)
+ {
+ printf("can't find %s partition", partition_name);
+ return -1;
+ }
+
+ out = mtd_write_partition(p);
+ if (out == NULL)
+ {
+ printf("could not estabilish write context for %s", partition_name);
+ return -1;
+ }
+
+ // do the actual erase, -1 = full partition erase
+ erased = mtd_erase_blocks(out, -1);
+
+ // erased = bytes erased, if zero, something borked
+ if (!erased)
+ {
+ printf("error erasing %s", partition_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cmd_mtd_erase_partition(const char *partition, const char *filesystem)
+{
+ return cmd_mtd_erase_raw_partition(partition);
+}
+
+
+int cmd_mtd_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
+{
+ mtd_scan_partitions();
+ const MtdPartition *p;
+ p = mtd_find_partition_by_name(partition);
+ if (p == NULL) {
+ return -1;
+ }
+ return mtd_mount_partition(p, mount_point, filesystem, read_only);
+}
+
+int cmd_mtd_get_partition_device(const char *partition, char *device)
+{
+ mtd_scan_partitions();
+ MtdPartition *p = mtd_find_partition_by_name(partition);
+ if (p == NULL)
+ return -1;
+ sprintf(device, "/dev/block/mtdblock%d", p->device_index);
+ return 0;
+}
diff --git a/mtdutils/mtdutils.h b/mtdutils/mtdutils.h
index 45d3ebc..c57d45d 100644
--- a/mtdutils/mtdutils.h
+++ b/mtdutils/mtdutils.h
@@ -53,4 +53,11 @@
off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos);
int mtd_write_close(MtdWriteContext *);
+struct MtdPartition {
+ int device_index;
+ unsigned int size;
+ unsigned int erase_size;
+ char *name;
+};
+
#endif // MTDUTILS_H_
diff --git a/nandroid-md5.sh b/nandroid-md5.sh
new file mode 100644
index 0000000..0db53ee
--- /dev/null
+++ b/nandroid-md5.sh
@@ -0,0 +1,4 @@
+#!/sbin/sh
+cd $1
+md5sum *img > nandroid.md5
+return $?
\ No newline at end of file
diff --git a/nandroid.c b/nandroid.c
new file mode 100644
index 0000000..4f7724a
--- /dev/null
+++ b/nandroid.c
@@ -0,0 +1,361 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <linux/input.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/wait.h>
+#include <sys/limits.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <signal.h>
+#include <sys/wait.h>
+
+#include "bootloader.h"
+#include "common.h"
+#include "cutils/properties.h"
+#include "firmware.h"
+#include "install.h"
+#include "minui/minui.h"
+#include "minzip/DirUtil.h"
+#include "roots.h"
+#include "recovery_ui.h"
+
+#include "../../external/yaffs2/yaffs2/utils/mkyaffs2image.h"
+#include "../../external/yaffs2/yaffs2/utils/unyaffs.h"
+
+#include <sys/vfs.h>
+
+#include "extendedcommands.h"
+#include "nandroid.h"
+
+int print_and_error(const char* message) {
+ ui_print("%s", message);
+ return 1;
+}
+
+int yaffs_files_total = 0;
+int yaffs_files_count = 0;
+void yaffs_callback(char* filename)
+{
+ char* justfile = basename(filename);
+ if (strlen(justfile) < 30)
+ ui_print("%s", justfile);
+ yaffs_files_count++;
+ if (yaffs_files_total != 0)
+ ui_set_progress((float)yaffs_files_count / (float)yaffs_files_total);
+ ui_reset_text_col();
+}
+
+void compute_directory_stats(char* directory)
+{
+ char tmp[PATH_MAX];
+ sprintf(tmp, "find %s | wc -l > /tmp/dircount", directory);
+ __system(tmp);
+ char count_text[100];
+ FILE* f = fopen("/tmp/dircount", "r");
+ fread(count_text, 1, sizeof(count_text), f);
+ fclose(f);
+ yaffs_files_count = 0;
+ yaffs_files_total = atoi(count_text);
+ ui_reset_progress();
+ ui_show_progress(1, 0);
+}
+
+int nandroid_backup_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) {
+ int ret = 0;
+ char* name = basename(mount_point);
+
+ struct stat file_info;
+ mkyaffs2image_callback callback = NULL;
+ if (0 != stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info)) {
+ callback = yaffs_callback;
+ }
+
+ ui_print("Backing up %s...\n", name);
+ if (0 != (ret = ensure_path_mounted(mount_point) != 0)) {
+ ui_print("Can't mount %s!\n", mount_point);
+ return ret;
+ }
+ compute_directory_stats(mount_point);
+ char tmp[PATH_MAX];
+ sprintf(tmp, "%s/%s.img", backup_path, name);
+ ret = mkyaffs2image(mount_point, tmp, 0, callback);
+ if (umount_when_finished) {
+ ensure_path_unmounted(mount_point);
+ }
+ if (0 != ret) {
+ ui_print("Error while making a yaffs2 image of %s!\n", mount_point);
+ return ret;
+ }
+ return 0;
+}
+
+int nandroid_backup_partition(const char* backup_path, char* root) {
+ return nandroid_backup_partition_extended(backup_path, root, 1);
+}
+
+int nandroid_backup(const char* backup_path)
+{
+ ui_set_background(BACKGROUND_ICON_INSTALLING);
+
+ if (ensure_path_mounted("/sdcard") != 0)
+ return print_and_error("Can't mount /sdcard\n");
+
+ int ret;
+ struct statfs s;
+ if (0 != (ret = statfs("/sdcard", &s)))
+ return print_and_error("Unable to stat /sdcard\n");
+ uint64_t bavail = s.f_bavail;
+ uint64_t bsize = s.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);
+ if (sdcard_free_mb < 150)
+ ui_print("There may not be enough free space to complete backup... continuing...\n");
+
+ char tmp[PATH_MAX];
+ sprintf(tmp, "mkdir -p %s", backup_path);
+ __system(tmp);
+
+#ifndef BOARD_RECOVERY_IGNORE_BOOTABLES
+ ui_print("Backing up boot...\n");
+ sprintf(tmp, "%s/%s", backup_path, "boot.img");
+ ret = backup_raw_partition("boot", tmp);
+ if (0 != ret)
+ return print_and_error("Error while dumping boot image!\n");
+
+ ui_print("Backing up recovery...\n");
+ sprintf(tmp, "%s/%s", backup_path, "recovery.img");
+ ret = backup_raw_partition("recovery", tmp);
+ if (0 != ret)
+ return print_and_error("Error while dumping recovery image!\n");
+#endif
+
+ if (0 != (ret = nandroid_backup_partition(backup_path, "/system")))
+ return ret;
+
+ if (0 != (ret = nandroid_backup_partition(backup_path, "/data")))
+ return ret;
+
+#ifdef BOARD_HAS_DATADATA
+ if (0 != (ret = nandroid_backup_partition(backup_path, "/datadata")))
+ return ret;
+#endif
+
+ struct stat st;
+ if (0 != stat("/sdcard/.android_secure", &st))
+ {
+ ui_print("No /sdcard/.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)))
+ return ret;
+ }
+
+ if (0 != (ret = nandroid_backup_partition_extended(backup_path, "/cache", 0)))
+ return ret;
+
+ Volume *vol = volume_for_path("/sd-ext");
+ if (vol == NULL || 0 != stat(vol->device, &st))
+ {
+ ui_print("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");
+ else if (0 != (ret = nandroid_backup_partition(backup_path, "SDEXT:")))
+ return ret;
+ }
+
+ ui_print("Generating md5 sum...\n");
+ sprintf(tmp, "nandroid-md5.sh %s", backup_path);
+ if (0 != (ret = __system(tmp))) {
+ ui_print("Error while generating md5 sum!\n");
+ return ret;
+ }
+
+ sync();
+ ui_set_background(BACKGROUND_ICON_NONE);
+ ui_reset_progress();
+ ui_print("\nBackup complete!\n");
+ return 0;
+}
+
+typedef int (*format_function)(char* root);
+
+static void ensure_directory(const char* dir) {
+ char tmp[PATH_MAX];
+ sprintf(tmp, "mkdir -p %s", dir);
+ __system(tmp);
+}
+
+int nandroid_restore_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) {
+ int ret = 0;
+ char* name = basename(mount_point);
+
+ char tmp[PATH_MAX];
+ sprintf(tmp, "%s/%s.img", backup_path, name);
+ struct stat file_info;
+ if (0 != (ret = statfs(tmp, &file_info))) {
+ ui_print("%s.img not found. Skipping restore of %s.\n", name, mount_point);
+ return 0;
+ }
+
+ ensure_directory(mount_point);
+
+ unyaffs_callback callback = NULL;
+ if (0 != stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info)) {
+ callback = yaffs_callback;
+ }
+
+ ui_print("Restoring %s...\n", name);
+ /*
+ if (0 != (ret = ensure_root_path_unmounted(root))) {
+ ui_print("Can't unmount %s!\n", mount_point);
+ return ret;
+ }
+ */
+ if (0 != (ret = format_device(mount_point))) {
+ ui_print("Error while formatting %s!\n", mount_point);
+ return ret;
+ }
+
+ if (0 != (ret = ensure_path_mounted(mount_point))) {
+ ui_print("Can't mount %s!\n", mount_point);
+ return ret;
+ }
+
+ if (0 != (ret = unyaffs(tmp, mount_point, callback))) {
+ ui_print("Error while restoring %s!\n", mount_point);
+ return ret;
+ }
+
+ if (umount_when_finished) {
+ ensure_path_unmounted(mount_point);
+ }
+
+ return 0;
+}
+
+int nandroid_restore_partition(const char* backup_path, const char* root) {
+ return nandroid_restore_partition_extended(backup_path, root, 1);
+}
+
+int nandroid_restore(const char* backup_path, int restore_boot, int restore_system, int restore_data, int restore_cache, int restore_sdext)
+{
+ ui_set_background(BACKGROUND_ICON_INSTALLING);
+ ui_show_indeterminate_progress();
+ yaffs_files_total = 0;
+
+ if (ensure_path_mounted("/sdcard") != 0)
+ return print_and_error("Can't mount /sdcard\n");
+
+ char tmp[PATH_MAX];
+
+ ui_print("Checking MD5 sums...\n");
+ sprintf(tmp, "cd %s && md5sum -c nandroid.md5", backup_path);
+ if (0 != __system(tmp))
+ return print_and_error("MD5 mismatch!\n");
+
+ int ret;
+#ifndef BOARD_RECOVERY_IGNORE_BOOTABLES
+ if (restore_boot)
+ {
+ ui_print("Erasing boot before restore...\n");
+ if (0 != (ret = format_device("boot")))
+ return print_and_error("Error while formatting BOOT:!\n");
+ sprintf(tmp, "%s/boot.img", backup_path);
+ ui_print("Restoring boot image...\n");
+ if (0 != (ret = restore_raw_partition("boot", tmp))) {
+ ui_print("Error while flashing boot image!");
+ return ret;
+ }
+ }
+#endif
+
+ if (restore_system && 0 != (ret = nandroid_restore_partition(backup_path, "/system")))
+ return ret;
+
+ if (restore_data && 0 != (ret = nandroid_restore_partition(backup_path, "/data")))
+ return ret;
+
+#ifdef BOARD_HAS_DATADATA
+ if (restore_data && 0 != (ret = nandroid_restore_partition(backup_path, "/datadata")))
+ return ret;
+#endif
+
+ if (restore_data && 0 != (ret = nandroid_restore_partition_extended(backup_path, "/sdcard/.android_secure", 0)))
+ return ret;
+
+ if (restore_cache && 0 != (ret = nandroid_restore_partition_extended(backup_path, "/cache", 0)))
+ return ret;
+
+ if (restore_sdext && 0 != (ret = nandroid_restore_partition(backup_path, "/sd-ext")))
+ return ret;
+
+ sync();
+ ui_set_background(BACKGROUND_ICON_NONE);
+ ui_reset_progress();
+ ui_print("\nRestore complete!\n");
+ return 0;
+}
+
+void nandroid_generate_timestamp_path(char* backup_path)
+{
+ time_t t = time(NULL);
+ struct tm *tmp = localtime(&t);
+ if (tmp == NULL)
+ {
+ struct timeval tp;
+ gettimeofday(&tp, NULL);
+ sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec);
+ }
+ else
+ {
+ strftime(backup_path, PATH_MAX, "/sdcard/clockworkmod/backup/%F.%H.%M.%S", tmp);
+ }
+}
+
+int nandroid_usage()
+{
+ printf("Usage: nandroid backup\n");
+ printf("Usage: nandroid restore <directory>\n");
+ return 1;
+}
+
+int nandroid_main(int argc, char** argv)
+{
+ if (argc > 3 || argc < 2)
+ return nandroid_usage();
+
+ if (strcmp("backup", argv[1]) == 0)
+ {
+ if (argc != 2)
+ return nandroid_usage();
+
+ char backup_path[PATH_MAX];
+ nandroid_generate_timestamp_path(backup_path);
+ return nandroid_backup(backup_path);
+ }
+
+ if (strcmp("restore", argv[1]) == 0)
+ {
+ if (argc != 3)
+ return nandroid_usage();
+ return nandroid_restore(argv[2], 1, 1, 1, 1, 1);
+ }
+
+ return nandroid_usage();
+}
diff --git a/nandroid.h b/nandroid.h
new file mode 100644
index 0000000..f124e11
--- /dev/null
+++ b/nandroid.h
@@ -0,0 +1,9 @@
+#ifndef NANDROID_H
+#define NANDROID_H
+
+int nandroid_main(int argc, char** argv);
+int nandroid_backup(const char* backup_path);
+int nandroid_restore(const char* backup_path, int restore_boot, int restore_system, int restore_data, int restore_cache, int restore_sdext);
+void nandroid_generate_timestamp_path(char* backup_path);
+
+#endif
\ No newline at end of file
diff --git a/reboot.c b/reboot.c
new file mode 100644
index 0000000..04aa9ae
--- /dev/null
+++ b/reboot.c
@@ -0,0 +1,72 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/reboot.h>
+#include <unistd.h>
+#include <cutils/properties.h>
+
+int reboot_main(int argc, char *argv[])
+{
+ int ret;
+ int nosync = 0;
+ int poweroff = 0;
+ int force = 0;
+
+ opterr = 0;
+ do {
+ int c;
+
+ c = getopt(argc, argv, "npf");
+
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 'n':
+ nosync = 1;
+ break;
+ case 'p':
+ poweroff = 1;
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case '?':
+ fprintf(stderr, "usage: %s [-n] [-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(!nosync)
+ sync();
+
+ if(force || argc > optind) {
+ if(poweroff)
+ ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
+ else if(argc > optind)
+ ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]);
+ else
+ ret = reboot(RB_AUTOBOOT);
+ } else {
+ if(poweroff) {
+ property_set("ctl.start", "poweroff");
+ ret = 0;
+ } else {
+ property_set("ctl.start", "reboot");
+ ret = 0;
+ }
+ }
+
+ if(ret < 0) {
+ perror("reboot");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(stderr, "reboot returned\n");
+ return 0;
+}
diff --git a/recovery.c b/recovery.c
index 9ad075d..f91edc1 100644
--- a/recovery.c
+++ b/recovery.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +30,7 @@
#include <time.h>
#include <unistd.h>
#include <dirent.h>
+#include <sys/stat.h>
#include "bootloader.h"
#include "common.h"
@@ -40,6 +42,8 @@
#include "recovery_ui.h"
#include "encryptedfs_provisioning.h"
+#include "extendedcommands.h"
+
static const struct option OPTIONS[] = {
{ "send_intent", required_argument, NULL, 's' },
{ "update_package", required_argument, NULL, 'u' },
@@ -55,6 +59,8 @@
static const char *LOG_FILE = "/cache/recovery/log";
static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
static const char *SDCARD_ROOT = "/sdcard";
+static int allow_display_toggle = 1;
+static const char *SDCARD_PACKAGE_FILE = "/sdcard/update.zip";
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
@@ -152,6 +158,7 @@
if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1);
FILE *fp = fopen(path, mode);
+ if (fp == NULL && path != COMMAND_FILE) LOGE("Can't open %s\n", path);
return fp;
}
@@ -171,7 +178,9 @@
get_args(int *argc, char ***argv) {
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
+#ifndef BOARD_HAS_NO_MISC_PARTITION
get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
+#endif
if (boot.command[0] != 0 && boot.command[0] != 255) {
LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
@@ -181,8 +190,10 @@
LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status);
}
+ struct stat file_info;
+
// --- if arguments weren't supplied, look in the bootloader control block
- if (*argc <= 1) {
+ if (*argc <= 1 && 0 != stat("/tmp/.ignorebootmessage", &file_info)) {
boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
const char *arg = strtok(boot.recovery, "\n");
if (arg != NULL && !strcmp(arg, "recovery")) {
@@ -226,10 +237,13 @@
strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
+#ifndef BOARD_HAS_NO_MISC_PARTITION
set_bootloader_message(&boot);
+#endif
}
-static void
+#ifndef BOARD_HAS_NO_MISC_PARTITION
+void
set_sdcard_update_bootloader_message() {
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
@@ -237,6 +251,7 @@
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
set_bootloader_message(&boot);
}
+#endif
// How much of the temp log we have copied to the copy in cache.
static long tmplog_offset = 0;
@@ -288,10 +303,12 @@
copy_log_file(LAST_LOG_FILE, false);
chmod(LAST_LOG_FILE, 0640);
+#ifndef BOARD_HAS_NO_MISC_PARTITION
// Reset to mormal system boot so recovery won't cycle indefinitely.
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
set_bootloader_message(&boot);
+#endif
// Remove the command file, so recovery won't repeat indefinitely.
if (ensure_path_mounted(COMMAND_FILE) != 0 ||
@@ -409,9 +426,8 @@
}
static char**
-prepend_title(const char** headers) {
- char* title[] = { "Android system recovery <"
- EXPAND(RECOVERY_API_VERSION) "e>",
+prepend_title(char** headers) {
+ char* title[] = { EXPAND(RECOVERY_VERSION),
"",
NULL };
@@ -431,23 +447,30 @@
return new_headers;
}
-static int
+int
get_menu_selection(char** headers, char** items, int menu_only,
int initial_selection) {
// throw away keys pressed previously, so user doesn't
// accidentally trigger menu items.
ui_clear_key_queue();
- ui_start_menu(headers, items, initial_selection);
+ int item_count = ui_start_menu(headers, items, initial_selection);
int selected = initial_selection;
int chosen_item = -1;
- while (chosen_item < 0) {
+ // Some users with dead enter keys need a way to turn on power to select.
+ // Jiggering across the wrapping menu is one "secret" way to enable it.
+ // We can't rely on /cache or /sdcard since they may not be available.
+ int wrap_count = 0;
+
+ while (chosen_item < 0 && chosen_item != GO_BACK) {
int key = ui_wait_key();
int visible = ui_text_visible();
int action = device_handle_key(key, visible);
+ int old_selected = selected;
+
if (action < 0) {
switch (action) {
case HIGHLIGHT_UP:
@@ -460,16 +483,40 @@
break;
case SELECT_ITEM:
chosen_item = selected;
+ if (ui_get_showing_back_button()) {
+ if (chosen_item == item_count) {
+ chosen_item = GO_BACK;
+ }
+ }
break;
case NO_ACTION:
break;
+ case GO_BACK:
+ chosen_item = GO_BACK;
+ break;
}
} else if (!menu_only) {
chosen_item = action;
}
+
+ if (abs(selected - old_selected) > 1) {
+ wrap_count++;
+ if (wrap_count == 3) {
+ wrap_count = 0;
+ if (ui_get_showing_back_button()) {
+ ui_print("Back menu button disabled.\n");
+ ui_set_showing_back_button(0);
+ }
+ else {
+ ui_print("Back menu button enabled.\n");
+ ui_set_showing_back_button(1);
+ }
+ }
+ }
}
ui_end_menu();
+ ui_clear_key_queue();
return chosen_item;
}
@@ -634,6 +681,10 @@
device_wipe_data();
erase_volume("/data");
erase_volume("/cache");
+ erase_volume("/datadata");
+ erase_volume("/datadata");
+ erase_volume("/sd-ext");
+ erase_volume("/sdcard/.android_secure");
ui_print("Data wipe complete.\n");
}
@@ -645,7 +696,9 @@
finish_recovery(NULL);
ui_reset_progress();
+ allow_display_toggle = 1;
int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0, 0);
+ allow_display_toggle = 0;
// device-specific code may take some action here. It may
// return one of the core actions handled in the switch
@@ -662,16 +715,20 @@
break;
case ITEM_WIPE_CACHE:
- ui_print("\n-- Wiping cache...\n");
- erase_volume("/cache");
- ui_print("Cache wipe complete.\n");
- if (!ui_text_visible()) return;
+ 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:
- ;
- int status = sdcard_directory(SDCARD_ROOT);
- if (status >= 0) {
+ if (confirm_selection("Confirm install?", "Yes - Install /sdcard/update.zip"))
+ {
+ ui_print("\n-- Install from sdcard...\n");
+ int status = install_package(SDCARD_PACKAGE_FILE);
if (status != INSTALL_SUCCESS) {
ui_set_background(BACKGROUND_ICON_ERROR);
ui_print("Installation aborted.\n");
@@ -682,6 +739,18 @@
}
}
break;
+ case ITEM_INSTALL_ZIP:
+ show_install_update_menu();
+ break;
+ case ITEM_NANDROID:
+ show_nandroid_menu();
+ break;
+ case ITEM_PARTITION:
+ show_partition_menu();
+ break;
+ case ITEM_ADVANCED:
+ show_advanced_menu();
+ break;
}
}
}
@@ -693,6 +762,29 @@
int
main(int argc, char **argv) {
+ if (strstr(argv[0], "recovery") == NULL)
+ {
+ if (strstr(argv[0], "flash_image") != NULL)
+ return flash_image_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], "unyaffs") != NULL)
+ return unyaffs_main(argc, argv);
+ if (strstr(argv[0], "nandroid"))
+ return nandroid_main(argc, argv);
+ if (strstr(argv[0], "reboot"))
+ return reboot_main(argc, argv);
+ if (strstr(argv[0], "setprop"))
+ return setprop_main(argc, argv);
+ return busybox_driver(argc, argv);
+ }
+ __system("/sbin/postrecoveryboot.sh");
+
+ int is_user_initiated_recovery = 0;
time_t start = time(NULL);
// If these fail, there's not really anywhere to complain...
@@ -701,7 +793,7 @@
printf("Starting recovery on %s", ctime(&start));
ui_init();
- ui_set_background(BACKGROUND_ICON_INSTALLING);
+ ui_print(EXPAND(RECOVERY_VERSION)"\n");
load_volume_table();
get_args(&argc, &argv);
@@ -757,7 +849,7 @@
printf("\n");
int status = INSTALL_SUCCESS;
-
+
if (toggle_secure_fs) {
if (strcmp(encrypted_fs_mode,"on") == 0) {
encrypted_fs_data.mode = MODE_ENCRYPTED_FS_ENABLED;
@@ -806,10 +898,31 @@
if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n");
} else {
+ LOGI("Checking for extendedcommand...\n");
status = INSTALL_ERROR; // No command specified
+ // we are starting up in user initiated recovery here
+ // let's set up some default options
+ signature_check_enabled = 0;
+ script_assert_enabled = 0;
+ is_user_initiated_recovery = 1;
+ ui_set_show_text(1);
+
+ if (extendedcommand_file_exists()) {
+ LOGI("Running extendedcommand...\n");
+ int ret;
+ if (0 == (ret = run_and_remove_extendedcommand())) {
+ status = INSTALL_SUCCESS;
+ ui_set_show_text(0);
+ }
+ else {
+ handle_failure(ret);
+ }
+ } else {
+ LOGI("Skipping execution of extendedcommand, file not found...\n");
+ }
}
- if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
+ if (status != INSTALL_SUCCESS && !is_user_initiated_recovery) ui_set_background(BACKGROUND_ICON_ERROR);
if (status != INSTALL_SUCCESS || ui_text_visible()) {
prompt_and_wait();
}
@@ -821,3 +934,7 @@
reboot(RB_AUTOBOOT);
return EXIT_SUCCESS;
}
+
+int get_allow_toggle_display() {
+ return allow_display_toggle;
+}
diff --git a/recovery_ui.h b/recovery_ui.h
index e451bdf..f34365f 100644
--- a/recovery_ui.h
+++ b/recovery_ui.h
@@ -64,11 +64,16 @@
#define HIGHLIGHT_UP -2
#define HIGHLIGHT_DOWN -3
#define SELECT_ITEM -4
+#define GO_BACK -5
#define ITEM_REBOOT 0
#define ITEM_APPLY_SDCARD 1
#define ITEM_WIPE_DATA 2
#define ITEM_WIPE_CACHE 3
+#define ITEM_INSTALL_ZIP 4
+#define ITEM_NANDROID 5
+#define ITEM_PARTITION 6
+#define ITEM_ADVANCED 7
// Header text to display above the main menu.
extern char* MENU_HEADERS[];
@@ -76,4 +81,10 @@
// Text of menu items.
extern char* MENU_ITEMS[];
+int
+get_menu_selection(char** headers, char** items, int menu_only, int initial_selection);
+
+void
+set_sdcard_update_bootloader_message();
+
#endif
diff --git a/roots.c b/roots.c
index 90b82d7..184bfd0 100644
--- a/roots.c
+++ b/roots.c
@@ -23,7 +23,7 @@
#include <ctype.h>
#include "mtdutils/mtdutils.h"
-#include "mtdutils/mounts.h"
+#include "mounts.h"
#include "roots.h"
#include "common.h"
#include "make_ext4fs.h"
diff --git a/setprop.c b/setprop.c
new file mode 100644
index 0000000..63ad2b4
--- /dev/null
+++ b/setprop.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include <cutils/properties.h>
+
+int setprop_main(int argc, char *argv[])
+{
+ if(argc != 3) {
+ fprintf(stderr,"usage: setprop <key> <value>\n");
+ return 1;
+ }
+
+ if(property_set(argv[1], argv[2])){
+ fprintf(stderr,"could not set property\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/ui.c b/ui.c
index 84a9b85..d973a50 100644
--- a/ui.c
+++ b/ui.c
@@ -29,11 +29,25 @@
#include "minui/minui.h"
#include "recovery_ui.h"
+#ifdef BOARD_HAS_NO_SELECT_BUTTON
+static int gShowBackButton = 1;
+#else
+static int gShowBackButton = 0;
+#endif
+
#define MAX_COLS 96
#define MAX_ROWS 32
-#define CHAR_WIDTH 10
-#define CHAR_HEIGHT 18
+#define MENU_MAX_COLS 64
+#define MENU_MAX_ROWS 250
+
+#ifndef BOARD_LDPI_RECOVERY
+ #define CHAR_WIDTH 10
+ #define CHAR_HEIGHT 18
+#else
+ #define CHAR_WIDTH 7
+ #define CHAR_HEIGHT 16
+#endif
#define PROGRESSBAR_INDETERMINATE_STATES 6
#define PROGRESSBAR_INDETERMINATE_FPS 15
@@ -43,6 +57,7 @@
static gr_surface gProgressBarIndeterminate[PROGRESSBAR_INDETERMINATE_STATES];
static gr_surface gProgressBarEmpty;
static gr_surface gProgressBarFill;
+static int ui_has_initialized = 0;
static const struct { gr_surface* surface; const char *name; } BITMAPS[] = {
{ &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" },
@@ -79,9 +94,10 @@
static int text_col = 0, text_row = 0, text_top = 0;
static int show_text = 0;
-static char menu[MAX_ROWS][MAX_COLS];
+static char menu[MENU_MAX_ROWS][MENU_MAX_COLS];
static int show_menu = 0;
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
// Key event input queue
static pthread_mutex_t key_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -148,10 +164,15 @@
}
}
+#define MENU_TEXT_COLOR 7, 133, 74, 255
+#define NORMAL_TEXT_COLOR 200, 200, 200, 255
+#define HEADER_TEXT_COLOR NORMAL_TEXT_COLOR
+
// Redraw everything on the screen. Does not flip pages.
// Should only be called with gUpdateMutex locked.
static void draw_screen_locked(void)
{
+ if (!ui_has_initialized) return;
draw_background_locked(gCurrentIcon);
draw_progress_locked();
@@ -160,29 +181,43 @@
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
int i = 0;
+ int j = 0;
+ int row = 0; // current row that we are drawing on
if (show_menu) {
- gr_color(64, 96, 255, 255);
- gr_fill(0, (menu_top+menu_sel) * CHAR_HEIGHT,
- gr_fb_width(), (menu_top+menu_sel+1)*CHAR_HEIGHT+1);
+ gr_color(MENU_TEXT_COLOR);
+ gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
+ gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);
- for (; i < menu_top + menu_items; ++i) {
+ gr_color(HEADER_TEXT_COLOR);
+ for (i = 0; i < menu_top; ++i) {
+ draw_text_line(i, menu[i]);
+ row++;
+ }
+
+ if (menu_items - menu_show_start + menu_top >= MAX_ROWS)
+ j = MAX_ROWS - menu_top;
+ else
+ j = menu_items - menu_show_start;
+
+ gr_color(MENU_TEXT_COLOR);
+ for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
if (i == menu_top + menu_sel) {
gr_color(255, 255, 255, 255);
- draw_text_line(i, menu[i]);
- gr_color(64, 96, 255, 255);
+ draw_text_line(i - menu_show_start , menu[i]);
+ gr_color(MENU_TEXT_COLOR);
} else {
- draw_text_line(i, menu[i]);
+ gr_color(MENU_TEXT_COLOR);
+ draw_text_line(i - menu_show_start, menu[i]);
}
+ row++;
}
- gr_fill(0, i*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
- gr_fb_width(), i*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
- ++i;
+ gr_fill(0, row*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
+ gr_fb_width(), row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
}
- gr_color(255, 255, 0, 255);
-
- for (; i < text_rows; ++i) {
- draw_text_line(i, text[(i+text_top) % text_rows]);
+ gr_color(NORMAL_TEXT_COLOR);
+ for (; row < text_rows; ++row) {
+ draw_text_line(row, text[(row+text_top) % text_rows]);
}
}
}
@@ -191,6 +226,7 @@
// Should only be called with gUpdateMutex locked.
static void update_screen_locked(void)
{
+ if (!ui_has_initialized) return;
draw_screen_locked();
gr_flip();
}
@@ -199,6 +235,7 @@
// Should only be called with gUpdateMutex locked.
static void update_progress_locked(void)
{
+ if (!ui_has_initialized) return;
if (show_text || !gPagesIdentical) {
draw_screen_locked(); // Must redraw the whole screen
gPagesIdentical = 1;
@@ -308,6 +345,7 @@
void ui_init(void)
{
+ ui_has_initialized = 1;
gr_init();
ev_init();
@@ -337,6 +375,23 @@
pthread_create(&t, NULL, input_thread, NULL);
}
+char *ui_copy_image(int icon, int *width, int *height, int *bpp) {
+ pthread_mutex_lock(&gUpdateMutex);
+ draw_background_locked(gBackgroundIcon[icon]);
+ *width = gr_fb_width();
+ *height = gr_fb_height();
+ *bpp = sizeof(gr_pixel) * 8;
+ int size = *width * *height * sizeof(gr_pixel);
+ char *ret = malloc(size);
+ if (ret == NULL) {
+ LOGE("Can't allocate %d bytes for image\n", size);
+ } else {
+ memcpy(ret, gr_fb_data(), size);
+ }
+ pthread_mutex_unlock(&gUpdateMutex);
+ return ret;
+}
+
void ui_set_background(int icon)
{
pthread_mutex_lock(&gUpdateMutex);
@@ -425,7 +480,17 @@
pthread_mutex_unlock(&gUpdateMutex);
}
-void ui_start_menu(char** headers, char** items, int initial_selection) {
+void ui_reset_text_col()
+{
+ pthread_mutex_lock(&gUpdateMutex);
+ text_col = 0;
+ pthread_mutex_unlock(&gUpdateMutex);
+}
+
+#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 i;
pthread_mutex_lock(&gUpdateMutex);
if (text_rows > 0 && text_cols > 0) {
@@ -435,17 +500,28 @@
menu[i][text_cols-1] = '\0';
}
menu_top = i;
- for (; i < text_rows; ++i) {
+ for (; i < MENU_MAX_ROWS; ++i) {
if (items[i-menu_top] == NULL) break;
- strncpy(menu[i], items[i-menu_top], text_cols-1);
+ strcpy(menu[i], MENU_ITEM_HEADER);
+ strncpy(menu[i] + MENU_ITEM_HEADER_LENGTH, items[i-menu_top], text_cols-1 - MENU_ITEM_HEADER_LENGTH);
menu[i][text_cols-1] = '\0';
}
+
+ if (gShowBackButton) {
+ strcpy(menu[i], " - +++++Go Back+++++");
+ ++i;
+ }
+
menu_items = i - menu_top;
show_menu = 1;
- menu_sel = initial_selection;
+ menu_sel = menu_show_start = initial_selection;
update_screen_locked();
}
pthread_mutex_unlock(&gUpdateMutex);
+ if (gShowBackButton) {
+ return menu_items - 1;
+ }
+ return menu_items;
}
int ui_menu_select(int sel) {
@@ -454,9 +530,21 @@
if (show_menu > 0) {
old_sel = menu_sel;
menu_sel = sel;
- if (menu_sel < 0) menu_sel = 0;
- if (menu_sel >= menu_items) menu_sel = menu_items-1;
+
+ if (menu_sel < 0) menu_sel = menu_items + menu_sel;
+ if (menu_sel >= menu_items) menu_sel = menu_sel - menu_items;
+
+
+ if (menu_sel < menu_show_start && menu_show_start > 0) {
+ menu_show_start = menu_sel;
+ }
+
+ if (menu_sel - menu_show_start + menu_top >= text_rows) {
+ menu_show_start = menu_sel + menu_top - text_rows + 1;
+ }
+
sel = menu_sel;
+
if (menu_sel != old_sel) update_screen_locked();
}
pthread_mutex_unlock(&gUpdateMutex);
@@ -513,3 +601,15 @@
key_queue_len = 0;
pthread_mutex_unlock(&key_queue_mutex);
}
+
+void ui_set_show_text(int value) {
+ show_text = value;
+}
+
+void ui_set_showing_back_button(int showBackButton) {
+ gShowBackButton = showBackButton;
+}
+
+int ui_get_showing_back_button() {
+ return gShowBackButton;
+}
diff --git a/updater/Android.mk b/updater/Android.mk
index dcc6a49..5c43e1c 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -4,6 +4,7 @@
updater_src_files := \
install.c \
+ ../mounts.c \
updater.c
#
@@ -24,6 +25,8 @@
LOCAL_STATIC_LIBRARIES += libext4_utils libz
endif
+LOCAL_STATIC_LIBRARIES += libflashutils libmtdutils libmmcutils libbmlutils
+
LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
LOCAL_STATIC_LIBRARIES += libmincrypt libbz
@@ -70,3 +73,9 @@
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
+
+
+file := $(PRODUCT_OUT)/utilities/update-binary
+ALL_PREBUILT += $(file)
+$(file) : $(TARGET_OUT)/bin/updater | $(ACP)
+ $(transform-prebuilt-to-target)
diff --git a/updater/install.c b/updater/install.c
index a596dc6..478055d 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,8 +32,10 @@
#include "edify/expr.h"
#include "mincrypt/sha.h"
#include "minzip/DirUtil.h"
-#include "mtdutils/mounts.h"
+#include "mounts.h"
+#include "flashutils/flashutils.h"
#include "mtdutils/mtdutils.h"
+#include "mmcutils/mmcutils.h"
#include "updater.h"
#include "applypatch/applypatch.h"
@@ -78,23 +81,11 @@
mkdir(mount_point, 0755);
- if (strcmp(partition_type, "MTD") == 0) {
- mtd_scan_partitions();
- const MtdPartition* mtd;
- mtd = mtd_find_partition_by_name(location);
- if (mtd == NULL) {
- fprintf(stderr, "%s: no mtd partition named \"%s\"",
- name, location);
+ if (strcmp(partition_type, "MTD") == 0 || strcmp(partition_type, "MMC") == 0) {
+ if (0 == mount_partition(location, mount_point, get_default_filesystem(), 0))
+ result = mount_point;
+ else
result = strdup("");
- goto done;
- }
- if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
- fprintf(stderr, "mtd mount of %s failed: %s\n",
- location, strerror(errno));
- result = strdup("");
- goto done;
- }
- result = mount_point;
} else {
if (mount(location, mount_point, fs_type,
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
@@ -204,33 +195,11 @@
goto done;
}
- if (strcmp(partition_type, "MTD") == 0) {
- mtd_scan_partitions();
- const MtdPartition* mtd = mtd_find_partition_by_name(location);
- if (mtd == NULL) {
- fprintf(stderr, "%s: no mtd partition named \"%s\"",
- name, location);
+ if (strcmp(partition_type, "MTD") == 0 || strcmp(partition_type, "MMC") == 0) {
+ if (0 != erase_partition(location, NULL)) {
result = strdup("");
goto done;
}
- MtdWriteContext* ctx = mtd_write_partition(mtd);
- if (ctx == NULL) {
- fprintf(stderr, "%s: can't write \"%s\"", name, location);
- result = strdup("");
- goto done;
- }
- if (mtd_erase_blocks(ctx, -1) == -1) {
- mtd_write_close(ctx);
- fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
- result = strdup("");
- goto done;
- }
- if (mtd_write_close(ctx) != 0) {
- fprintf(stderr, "%s: failed to close \"%s\"", name, location);
- result = strdup("");
- goto done;
- }
- result = location;
#ifdef USE_EXT4
} else if (strcmp(fs_type, "ext4") == 0) {
reset_ext4fs_info();
@@ -247,7 +216,7 @@
fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
name, fs_type, partition_type);
}
-
+ result = location;
done:
free(fs_type);
free(partition_type);
@@ -680,57 +649,10 @@
goto done;
}
- mtd_scan_partitions();
- const MtdPartition* mtd = mtd_find_partition_by_name(partition);
- if (mtd == NULL) {
- fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
+ if (0 == restore_raw_partition(partition, filename))
+ result = strdup(partition);
+ else
result = strdup("");
- goto done;
- }
-
- MtdWriteContext* ctx = mtd_write_partition(mtd);
- if (ctx == NULL) {
- fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
- name, partition);
- result = strdup("");
- goto done;
- }
-
- bool success;
-
- FILE* f = fopen(filename, "rb");
- if (f == NULL) {
- fprintf(stderr, "%s: can't open %s: %s\n",
- name, filename, strerror(errno));
- result = strdup("");
- goto done;
- }
-
- success = true;
- char* buffer = malloc(BUFSIZ);
- int read;
- while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
- int wrote = mtd_write_data(ctx, buffer, read);
- success = success && (wrote == read);
- if (!success) {
- fprintf(stderr, "mtd_write_data to %s failed: %s\n",
- partition, strerror(errno));
- }
- }
- free(buffer);
- fclose(f);
-
- if (mtd_erase_blocks(ctx, -1) == -1) {
- fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
- }
- if (mtd_write_close(ctx) != 0) {
- fprintf(stderr, "%s: error closing write of %s\n", name, partition);
- }
-
- printf("%s %s partition from %s\n",
- success ? "wrote" : "failed to write", partition, filename);
-
- result = success ? partition : strdup("");
done:
if (result != partition) free(partition);
diff --git a/utilities/Android.mk b/utilities/Android.mk
new file mode 100644
index 0000000..f6b6e64
--- /dev/null
+++ b/utilities/Android.mk
@@ -0,0 +1,45 @@
+LOCAL_PATH := $(call my-dir)
+
+ifndef BOARD_HAS_SMALL_RECOVERY
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := e2fsck
+LOCAL_MODULE_TAGS := eng
+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 := fix_permissions
+LOCAL_MODULE_TAGS := eng
+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 := eng
+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 := sdparted
+LOCAL_MODULE_TAGS := eng
+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 := tune2fs
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+endif
diff --git a/utilities/e2fsck b/utilities/e2fsck
new file mode 100644
index 0000000..2844a1d
--- /dev/null
+++ b/utilities/e2fsck
Binary files differ
diff --git a/utilities/fix_permissions b/utilities/fix_permissions
new file mode 100644
index 0000000..a6db514
--- /dev/null
+++ b/utilities/fix_permissions
@@ -0,0 +1,484 @@
+#! /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 "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | $WC -l )
+ I=0
+ $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | while read all_line; do
+ I=$( $EXPR $I + 1 )
+ fp_package "$all_line" $I $FP_NUMS
+ done
+}
+
+fp_single()
+{
+ FP_SFOUND=$( $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | $GREP -i $ONLY_ONE | wc -l )
+ if $TEST $FP_SFOUND -gt 1; then
+ fp_print "Cannot perform single operation on $FP_SFOUND matched package(s)."
+ elif $TEST $FP_SFOUND = "" -o $FP_SFOUND -eq 0; then
+ fp_print "Could not find the package you specified in the packages.xml file."
+ else
+ FP_SPKG=$( $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | $GREP -i $ONLY_ONE )
+ fp_package "${FP_SPKG}" 1 1
+ fi
+}
+
+fp_package()
+{
+ pkgline=$1
+ curnum=$2
+ endnum=$3
+ CODEPATH=$( $ECHO $pkgline | $SED 's%.* codePath="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
+ PACKAGE=$( $ECHO $pkgline | $SED 's%.* name="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
+ UID=$( $ECHO $pkgline | $SED 's%.*serId="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
+ GID=$UID
+ APPDIR=$( $ECHO $CODEPATH | $SED 's%^\(.*\)/.*%\1%' )
+ APK=$( $ECHO $CODEPATH | $SED 's%^.*/\(.*\..*\)$%\1%' )
+
+ #debug
+ if $TEST $DEBUG -eq 1; then
+ fp_print "CODEPATH: $CODEPATH APPDIR: $APPDIR APK:$APK UID/GID:$UID:$GID"
+ fi
+
+ #check for existence of apk
+ if $TEST -e $CODEPATH; then
+ fp_print "Processing ($curnum of $endnum): $PACKAGE..."
+
+ #lets get existing permissions of CODEPATH
+ OLD_UGD=$( $LS -ln "$CODEPATH" )
+ OLD_PER=$( $ECHO $OLD_UGD | $CUT -d ' ' -f1 )
+ OLD_UID=$( $ECHO $OLD_UGD | $CUT -d ' ' -f3 )
+ OLD_GID=$( $ECHO $OLD_UGD | $CUT -d ' ' -f4 )
+
+ #apk source dirs
+ if $TEST "$APPDIR" = "/system/app"; then
+ #skip system apps if set
+ if $TEST "$NOSYSTEM" = "1"; then
+ fp_print "***SKIPPING SYSTEM APP ($PACKAGE)!"
+ return
+ fi
+ fp_chown_uid $OLD_UID 0 "$CODEPATH"
+ fp_chown_gid $OLD_GID 0 "$CODEPATH"
+ fp_chmod $OLD_PER "rw-r--r--" 644 "$CODEPATH"
+ elif $TEST "$APPDIR" = "/data/app" || $TEST "$APPDIR" = "/sd-ext/app"; then
+ fp_chown_uid $OLD_UID 1000 "$CODEPATH"
+ fp_chown_gid $OLD_GID 1000 "$CODEPATH"
+ fp_chmod $OLD_PER "rw-r--r--" 644 "$CODEPATH"
+ elif $TEST "$APPDIR" = "/data/app-private" || $TEST "$APPDIR" = "/sd-ext/app-private"; then
+ fp_chown_uid $OLD_UID 1000 "$CODEPATH"
+ fp_chown_gid $OLD_GID $GID "$CODEPATH"
+ fp_chmod $OLD_PER "rw-r-----" 640 "$CODEPATH"
+ fi
+ else
+ fp_print "$CODEPATH does not exist ($curnum of $endnum). Reinstall..."
+ if $TEST $REMOVE -eq 1; then
+ if $TEST -d /data/data/$PACKAGE ; then
+ fp_print "Removing stale dir /data/data/$PACKAGE"
+ if $TEST $SIMULATE -eq 0 ; then
+ $RM -R /data/data/$PACKAGE
+ fi
+ fi
+ fi
+ fi
+
+ #the data/data for the package
+ if $TEST -d "/data/data/$PACKAGE"; then
+ #find all directories in /data/data/$PACKAGE
+ $FIND /data/data/$PACKAGE -type d -exec $LS -ldn {} \; | while read dataline; do
+ #get existing permissions of that directory
+ OLD_PER=$( $ECHO $dataline | $CUT -d ' ' -f1 )
+ OLD_UID=$( $ECHO $dataline | $CUT -d ' ' -f3 )
+ OLD_GID=$( $ECHO $dataline | $CUT -d ' ' -f4 )
+ FILEDIR=$( $ECHO $dataline | $CUT -d ' ' -f9 )
+ FOURDIR=$( $ECHO $FILEDIR | $CUT -d '/' -f5 )
+
+ #set defaults for iteration
+ ISLIB=0
+ REVPERM=755
+ REVPSTR="rwxr-xr-x"
+ REVUID=$UID
+ REVGID=$GID
+
+ if $TEST "$FOURDIR" = ""; then
+ #package directory, perms:755 owner:$UID:$GID
+ fp_chmod $OLD_PER "rwxr-xr-x" 755 "$FILEDIR"
+ elif $TEST "$FOURDIR" = "lib"; then
+ #lib directory, perms:755 owner:1000:1000
+ #lib files, perms:755 owner:1000:1000
+ ISLIB=1
+ REVPERM=755
+ REVPSTR="rwxr-xr-x"
+ REVUID=1000
+ REVGID=1000
+ fp_chmod $OLD_PER "rwxr-xr-x" 755 "$FILEDIR"
+ elif $TEST "$FOURDIR" = "shared_prefs"; then
+ #shared_prefs directories, perms:771 owner:$UID:$GID
+ #shared_prefs files, perms:660 owner:$UID:$GID
+ REVPERM=660
+ REVPSTR="rw-rw----"
+ fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
+ elif $TEST "$FOURDIR" = "databases"; then
+ #databases directories, perms:771 owner:$UID:$GID
+ #databases files, perms:660 owner:$UID:$GID
+ REVPERM=660
+ REVPSTR="rw-rw----"
+ fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
+ elif $TEST "$FOURDIR" = "cache"; then
+ #cache directories, perms:771 owner:$UID:$GID
+ #cache files, perms:600 owner:$UID:GID
+ REVPERM=600
+ REVPSTR="rw-------"
+ fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
+ else
+ #other directories, perms:771 owner:$UID:$GID
+ REVPERM=771
+ REVPSTR="rwxrwx--x"
+ fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
+ fi
+
+ #change ownership of directories matched
+ if $TEST "$ISLIB" = "1"; then
+ fp_chown_uid $OLD_UID 1000 "$FILEDIR"
+ fp_chown_gid $OLD_GID 1000 "$FILEDIR"
+ else
+ fp_chown_uid $OLD_UID $UID "$FILEDIR"
+ fp_chown_gid $OLD_GID $GID "$FILEDIR"
+ fi
+
+ #if any files exist in directory with improper permissions reset them
+ $FIND $FILEDIR -type f -maxdepth 1 ! -perm $REVPERM -exec $LS -ln {} \; | while read subline; do
+ OLD_PER=$( $ECHO $subline | $CUT -d ' ' -f1 )
+ SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
+ fp_chmod $OLD_PER $REVPSTR $REVPERM "$SUBFILE"
+ done
+
+ #if any files exist in directory with improper user reset them
+ $FIND $FILEDIR -type f -maxdepth 1 ! -user $REVUID -exec $LS -ln {} \; | while read subline; do
+ OLD_UID=$( $ECHO $subline | $CUT -d ' ' -f3 )
+ SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
+ fp_chown_uid $OLD_UID $REVUID "$SUBFILE"
+ done
+
+ #if any files exist in directory with improper group reset them
+ $FIND $FILEDIR -type f -maxdepth 1 ! -group $REVGID -exec $LS -ln {} \; | while read subline; do
+ OLD_GID=$( $ECHO $subline | $CUT -d ' ' -f4 )
+ SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
+ fp_chown_gid $OLD_GID $REVGID "$SUBFILE"
+ done
+ done
+ fi
+}
+
+date_diff()
+{
+ if $TEST $# -ne 2; then
+ FP_DDM="E"
+ FP_DDS="E"
+ return
+ fi
+ FP_DDD=$( $EXPR $2 - $1 )
+ FP_DDM=$( $EXPR $FP_DDD / 60 )
+ FP_DDS=$( $EXPR $FP_DDD % 60 )
+}
+
+fp_end()
+{
+ if $TEST $SYSREMOUNT -eq 1; then
+ $MOUNT -o remount,ro $DEVICE /system > /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/utilities/parted b/utilities/parted
new file mode 100644
index 0000000..bb3d432
--- /dev/null
+++ b/utilities/parted
Binary files differ
diff --git a/utilities/sdparted b/utilities/sdparted
new file mode 100644
index 0000000..d2a46a4
--- /dev/null
+++ b/utilities/sdparted
@@ -0,0 +1,637 @@
+#!/sbin/sh
+
+# do logging, if not excluded with -x
+LOGFILE="/data/sdparted.log"
+[ "$1" != "-x" ] && echo "$0" "$@" >> "$LOGFILE" && "$0" -x "$@" 2>&1 | tee -a "$LOGFILE" && exit
+shift
+
+ShowError() { echo ; echo " err: $1" ; echo ; exit 1 ; }
+
+ShowMessage() { echo ; echo " msg: $1" ; }
+
+ShowHelp() {
+
+cat <<DONEHELP
+
+$SCRIPTNAME v$SCRIPTREV created by $MYNAME
+
+if you use this script in your work, please give some credit. thanks.
+
+requirements: cm-recovery-v1.4
+
+usage: $SCRIPTNAME [options]
+
+
+options:
+
+ --fatsize|-fs SIZE[MG] set the size of the fat32 partition to <SIZE>.
+ default=total sdcard size - (ext + swap)
+
+ --extsize|-es SIZE[MG] set the size of the ext partition to <SIZE>.
+ default=$EXTSIZE
+
+ --swapsize|-ss SIZE[MG] set the size of the swap partition to <SIZE>.
+ if set to 0, no swap partition will be created.
+ default=$SWAPSIZE
+
+ --extfs|-efs TYPE set the filesystem of ext partition to <TYPE>.
+ valid types=ext2, ext3, ext4
+ default=$EXTFS
+
+
+ --upgradefs|-ufs TYPE upgrades existing ext partition to <TYPE>.
+ this operation will NOT wipe your sdcard and
+ cannot be used with any partition creation options.
+ valid types=ext3, ext4
+
+ --downgradefs|-dfs TYPE downgrades existing ext partition to <TYPE>.
+ this operation will NOT wipe your sdcard and
+ cannot be used with any partition creation options.
+ valid types=ext2
+
+
+ --interactive|-i interactive mode
+
+ --help|-h display this help
+
+ --printonly|-po display sdcard information
+
+ --silent|-s do not prompt user, not even initial warning.
+
+
+examples:
+ $SCRIPTNAME creates swap=$SWAPSIZE ext2=$EXTSIZE fat32=remaining free space
+ $SCRIPTNAME -efs ext4 creates swap=$SWAPSIZE ext4=$EXTSIZE fat32=remaining free space
+ $SCRIPTNAME -fs 1.5G -efs ext3 creates swap=$SWAPSIZE ext3=$EXTSIZE fat32=1536
+ $SCRIPTNAME -es 256M -ss 0 creates no swap ext2=256 fat32=remaining free space
+ $SCRIPTNAME -ufs ext4 upgrades ext partition to ext4
+
+DONEHELP
+
+}
+
+UserAbort() {
+
+ WHILEEXIT=
+
+ while [ -z "$WHILEEXIT" ]
+ do
+ echo -n "do you want to continue? (Y/n) "
+ read response
+ echo
+ [ "$response" = "Y" ] || [ "$response" = "n" ] || [ "$response" = "N" ] && WHILEEXIT="$response"
+ done
+
+ echo "$response" > /dev/null 2>&1 >>"$LOGFILE"
+
+ [ "$response" != "Y" ]
+
+}
+
+UnmountAll () {
+
+ # unmount all partitions so we can work with $SDPATH
+ # i'm assuming no more than 3 partitions
+ # maybe make a little more elegant later
+ echo -n "unmounting all partitions..."
+ umount "$FATPATH" > /dev/null 2>&1 >>"$LOGFILE"
+ umount "$EXTPATH" > /dev/null 2>&1 >>"$LOGFILE"
+ umount "$SWAPPATH" > /dev/null 2>&1 >>"$LOGFILE"
+ echo "done"
+ echo
+
+}
+
+
+CheckReqs() {
+
+ echo -n "checking script requirements..."
+ # check for valid sdcard
+ [ -e $SDPATH ] || ShowError "$SDPATH does not exist!"
+
+ # look for necessary programs
+ [ -e $CMPARTED ] || ShowError "$CMPARTED does not exist!"
+ [ -e $CMTUNE2FS ] || ShowError "$CMTUNE2FS does not exist!"
+ [ -e $CME2FSCK ] || ShowError "$CME2FSCK does not exist!"
+
+ # verify cm-v1.4
+ PARTEDREV=`"$CMPARTED" "$SDPATH" version | grep Parted | cut -d" " -f3`
+ [ "$PARTEDREV" == "1.8.8.1.179-aef3" ] || ShowError "you are not using parted v1.8.8.1.179-aef3!"
+ echo "done"
+ echo
+
+}
+
+CheckTableType() {
+
+ TABLETYPE=`"$CMPARTED" "$SDPATH" print | grep Table: | cut -d" " -f3`
+
+ [ "$TABLETYPE" == "loop" -o "$TABLETYPE" == "msdos" ] && TTISOK=1 || TTISOK=0
+ [ "$TABLETYPE" == "loop" ] && TTISLOOP=1 || TTISLOOP=0
+ [ "$TABLETYPE" == "msdos" ] && TTISMSDOS=1 || TTISMOSDOS=0
+
+}
+
+ValidateExtArg() {
+
+ FUNC_RET="nonzero"
+
+ # validating argument
+ [ "$1" != "ext2" ] && [ "$1" != "ext3" ] && [ "$1" != "ext4" ] && FUNC_RET=
+
+ [ -z "$FUNC_RET" ] && [ -z "$IMODE" ] && ShowError "$1 is not a valid filesystem."
+ [ -z "$FUNC_RET" ] && [ -n "$IMODE" ] && ShowMessage "$1 is not a valid filesystem."
+
+ # return valid argument
+ [ -n "$FUNC_RET" ] && FUNC_RET="$1"
+
+}
+
+ValidateSizeArg() {
+
+ # check for zero-length arg to protect expr length
+ [ -z "$1" ] && ShowError "zero-length argument passed to size-validator"
+
+ SIZEMB=
+ ARGLEN=`expr length $1`
+ SIZELEN=$(($ARGLEN-1))
+ SIZEARG=`expr substr $1 1 $SIZELEN`
+ SIZEUNIT=`expr substr $1 $ARGLEN 1`
+
+ # check if SIZEARG is an integer
+ if [ $SIZEARG -eq $SIZEARG 2> /dev/null ] ; then
+ # look for G
+ [ "$SIZEUNIT" == "G" ] && SIZEMB=$(($SIZEARG * 1024))
+ # look for M
+ [ "$SIZEUNIT" == "M" ] && SIZEMB=$SIZEARG
+ # no units on arg AND prevents using bogus size units
+ [ -z "$SIZEMB" ] && [ $SIZEUNIT -eq $SIZEUNIT 2> /dev/null ] && SIZEMB=$1
+ # check if SIZEARG is a floating point number, GB only
+ elif [ `expr index "$SIZEARG" .` != 0 ] && [ "$SIZEUNIT" == "G" ] ; then
+ INT=`echo "$SIZEARG" | cut -d"." -f1`
+ FRAC=`echo "$SIZEARG" | cut -d"." -f2`
+ SIGDIGITS=`expr length $FRAC`
+
+ [ -z "$INT" ] && INT=0
+ INTMB=$(($INT * 1024))
+ FRACMB=$((($FRAC * 1024) / (10**$SIGDIGITS)))
+ SIZEMB=$(($INTMB + $FRACMB))
+ # it's not a valid size
+ else
+ [ -z "$IMODE" ] && ShowError "$1 is not a valid size"
+ fi
+
+ [ -z "$SIZEMB" ] && [ -n "$IMODE" ] && ShowMessage "$1 is not a valid size"
+
+ # return valid argument in MB
+ FUNC_RET=$SIZEMB
+
+}
+
+CalculatePartitions() {
+
+ # get size of sdcard in MB & do some math
+ SDSIZEMB=`"$CMPARTED" "$SDPATH" unit MB print | grep $SDPATH | cut -d" " -f3`
+ SDSIZE=${SDSIZEMB%MB}
+ [ -n "$FATSIZE" ] || FATSIZE=$(($SDSIZE - $EXTSIZE - $SWAPSIZE))
+ EXTEND=$(($FATSIZE + $EXTSIZE))
+ SWAPEND=$(($EXTEND + $SWAPSIZE))
+
+ # check for fatsize of 0
+ [ $FATSIZE -le 0 ] && ShowError "must have a fat32 partition greater than 0MB"
+
+ # check for zero-length sdsize...
+ # indicative of parted not reporting length
+ # correctly b/c of error on sdcard
+ [ -z "$SDSIZE" ] && ShowError "zero-length argument passed to partition-calculator"
+
+ # make sure we're not being asked to do the impossible
+ [ $(($FATSIZE + $EXTSIZE + $SWAPSIZE)) -gt $SDSIZE ] && [ -z "$IMODE" ] && ShowError "sum of requested partitions is greater than sdcard size"
+
+}
+
+
+UpgradeDowngradeOnly() {
+
+ if [ -n "$UEXTFSONLY" ] ; then
+ echo
+ [ -n "$CREATEPART" ] && ShowError "cannot use upgrade option when creating partitions, use -efs instead"
+ [ -n "$DEXTFSONLY" ] && ShowError "cannot upgrade AND downgrade, it just doesn't make sense"
+ echo "you have chosen to upgrade $EXTPATH to $UEXTFSONLY."
+ echo "this action will NOT delete any data from sdcard."
+ echo
+ [ -z "$SILENTRUN" ] && UserAbort && ShowError "script canceled by user"
+ echo
+ UpgradeExt "$UEXTFSONLY"
+ ShowCardInfo
+ elif [ -n "$DEXTFSONLY" ] ; then
+ echo
+ [ -n "$CREATEPART" ] && ShowError "cannot use downgrade option when creating partitions."
+ [ -n "$UEXTFSONLY" ] && ShowError "cannot downgrade AND upgrade, it just doesn't make sense."
+ echo "you have chosen to downgrade $EXTPATH to $DEXTFSONLY."
+ echo "this action will NOT delete any data from sdcard."
+ echo
+ [ -z "$SILENTRUN" ] && UserAbort && ShowError "script canceled by user"
+ echo
+ DowngradeExt "$DEXTFSONLY"
+ ShowCardInfo
+ fi
+
+}
+
+PrepareSdCard() {
+
+ echo
+ if [ $TTISOK -eq 0 ] ; then
+ echo "partition 1 may not be aligned to cylinder boundaries."
+ echo "to continue, this must be corrected."
+ elif [ $TTISLOOP -gt 0 ] ; then
+ echo "your sdcard's partition table type is $TABLETYPE."
+ echo "to continue, partition table must be set to 'msdos'."
+ elif [ $TTISMSDOS -gt 0 ] ; then
+ # just a reminder..in a later version,
+ # i may implement resizing of partitions,
+ # so this will be unnecessary. but until then...
+ echo "to continue, all existing partitions must be removed."
+ else
+ # this is not good, and should never happen
+ # if it does, there is a serious problem
+ ShowError "sdcard failed table type check."
+ fi
+
+ echo
+ echo "this action will remove all data from your sdcard."
+ echo
+ [ -z "$SILENTRUN" ] && UserAbort && ShowError "script canceled by user"
+
+ [ $TTISOK -eq 0 ] && echo -n "correcting cylinder boundaries..."
+ [ $TTISLOOP -gt 0 ] && echo -n "setting partition table to msdos..."
+ [ $TTISMSDOS -gt 0 ] && echo -n "removing all partitions..."
+
+ "$CMPARTED" -s "$SDPATH" mklabel msdos 2>&1 >>"$LOGFILE"
+ echo "done"
+ echo
+
+}
+
+ShowActions() {
+
+ echo
+ echo "total size of sdcard=$SDSIZEMB"
+ echo
+ echo "the following actions will be performed:"
+ echo " -create $FATSIZE""MB fat32 partition"
+ [ $EXTSIZE -gt 0 ] && echo " -create $EXTSIZE""MB ext2 partition"
+ [ $SWAPSIZE -gt 0 ] && echo " -create $SWAPSIZE""MB swap partition"
+ [ "$EXTFS" != "ext2" ] && echo " -ext2 partition will be upgraded to $EXTFS"
+ echo
+ [ -z "$SILENTRUN" ] && UserAbort && ShowError "script canceled by user"
+ echo
+
+}
+
+ShowCardInfo() {
+
+ CheckTableType
+
+ echo
+ echo "retrieving current sdcard information..."
+
+ if [ $TTISOK -gt 0 ] ; then
+ echo
+ parted "$SDPATH" print
+ echo
+ echo "script log is located @ /data/sdparted.log"
+ exit 0
+ else
+ echo
+ echo "partition 1 may not be aligned to cylinder boundaries."
+ ShowError "cannot complete print operation."
+ fi
+ echo
+
+}
+
+
+PartitionSdCard() {
+
+ echo "performing selected actions..."
+ echo
+
+ if [ $FATSIZE -gt 0 ] ; then
+ echo -n "creating fat32 partition..."
+ "$CMPARTED" -s "$SDPATH" mkpartfs primary fat32 0 "$FATSIZE"MB 2>&1 >>"$LOGFILE"
+ echo "done"
+ fi
+
+ if [ $EXTSIZE -gt 0 ] ; then
+ echo -n "creating ext2 partition..."
+ "$CMPARTED" -s "$SDPATH" mkpartfs primary ext2 "$FATSIZE"MB "$EXTEND"MB 2>&1 >>"$LOGFILE"
+ echo "done"
+ fi
+
+ if [ $SWAPSIZE -gt 0 ] ; then
+ echo -n "creating swap partition..."
+ "$CMPARTED" -s "$SDPATH" mkpartfs primary linux-swap "$EXTEND"MB "$SWAPEND"MB 2>&1 >>"$LOGFILE"
+ echo "done"
+ fi
+ echo
+
+}
+
+UpgradeExt() {
+
+ # check for no upgrade
+ [ "$1" == "ext2" ] && return
+ # check for ext partition
+ [ ! -e "$EXTPATH" ] && ShowError "$EXTPATH does not exist"
+
+ # have to use -m switch for this check b/c parted incorrectly
+ # reports all ext partitions as ext2 when running print <number>
+ CHECKEXTFS=`"$CMPARTED" -m "$SDPATH" print | grep ext | cut -d":" -f5`
+ [ "$CHECKEXTFS" == "$1" ] && ShowError "$EXTPATH is already $1"
+
+ # grabbed the code bits for ext3 from upgrade_fs(credit:cyanogen)
+ # check for ext2...must upgrade to ext3 first b4 ext4
+ if [ "$1" == "ext3" -o "$1" == "ext4" ] ; then
+ echo -n "adding journaling to $EXTPATH..."
+ umount /system/sd > /dev/null 2>&1 >>"$LOGFILE"
+ "$CME2FSCK" -p "$EXTPATH" 2>&1 >>"$LOGFILE"
+ "$CMTUNE2FS" -c0 -i0 -j "$EXTPATH" 2>&1 >>"$LOGFILE"
+ echo "done"
+ fi
+
+ # and got convert to ext4 from xda-forum(credit:Denkai)
+ if [ "$1" == "ext4" ] ; then
+ echo -n "converting $EXTPATH to ext4 filesystem..."
+ umount /system/sd > /dev/null 2>&1 >>"$LOGFILE"
+ "$CMTUNE2FS" -O extents,uninit_bg,dir_index "$EXTPATH" 2>&1 >>"$LOGFILE"
+ "$CME2FSCK" -fpDC0 "$EXTPATH" 2>&1 >>"$LOGFILE"
+ echo "done"
+ fi
+ echo
+
+}
+
+DowngradeExt() {
+
+ # check for ext partition
+ [ ! -e "$EXTPATH" ] && ShowError "$EXTPATH does not exist"
+
+ # have to use print for this check b/c parted incorrectly
+ # reports all ext partitions as ext2 when running print <number>
+ CHECKEXTFS=`"$CMPARTED" -m "$SDPATH" print | grep ext | cut -d":" -f5`
+ [ "$CHECKEXTFS" == "$1" ] && ShowError "$EXTPATH is already $1"
+
+ if [ "$CHECKEXTFS" == "ext4" -o "$1" == "ext3" ] ; then
+ # interweb says downgrading from ext4 is not possible
+ # without a backup/restore procedure.
+ # if i figure it out, i'll implement it.
+ ShowError "downgrading from ext4 is not currently supported"
+ fi
+
+ if [ "$1" == "ext2" ] ; then
+ echo -n "removing journaling from $EXTPATH..."
+ umount /system/sd > /dev/null 2>&1 >>"$LOGFILE"
+ "$CMTUNE2FS" -O ^has_journal "$EXTPATH" 2>&1 >>"$LOGFILE"
+ "$CME2FSCK" -fp "$EXTPATH" 2>&1 >>"$LOGFILE"
+ echo "done"
+ fi
+ echo
+
+}
+
+
+Interactive() {
+
+cat <<DONEINSTRUCT
+
+sdparted interactive mode
+
+rules:
+1. no answer means you accept default value
+2. enter '0' for no partition
+
+DONEINSTRUCT
+
+ UserAbort && ShowError "script canceled by user"
+
+ CalculatePartitions
+
+ GetSwapSize
+
+ FATSIZE=
+
+ CalculatePartitions
+
+ GetExtSize
+
+ GetExtType
+
+ FATSIZE=
+
+ CalculatePartitions
+
+ GetFatSize
+
+}
+
+GetSwapSize() {
+
+ SWAPTEST=
+
+ while [ -z "$SWAPTEST" ]
+ do
+ echo
+ echo -n "swap partition size [default=$SWAPSIZE]: "
+ read SWAPRESP
+
+ [ -z "$SWAPRESP" ] && SWAPRESP="$SWAPSIZE"
+ echo "$SWAPRESP" > /dev/null 2>&1 >>"$LOGFILE"
+
+ ValidateSizeArg "$SWAPRESP"
+ SWAPTEST="$FUNC_RET"
+ [ -n "$SWAPTEST" ] && [ $SWAPTEST -gt $SDSIZE ] && ShowMessage "$SWAPRESP > available space($(($SDSIZE))M)." && SWAPTEST=
+ done
+
+ SWAPSIZE=$SWAPTEST
+
+}
+
+GetExtSize() {
+
+ EXTTEST=
+
+ while [ -z "$EXTTEST" ]
+ do
+ echo
+ echo -n "ext partition size [default=$EXTSIZE]: "
+ read EXTRESP
+
+ [ -z "$EXTRESP" ] && EXTRESP="$EXTSIZE"
+ echo "$EXTRESP" > /dev/null 2>&1 >>"$LOGFILE"
+
+ ValidateSizeArg "$EXTRESP"
+ EXTTEST="$FUNC_RET"
+
+ [ -n "$EXTTEST" ] && [ $EXTTEST -gt $(($SDSIZE - $SWAPSIZE)) ] && ShowMessage "$EXTRESP > available space($(($SDSIZE - $SWAPSIZE))M)." && EXTTEST=
+ done
+
+ EXTSIZE=$EXTTEST
+
+}
+
+GetExtType() {
+
+ FSTEST=
+
+ while [ -z "$FSTEST" ]
+ do
+ echo
+ echo -n "ext partition type [default=$EXTFS]: "
+ read FSRESP
+
+ [ -z "$FSRESP" ] && FSRESP="$EXTFS"
+ echo "$FSRESP" > /dev/null 2>&1 >>"$LOGFILE"
+
+ ValidateExtArg "$FSRESP"
+ FSTEST="$FUNC_RET"
+ done
+
+ EXTFS="$FSTEST"
+
+}
+
+GetFatSize() {
+
+ FATTEST=
+
+ while [ -z "$FATTEST" ]
+ do
+ echo
+ echo -n "fat partition size [default=$FATSIZE]: "
+ read FATRESP
+
+ [ -z "$FATRESP" ] && FATRESP="$FATSIZE"
+ echo "$FATRESP" > /dev/null 2>&1 >>"$LOGFILE"
+
+ ValidateSizeArg "$FATRESP"
+ FATTEST="$FUNC_RET"
+
+ [ -n "$FATTEST" ] && [ $FATTEST -gt $FATSIZE ] && ShowMessage "$FATRESP > available space($(($SDSIZE - $SWAPSIZE - $EXTSIZE))M)." && FATTEST=
+ [ -n "$FATTEST" ] && [ $FATTEST -le 0 ] && ShowMessage "must have a fat32 partition greater than 0MB" && FATTEST=
+ done
+
+ FATSIZE=$FATTEST
+
+}
+
+
+SCRIPTNAME="sdparted"
+SCRIPTREV="0.6"
+MYNAME="51dusty"
+
+IMODE=
+SILENTRUN=
+CREATEPART=
+FUNC_RET=
+
+UEXTFSONLY=
+DEXTFSONLY=
+
+TTISOK=
+TTISLOOP=
+TTISMSDOS=
+
+SDSIZE=
+SDSIZEMB=
+if [ -z "$SDPATH" ]
+then
+ SDPATH="/dev/block/mmcblk0"
+else
+ echo Found SDPATH=$SDPATH
+fi
+
+FATSIZE=
+FATTYPE="fat32"
+FATPATH=$SDPATH"p1"
+
+EXTSIZE=512
+EXTFS="ext2"
+EXTPATH=$SDPATH"p2"
+EXTEND=
+
+SWAPSIZE=32
+SWAPTYPE="linux-swap"
+SWAPPATH=$SDPATH"p3"
+SWAPEND=
+
+CMPARTED="/sbin/parted"
+CMTUNE2FS="/sbin/tune2fs"
+CME2FSCK="/sbin/e2fsck"
+
+# give the output some breathing room
+echo "$SCRIPTREV" >> "$LOGFILE"
+echo
+
+# check for arguments
+while [ $# -gt 0 ] ; do
+ case "$1" in
+
+ -h|--help) ShowHelp ; exit 0 ;;
+
+ -fs|--fatsize) shift ; ValidateSizeArg "$1" ; FATSIZE="$FUNC_RET" ; CREATEPART="$1" ;;
+ -es|--extsize) shift ; ValidateSizeArg "$1" ; EXTSIZE="$FUNC_RET" ; CREATEPART="$1" ;;
+ -ss|--swapsize) shift ; ValidateSizeArg "$1" ; SWAPSIZE="$FUNC_RET" ; CREATEPART="$1" ;;
+ -efs|--extfs) shift ; ValidateExtArg "$1" ; EXTFS="$FUNC_RET" ; CREATEPART="$1" ;;
+
+ -ufs|--upgradefs) shift ; ValidateExtArg "$1" ; UEXTFSONLY="$FUNC_RET" ;;
+ -dfs|--downgradefs) shift ; ValidateExtArg "$1" ; DEXTFSONLY="$FUNC_RET" ;;
+
+ -i|--interactive) IMODE="$1" ;;
+
+ -s|--silent) SILENTRUN="$1" ;;
+
+ -po|--printonly) ShowCardInfo ;;
+
+ *) ShowHelp ; ShowError "unknown argument '$1'" ;;
+
+ esac
+ shift
+done
+
+# can't do silent when in interactive mode
+[ -n "$IMODE" ] && SILENTRUN=
+
+# make sure sdcard exists and all needed files are here
+CheckReqs
+
+# unmount all
+UnmountAll
+
+# upgrade only? downgrade only?
+UpgradeDowngradeOnly
+
+# check table
+CheckTableType
+
+# prep card
+PrepareSdCard
+
+# check for interactive mode
+[ -n "$IMODE" ] && Interactive
+
+# do some math
+CalculatePartitions
+
+# last chance to cancel
+ShowActions
+
+# partition card
+PartitionSdCard
+
+# upgrade fs if necessary
+UpgradeExt "$EXTFS"
+
+# say goodbye and show print output
+ShowCardInfo
diff --git a/utilities/tune2fs b/utilities/tune2fs
new file mode 100755
index 0000000..4bd02f6
--- /dev/null
+++ b/utilities/tune2fs
Binary files differ