mirror of
https://github.com/CTCaer/CTCaer-CWM.git
synced 2024-11-23 09:59:45 +00:00
Merge from ClockworkMod recovery
Change-Id: Id5b312147173ced559a62d97029acede6c2f8766
This commit is contained in:
commit
df1e406782
75
Android.mk
75
Android.mk
@ -5,6 +5,7 @@ LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
commands_recovery_local_path := $(LOCAL_PATH)
|
||||
# LOCAL_CPP_EXTENSION := .c
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
recovery.c \
|
||||
@ -13,15 +14,30 @@ LOCAL_SRC_FILES := \
|
||||
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_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
|
||||
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 @@ LOCAL_C_INCLUDES += system/extras/ext4_utils
|
||||
|
||||
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 @@ LOCAL_STATIC_LIBRARIES := libmincrypt libcutils libstdc++ libc
|
||||
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
|
||||
|
8
bmlutils/Android.mk
Normal file
8
bmlutils/Android.mk
Normal file
@ -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)
|
100
bmlutils/bmlutils.c
Normal file
100
bmlutils/bmlutils.c
Normal file
@ -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;
|
||||
}
|
@ -47,4 +47,13 @@ struct bootloader_message {
|
||||
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
|
||||
|
15
common.h
15
common.h
@ -34,10 +34,13 @@ void ui_clear_key_queue();
|
||||
// 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 @@ int ui_menu_select(int sel);
|
||||
// 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)
|
||||
|
@ -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_recovery_start() {
|
||||
}
|
||||
|
||||
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_reboot_now(volatile char* key_pressed, int key_code) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
|
@ -10,6 +10,7 @@ on init
|
||||
symlink /system/etc /etc
|
||||
|
||||
mkdir /sdcard
|
||||
mkdir /emmc
|
||||
mkdir /system
|
||||
mkdir /data
|
||||
mkdir /cache
|
||||
|
972
extendedcommands.c
Normal file
972
extendedcommands.c
Normal file
@ -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;
|
||||
}
|
46
extendedcommands.h
Normal file
46
extendedcommands.h
Normal file
@ -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();
|
35
firmware.h
Normal file
35
firmware.h
Normal file
@ -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
|
98
flashutils/Android.mk
Normal file
98
flashutils/Android.mk
Normal file
@ -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
|
150
flashutils/dump_image.c
Normal file
150
flashutils/dump_image.c
Normal file
@ -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]);
|
||||
}
|
103
flashutils/erase_image.c
Normal file
103
flashutils/erase_image.c
Normal file
@ -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]);
|
||||
}
|
@ -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 @@ int main(int argc, char **argv) {
|
||||
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;
|
||||
}
|
160
flashutils/flashutils.c
Normal file
160
flashutils/flashutils.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
51
flashutils/flashutils.h
Normal file
51
flashutils/flashutils.h
Normal file
@ -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
|
127
install.c
127
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 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
||||
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 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
||||
}
|
||||
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 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
||||
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 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
||||
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 @@ install_package(const char *path)
|
||||
|
||||
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.
|
||||
|
@ -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_
|
||||
|
22
killrecovery.sh
Executable file
22
killrecovery.sh
Executable file
@ -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
|
@ -7,6 +7,10 @@ LOCAL_C_INCLUDES +=\
|
||||
external/libpng\
|
||||
external/zlib
|
||||
|
||||
ifneq ($(BOARD_LDPI_RECOVERY),)
|
||||
LOCAL_CFLAGS += -DBOARD_LDPI_RECOVERY='"$(BOARD_LDPI_RECOVERY)"'
|
||||
endif
|
||||
|
||||
LOCAL_MODULE := libminui
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
288
minui/events.c
288
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 @@ int ev_init(void)
|
||||
|
||||
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 @@ int ev_init(void)
|
||||
|
||||
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 @@ int ev_get(struct input_event *ev, unsigned dont_wait)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
minui/font_7x16.h
Normal file
15
minui/font_7x16.h
Normal file
File diff suppressed because one or more lines are too long
@ -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 @@ static int get_framebuffer(GGLSurface *fb)
|
||||
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 @@ static int get_framebuffer(GGLSurface *fb)
|
||||
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);
|
||||
|
||||
|
@ -125,7 +125,7 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
|
||||
|
||||
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 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
16
mmcutils/Android.mk
Normal file
16
mmcutils/Android.mk
Normal file
@ -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
|
591
mmcutils/mmcutils.c
Normal file
591
mmcutils/mmcutils.c
Normal file
@ -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;
|
||||
}
|
88
mmcutils/mmcutils.h
Normal file
88
mmcutils/mmcutils.h
Normal file
@ -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_
|
||||
|
||||
|
@ -5,20 +5,12 @@ LOCAL_PATH := $(call my-dir)
|
||||
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
|
||||
|
@ -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 @@ ssize_t mtd_read_data(MtdReadContext *ctx, char *data, size_t len)
|
||||
read += ctx->partition->erase_size;
|
||||
}
|
||||
|
||||
if (read >= len) {
|
||||
if (read >= (int)len) {
|
||||
return read;
|
||||
}
|
||||
|
||||
@ -569,3 +562,295 @@ off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -53,4 +53,11 @@ off_t mtd_erase_blocks(MtdWriteContext *, int blocks); /* 0 ok, -1 for all */
|
||||
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_
|
||||
|
4
nandroid-md5.sh
Normal file
4
nandroid-md5.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/sbin/sh
|
||||
cd $1
|
||||
md5sum *img > nandroid.md5
|
||||
return $?
|
361
nandroid.c
Normal file
361
nandroid.c
Normal file
@ -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();
|
||||
}
|
9
nandroid.h
Normal file
9
nandroid.h
Normal file
@ -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
|
72
reboot.c
Normal file
72
reboot.c
Normal file
@ -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;
|
||||
}
|
151
recovery.c
151
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 *INTENT_FILE = "/cache/recovery/intent";
|
||||
static const char *LOG_FILE = "/cache/recovery/log";
|
||||
static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
|
||||
static const char *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 @@ fopen_path(const char *path, const char *mode) {
|
||||
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 @@ static void
|
||||
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 @@ get_args(int *argc, char ***argv) {
|
||||
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 @@ get_args(int *argc, char ***argv) {
|
||||
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 @@ set_sdcard_update_bootloader_message() {
|
||||
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 @@ finish_recovery(const char *send_intent) {
|
||||
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 @@ copy_sideloaded_package(const char* original_path) {
|
||||
}
|
||||
|
||||
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 @@ prepend_title(const char** headers) {
|
||||
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 @@ get_menu_selection(char** headers, char** items, int menu_only,
|
||||
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 @@ wipe_data(int confirm) {
|
||||
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 @@ prompt_and_wait() {
|
||||
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 @@ prompt_and_wait() {
|
||||
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 @@ prompt_and_wait() {
|
||||
}
|
||||
}
|
||||
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 @@ print_property(const char *key, const char *name, void *cookie) {
|
||||
|
||||
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 @@ main(int argc, char **argv) {
|
||||
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);
|
||||
|
||||
@ -806,10 +898,31 @@ main(int argc, char **argv) {
|
||||
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 @@ main(int argc, char **argv) {
|
||||
reboot(RB_AUTOBOOT);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int get_allow_toggle_display() {
|
||||
return allow_display_toggle;
|
||||
}
|
||||
|
@ -64,11 +64,16 @@ int device_wipe_data();
|
||||
#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 @@ extern char* MENU_HEADERS[];
|
||||
// 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
|
||||
|
2
roots.c
2
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"
|
||||
|
18
setprop.c
Normal file
18
setprop.c
Normal file
@ -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;
|
||||
}
|
146
ui.c
146
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 gBackgroundIcon[NUM_BACKGROUND_ICONS];
|
||||
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_cols = 0, text_rows = 0;
|
||||
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 @@ static void draw_text_line(int row, const char* t) {
|
||||
}
|
||||
}
|
||||
|
||||
#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 @@ static void draw_screen_locked(void)
|
||||
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 @@ static void draw_screen_locked(void)
|
||||
// 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 @@ static void update_screen_locked(void)
|
||||
// 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 @@ static void *input_thread(void *cookie)
|
||||
|
||||
void ui_init(void)
|
||||
{
|
||||
ui_has_initialized = 1;
|
||||
gr_init();
|
||||
ev_init();
|
||||
|
||||
@ -337,6 +375,23 @@ void ui_init(void)
|
||||
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 @@ void ui_print(const char *fmt, ...)
|
||||
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 @@ void ui_start_menu(char** headers, char** items, int initial_selection) {
|
||||
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 @@ int ui_menu_select(int sel) {
|
||||
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 @@ void ui_clear_key_queue() {
|
||||
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;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ LOCAL_PATH := $(call my-dir)
|
||||
|
||||
updater_src_files := \
|
||||
install.c \
|
||||
../mounts.c \
|
||||
updater.c
|
||||
|
||||
#
|
||||
@ -24,6 +25,8 @@ LOCAL_C_INCLUDES += system/extras/ext4_utils
|
||||
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_MODULE := updater
|
||||
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)
|
||||
|
@ -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 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
|
||||
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 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
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 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
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 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
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);
|
||||
|
45
utilities/Android.mk
Normal file
45
utilities/Android.mk
Normal file
@ -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
|
BIN
utilities/e2fsck
Normal file
BIN
utilities/e2fsck
Normal file
Binary file not shown.
484
utilities/fix_permissions
Normal file
484
utilities/fix_permissions
Normal file
@ -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
|
BIN
utilities/parted
Normal file
BIN
utilities/parted
Normal file
Binary file not shown.
637
utilities/sdparted
Normal file
637
utilities/sdparted
Normal file
@ -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
|
BIN
utilities/tune2fs
Executable file
BIN
utilities/tune2fs
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user