// Copyright ClockworkMod, LLC. Reference and porting purposes only. Usage of the extendedcommand API // is restricted to those granted explicit permission, or by use of the ROM Manager Recovery API. // https://github.com/koush/TestRomManager #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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" #include "flashutils/flashutils.h" #include "edify/expr.h" #include "mtdutils/mtdutils.h" #include "mmcutils/mmcutils.h" //#include "edify/parser.h" Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { char** args = ReadVarArgs(state, argc, argv); if (args == NULL) { return NULL; } int size = 0; int i; for (i = 0; i < argc; ++i) { size += strlen(args[i]); } char* buffer = malloc(size+1); size = 0; for (i = 0; i < argc; ++i) { strcpy(buffer+size, args[i]); size += strlen(args[i]); free(args[i]); } free(args); buffer[size] = '\0'; char* line = strtok(buffer, "\n"); while (line) { ui_print("%s\n", line); line = strtok(NULL, "\n"); } return StringValue(buffer); } Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc < 1) { return ErrorAbort(state, "%s() expects at least 1 arg", name); } char** args = ReadVarArgs(state, argc, argv); if (args == NULL) { return NULL; } char** args2 = malloc(sizeof(char*) * (argc+1)); memcpy(args2, args, sizeof(char*) * argc); args2[argc] = NULL; fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc); pid_t child = fork(); if (child == 0) { execv(args2[0], args2); fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno)); _exit(1); } int status; waitpid(child, &status, 0); if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { fprintf(stderr, "run_program: child exited with status %d\n", WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { fprintf(stderr, "run_program: child terminated by signal %d\n", WTERMSIG(status)); } int i; for (i = 0; i < argc; ++i) { free(args[i]); } free(args); free(args2); char buffer[20]; sprintf(buffer, "%d", status); return StringValue(strdup(buffer)); } Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; if (argc != 1) { return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc); } char *path; if (ReadArgs(state, argv, 1, &path) < 0) { return NULL; } ui_print("Formatting %s...\n", path); if (0 != format_volume(path)) { free(path); return StringValue(strdup("")); } if (strcmp(path, "/data") == 0 && has_datadata()) { ui_print("Formatting /datadata...\n", path); if (0 != format_volume("/datadata")) { free(path); return StringValue(strdup("")); } if (0 != format_volume("/sdcard/.android_secure")) { free(path); return StringValue(strdup("")); } } done: return StringValue(strdup(path)); } Value* BackupFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; if (argc != 1) { return ErrorAbort(state, "%s() expects 1 args, got %d", name, argc); } char* path; if (ReadArgs(state, argv, 1, &path) < 0) { return NULL; } if (0 != nandroid_backup(path)) return StringValue(strdup("")); return StringValue(strdup(path)); } Value* RestoreFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc < 1) { return ErrorAbort(state, "%s() expects at least 1 arg", name); } char** args = ReadVarArgs(state, argc, argv); if (args == NULL) { return NULL; } char** args2 = malloc(sizeof(char*) * (argc+1)); memcpy(args2, args, sizeof(char*) * argc); args2[argc] = NULL; char* path = strdup(args2[0]); int restoreboot = 1; int restoresystem = 1; int restoredata = 1; int restorecache = 1; int restoresdext = 1; int i; for (i = 1; i < argc; i++) { if (args2[i] == NULL) continue; if (strcmp(args2[i], "noboot") == 0) restoreboot = 0; else if (strcmp(args2[i], "nosystem") == 0) restoresystem = 0; else if (strcmp(args2[i], "nodata") == 0) restoredata = 0; else if (strcmp(args2[i], "nocache") == 0) restorecache = 0; else if (strcmp(args2[i], "nosd-ext") == 0) restoresdext = 0; } for (i = 0; i < argc; ++i) { free(args[i]); } free(args); free(args2); if (0 != nandroid_restore(path, restoreboot, restoresystem, restoredata, restorecache, restoresdext, 0)) { free(path); return StringValue(strdup("")); } return StringValue(path); } Value* InstallZipFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; if (argc != 1) { return ErrorAbort(state, "%s() expects 1 args, got %d", name, argc); } char* path; if (ReadArgs(state, argv, 1, &path) < 0) { return NULL; } if (0 != install_zip(path)) return StringValue(strdup("")); return StringValue(strdup(path)); } Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; if (argc != 1) { return ErrorAbort(state, "%s() expects 1 args, got %d", name, argc); } char* path; if (ReadArgs(state, argv, 1, &path) < 0) { return NULL; } if (0 != ensure_path_mounted(path)) return StringValue(strdup("")); return StringValue(strdup(path)); } void RegisterRecoveryHooks() { RegisterFunction("mount", MountFn); RegisterFunction("format", FormatFn); RegisterFunction("ui_print", UIPrintFn); RegisterFunction("run_program", RunProgramFn); RegisterFunction("backup_rom", BackupFn); RegisterFunction("restore_rom", RestoreFn); RegisterFunction("install_zip", InstallZipFn); } static int hasInitializedEdify = 0; int run_script_from_buffer(char* script_data, int script_len, char* filename) { if (!hasInitializedEdify) { RegisterBuiltins(); RegisterRecoveryHooks(); FinishRegistration(); hasInitializedEdify = 1; } Expr* root; int error_count = 0; yy_scan_bytes(script_data, script_len); int error = yyparse(&root, &error_count); printf("parse returned %d; %d errors encountered\n", error, error_count); if (error == 0 || error_count > 0) { //ExprDump(0, root, buffer); State state; state.cookie = NULL; state.script = script_data; state.errmsg = NULL; char* result = Evaluate(&state, root); if (result == NULL) { printf("result was NULL, message is: %s\n", (state.errmsg == NULL ? "(NULL)" : state.errmsg)); free(state.errmsg); return -1; } else { printf("result is [%s]\n", result); } } return 0; } #define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand" 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."); } ui_print("Verifying SD Card marker...\n"); struct stat st; if (stat("/sdcard/clockworkmod/.salted_hash", &st) != 0) { ui_print("SD Card marker not found...\n"); if (volume_for_path("/emmc") != NULL) { ui_print("Checking Internal SD Card marker...\n"); ensure_path_unmounted("/sdcard"); if (ensure_path_mounted_at_mount_point("/emmc", "/sdcard") != 0) { ui_print("Internal SD Card marker not found... continuing anyways.\n"); // unmount everything, and remount as normal ensure_path_unmounted("/emmc"); ensure_path_unmounted("/sdcard"); ensure_path_mounted("/sdcard"); } } } sprintf(tmp, "/tmp/%s", basename(EXTENDEDCOMMAND_SCRIPT)); int ret; #ifdef I_AM_KOUSH if (0 != (ret = before_run_script(tmp))) { ui_print("Error processing ROM Manager script. Please verify that you are performing the backup, restore, or ROM installation from ROM Manager v4.4.0.0 or higher.\n"); return ret; } #endif return run_script(tmp); } int extendedcommand_file_exists() { struct stat file_info; return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info); } int edify_main(int argc, char** argv) { load_volume_table(); process_volumes(); RegisterBuiltins(); RegisterRecoveryHooks(); FinishRegistration(); if (argc != 2) { printf("edify \n"); return 1; } FILE* f = fopen(argv[1], "r"); if (f == NULL) { printf("%s: %s: No such file or directory\n", argv[0], argv[1]); return 1; } char buffer[8192]; int size = fread(buffer, 1, 8191, f); fclose(f); buffer[size] = '\0'; Expr* root; int error_count = 0; yy_scan_bytes(buffer, size); int error = yyparse(&root, &error_count); printf("parse returned %d; %d errors encountered\n", error, error_count); if (error == 0 || error_count > 0) { //ExprDump(0, root, buffer); State state; state.cookie = NULL; state.script = buffer; state.errmsg = NULL; char* result = Evaluate(&state, root); if (result == NULL) { printf("result was NULL, message is: %s\n", (state.errmsg == NULL ? "(NULL)" : state.errmsg)); free(state.errmsg); } else { printf("result is [%s]\n", result); } } return 0; } 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; }