int twrp_backup_wrapper(const char* backup_path, const char* backup_file_image, int callback) { Volume *v = volume_for_path(backup_path); if (v == NULL) { ui_print("Unable to find volume.\n"); return -1; } if (!is_path_mounted(backup_path)) { LOGE("Unable to find mounted volume: '%s'\n", v->mount_point); return -1; } // Always use split format (simpler code) - Build lists of files to backup char tmp[PATH_MAX]; int backup_count; ui_print("Breaking backup file into multiple archives...\nGenerating file lists\n"); backup_count = Make_File_List(backup_path); if (backup_count < 1) { LOGE("Error generating file list!\n"); return -1; } // check we are not backing up an empty volume as it would fail to restore (tar: short read) // check first if a filelist was generated. If not, ensure volume is 0 size. Else, it could be an error while if (!file_found("/tmp/list/filelist000")) { ui_print("Nothing to backup. Skipping %s\n", BaseName(backup_path)); return 0; } unsigned long long total_bsize = 0, file_size = 0; int index; int nand_starts = 1; last_size_update = 0; set_perf_mode(1); for (index = 0; index < backup_count; index++) { compute_twrp_backup_stats(index); // folder /data/media and google cached music are excluded from tar by Generate_File_Lists(...) if (nandroid_get_default_backup_format() == NANDROID_BACKUP_FORMAT_TAR) sprintf(tmp, "(tar -cpvf '%s%03i' -T /tmp/list/filelist%03i) 2> /proc/self/fd/1 ; exit $?", backup_file_image, index, index); else sprintf(tmp, "set -o pipefail ; (tar -cpv -T /tmp/list/filelist%03i | pigz -c -%d >'%s%03i') 2> /proc/self/fd/1 ; exit $?", index, compression_value.value, backup_file_image, index); ui_print(" * Backing up archive %i/%i\n", (index + 1), backup_count); FILE *fp = __popen(tmp, "r"); if (fp == NULL) { LOGE("Unable to execute tar.\n"); set_perf_mode(0); return -1; } while (fgets(tmp, PATH_MAX, fp) != NULL) { #ifdef PHILZ_TOUCH_RECOVERY if (user_cancel_nandroid(&fp, backup_file_image, 1, &nand_starts)) { set_perf_mode(0); return -1; } #endif tmp[PATH_MAX - 1] = '\0'; if (callback) { update_size_progress(backup_file_image); nandroid_callback(tmp); } } #ifdef PHILZ_TOUCH_RECOVERY ui_print_preset_colors(0, NULL); #endif if (0 != __pclose(fp)) { set_perf_mode(0); return -1; } sprintf(tmp, "%s%03i", backup_file_image, index); file_size = Get_File_Size(tmp); if (file_size == 0) { LOGE("Backup file size for '%s' is 0 bytes!\n", tmp); set_perf_mode(0); return -1; } total_bsize += file_size; } __system("cd /tmp && rm -rf list"); set_perf_mode(0); ui_print("Total backup size:\n %llu bytes.\n", total_bsize); return 0; }
// If the package contains an update binary, extract it and run it. static int try_update_binary(const char *path, ZipArchive *zip) { struct statfs st; char* binary = (char*)malloc(20); if (statfs(INCLUDED_BINARY_NAME, &st) != 0) { // No update-binary included in recovery, extract it from the zip strcpy(binary, "/tmp/update_binary"); const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); if (binary_entry == NULL) { mzCloseZipArchive(zip); return INSTALL_CORRUPT; } unlink(binary); int fd = creat(binary, 0755); if (fd < 0) { mzCloseZipArchive(zip); LOGE("Can't make %s\n", binary); return 1; } bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); close(fd); mzCloseZipArchive(zip); if (!ok) { LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME); return 1; } } else { // Use the update-binary that is included in the recovery strcpy(binary, INCLUDED_BINARY_NAME); LOGI("Using update-binary included in recovery: '%s'.\n", binary); } int pipefd[2]; pipe(pipefd); // When executing the update binary contained in the package, the // arguments passed are: // // - the version number for this interface // // - an fd to which the program can write in order to update the // progress bar. The program can write single-line commands: // // progress <frac> <secs> // fill up the next <frac> part of of the progress bar // over <secs> seconds. If <secs> is zero, use // set_progress commands to manually control the // progress of this segment of the bar // // set_progress <frac> // <frac> should be between 0.0 and 1.0; sets the // progress bar within the segment defined by the most // recent progress command. // // firmware <"hboot"|"radio"> <filename> // arrange to install the contents of <filename> in the // given partition on reboot. // // (API v2: <filename> may start with "PACKAGE:" to // indicate taking a file from the OTA package.) // // (API v3: this command no longer exists.) // // ui_print <string> // display <string> on the screen. // // - the name of the package zip file. // char** args = malloc(sizeof(char*) * 5); args[0] = binary; args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk args[2] = malloc(10); sprintf(args[2], "%d", pipefd[1]); args[3] = (char*)path; args[4] = NULL; pid_t pid = fork(); if (pid == 0) { close(pipefd[0]); execv(binary, args); fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno)); _exit(-1); } close(pipefd[1]); char buffer[1024]; FILE* from_child = fdopen(pipefd[0], "r"); while (fgets(buffer, sizeof(buffer), from_child) != NULL) { char* command = strtok(buffer, " \n"); if (command == NULL) { continue; } else if (strcmp(command, "progress") == 0) { char* fraction_s = strtok(NULL, " \n"); char* seconds_s = strtok(NULL, " \n"); float fraction = strtof(fraction_s, NULL); int seconds = strtol(seconds_s, NULL, 10); ui_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds); } else if (strcmp(command, "set_progress") == 0) { char* fraction_s = strtok(NULL, " \n"); float fraction = strtof(fraction_s, NULL); ui_set_progress(fraction); } else if (strcmp(command, "ui_print") == 0) { char* str = strtok(NULL, "\n"); if (str) { ui_print("%s", str); } else { ui_print("\n"); } } else { LOGE("unknown command [%s]\n", command); } } fclose(from_child); int status; waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status)); return INSTALL_ERROR; } return INSTALL_SUCCESS; }
// 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); i = 0; while (headers[i]) { i++; } const char** fixed_headers = (const char*)malloc((i + 3) * sizeof(char*)); i = 0; while (headers[i]) { fixed_headers[i] = headers[i]; i++; } fixed_headers[i] = directory; fixed_headers[i + 1] = ""; fixed_headers[i + 2 ] = NULL; 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(fixed_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); free(fixed_headers); return return_value; }
void toggle_signature_check() { signature_check_enabled = !signature_check_enabled; ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled"); }
void show_partition_menu() { static char* headers[] = { "Mounts and Storage Menu", "", NULL }; static MountMenuEntry* mount_menue = NULL; static FormatMenuEntry* format_menue = NULL; typedef char* string; int i, mountable_volumes, formatable_volumes; int num_volumes; Volume* device_volumes; num_volumes = get_num_volumes(); device_volumes = get_device_volumes(); string options[255]; if(!device_volumes) return; mountable_volumes = 0; formatable_volumes = 0; mount_menue = malloc(num_volumes * sizeof(MountMenuEntry)); format_menue = malloc(num_volumes * sizeof(FormatMenuEntry)); for (i = 0; i < num_volumes; ++i) { Volume* v = &device_volumes[i]; if(strcmp("ramdisk", v->fs_type) != 0 && strcmp("mtd", v->fs_type) != 0 && strcmp("emmc", v->fs_type) != 0 && strcmp("bml", v->fs_type) != 0) { sprintf(&mount_menue[mountable_volumes].mount, "mount %s", v->mount_point); sprintf(&mount_menue[mountable_volumes].unmount, "unmount %s", v->mount_point); mount_menue[mountable_volumes].v = &device_volumes[i]; ++mountable_volumes; if (is_safe_to_format(v->mount_point)) { sprintf(&format_menue[formatable_volumes].txt, "format %s", v->mount_point); format_menue[formatable_volumes].v = &device_volumes[i]; ++formatable_volumes; } } else if (strcmp("ramdisk", v->fs_type) != 0 && strcmp("mtd", v->fs_type) == 0 && is_safe_to_format(v->mount_point)) { sprintf(&format_menue[formatable_volumes].txt, "format %s", v->mount_point); format_menue[formatable_volumes].v = &device_volumes[i]; ++formatable_volumes; } } static char* confirm_format = "Confirm format?"; static char* confirm = "Yes - Format"; char confirm_string[255]; for (;;) { for (i = 0; i < mountable_volumes; i++) { MountMenuEntry* e = &mount_menue[i]; Volume* v = e->v; if(is_path_mounted(v->mount_point)) options[i] = e->unmount; else options[i] = e->mount; } for (i = 0; i < formatable_volumes; i++) { FormatMenuEntry* e = &format_menue[i]; options[mountable_volumes+i] = e->txt; } options[mountable_volumes+formatable_volumes] = "mount USB storage"; options[mountable_volumes+formatable_volumes + 1] = NULL; int chosen_item = get_menu_selection(headers, &options, 0, 0); if (chosen_item == GO_BACK) break; if (chosen_item == (mountable_volumes+formatable_volumes)) { show_mount_usb_storage_menu(); } else if (chosen_item < mountable_volumes) { MountMenuEntry* e = &mount_menue[chosen_item]; Volume* v = e->v; if (is_path_mounted(v->mount_point)) { if (0 != ensure_path_unmounted(v->mount_point)) ui_print("Error unmounting %s!\n", v->mount_point); } else { if (0 != ensure_path_mounted(v->mount_point)) ui_print("Error mounting %s!\n", v->mount_point); } } else if (chosen_item < (mountable_volumes + formatable_volumes)) { chosen_item = chosen_item - mountable_volumes; FormatMenuEntry* e = &format_menue[chosen_item]; Volume* v = e->v; sprintf(confirm_string, "%s - %s", v->mount_point, confirm_format); if (!confirm_selection(confirm_string, confirm)) continue; ui_print("Formatting %s...\n", v->mount_point); if (0 != format_volume(v->mount_point)) ui_print("Error formatting %s!\n", v->mount_point); else ui_print("Done.\n"); } } free(mount_menue); free(format_menue); }
static int update_directory(const char* path, const char* unmount_when_done) { ensure_path_mounted(path); const char* MENU_HEADERS[] = { "Choose a package to install:", path, "", NULL }; DIR* d; struct dirent* de; d = opendir(path); if (d == NULL) { LOGE("error opening %s: %s\n", path, strerror(errno)); if (unmount_when_done != NULL) { ensure_path_unmounted(unmount_when_done); } return 0; } char** headers = prepend_title(MENU_HEADERS); int d_size = 0; int d_alloc = 10; char** dirs = malloc(d_alloc * sizeof(char*)); int z_size = 1; int z_alloc = 10; char** zips = malloc(z_alloc * sizeof(char*)); zips[0] = strdup("../"); while ((de = readdir(d)) != NULL) { int name_len = strlen(de->d_name); if (de->d_type == DT_DIR) { // skip "." and ".." entries if (name_len == 1 && de->d_name[0] == '.') continue; if (name_len == 2 && de->d_name[0] == '.' && de->d_name[1] == '.') continue; if (d_size >= d_alloc) { d_alloc *= 2; dirs = realloc(dirs, d_alloc * sizeof(char*)); } dirs[d_size] = malloc(name_len + 2); strcpy(dirs[d_size], de->d_name); dirs[d_size][name_len] = '/'; dirs[d_size][name_len+1] = '\0'; ++d_size; } else if (de->d_type == DT_REG && name_len >= 4 && strncasecmp(de->d_name + (name_len-4), ".zip", 4) == 0) { if (z_size >= z_alloc) { z_alloc *= 2; zips = realloc(zips, z_alloc * sizeof(char*)); } zips[z_size++] = strdup(de->d_name); } } closedir(d); qsort(dirs, d_size, sizeof(char*), compare_string); qsort(zips, z_size, sizeof(char*), compare_string); // append dirs to the zips list if (d_size + z_size + 1 > z_alloc) { z_alloc = d_size + z_size + 1; zips = realloc(zips, z_alloc * sizeof(char*)); } memcpy(zips + z_size, dirs, d_size * sizeof(char*)); free(dirs); z_size += d_size; zips[z_size] = NULL; int result; int chosen_item = 0; do { chosen_item = get_menu_selection(headers, zips, 1, chosen_item); char* item = zips[chosen_item]; int item_len = strlen(item); if (chosen_item == 0) { // item 0 is always "../" // go up but continue browsing (if the caller is update_directory) result = -1; break; } else if (item[item_len-1] == '/') { // recurse down into a subdirectory char new_path[PATH_MAX]; strlcpy(new_path, path, PATH_MAX); strlcat(new_path, "/", PATH_MAX); strlcat(new_path, item, PATH_MAX); new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/' result = update_directory(new_path, unmount_when_done); if (result >= 0) break; } else { // selected a zip file: attempt to install it, and return // the status to the caller. char new_path[PATH_MAX]; strlcpy(new_path, path, PATH_MAX); strlcat(new_path, "/", PATH_MAX); strlcat(new_path, item, PATH_MAX); ui_print("\n-- Install %s ...\n", path); set_sdcard_update_bootloader_message(); char* copy = copy_sideloaded_package(new_path); if (unmount_when_done != NULL) { ensure_path_unmounted(unmount_when_done); } if (copy) { result = install_package(copy); free(copy); } else { result = INSTALL_ERROR; } break; } } while (true); int i; for (i = 0; i < z_size; ++i) free(zips[i]); free(zips); free(headers); if (unmount_when_done != NULL) { ensure_path_unmounted(unmount_when_done); } return result; }
int main(int argc, char **argv) { if (argc == 2 && strcmp(argv[1], "adbd") == 0) { adb_main(); return 0; } // Recovery needs to install world-readable files, so clear umask // set by init umask(0); if (strcmp(basename(argv[0]), "recovery") != 0) { if (strstr(argv[0], "minizip") != NULL) return minizip_main(argc, argv); if (strstr(argv[0], "dedupe") != NULL) return dedupe_main(argc, argv); if (strstr(argv[0], "flash_image") != NULL) return flash_image_main(argc, argv); if (strstr(argv[0], "volume") != NULL) return volume_main(argc, argv); if (strstr(argv[0], "edify") != NULL) return edify_main(argc, argv); if (strstr(argv[0], "dump_image") != NULL) return dump_image_main(argc, argv); if (strstr(argv[0], "erase_image") != NULL) return erase_image_main(argc, argv); if (strstr(argv[0], "mkyaffs2image") != NULL) return mkyaffs2image_main(argc, argv); if (strstr(argv[0], "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); #ifdef BOARD_RECOVERY_HANDLES_MOUNT if (strstr(argv[0], "mount") && argc == 2 && !strstr(argv[0], "umount")) { load_volume_table(); return ensure_path_mounted(argv[1]); } #endif if (strstr(argv[0], "poweroff")){ 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... freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL); freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL); printf("Starting recovery on %s", ctime(&start)); device_ui_init(&ui_parameters); ui_init(); #ifndef PHILZ_TOUCH_RECOVERY //fast_ui_init() launched by below device_recovery_start() will wipe any ui_print before it ui_print(EXPAND(RECOVERY_VERSION)"\n"); #endif load_volume_table(); process_volumes(); LOGI("Processing arguments.\n"); get_args(&argc, &argv); int previous_runs = 0; const char *send_intent = NULL; const char *update_package = NULL; int wipe_data = 0, wipe_cache = 0; LOGI("Checking arguments.\n"); int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { switch (arg) { case 'p': previous_runs = atoi(optarg); break; case 's': send_intent = optarg; break; case 'u': update_package = optarg; break; case 'w': #ifndef BOARD_RECOVERY_ALWAYS_WIPES wipe_data = wipe_cache = 1; #endif break; case 'c': wipe_cache = 1; break; case 't': ui_show_text(1); break; case '?': LOGE("Invalid command argument\n"); continue; } } LOGI("device_recovery_start()\n"); device_recovery_start(); #ifdef PHILZ_TOUCH_RECOVERY ui_print(EXPAND(RECOVERY_VERSION)"\n"); ui_print("CWM Base version: "EXPAND(CWM_BASE_VERSION)"\n"); #endif printf("Command:"); for (arg = 0; arg < argc; arg++) { printf(" \"%s\"", argv[arg]); } printf("\n"); if (update_package) { // For backwards compatibility on the cache partition only, if // we're given an old 'root' path "CACHE:foo", change it to // "/cache/foo". if (strncmp(update_package, "CACHE:", 6) == 0) { int len = strlen(update_package) + 10; char* modified_path = malloc(len); strlcpy(modified_path, "/cache/", len); strlcat(modified_path, update_package+6, len); printf("(replacing path \"%s\" with \"%s\")\n", update_package, modified_path); update_package = modified_path; } } printf("\n"); property_list(print_property, NULL); printf("\n"); int status = INSTALL_SUCCESS; if (update_package != NULL) { status = install_package(update_package); if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); } else if (wipe_data) { if (device_wipe_data()) status = INSTALL_ERROR; if (erase_volume("/data")) status = INSTALL_ERROR; if (has_datadata() && erase_volume("/datadata")) status = INSTALL_ERROR; if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n"); } else if (wipe_cache) { 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); ui_set_background(BACKGROUND_ICON_CLOCKWORK); 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 && !is_user_initiated_recovery) { ui_set_show_text(1); ui_set_background(BACKGROUND_ICON_ERROR); } if (status != INSTALL_SUCCESS || ui_text_visible()) { prompt_and_wait(); } verify_root_and_recovery(); // If there is a radio image pending, reboot now to install it. maybe_install_firmware_update(send_intent); // Otherwise, get ready to boot the main system... finish_recovery(send_intent); sync(); if(!poweroff) { ui_print("Rebooting...\n"); android_reboot(ANDROID_RB_RESTART, 0, 0); } else { ui_print("Shutting down...\n"); android_reboot(ANDROID_RB_POWEROFF, 0, 0); } return EXIT_SUCCESS; }
static void prompt_and_wait() { char** headers = prepend_title((const char**)MENU_HEADERS); for (;;) { finish_recovery(NULL); ui_reset_progress(); int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0, 0); // device-specific code may take some action here. It may // return one of the core actions handled in the switch // statement below. chosen_item = device_perform_action(chosen_item); int status; int wipe_cache; switch (chosen_item) { case ITEM_REBOOT: return; case ITEM_WIPE_DATA: wipe_data(ui_text_visible()); if (!ui_text_visible()) return; 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; break; case ITEM_APPLY_SDCARD: status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache); if (status == INSTALL_SUCCESS && wipe_cache) { ui_print("\n-- Wiping cache (at package request)...\n"); if (erase_volume("/cache")) { ui_print("Cache wipe failed.\n"); } else { ui_print("Cache wipe complete.\n"); } } if (status >= 0) { if (status != INSTALL_SUCCESS) { ui_set_background(BACKGROUND_ICON_ERROR); ui_print("Installation aborted.\n"); } else if (!ui_text_visible()) { return; // reboot if logs aren't visible } else { ui_print("\nInstall from sdcard complete.\n"); } } break; case ITEM_APPLY_CACHE: // Don't unmount cache at the end of this. status = update_directory(CACHE_ROOT, NULL, &wipe_cache); if (status == INSTALL_SUCCESS && wipe_cache) { ui_print("\n-- Wiping cache (at package request)...\n"); if (erase_volume("/cache")) { ui_print("Cache wipe failed.\n"); } else { ui_print("Cache wipe complete.\n"); } } if (status >= 0) { if (status != INSTALL_SUCCESS) { ui_set_background(BACKGROUND_ICON_ERROR); ui_print("Installation aborted.\n"); } else if (!ui_text_visible()) { return; // reboot if logs aren't visible } else { ui_print("\nInstall from cache complete.\n"); } } break; } } }
int main(int argc, char **argv) { time_t start = time(NULL); // If these fail, there's not really anywhere to complain... freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL); freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL); printf("Starting recovery on %s", ctime(&start)); device_ui_init(&ui_parameters); ui_init(); ui_set_background(BACKGROUND_ICON_INSTALLING); load_volume_table(); get_args(&argc, &argv); int previous_runs = 0; const char *send_intent = NULL; const char *update_package = NULL; int wipe_data = 0, wipe_cache = 0; int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { switch (arg) { case 'p': previous_runs = atoi(optarg); break; case 's': send_intent = optarg; break; case 'u': update_package = optarg; break; case 'w': wipe_data = wipe_cache = 1; break; case 'c': wipe_cache = 1; break; case 't': ui_show_text(1); break; case '?': LOGE("Invalid command argument\n"); continue; } } device_recovery_start(); printf("Command:"); for (arg = 0; arg < argc; arg++) { printf(" \"%s\"", argv[arg]); } printf("\n"); if (update_package) { // For backwards compatibility on the cache partition only, if // we're given an old 'root' path "CACHE:foo", change it to // "/cache/foo". if (strncmp(update_package, "CACHE:", 6) == 0) { int len = strlen(update_package) + 10; char* modified_path = malloc(len); strlcpy(modified_path, "/cache/", len); strlcat(modified_path, update_package+6, len); printf("(replacing path \"%s\" with \"%s\")\n", update_package, modified_path); update_package = modified_path; } } printf("\n"); property_list(print_property, NULL); printf("\n"); int status = INSTALL_SUCCESS; if (update_package != NULL) { status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE); if (status == INSTALL_SUCCESS && wipe_cache) { if (erase_volume("/cache")) { LOGE("Cache wipe (requested by package) failed."); } } if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); } else if (wipe_data) { if (device_wipe_data()) status = INSTALL_ERROR; if (erase_volume("/data")) status = INSTALL_ERROR; if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n"); } else if (wipe_cache) { if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n"); } else { status = INSTALL_ERROR; // No command specified } if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR); if (status != INSTALL_SUCCESS || ui_text_visible()) { prompt_and_wait(); } // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui_print("Rebooting...\n"); android_reboot(ANDROID_RB_RESTART, 0, 0); return EXIT_SUCCESS; }
static void prompt_and_wait() { const char** headers = prepend_title((const char**)MENU_HEADERS); for (;;) { finish_recovery(NULL); ui_reset_progress(); ui_root_menu = 1; // ui_menu_level is a legacy variable that i am keeping around to prevent build breakage. ui_menu_level = 0; // allow_display_toggle = 1; int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0, 0); ui_menu_level = 1; ui_root_menu = 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 // statement below. chosen_item = device_perform_action(chosen_item); int status; int ret = 0; for (;;) { switch (chosen_item) { case ITEM_REBOOT: return; case ITEM_WIPE_DATA: wipe_data(ui_text_visible()); if (!ui_text_visible()) return; break; case ITEM_WIPE_CACHE: if (confirm_selection("Confirm wipe?", "Yes - Wipe Cache")) { ui_print("\n-- Wiping cache...\n"); erase_volume("/cache"); ui_print("Cache wipe complete.\n"); if (!ui_text_visible()) return; } break; case ITEM_BACKUP_DATA: ui_print("\n-- Not really backing up data...\n"); break; case ITEM_ADVANCED: ret = show_advanced_menu(); break; } if (ret == REFRESH) { ret = 0; continue; } break; } } }
int main(int argc, char **argv) { if (argc == 2 && strcmp(argv[1], "adbd") == 0) { adb_main(); return 0; } // Recovery needs to install world-readable files, so clear umask // set by init umask(0); char* command = argv[0]; char* stripped = strrchr(argv[0], '/'); if (stripped) command = stripped + 1; if (strcmp(command, "recovery") != 0) { struct recovery_cmd cmd = get_command(command); if (cmd.name) return cmd.main_func(argc, argv); #ifdef BOARD_RECOVERY_HANDLES_MOUNT if (!strcmp(command, "mount") && argc == 2) { load_volume_table(); return ensure_path_mounted(argv[1]); } #endif if (!strcmp(command, "setup_adbd")) { load_volume_table(); setup_adbd(); return 0; } if (!strcmp(command, "start")) { property_set("ctl.start", argv[1]); return 0; } if (!strcmp(command, "stop")) { property_set("ctl.stop", argv[1]); return 0; } /* Make sure stdout is not fully buffered, we don't want to * have issues when calling busybox commands */ setlinebuf(stdout); 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... freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL); freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL); printf("Starting recovery on %s\n", ctime(&start)); device_ui_init(&ui_parameters); ui_init(); ui_print(EXPAND(RECOVERY_VERSION)"\n"); #ifdef BOARD_RECOVERY_SWIPE #ifndef BOARD_TOUCH_RECOVERY //display directions for swipe controls ui_print("Swipe up/down to change selections.\n"); ui_print("Swipe to the right for enter.\n"); ui_print("Swipe to the left for back.\n"); #endif #endif load_volume_table(); process_volumes(); vold_client_start(&v_callbacks, 0); vold_set_automount(1); setup_legacy_storage_paths(); LOGI("Processing arguments.\n"); ensure_path_mounted(LAST_LOG_FILE); rotate_last_logs(10); get_args(&argc, &argv); int previous_runs = 0; const char *send_intent = NULL; const char *update_package = NULL; const char *update_ubuntu_package = NULL; const char *user_data_update_package = NULL; int wipe_data = 0, wipe_cache = 0; int sideload = 0; int headless = 0; try_autodeploy(AUTODEPLOY_PACKAGE_FILE); try_autodeploy(AUTODEPLOY_PACKAGE_FILE_MULTI); LOGI("Checking arguments.\n"); int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { switch (arg) { case 'p': previous_runs = atoi(optarg); break; case 's': send_intent = optarg; break; case 'u': update_package = optarg; break; case 'd': user_data_update_package = optarg; break; case 'w': #ifndef BOARD_RECOVERY_ALWAYS_WIPES wipe_data = wipe_cache = 1; #endif break; case 'h': ui_set_background(BACKGROUND_ICON_CID); ui_show_text(0); headless = 1; break; case 'c': wipe_cache = 1; break; case 't': ui_show_text(1); break; case 'l': sideload = 1; break; case 'v': update_ubuntu_package = UBUNTU_UPDATE_SCRIPT; break; case '?': LOGE("Invalid command argument\n"); continue; } } struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "/file_contexts" } }; sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { fprintf(stderr, "Warning: No file_contexts\n"); ui_print("Warning: No file_contexts\n"); } LOGI("device_recovery_start()\n"); device_recovery_start(); printf("Command:"); for (arg = 0; arg < argc; arg++) { printf(" \"%s\"", argv[arg]); } printf("\n"); if (update_package) { // For backwards compatibility on the cache partition only, if // we're given an old 'root' path "CACHE:foo", change it to // "/cache/foo". if (strncmp(update_package, "CACHE:", 6) == 0) { int len = strlen(update_package) + 10; char* modified_path = malloc(len); strlcpy(modified_path, "/cache/", len); strlcat(modified_path, update_package+6, len); printf("(replacing path \"%s\" with \"%s\")\n", update_package, modified_path); update_package = modified_path; } } printf("\n"); property_list(print_property, NULL); printf("\n"); int status = INSTALL_SUCCESS; if (update_package != NULL) { status = install_package(update_package); if (status != INSTALL_SUCCESS) { copy_logs(); ui_print("Installation aborted.\n"); } } else if (update_ubuntu_package != NULL) { LOGI("Performing Ubuntu update"); ui_set_background(BACKGROUND_ICON_INSTALLING); ui_show_indeterminate_progress(); ui_print("Installing Ubuntu update.\n"); char tmp[PATH_MAX]; sprintf(tmp, "%s %s", UBUNTU_UPDATE_SCRIPT, UBUNTU_COMMAND_FILE ); __system(tmp); LOGI("Ubuntu update complete"); ui_print("Ubuntu update complete.\n"); } else if (wipe_data) { if (device_wipe_data()) status = INSTALL_ERROR; ignore_data_media_workaround(1); if (erase_volume("/data")) status = INSTALL_ERROR; ignore_data_media_workaround(0); if (has_datadata() && erase_volume("/datadata")) status = INSTALL_ERROR; if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) { copy_logs(); ui_print("Data wipe failed.\n"); } } else if (wipe_cache) { if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) { copy_logs(); 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; if (!headless) { ui_set_show_text(1); ui_set_background(BACKGROUND_ICON_UBUNTU); } 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 (sideload) { signature_check_enabled = 0; if (!headless) ui_set_show_text(1); if (0 == apply_from_adb()) { status = INSTALL_SUCCESS; ui_set_show_text(0); } } if (headless) { headless_wait(); } if (user_data_update_package != NULL) { status = install_package(user_data_update_package); if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); } if (status != INSTALL_SUCCESS && !is_user_initiated_recovery) { ui_set_show_text(1); ui_set_background(BACKGROUND_ICON_ERROR); } else if (status != INSTALL_SUCCESS || ui_text_visible()) { prompt_and_wait(); } // We reach here when in main menu we choose reboot main system or for some wipe commands on start // If there is a radio image pending, reboot now to install it. maybe_install_firmware_update(send_intent); // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui_print("Rebooting...\n"); reboot_main_system(ANDROID_RB_RESTART, 0, 0); return EXIT_SUCCESS; }
int get_menu_selection(const char** headers, char** items, int menu_only, int initial_selection) { // throw away keys pressed previously, so user doesn't // accidentally trigger menu items. ui_clear_key_queue(); int item_count = ui_start_menu(headers, items, initial_selection); int selected = initial_selection; int chosen_item = -1; // NO_ACTION int wrap_count = 0; while (chosen_item < 0 && chosen_item != GO_BACK) { int key = ui_wait_key(); int visible = ui_text_visible(); if (key == -1) { // ui_wait_key() timed out if (ui_text_ever_visible()) { continue; } else { LOGI("timed out waiting for key input; rebooting.\n"); ui_end_menu(); return ITEM_REBOOT; } } else if (key == -2) { // we are returning from ui_cancel_wait_key(): trigger a GO_BACK return GO_BACK; } else if (key == -3) { // an USB device was plugged in (returning from ui_wait_key()) return REFRESH; } int action = ui_handle_key(key, visible); int old_selected = selected; selected = ui_get_selected_item(); if (action < 0) { switch (action) { case HIGHLIGHT_UP: --selected; selected = ui_menu_select(selected); break; case HIGHLIGHT_DOWN: ++selected; selected = ui_menu_select(selected); break; case SELECT_ITEM: chosen_item = selected; if (ui_is_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 == 5) { wrap_count = 0; if (ui_get_rainbow_mode()) { ui_set_rainbow_mode(0); ui_print("Rainbow mode disabled\n"); } else { ui_set_rainbow_mode(1); ui_print("Rainbow mode enabled!\n"); } } } } ui_end_menu(); ui_clear_key_queue(); return chosen_item; }
static int erase_volume(const char *volume) { bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); ui_set_background(BACKGROUND_ICON_INSTALLING); ui_show_indeterminate_progress(); saved_log_file* head = NULL; if (is_cache) { // If we're reformatting /cache, we load any // "/cache/recovery/last*" files into memory, so we can restore // them after the reformat. ensure_path_mounted(volume); DIR* d; struct dirent* de; d = opendir(CACHE_LOG_DIR); if (d) { char path[PATH_MAX]; strcpy(path, CACHE_LOG_DIR); strcat(path, "/"); int path_len = strlen(path); while ((de = readdir(d)) != NULL) { if (strncmp(de->d_name, "last", 4) == 0) { saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file)); strcpy(path+path_len, de->d_name); p->name = strdup(path); if (stat(path, &(p->st)) == 0) { // truncate files to 512kb if (p->st.st_size > (1 << 19)) { p->st.st_size = 1 << 19; } p->data = (unsigned char*) malloc(p->st.st_size); FILE* f = fopen(path, "rb"); fread(p->data, 1, p->st.st_size, f); fclose(f); p->next = head; head = p; } else { free(p); } } } closedir(d); } else { if (errno != ENOENT) { printf("opendir failed: %s\n", strerror(errno)); } } } ui_print("Formatting %s...\n", volume); ensure_path_unmounted(volume); int result = format_volume(volume); if (is_cache) { while (head) { FILE* f = fopen_path(head->name, "wb"); if (f) { fwrite(head->data, 1, head->st.st_size, f); fclose(f); chmod(head->name, head->st.st_mode); chown(head->name, head->st.st_uid, head->st.st_gid); } free(head->name); free(head->data); saved_log_file* temp = head->next; free(head); head = temp; } // Any part of the log we'd copied to cache is now gone. // Reset the pointer so we copy from the beginning of the temp // log. tmplog_offset = 0; copy_logs(); } return result; }
void wipe_data(int confirm) { if (confirm) { static char** title_headers = NULL; if (title_headers == NULL) { char* headers[] = { "Confirm wipe of all user data?", " Confirm?", "", NULL }; title_headers = prepend_title((const char**)headers); } char* items[] = { " No", " No", " No", " No", " No", " No", " No", " Yes -- delete all user data", // [7] " No", " No", " No", NULL }; int chosen_item = get_menu_selection(title_headers, items, 1, 0); if (chosen_item != 7) { return; } } ui_print("\n-- Wiping data...\n"); device_wipe_data(); erase_volume("/data"); erase_volume("/cache"); if (has_datadata()) { erase_volume("/datadata"); } erase_volume("/sd-ext"); ensure_path_mounted("/sdcard"); #ifdef BOARD_HAS_REMOVABLE_STORAGE ensure_path_mounted("/external_sd"); if( access( "/sdcard/clockworkmod/.is_as_external", F_OK ) != -1) { erase_volume("/external_sd/.android_secure"); } else { #endif erase_volume("/sdcard/.android_secure"); #ifdef BOARD_HAS_REMOVABLE_STORAGE } #endif ui_print("Data wipe complete.\n"); ensure_path_mounted("/data"); ensure_path_mounted("/sdcard"); ensure_path_mounted("/external_sd"); struct stat st; if (0 == lstat("/sdcard/0", &st)) { char* layout_version = "2"; FILE* f = fopen("/data/.layout_version", "wb"); if (NULL != f) { fwrite(layout_version, 1, 2, f); fclose(f); } else { LOGI("error opening /data/.layout_version for write.\n"); } } else if (0 == lstat("/external_sd/0", &st)) { char* layout_version = "2"; FILE* f = fopen("/data/.layout_version", "wb"); if (NULL != f) { fwrite(layout_version, 1, 2, f); fclose(f); } else { LOGI("error opening /data/.layout_version for write.\n"); } } else { LOGI("/sdcard/0,/external_sd/0 not found. migration may occur in Android 4.2.\n"); } ensure_path_unmounted("/data"); }
int main() { char buf[64], *v[SZ]; struct alias *a; int n, i, r, skip_actions; FILE *f; pthread_t rv, ks; ui_init(); ui_animation(0); f = fopen("commands.desc", "r"); if(f == NULL) { ui_print("failed to open commands.desc\n"); goto end; } // parse command list while(fgets(buf, 64, f)) { for(i = 0, v[i] = strtok(buf, " \n"); v[i]; v[++i] = strtok(0, " \n")); parse_line(i, v); } fclose(f); // init bin for(i = 0;; ) { a = get_alias("bin", i++); if(!a) break; ui_bin_add_tag(a->str); } ui_bin_add_tag("timeout"); // init options tip ui_tip_update(1, "Press the corresponding key to perform that function:"); ui_tip_update(3, "<S> Handler Speed"); ui_tip_update(4, "<R> Reset"); ui_tip_update(5, "<Q> Quit"); // init io r = io_init(); ptsname_r(r, buf, 64); ui_print("pts name is: %s (%d)\n", buf, r); // init wait queue wait_queue_init(); // init receiver pthread_create(&rv, NULL, receiver, NULL); // init keyserver pthread_create(&ks, NULL, keyserver, NULL); again: ui_print("\n\nnew routine:\n"); skip_actions = 0; for(wait_queue_init(), i = 0; i < lscount; i++) { if(skip_actions && (!strcmp(lines[i].argv[0], "send") || !strcmp(lines[i].argv[0], "wait"))) continue; if(exec_line(lines[i].argc, lines[i].argv) < 0) skip_actions = 1; } wait_queue_deinit(); if(!stop) goto again; end: ui_deinit(); io_deinit(); }
int nandroid_backup(const char* backup_path) { nandroid_backup_bitfield = 0; ui_set_background(BACKGROUND_ICON_INSTALLING); refresh_default_backup_handler(); if (ensure_path_mounted(backup_path) != 0) { return print_and_error("Can't mount backup path.\n"); } Volume* volume = volume_for_path(backup_path); if (NULL == volume) return print_and_error("Unable to find volume for backup path.\n"); if (is_data_media_volume_path(volume->mount_point)) volume = volume_for_path("/data"); int ret; struct statfs s; if (NULL != volume) { if (0 != (ret = statfs(volume->mount_point, &s))) return print_and_error("Unable to stat backup path.\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]; ensure_directory(backup_path); if (0 != (ret = nandroid_backup_partition(backup_path, "/boot"))) return ret; if (0 != (ret = nandroid_backup_partition(backup_path, "/uboot"))) return ret; if (0 != (ret = nandroid_backup_partition(backup_path, "/recovery"))) return ret; Volume *vol = volume_for_path("/wimax"); if (vol != NULL && 0 == stat(vol->device, &s)) { char serialno[PROPERTY_VALUE_MAX]; ui_print("Backing up WiMAX...\n"); serialno[0] = 0; property_get("ro.serialno", serialno, ""); sprintf(tmp, "%s/wimax.%s.img", backup_path, serialno); ret = backup_raw_partition(vol->fs_type, vol->device, tmp); if (0 != ret) return print_and_error("Error while dumping WiMAX image!\n"); } if (0 != (ret = nandroid_backup_partition(backup_path, "/system"))) return ret; if (0 != (ret = nandroid_backup_partition(backup_path, "/data"))) return ret; if (has_datadata()) { if (0 != (ret = nandroid_backup_partition(backup_path, "/datadata"))) return ret; } if (is_data_media() || 0 != stat("/sdcard/.android_secure", &s)) { ui_print("No /sdcard/.android_secure found. Skipping backup of applications on external storage.\n"); } 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; vol = volume_for_path("/sd-ext"); if (vol == NULL || 0 != stat(vol->device, &s)) { 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, "/sd-ext"))) 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; } sprintf(tmp, "cp /tmp/recovery.log %s/recovery.log", backup_path); __system(tmp); sprintf(tmp, "chmod -R 777 %s ; chmod -R u+r,u+w,g+r,g+w,o+r,o+w /sdcard/clockworkmod ; chmod u+x,g+x,o+x /sdcard/clockworkmod/backup ; chmod u+x,g+x,o+x /sdcard/clockworkmod/blobs", backup_path); __system(tmp); sync(); ui_set_background(BACKGROUND_ICON_NONE); ui_reset_progress(); ui_print("\nBackup complete!\n"); return 0; }
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); if (strstr(argv[0], "getprop")) return getprop_main(argc, argv); return busybox_driver(argc, argv); } int is_user_initiated_recovery = 0; time_t start = time(NULL); // If these fail, there's not really anywhere to complain... freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL); freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL); fprintf(stderr, "Starting recovery on %s", ctime(&start)); ui_init(); ui_print(EXPAND(RECOVERY_VERSION)"\n"); //get_args(&argc, &argv); int previous_runs = 0; const char *send_intent = NULL; const char *update_package = NULL; int wipe_data = 0, wipe_cache = 0; int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { switch (arg) { case 'p': previous_runs = atoi(optarg); break; case 's': send_intent = optarg; break; case 'u': update_package = optarg; break; case 'w': wipe_data = wipe_cache = 1; break; case 'c': wipe_cache = 1; break; case '?': LOGE("Invalid command argument\n"); continue; } } //device_recovery_start(); fprintf(stderr, "Command:"); for (arg = 0; arg < argc; arg++) { fprintf(stderr, " \"%s\"", argv[arg]); } fprintf(stderr, "\n\n"); property_list(print_property, NULL); fprintf(stderr, "\n"); int status = INSTALL_SUCCESS; //Register amend commands RecoveryCommandContext ctx = { NULL }; if (register_update_commands(&ctx)) { LOGE("Can't install update commands\n"); } if (update_package != NULL) { status = install_package(update_package); if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); } else if (wipe_data) { if (device_wipe_data()) status = INSTALL_ERROR; if (erase_root("DATA:")) status = INSTALL_ERROR; if (wipe_cache && erase_root("CACHE:")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n"); } else if (wipe_cache) { if (wipe_cache && erase_root("CACHE:")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n"); } else { status = INSTALL_ERROR; // No command specified } if (status != INSTALL_SUCCESS || ui_text_visible()) prompt_and_wait(); // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui_print("Rebooting...\n"); sync(); reboot(RB_AUTOBOOT); return EXIT_SUCCESS; }
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); nandroid_restore_handler restore_handler = NULL; const char *filesystems[] = { "yaffs2", "ext2", "ext3", "ext4", "vfat", "rfs", NULL }; const char* backup_filesystem = NULL; Volume *vol = volume_for_path(mount_point); const char *device = NULL; if (vol != NULL) device = vol->device; char tmp[PATH_MAX]; sprintf(tmp, "%s/%s.img", backup_path, name); struct stat file_info; if (strcmp(backup_path, "-") == 0) { if (vol) backup_filesystem = vol->fs_type; restore_handler = tar_extract_wrapper; strcpy(tmp, "/proc/self/fd/0"); } else if (0 != (ret = statfs(tmp, &file_info))) { // can't find the backup, it may be the new backup format? // iterate through the backup types printf("couldn't find default\n"); char *filesystem; int i = 0; while ((filesystem = filesystems[i]) != NULL) { sprintf(tmp, "%s/%s.%s.img", backup_path, name, filesystem); if (0 == (ret = statfs(tmp, &file_info))) { backup_filesystem = filesystem; restore_handler = unyaffs_wrapper; break; } sprintf(tmp, "%s/%s.%s.tar", backup_path, name, filesystem); if (0 == (ret = statfs(tmp, &file_info))) { backup_filesystem = filesystem; restore_handler = tar_extract_wrapper; break; } sprintf(tmp, "%s/%s.%s.dup", backup_path, name, filesystem); if (0 == (ret = statfs(tmp, &file_info))) { backup_filesystem = filesystem; restore_handler = dedupe_extract_wrapper; break; } i++; } if (backup_filesystem == NULL || restore_handler == NULL) { ui_print("%s.img not found. Skipping restore of %s.\n", name, mount_point); return 0; } else { printf("Found new backup image: %s\n", tmp); } } // If the fs_type of this volume is "auto" or mount_point is /data // and is_data_media, let's revert // to using a rm -rf, rather than trying to do a // ext3/ext4/whatever format. // This is because some phones (like DroidX) will freak out if you // reformat the /system or /data partitions, and not boot due to // a locked bootloader. // Other devices, like the Galaxy Nexus, XOOM, and Galaxy Tab 10.1 // have a /sdcard symlinked to /data/media. // Or of volume does not exist (.android_secure), just rm -rf. if (vol == NULL || 0 == strcmp(vol->fs_type, "auto")) backup_filesystem = NULL; if (0 == strcmp(vol->mount_point, "/data") && is_data_media()) backup_filesystem = NULL; ensure_directory(mount_point); int callback = stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info) != 0; ui_print("Restoring %s...\n", name); if (backup_filesystem == NULL) { if (0 != (ret = format_volume(mount_point))) { ui_print("Error while formatting %s!\n", mount_point); return ret; } } else if (0 != (ret = format_device(device, mount_point, backup_filesystem))) { 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 (restore_handler == NULL) restore_handler = get_restore_handler(mount_point); // override restore handler for undump if (strcmp(backup_path, "-") == 0) { restore_handler = tar_undump_wrapper; } if (restore_handler == NULL) { ui_print("Error finding an appropriate restore handler.\n"); return -2; } if (0 != (ret = restore_handler(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; }
static void prompt_and_wait() { char** headers = prepend_title((const char**)MENU_HEADERS); for (;;) { finish_recovery(NULL); ui_reset_progress(); ui_root_menu = 1; // ui_menu_level is a legacy variable that i am keeping around to prevent build breakage. ui_menu_level = 0; // allow_display_toggle = 1; int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0, 0); ui_menu_level = 1; ui_root_menu = 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 // statement below. chosen_item = device_perform_action(chosen_item); int status; switch (chosen_item) { case ITEM_REBOOT: poweroff=0; return; case ITEM_WIPE_DATA: wipe_data(ui_text_visible()); if (!ui_text_visible()) return; break; case ITEM_WIPE_CACHE: if (confirm_selection("Confirm wipe?", "Yes - Wipe Cache")) { ui_print("\n-- Wiping cache...\n"); erase_volume("/cache"); ui_print("Cache wipe complete.\n"); if (!ui_text_visible()) return; } break; case ITEM_APPLY_SDCARD: show_install_update_menu(); break; case ITEM_NANDROID: show_nandroid_menu(); break; case ITEM_PARTITION: show_partition_menu(); break; case ITEM_ADVANCED: show_advanced_menu(); break; case ITEM_PHILZ_MENU: show_philz_settings(); break; case ITEM_POWEROFF: poweroff = 1; return; } } }
static int print_and_error(const char* message) { ui_print("%s", message); return 1; }
void ui_init(void) { ui_has_initialized = 1; gr_init(); ev_init(input_callback, NULL); #ifdef BOARD_TOUCH_RECOVERY touch_init(); #endif text_col = text_row = 0; text_rows = gr_fb_height() / CHAR_HEIGHT; max_menu_rows = text_rows - MIN_LOG_ROWS; #ifdef BOARD_TOUCH_RECOVERY max_menu_rows = get_max_menu_rows(max_menu_rows); #endif if (max_menu_rows > MENU_MAX_ROWS) max_menu_rows = MENU_MAX_ROWS; if (text_rows > MAX_ROWS) text_rows = MAX_ROWS; text_top = 1; text_cols = gr_fb_width() / CHAR_WIDTH; if (text_cols > MAX_COLS - 1) text_cols = MAX_COLS - 1; int i; for (i = 0; BITMAPS[i].name != NULL; ++i) { int result = res_create_surface(BITMAPS[i].name, BITMAPS[i].surface); if (result < 0) { LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result); } } gProgressBarIndeterminate = malloc(ui_parameters.indeterminate_frames * sizeof(gr_surface)); for (i = 0; i < ui_parameters.indeterminate_frames; ++i) { char filename[40]; // "indeterminate01.png", "indeterminate02.png", ... sprintf(filename, "indeterminate%02d", i+1); int result = res_create_surface(filename, gProgressBarIndeterminate+i); if (result < 0) { LOGE("Missing bitmap %s\n(Code %d)\n", filename, result); } } if (ui_parameters.installing_frames > 0) { gInstallationOverlay = malloc(ui_parameters.installing_frames * sizeof(gr_surface)); for (i = 0; i < ui_parameters.installing_frames; ++i) { char filename[40]; // "icon_installing_overlay01.png", // "icon_installing_overlay02.png", ... sprintf(filename, "icon_installing_overlay%02d", i+1); int result = res_create_surface(filename, gInstallationOverlay+i); if (result < 0) { LOGE("Missing bitmap %s\n(Code %d)\n", filename, result); } } // Adjust the offset to account for the positioning of the // base image on the screen. if (gBackgroundIcon[BACKGROUND_ICON_INSTALLING] != NULL) { gr_surface bg = gBackgroundIcon[BACKGROUND_ICON_INSTALLING]; ui_parameters.install_overlay_offset_x += (gr_fb_width() - gr_get_width(bg)) / 2; ui_parameters.install_overlay_offset_y += (gr_fb_height() - gr_get_height(bg)) / 2; } } else { gInstallationOverlay = NULL; } char enable_key_repeat[PROPERTY_VALUE_MAX]; property_get("ro.cwm.enable_key_repeat", enable_key_repeat, ""); if (!strcmp(enable_key_repeat, "true") || !strcmp(enable_key_repeat, "1")) { boardEnableKeyRepeat = 1; char key_list[PROPERTY_VALUE_MAX]; property_get("ro.cwm.repeatable_keys", key_list, ""); if (strlen(key_list) == 0) { boardRepeatableKeys[boardNumRepeatableKeys++] = KEY_UP; boardRepeatableKeys[boardNumRepeatableKeys++] = KEY_DOWN; boardRepeatableKeys[boardNumRepeatableKeys++] = KEY_VOLUMEUP; boardRepeatableKeys[boardNumRepeatableKeys++] = KEY_VOLUMEDOWN; } else { char *pch = strtok(key_list, ","); while (pch != NULL) { boardRepeatableKeys[boardNumRepeatableKeys++] = atoi(pch); pch = strtok(NULL, ","); } } } pthread_t t; pthread_create(&t, NULL, progress_thread, NULL); pthread_create(&t, NULL, input_thread, NULL); ui_print("编译作者 mandfx\n"); ui_print("支持微博 weibo.com/AnZhiDenG\n"); ui_print("编译时间 2013-11-16\n\n"); }
int nandroid_restore(const char* backup_path, int restore_boot, int restore_system, int restore_data, int restore_cache, int restore_sdext, int restore_wimax) { ui_set_background(BACKGROUND_ICON_INSTALLING); ui_show_indeterminate_progress(); nandroid_files_total = 0; if (ensure_path_mounted(backup_path) != 0) return print_and_error("Can't mount backup path\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; if (restore_boot) { if (NULL != volume_for_path("/boot") && 0 != (ret = nandroid_restore_partition(backup_path, "/boot"))) return ret; if (NULL != volume_for_path("/uboot") && 0 != (ret = nandroid_restore_partition(backup_path, "/uboot"))) return ret; if (NULL != volume_for_path("/recovery") && 0 != (ret = nandroid_restore_partition(backup_path, "/recovery"))) return ret; } struct stat s; Volume *vol = volume_for_path("/wimax"); if (restore_wimax && vol != NULL && 0 == stat(vol->device, &s)) { char serialno[PROPERTY_VALUE_MAX]; serialno[0] = 0; property_get("ro.serialno", serialno, ""); sprintf(tmp, "%s/wimax.%s.img", backup_path, serialno); struct stat st; if (0 != stat(tmp, &st)) { ui_print("WARNING: WiMAX partition exists, but nandroid\n"); ui_print(" backup does not contain WiMAX image.\n"); ui_print(" You should create a new backup to\n"); ui_print(" protect your WiMAX keys.\n"); } else { ui_print("Erasing WiMAX before restore...\n"); if (0 != (ret = format_volume("/wimax"))) return print_and_error("Error while formatting wimax!\n"); ui_print("Restoring WiMAX image...\n"); if (0 != (ret = restore_raw_partition(vol->fs_type, vol->device, tmp))) return ret; } } 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; if (has_datadata()) { if (restore_data && 0 != (ret = nandroid_restore_partition(backup_path, "/datadata"))) return ret; } 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 toggle_script_asserts() { script_assert_enabled = !script_assert_enabled; ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled"); }
void show_advanced_menu() { static char* headers[] = { "Advanced Menu", "", NULL }; static char* list[] = { "reboot recovery", "reboot to bootloader", "power off", "wipe dalvik cache", "report error", "key test", "show log", "partition sdcard", "partition external sdcard", "partition internal sdcard", NULL }; char bootloader_mode[PROPERTY_VALUE_MAX]; property_get("ro.bootloader.mode", bootloader_mode, ""); if (!strcmp(bootloader_mode, "download")) { list[1] = "reboot to download mode"; } if (!can_partition("/sdcard")) { list[7] = NULL; } if (!can_partition("/external_sd")) { list[8] = NULL; } if (!can_partition("/emmc")) { list[9] = NULL; } for (;;) { int chosen_item = get_filtered_menu_selection(headers, list, 0, 0, sizeof(list) / sizeof(char*)); if (chosen_item == GO_BACK) break; switch (chosen_item) { case 0: { ui_print("Rebooting recovery...\n"); reboot_main_system(ANDROID_RB_RESTART2, 0, "recovery"); break; } case 1: { if (!strcmp(bootloader_mode, "download")) { ui_print("Rebooting to download mode...\n"); reboot_main_system(ANDROID_RB_RESTART2, 0, "download"); } else { ui_print("Rebooting to bootloader...\n"); reboot_main_system(ANDROID_RB_RESTART2, 0, "bootloader"); } break; } case 2: { ui_print("Shutting down...\n"); reboot_main_system(ANDROID_RB_POWEROFF, 0, 0); break; } case 3: 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"); ui_print("Dalvik Cache wiped.\n"); } ensure_path_unmounted("/data"); break; case 4: handle_failure(1); break; case 5: { 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 6: ui_printlogtail(12); break; case 7: partition_sdcard("/sdcard"); break; case 8: partition_sdcard("/external_sd"); break; case 9: partition_sdcard("/emmc"); break; } } }
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", "Show log", "Partition SD Card", "Fix Permissions", #ifdef BOARD_HAS_SDCARD_INTERNAL "Partition Internal SD Card", #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_wrapper("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"); ui_print("Dalvik Cache wiped.\n"); } ensure_path_unmounted("/data"); 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"); struct keyStruct{ int code; int x; int y; }*key; int action; do { key = ui_wait_key(); if(key->code == ABS_MT_POSITION_X) { action = device_handle_mouse(key, 1); ui_print("Touch: X: %d\tY: %d\n", key->x, key->y); } else { action = device_handle_key(key->code, 1); ui_print("Key: %x\n", key->code); } } while (action != GO_BACK); break; } case 5: { ui_printlogtail(12); break; } case 6: { static char* ext_fs[] = { "ext2", "ext3", "ext4", NULL }; static char* ext_sizes[] = { "0M", "128M", "256M", "512M", "1024M", "2048M", "4096M", NULL }; static char* swap_sizes[] = { "0M", "32M", "64M", "128M", "256M", NULL }; static char* ext_fs_headers[] = { "Ext File System", "", NULL }; static char* ext_headers[] = { "Ext Size", "", NULL }; static char* swap_headers[] = { "Swap Size", "", NULL }; int ext_fs_selected = get_menu_selection(ext_fs_headers, ext_fs, 0, 0); if (ext_fs_selected == GO_BACK) return; 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 %s -s", ext_sizes[ext_size], swap_sizes[swap_size], ext_fs[ext_fs_selected]); 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 7: { ensure_path_mounted("/system"); ensure_path_mounted("/data"); ui_print("Fixing permissions...\n"); __system("fix_permissions"); ui_print("Done!\n"); break; } case 8: { static char* ext_fs[] = { "ext2", "ext3", "ext4", NULL }; static char* ext_sizes[] = { "0M", "128M", "256M", "512M", "1024M", "2048M", "4096M", NULL }; static char* swap_sizes[] = { "0M", "32M", "64M", "128M", "256M", NULL }; static char* ext_fs_headers[] = { "Ext File System", "", NULL }; static char* ext_headers[] = { "Data Size", "", NULL }; static char* swap_headers[] = { "Swap Size", "", NULL }; int ext_fs_selected = get_menu_selection(ext_fs_headers, ext_fs, 0, 0); if (ext_fs_selected == GO_BACK) return; 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 %s -s", ext_sizes[ext_size], swap_sizes[swap_size], ext_fs[ext_fs_selected]); 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; } } } }
int format_unknown_device(const char *device, const char* path, const char *fs_type) { LOGI("Formatting unknown device.\n"); if (fs_type != NULL && get_flash_type(fs_type) != UNSUPPORTED) return erase_raw_partition(fs_type, device); // if this is SDEXT:, don't worry about it if it does not exist. 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 (NULL != fs_type) { if (strcmp("ext3", fs_type) == 0) { LOGI("Formatting ext3 device.\n"); if (0 != ensure_path_unmounted(path)) { LOGE("Error while unmounting %s.\n", path); return -12; } return format_ext3_device(device); } if (strcmp("ext2", fs_type) == 0) { LOGI("Formatting ext2 device.\n"); if (0 != ensure_path_unmounted(path)) { LOGE("Error while unmounting %s.\n", path); return -12; } return format_ext2_device(device); } } 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]; if (strcmp(path, "/data") == 0) { sprintf(tmp, "cd /data ; for f in $(ls -a | grep -v ^media$); do rm -rf $f; done"); __system(tmp); // if the /data/media sdcard has already been migrated for android 4.2, // prevent the migration from happening again by writing the .layout_version struct stat st; if (0 == lstat("/data/media/0", &st)) { char* layout_version = "2"; FILE* f = fopen("/data/.layout_version", "wb"); if (NULL != f) { fwrite(layout_version, 1, 2, f); fclose(f); } else { LOGI("error opening /data/.layout_version for write.\n"); } } else { LOGI("/data/media/0 not found. migration may occur.\n"); } } else { sprintf(tmp, "rm -rf %s/*", path); __system(tmp); sprintf(tmp, "rm -rf %s/.*", path); __system(tmp); } ensure_path_unmounted(path); return 0; }
void show_advanced_menu() { static char* headers[] = { "Advanced Menu", "", NULL }; static char* list[] = { "reboot recovery", "reboot download", "wipe dalvik cache", "wipe battery stats", "report error", "key test", "show log", "fix permissions", "sk8's fix permissions", NULL }; for (;;) { int chosen_item = get_filtered_menu_selection(headers, list, 0, 0, sizeof(list) / sizeof(char*)); if (chosen_item == GO_BACK) break; switch (chosen_item) { case 0: android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); break; case 1: android_reboot(ANDROID_RB_RESTART2, 0, "download"); break; case 2: 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"); ui_print("Dalvik Cache wiped.\n"); } ensure_path_unmounted("/data"); break; case 3: if (confirm_selection( "Confirm wipe?", "Yes - Wipe Battery Stats")) wipe_battery_stats(); break; case 4: handle_failure(1); break; case 5: { 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 6: ui_printlogtail(12); break; case 7: ensure_path_mounted("/system"); ensure_path_mounted("/data"); ensure_path_mounted("/emmc"); ui_print("Fixing permissions...\n"); __system("fix_permissions"); ui_print("Done!\n"); break; case 8: ensure_path_mounted("/system"); ensure_path_mounted("/data"); ui_print("Fixing permissions & removing stale directories (logging disabled)...\n"); __system("fix_permissions -l -r"); ui_print("Done!\n"); break; } } }
int exec_line(int argc, char *argv[]) { struct alias *al; int i; if(!argc) return 0; ui_print("do action: "); for(i = 0; i < argc; i++) ui_print("%s ", argv[i]); ui_print("\n"); if(strcmp(argv[0], "load") == 0) { ui_animation(1); } else if(strcmp(argv[0], "unload") == 0) { ui_animation(3); } else if(strcmp(argv[0], "poweron") == 0) { power_state = 1; } else if(strcmp(argv[0], "poweroff") == 0) { power_state = 1; } else if(strcmp(argv[0], "putbin") == 0) { for(i = 0;;) { al = get_alias("bin", i++); if(al) ui_bin_update(i, al->arg); else break; } al = get_alias("timeout", 0); if(al) ui_bin_update(i, al->arg); } else if(strncmp(argv[0], "send", 4) == 0) { if(strcmp(argv[0], "send_txt") == 0) { io_send("\002"); ui_print("--> <STX>\n"); } for(i = 1; i < argc; i++) { const char *s = argv[i]; if(strcmp(s, "power_state") == 0) s = power_state? "1": "NULL"; al = get_alias(s, 0); ui_print("--> %s\n", al? al->str: s); io_send(al? al->str: s); } if(strcmp(argv[0], "send_txt") == 0) { io_send("\003"); ui_print("--> <ETX>\n"); } } else if(strcmp(argv[0], "wait") == 0) { for(i = 1; i < argc; i++) wait_queue_add_tail(argv[i]); for(;!wait_queue_empty(); ui_animation(2)); } else if(strcmp(argv[0], "wait_timeout") == 0) { struct timeval a, b, d; int t; al = get_alias("timeout", 0); t = al? al->num: TIMEOUT; for(i = 1; i < argc; i++) wait_queue_add_tail(argv[i]); gettimeofday(&a, NULL); for(;!wait_queue_empty(); ui_animation(2)) { gettimeofday(&b, NULL); timersub(&b, &a, &d); if(d.tv_sec > t) { ui_print("timeout for waiting %s\n", wait_queue_head()); al->arg++; return -1; } } } else if(strcmp(argv[0], "handshake") == 0) { char word[SZ]; ui_print("--> %s\n", argv[1]); io_send(argv[1]); while(io_get_word(word) <= 0); ui_print("<-- %s\n", word); if(strcmp(word, argv[2]) != 0) return -1; } return 0; }
int format_unknown_device(const char *device, const char* path, const char *fs_type) { LOGI("Formatting unknown device.\n"); if (fs_type != NULL && get_flash_type(fs_type) != UNSUPPORTED) return erase_raw_partition(fs_type, device); // if this is SDEXT:, don't worry about it if it does not exist. 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 (NULL != fs_type) { if (strcmp("ext3", fs_type) == 0) { LOGI("Formatting ext3 device.\n"); if (0 != ensure_path_unmounted(path)) { LOGE("Error while unmounting %s.\n", path); return -12; } return format_ext3_device(device); } if (strcmp("ext2", fs_type) == 0) { LOGI("Formatting ext2 device.\n"); if (0 != ensure_path_unmounted(path)) { LOGE("Error while unmounting %s.\n", path); return -12; } return format_ext2_device(device); } } 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]; if (strcmp(path, "/data") == 0) { sprintf(tmp, "cd /data ; for f in $(ls -a | grep -v ^media$); do rm -rf $f; done"); __system(tmp); } else { sprintf(tmp, "rm -rf %s/*", path); __system(tmp); sprintf(tmp, "rm -rf %s/.*", path); __system(tmp); } ensure_path_unmounted(path); return 0; }
// custom raw restore handler // used to restore efs in raw mode or modem.bin files // for now, only called directly from outside functions (not from nandroid_restore()) // user selects an image file to restore, so backup_file_image path is already mounted int dd_raw_restore_handler(const char* backup_file_image, const char* root) { ui_print("\n>> Restoring %s...\n", root); Volume *vol = volume_for_path(root); if (vol == NULL || vol->fs_type == NULL) { ui_print("volume not found! Skipping raw restore of %s...\n", root); return 0; } ui_set_background(BACKGROUND_ICON_INSTALLING); ui_show_indeterminate_progress(); // make sure we have a valid image file name int i = 0; char errmsg[PATH_MAX]; char tmp[PATH_MAX]; char filename[PATH_MAX]; const char *raw_image_format[] = { ".img", ".bin", NULL }; sprintf(filename, "%s", BaseName(backup_file_image)); while (raw_image_format[i] != NULL) { if (strlen(filename) > strlen(raw_image_format[i]) && strcmp(filename + strlen(filename) - strlen(raw_image_format[i]), raw_image_format[i]) == 0 && strncmp(filename, vol->mount_point + 1, strlen(vol->mount_point)-1) == 0) { break; } i++; } if (raw_image_format[i] == NULL) { sprintf(errmsg, "invalid image file! Failed to restore %s to %s\n", filename, root); return print_and_error(errmsg, NANDROID_ERROR_GENERAL); } //make sure file exists if (!file_found(backup_file_image)) { sprintf(errmsg, "%s not found. Skipping restore of %s\n", backup_file_image, root); return print_and_error(errmsg, NANDROID_ERROR_GENERAL); } //restore raw image int ret = 0; char* device_mmcblk; ui_print("Restoring %s to %s\n", filename, vol->mount_point); if (strstr(vol->blk_device, "/dev/block/mmcblk") != NULL || strstr(vol->blk_device, "/dev/block/mtdblock") != NULL) { sprintf(tmp, "raw-backup.sh -r '%s' %s %s", backup_file_image, vol->blk_device, vol->mount_point); } else if (vol->blk_device2 != NULL && (strstr(vol->blk_device2, "/dev/block/mmcblk") != NULL || strstr(vol->blk_device2, "/dev/block/mtdblock") != NULL)) { sprintf(tmp, "raw-backup.sh -r '%s' %s %s", backup_file_image, vol->blk_device2, vol->mount_point); } else if ((device_mmcblk = readlink_device_blk(root)) != NULL) { sprintf(tmp, "raw-backup.sh -r '%s' %s %s", backup_file_image, device_mmcblk, vol->mount_point); free(device_mmcblk); } else { sprintf(errmsg, "raw restore: no device found (%s)\n", root); return print_and_error(errmsg, NANDROID_ERROR_GENERAL); } ret = __system(tmp); if (0 != ret) { sprintf(errmsg, "failed raw restore of %s to %s\n", filename, root); print_and_error(errmsg, ret); } else { finish_nandroid_job(); } sprintf(tmp, "%s/log.txt", DirName(backup_file_image)); ui_print_custom_logtail(tmp, 3); return ret; }