static void wipe_data(int confirm) { if (confirm) { char* headers[] = { "Confirm wipe of all user data?", " THIS CAN NOT BE UNDONE.", "", NULL }; char* items[] = { " No", " No", " No", " No", " No", " No", " No", " Yes -- delete all user data", // [7] " No", " No", " No", NULL }; int chosen_item = show_interactive_menu(headers, items); hide_menu_selection(); if (chosen_item != 8) return; } ui_led_blink(1); ui_print("\n-- Wiping data...\n"); device_wipe_data(); erase_root("DATA:"); erase_root("CACHE:"); ensure_common_roots_mounted(); ui_print("Data wipe complete.\n"); ui_led_toggle(0); }
void run_shell_script(const char *command, int stdoutToUI, char** extra_env_variables) { char *argp[] = {PHONE_SHELL, "-c", NULL, NULL}; //check it if (!command) return; //add the command argp[2] = (char *)command; fprintf(stderr, "Running Shell Script: \"%s\"\n", command); //interactive menu shared memory node int imenu_fd = 0; //pipes int script_pipefd[2]; if (stdoutToUI) { pipe(script_pipefd); if((imenu_fd = open(INTERACTIVE_MENU_SHM, (O_CREAT | O_RDWR), 666)) < 0 ) { LOGE("Failed opening the shared memory node for interactive menu.\n"); LOGE("Interactive menu disabled.\n"); } else { ftruncate(imenu_fd, sizeof(interactive_menu_struct)); if ((interactive_menu = ((interactive_menu_struct*) mmap(0, sizeof(interactive_menu_struct), (PROT_READ | PROT_WRITE), MAP_SHARED, imenu_fd, 0))) == MAP_FAILED) { LOGE("Failed opening the shared memory node for interactive menu.\n"); LOGE("Interactive menu disabled.\n"); interactive_menu = NULL; } else { interactive_menu->in_trigger = 0; interactive_menu->out_trigger = 0; interactive_menu->header[0] = '\0'; interactive_menu->items[0][0] = '\0'; } } } pid_t child = fork(); if (child == 0) { if (stdoutToUI) { //put stdout to the pipe only close(script_pipefd[0]); dup2(script_pipefd[1], 1); } if (extra_env_variables != NULL) { while (*extra_env_variables) { fprintf(stderr, "run_shell_script: child env variable %s\n", *extra_env_variables); putenv(*extra_env_variables); extra_env_variables++; } } execv(PHONE_SHELL, argp); fprintf(stderr, "run_shell_script: execv failed: %s\n", strerror(errno)); _exit(1); } //status for the waitpid int sts; if (stdoutToUI) { char buffer[1024+1]; //nonblocking mode int f = fcntl(script_pipefd[0], F_GETFL, 0); // Set bit for non-blocking flag f |= O_NONBLOCK; // Change flags on fd fcntl(script_pipefd[0], F_SETFL, f); while (1) { //maybe use signalling if (interactive_menu != NULL && interactive_menu->in_trigger) { interactive_menu->in_trigger = 0; fprintf(stderr, "run_shell_script: interactive_menu triggered\n"); //first print the rest, but don't bother if there is an error int rv = read(script_pipefd[0], buffer, 1024); if (rv > 0) { buffer[rv] = 0; ui_print_raw(buffer); } //parse the name and headers char* headers[3]; char* items[20]; headers[0] = interactive_menu->header; headers[1] = " "; headers[2] = NULL; int i; for (i = 0; interactive_menu->items[i][0] && i < 20; i++) items[i] = interactive_menu->items[i]; items[i] = NULL; //show the menu ui_led_toggle(0); fprintf(stderr, "run_shell_script: showing interactive menu\n"); int chosen_item = show_interactive_menu(headers, items); ui_led_blink(1); interactive_menu->header[0] = '\0'; interactive_menu->items[0][0] = '\0'; interactive_menu->out_trigger = chosen_item; } int rv = read(script_pipefd[0], buffer, 1024); if (rv <= 0) { if(errno == EAGAIN) { if (waitpid(child, &sts, WNOHANG)) { //do one last check (race) int rv = read(script_pipefd[0], buffer, 1024); if (rv > 0) { buffer[rv] = 0; ui_print_raw(buffer); } break; } continue; } fprintf(stderr, "run_shell_script: there was a read error %d.\n", errno); waitpid(child, &sts, 0); break; } //if the string is read only partially, it won't be null terminated buffer[rv] = 0; ui_print_raw(buffer); } } else waitpid(child, &sts, 0); //check exit status if (WIFEXITED(sts)) { if (WEXITSTATUS(sts) != 0) { fprintf(stderr, "run_shell_script: child exited with status %d.\n", WEXITSTATUS(sts)); } } else if (WIFSIGNALED(sts)) { fprintf(stderr, "run_shell_script: child terminated by signal %d.\n", WTERMSIG(sts)); } if (stdoutToUI) { //close the pipe here after killing the process close(script_pipefd[1]); close(script_pipefd[0]); if (imenu_fd > 0) { close(imenu_fd); remove(INTERACTIVE_MENU_SHM); } interactive_menu = NULL; } }
/** * @brief SD LED Toggle. */ void ui_led_sd_toggle( void ) { ui_led_toggle( &ui_led_sd ); }
static void prompt_and_wait() { char* menu_files[MAX_MENU_LEVEL] = { NULL }; char* menu_scripts[MAX_MENU_LEVEL] = { NULL }; int menu_sel[MAX_MENU_LEVEL] = { 0 }; unsigned int menu_level = 0; int menu_result; //always ensure if mountings are good ensure_common_roots_mounted(); //initialize the recovery -> either call the script for initalization, or switch to full version #if !OPEN_RCVR_VERSION_LITE run_shell_script("/bin/init_recovery.sh "OPEN_RECOVERY_PHONE_SWITCH, 1, NULL); #endif menu_files[0] = malloc(strlen(MAIN_MENU_FILE)+1); strcpy(menu_files[0], MAIN_MENU_FILE); ui_led_blink(1); create_menu(menu_files[0], menu_scripts[0]); ui_led_toggle(0); int title_length; char** headers; headers = prepend_title(MENU_HEADERS, &title_length); int override_initial_selection = -1; int call_finish_in_loop = 1; for (;;) { if (call_finish_in_loop) { finish_recovery(NULL); call_finish_in_loop = 0; } int menu_item; if (override_initial_selection != -1) { menu_item = get_menu_selection(headers, MENU_ITEMS, MENU_ITEMS_SELECTABLE, title_length, override_initial_selection, 0); override_initial_selection = -1; } else menu_item = get_menu_selection(headers, MENU_ITEMS, MENU_ITEMS_SELECTABLE, title_length, 0, 0); // Parse open recovery commands int chosen_item = select_action(menu_item); chosen_item = device_perform_action(chosen_item); //if tag, menu, or scripted menu -> don't hide menu //do it here explicitly, it would be a mess in the switch if (chosen_item != ITEM_TAG && chosen_item != ITEM_NEW_MENU && chosen_item != ITEM_NEW_MENU_SCRIPTED) hide_menu_selection(); fprintf(stderr, "Menu: %d, %d, %s\n", menu_item, chosen_item, MENU_ITEMS_TARGET[menu_item]); switch (chosen_item) { case ITEM_REBOOT: return; case ITEM_WIPE_DATA: wipe_data(ui_text_visible()); if (!ui_text_visible()) return; ui_set_background(BACKGROUND_ICON_ERROR); break; case ITEM_WIPE_CACHE: ui_print("\n-- Wiping cache...\n"); ui_led_blink(1); erase_root("CACHE:"); ensure_common_roots_mounted(); ui_led_toggle(0); ui_print("Cache wipe complete.\n"); if (!ui_text_visible()) return; ui_set_background(BACKGROUND_ICON_ERROR); break; case ITEM_APPLY_SDCARD: //HACK for "error: a label can only be part of a statement and a declaration is not a statement" //the rule is retarted, the follwing "dummy" statement is cut in optimization override_initial_selection=override_initial_selection; //confirm it char* confirm_headers[] = { "Confirm installing update package?", MENU_ITEMS[menu_item], "", NULL }; char* confirm_items[] = { "Yes", "No", NULL }; int confirm_item = show_interactive_menu(confirm_headers, confirm_items); if (confirm_item == 1) //YES! { ui_print("\n-- Install from sdcard...\n"); ui_led_blink(1); ensure_common_roots_unmounted(); ensure_root_path_mounted("SDCARD:"); set_sdcard_update_bootloader_message(); call_finish_in_loop = 1; int status = install_package(MENU_ITEMS_TARGET[menu_item]); ensure_common_roots_mounted(); 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 { if (firmware_update_pending()) { ui_set_background(BACKGROUND_ICON_ERROR); ui_print("\nReboot via menu to complete\n" "installation.\n"); } else { ui_set_background(BACKGROUND_ICON_ERROR); ui_print("\nInstall from sdcard complete.\n"); } } create_menu(menu_files[menu_level], menu_scripts[menu_level]); free(headers); headers = prepend_title(MENU_HEADERS, &title_length); ui_led_toggle(0); } override_initial_selection = menu_item; break; case ITEM_SHELL_SCRIPT: ui_print("\n-- Shell script...\n"); ui_print("%s\n", MENU_ITEMS_TARGET[menu_item]); ui_led_blink(1); ensure_common_roots_mounted(); run_shell_script(MENU_ITEMS_TARGET[menu_item], 1, NULL); create_menu(menu_files[menu_level], menu_scripts[menu_level]); free(headers); headers = prepend_title(MENU_HEADERS, &title_length); ui_led_toggle(0); ui_print("Done.\n"); override_initial_selection = menu_item; break; case ITEM_TAG: if (MENU_ITEMS_TAG[menu_item] == 0x00) { int tag_fd = creat(MENU_ITEMS_TARGET[menu_item], 0644); if (tag_fd < 0) LOGE("Failed to set the tag.\n"); else { MENU_ITEMS_TAG[menu_item] = 0x01; MENU_ITEMS[menu_item][1] = 'X'; close(tag_fd); } } else if (MENU_ITEMS_TAG[menu_item] == 0x01) //just a little check if 0xFF aint there if bug is present { remove(MENU_ITEMS_TARGET[menu_item]); MENU_ITEMS_TAG[menu_item] = 0x00; MENU_ITEMS[menu_item][1] = ' '; } override_initial_selection = menu_item; break; case ITEM_NEW_MENU: if (menu_level + 1 >= MAX_MENU_LEVEL) { //too much menus, ignore break; } ui_led_blink(1); if (!strcmp(MENU_ITEMS_TARGET[menu_item], "..")) { if (menu_level) { free(menu_files[menu_level]); menu_files[menu_level] = NULL; if (menu_scripts[menu_level]) { free(menu_scripts[menu_level]); menu_scripts[menu_level] = NULL; } menu_sel[menu_level] = 0; menu_level--; override_initial_selection = menu_sel[menu_level]; } } else { menu_sel[menu_level] = menu_item; menu_level++; menu_files[menu_level] = malloc(strlen(MENU_ITEMS_TARGET[menu_item]) + 1); strcpy(menu_files[menu_level], MENU_ITEMS_TARGET[menu_item]); } ensure_common_roots_mounted(); menu_result = create_menu(menu_files[menu_level], menu_scripts[menu_level]); //if fail, remove the new menu if (menu_result && menu_level) { free(menu_files[menu_level]); menu_files[menu_level] = NULL; if (menu_scripts[menu_level]) { free(menu_scripts[menu_level]); menu_scripts[menu_level] = NULL; } menu_level--; } free(headers); headers = prepend_title(MENU_HEADERS, &title_length); ui_led_toggle(0); break; case ITEM_NEW_MENU_SCRIPTED: if (menu_level + 1 >= MAX_MENU_LEVEL) { //too much menus, ignore break; } ui_led_blink(1); char cmdBuff[MAX_LINE_LENGTH]; strcpy(cmdBuff, MENU_ITEMS_TARGET[menu_item]); char* ptr; //menufile:script ptr = strtok(cmdBuff, ":"); if (ptr != NULL) { menu_sel[menu_level] = menu_item; menu_level++; menu_files[menu_level] = malloc(strlen(ptr) + 1); strcpy(menu_files[menu_level], ptr); ptr = strtok(NULL, ""); if (ptr != NULL) { if (ptr[0] == '/' || (ptr[0] == '\"' && ptr[1] == '/')) { menu_scripts[menu_level] = malloc(strlen(ptr) + 1); strcpy(menu_scripts[menu_level], ptr); } else { menu_scripts[menu_level] = malloc(strlen(CUSTOM_SHELL_SCRIPT_PATH) + strlen(ptr) + 2); if (ptr[0] == '\"') sprintf(menu_scripts[menu_level], "\"%s/%s", CUSTOM_SHELL_SCRIPT_PATH, ptr+1); else sprintf(menu_scripts[menu_level], "%s/%s", CUSTOM_SHELL_SCRIPT_PATH, ptr); } } ensure_common_roots_mounted(); menu_result = create_menu(menu_files[menu_level], menu_scripts[menu_level]); //if fail, remove the new menu if (menu_result && menu_level) { free(menu_files[menu_level]); menu_files[menu_level] = NULL; if (menu_scripts[menu_level]) { free(menu_scripts[menu_level]); menu_scripts[menu_level] = NULL; } menu_level--; } free(headers); headers = prepend_title(MENU_HEADERS, &title_length); } ui_led_toggle(0); break; case ITEM_CONSOLE: #if OPEN_RECOVERY_HAVE_CONSOLE ensure_common_roots_mounted(); ui_print("Opening console...\n"); int console_error = run_console(NULL); if (console_error) if (console_error == CONSOLE_FORCE_QUIT) ui_print("Console was forcibly closed.\n"); else if (console_error == CONSOLE_FAILED_START) ui_print("Console failed to start.\n"); else { ui_print("Closing console...\n"); //don't bother printing error to UI fprintf(stderr, "Console closed with error %d.\n", console_error); } else ui_print("Closing console...\n"); create_menu(menu_files[menu_level], menu_scripts[menu_level]); free(headers); headers = prepend_title(MENU_HEADERS, &title_length); #else LOGE("This phone doesn't support console.\n"); #endif override_initial_selection = menu_item; break; case ITEM_ERROR: LOGE("Unknown command: %s.\n", MENU_ITEMS_ACTION[menu_item]); break; } } }