int format_volume(const char* volume) { Volume* v = volume_for_path(volume); if (v == NULL) { LOGE("unknown volume \"%s\"\n", volume); return -1; } if (strcmp(v->fs_type, "ramdisk") == 0) { // you can't format the ramdisk. LOGE("can't format_volume \"%s\"", volume); return -1; } if (strcmp(v->mount_point, volume) != 0) { LOGE("can't give path \"%s\" to format_volume\n", volume); return -1; } if (ensure_path_unmounted(volume) != 0) { LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point); return -1; } if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) { mtd_scan_partitions(); const MtdPartition* partition = mtd_find_partition_by_name(v->device); if (partition == NULL) { LOGE("format_volume: no MTD partition \"%s\"\n", v->device); return -1; } MtdWriteContext *write = mtd_write_partition(partition); if (write == NULL) { LOGW("format_volume: can't open MTD \"%s\"\n", v->device); return -1; } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { LOGW("format_volume: can't erase MTD \"%s\"\n", v->device); mtd_write_close(write); return -1; } else if (mtd_write_close(write)) { LOGW("format_volume: can't close MTD \"%s\"\n", v->device); return -1; } return 0; } if (strcmp(v->fs_type, "ext4") == 0) { reset_ext4fs_info(); int result = make_ext4fs(v->device, NULL, NULL, 0, 0, 0); if (result != 0) { LOGE("format_volume: make_extf4fs failed on %s\n", v->device); return -1; } return 0; } LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; }
//INTENT_MOUNT, mount recovery.fstab static intentResult* intent_unmount(int argc, char* argv[]) { return_intent_result_if_fail(argc == 1); return_intent_result_if_fail(argv != NULL); int result = ensure_path_unmounted(argv[0]); if (result == 0) return miuiIntent_result_set(result, "ok"); return miuiIntent_result_set(result, "fail"); }
int bml_check_volume(const char *path) { ui_print("Checking %s...\n", path); ensure_path_unmounted(path); if (0 == ensure_path_mounted(path)) { ensure_path_unmounted(path); return 0; } Volume *vol = volume_for_path(path); if (vol == NULL) { LOGE("Unable process volume! Skipping...\n"); return 0; } ui_print("%s may be rfs. Checking...\n", path); char tmp[PATH_MAX]; sprintf(tmp, "mount -t rfs %s %s", vol->device, path); int ret = __system(tmp); printf("%d\n", ret); return ret == 0 ? 1 : 0; }
// backup /data/media support // we reach here only if backup_data_media == 1 // backup_data_media can be set to 1 only in "custom backup and restore" menu AND if is_data_media() && !twrp_backup_mode.value int nandroid_backup_datamedia(const char* backup_path) { char tmp[PATH_MAX]; ui_print("\n>> Backing up /data/media...\n"); if (is_data_media_volume_path(backup_path)) { // non fatal failure LOGE(" - can't backup folder to its self, skipping...\n"); return 0; } if (0 != ensure_path_mounted("/data")) return -1; sprintf(tmp, "%s/%s", get_primary_storage_path(), NANDROID_HIDE_PROGRESS_FILE); ensure_path_mounted(tmp); int callback = !file_found(tmp); compute_directory_stats("/data/media"); Volume *v = volume_for_path("/data"); if (v == NULL) return -1; char backup_file_image[PATH_MAX]; sprintf(backup_file_image, "%s/datamedia.%s", backup_path, v->fs_type == NULL ? "auto" : v->fs_type); int fmt; fmt = nandroid_get_default_backup_format(); if (fmt == NANDROID_BACKUP_FORMAT_TAR) { sprintf(tmp, "cd / ; touch %s.tar ; set -o pipefail ; (tar -cpv data/media | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.) 2> /proc/self/fd/1 ; exit $?", backup_file_image, backup_file_image); } else if (fmt == NANDROID_BACKUP_FORMAT_TGZ) { sprintf(tmp, "cd / ; touch %s.tar.gz ; set -o pipefail ; (tar -cpv data/media | pigz -c -%d | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.gz.) 2> /proc/self/fd/1 ; exit $?", backup_file_image, compression_value.value, backup_file_image); } else { // non fatal failure LOGE(" - backup format must be tar(.gz), skipping...\n"); return 0; } int ret; ret = do_tar_compress(tmp, callback, backup_file_image); ensure_path_unmounted("/data"); if (0 != ret) return print_and_error("Failed to backup /data/media!\n", ret); ui_print("Backup of /data/media completed.\n"); return 0; }
int nandroid_restore_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) { int ret = 0; char* name = basename(mount_point); char tmp[PATH_MAX]; sprintf(tmp, "%s/%s.img", backup_path, name); struct stat file_info; if (0 != (ret = statfs(tmp, &file_info))) { ui_print("%s.img not found. Skipping restore of %s.\n", name, mount_point); return 0; } ensure_directory(mount_point); int callback = stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info) != 0; ui_print("Restoring %s...\n", name); /* if (0 != (ret = ensure_root_path_unmounted(root))) { ui_print("Can't unmount %s!\n", mount_point); return ret; } */ if (0 != (ret = format_volume(mount_point))) { ui_print("Error while formatting %s!\n", mount_point); return ret; } if (0 != (ret = ensure_path_mounted(mount_point))) { ui_print("Can't mount %s!\n", mount_point); return ret; } nandroid_restore_handler restore_handler = get_restore_handler(mount_point); 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 int copy_databk_to_data(){ printf("begin copy databk to data\n"); char *argv_execv[] = {"data_resume.sh", NULL}; ensure_path_mounted("/data"); ensure_path_mounted("/system"); pid_t pid =fork(); if(pid==0){ execv("/system/bin/data_resume.sh",argv_execv); _exit(-1); } int status; waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { printf("Error (Status %d),fail to resume data\n", WEXITSTATUS(status)); ensure_path_unmounted("/data"); ensure_path_unmounted("/system"); return -1; } printf("copy databk to data succeed\n"); ensure_path_unmounted("/data"); ensure_path_unmounted("/system"); return 0; }
/* add by cjcheng start... */ static int smdt_update_directory(const char* path, const char* unmount_when_done, int* wipe_cache) { ensure_path_mounted(path); int result; char new_path[PATH_MAX]; strlcpy(new_path, path, PATH_MAX); strlcat(new_path, "/", PATH_MAX); strlcat(new_path, "update.zip", PATH_MAX); ui->Print("\n-- Install %s ...\n", new_path); if (access(new_path, F_OK) == 0) { ui->Print("\n read -- %s ok...\n", new_path); ui->SetTipTitle(RecoveryUI::TIP_TITLE_READ_PACKAGE); } else { ui->Print("\n read -- %s error...\n", new_path); if (unmount_when_done != NULL) { ensure_path_unmounted(unmount_when_done); } return INSTALL_ERROR; } 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, wipe_cache, TEMPORARY_INSTALL_FILE); free(copy); } else { result = INSTALL_ERROR; } return result; }
// clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and // record any intent we were asked to communicate back to the system. // this function is idempotent: call it as many times as you like. static void finish_recovery(const char *send_intent) { // By this point, we're ready to return to the main system... if (send_intent != NULL) { FILE *fp = fopen_path(INTENT_FILE, "w"); if (fp == NULL) { LOGE("Can't open %s\n", INTENT_FILE); } else { fputs(send_intent, fp); check_and_fclose(fp, INTENT_FILE); } } // Save the locale to cache, so if recovery is next started up // without a --locale argument (eg, directly from the bootloader) // it will use the last-known locale. if (locale != NULL) { LOGI("Saving locale \"%s\"\n", locale); FILE* fp = fopen_path(LOCALE_FILE, "w"); fwrite(locale, 1, strlen(locale), fp); fflush(fp); fsync(fileno(fp)); check_and_fclose(fp, LOCALE_FILE); } // Copy logs to cache so the system can find out what happened. copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); chmod(LOG_FILE, 0600); chown(LOG_FILE, 1000, 1000); // system user chmod(LAST_LOG_FILE, 0640); chmod(LAST_INSTALL_FILE, 0644); // Reset to normal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; memset(&boot, 0, sizeof(boot)); set_bootloader_message(&boot); // Remove the command file, so recovery won't repeat indefinitely. if (ensure_path_mounted(COMMAND_FILE) != 0 || (unlink(COMMAND_FILE) && errno != ENOENT)) { LOGW("Can't unlink %s\n", COMMAND_FILE); } ensure_path_unmounted(CACHE_ROOT); sync(); // For good measure. }
int ensure_path_unmounted (const char *path) { // if we are using /data/media, do not ever unmount volumes /data or /sdcard if (volume_for_path ("/sdcard") == NULL && (strstr (path, "/sdcard") == path || strstr (path, "/data") == path)) { return 0; } Volume *v = volume_for_path (path); if (v == NULL) { // no /sdcard? let's assume /data/media if (strstr (path, "/sdcard") == path && is_data_media ()) { return ensure_path_unmounted ("/data"); } LOGE ("unknown volume for path [%s]\n", path); return -1; } if (strcmp (v->fs_type, "ramdisk") == 0) { // the ramdisk is always mounted; you can't unmount it. return -1; } int result; result = scan_mounted_volumes (); if (result < 0) { LOGE ("failed to scan mounted volumes\n"); return -1; } const MountedVolume *mv = find_mounted_volume_by_mount_point (v->mount_point); if (mv == NULL) { // volume is already unmounted return 0; } return unmount_mounted_volume (mv); }
int nandroid_restore_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) { int ret = 0; char* name = basename(mount_point); char tmp[PATH_MAX]; sprintf(tmp, "%s/%s.img", backup_path, name); struct stat file_info; if (0 != (ret = statfs(tmp, &file_info))) { ui_print("%s.img没有发现. 放弃还原 %s.\n", name, mount_point); return 0; } ensure_directory(mount_point); unyaffs_callback callback = NULL; if (0 != stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info)) { callback = yaffs_callback; } ui_print("还原 %s...\n", name); /* if (0 != (ret = ensure_root_path_unmounted(root))) { ui_print("Can't unmount %s!\n", mount_point); return ret; } */ if (0 != (ret = format_volume(mount_point))) { ui_print("格式化时出错 %s!\n", mount_point); return ret; } if (0 != (ret = ensure_path_mounted(mount_point))) { ui_print("不能挂载 %s!\n", mount_point); return ret; } if (0 != (ret = unyaffs(tmp, mount_point, callback))) { ui_print("还原时出错 %s!\n", mount_point); return ret; } if (umount_when_finished) { ensure_path_unmounted(mount_point); } return 0; }
int nandroid_backup_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) { int ret = 0; char name[PATH_MAX]; char tmp[PATH_MAX]; strcpy(name, basename(mount_point)); struct stat file_info; build_configuration_path(tmp, NANDROID_HIDE_PROGRESS_FILE); ensure_path_mounted(tmp); int callback = stat(tmp, &file_info) != 0; ui_print("Backing up %s...\n", name); if (0 != (ret = ensure_path_mounted(mount_point) != 0)) { ui_print("Can't mount %s!\n", mount_point); return ret; } compute_directory_stats(mount_point); scan_mounted_volumes(); Volume *v = volume_for_path(mount_point); const MountedVolume *mv = NULL; if (v != NULL) mv = find_mounted_volume_by_mount_point(v->mount_point); if (strcmp(backup_path, "-") == 0) sprintf(tmp, "/proc/self/fd/1"); else if (mv == NULL || mv->filesystem == NULL) sprintf(tmp, "%s/%s.auto", backup_path, name); else sprintf(tmp, "%s/%s.%s", backup_path, name, mv->filesystem); nandroid_backup_handler backup_handler = get_backup_handler(mount_point); if (backup_handler == NULL) { ui_print("Error finding an appropriate backup handler.\n"); return -2; } ret = backup_handler(mount_point, tmp, callback); if (umount_when_finished) { ensure_path_unmounted(mount_point); } if (0 != ret) { ui_print("Error while making a backup image of %s!\n", mount_point); return ret; } ui_print("Backup of %s completed.\n", name); return 0; }
static int erase_volume(const char *volume) { ui->SetBackground(RecoveryUI::INSTALLING); ui->SetProgressType(RecoveryUI::INDETERMINATE); ui->Print("Formatting %s...\n", volume); ensure_path_unmounted(volume); if (strcmp(volume, "/cache") == 0) { // 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; } return format_volume(volume); }
static int erase_volume(const char *volume) { ui_set_background(BACKGROUND_ICON_INSTALLING); ui_show_indeterminate_progress(); ui_print("Formatting %s...\n", volume); ensure_path_unmounted(volume); if (strcmp(volume, "/cache") == 0) { // 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; } return format_volume(volume); }
int nandroid_backup_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) { int ret = 0; char name[PATH_MAX]; strcpy(name, basename(mount_point)); struct stat file_info; int callback = stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info) != 0; ui_print("备份中 %s...\n", name); if (0 != (ret = ensure_path_mounted(mount_point) != 0)) { ui_print("无法挂载 %s!\n", mount_point); return ret; } compute_directory_stats(mount_point); char tmp[PATH_MAX]; scan_mounted_volumes(); Volume *v = volume_for_path(mount_point); MountedVolume *mv = NULL; if (v != NULL) mv = find_mounted_volume_by_mount_point(v->mount_point); if (strcmp(backup_path, "-") == 0) sprintf(tmp, "/proc/self/fd/1"); else if (mv == NULL || mv->filesystem == NULL) sprintf(tmp, "%s/%s.auto", backup_path, name); else sprintf(tmp, "%s/%s.%s", backup_path, name, mv->filesystem); nandroid_backup_handler backup_handler = get_backup_handler(mount_point); if (backup_handler == NULL) { ui_print("找不到合适的备份方案.\n"); return -2; } ret = backup_handler(mount_point, tmp, callback); if (umount_when_finished) { ensure_path_unmounted(mount_point); } if (0 != ret) { ui_print("生成下列镜像文件时失败: %s!\n", mount_point); return ret; } ui_print("备份 %s 完成.\n", name); return 0; }
int setup_install_mounts() { if (fstab == NULL) { LOGE("can't set up install mounts: no fstab loaded\n"); return -1; } for (int i = 0; i < fstab->num_entries; ++i) { Volume* v = fstab->recs + i; if (strcmp(v->mount_point, "/tmp") == 0 || strcmp(v->mount_point, "/cache") == 0) { if (ensure_path_mounted(v->mount_point) != 0) return -1; } else { if (ensure_path_unmounted(v->mount_point) != 0) return -1; } } return 0; }
void erase_dalvik_cache(int orscallback) { if(orscallback && orswipeprompt && !confirm_selection("Confirm wipe?","Yes- Wipe Dalvik Cache")) { ui_print("Skipping dalvik cache wipe...\n"); return; } if (0 != ensure_path_mounted("/data")) return; ensure_path_mounted("/sd-ext"); ensure_path_mounted("/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"); return; }
int verify_root_and_recovery() { if (ensure_path_mounted("/system") != 0) return 0; int ret = 0; struct stat st; if (0 == lstat("/system/etc/install-recovery.sh", &st)) { if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { ui_show_text(1); ret = 1; if (confirm_selection("ROM may flash stock recovery on boot. Fix?", "Yes - Disable recovery flash")) { __system("chmod -x /system/etc/install-recovery.sh"); } } } if (0 == lstat("/system/bin/su", &st)) { if (S_ISREG(st.st_mode)) { if ((st.st_mode & (S_ISUID | S_ISGID)) != (S_ISUID | S_ISGID)) { ui_show_text(1); ret = 1; if (confirm_selection("Root access possibly lost. Fix?", "Yes - Fix root (/system/bin/su)")) { __system("chmod 6755 /system/bin/su"); } } } } if (0 == lstat("/system/xbin/su", &st)) { if (S_ISREG(st.st_mode)) { if ((st.st_mode & (S_ISUID | S_ISGID)) != (S_ISUID | S_ISGID)) { ui_show_text(1); ret = 1; if (confirm_selection("Root access possibly lost. Fix?", "Yes - Fix root (/system/xbin/su)")) { __system("chmod 6755 /system/xbin/su"); } } } } ensure_path_unmounted("/system"); return ret; }
// reboot: Reboot the system. Return -1 on error, no return on success int tw_reboot(RebootCommand command) { if (DataManager_GetIntValue(TW_BACKUP_SYSTEM_SIZE) < DataManager_GetIntValue(TW_MIN_SYSTEM_VAR)) { update_system_details(); if (DataManager_GetIntValue(TW_BACKUP_SYSTEM_SIZE) < DataManager_GetIntValue(TW_MIN_SYSTEM_VAR)) { LOGE("System is not installed - preventing reboot!\n"); return -1; } } // Always force a sync before we reboot sync(); ensure_path_unmounted("/sdcard"); switch (command) { case rb_current: case rb_system: finish_recovery("s"); sync(); check_and_run_script("/sbin/rebootsystem.sh", "reboot system"); return reboot(RB_AUTOBOOT); case rb_recovery: check_and_run_script("/sbin/rebootrecovery.sh", "reboot recovery"); return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "recovery"); case rb_bootloader: check_and_run_script("/sbin/rebootbootloader.sh", "reboot bootloader"); return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "bootloader"); case rb_poweroff: check_and_run_script("/sbin/poweroff.sh", "power off"); return reboot(RB_POWER_OFF); case rb_download: check_and_run_script("/sbin/rebootdownload.sh", "reboot download"); return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "download"); return 1; default: return -1; } return -1; }
void device_toggle_truedualboot(void) { char confirm[PATH_MAX]; int enable = dualboot_is_tdb_enabled(); #ifndef PHILZ_TOUCH_RECOVERY ui_setMenuTextColor(MENU_TEXT_COLOR_RED); #endif sprintf(confirm, "Yes - %s TrueDualBoot", enable?"DISABLE":"ENABLE"); if (confirm_selection("This will WIPE DATA. Confirm?", confirm)) { // unmount /data if(ensure_path_unmounted("/data")!=0) { LOGE("Error unmounting /data!\n"); return; } // format /data ui_set_background(BACKGROUND_ICON_INSTALLING); ui_show_indeterminate_progress(); ui_print("Formatting /data...\n"); set_force_raw_format_enabled(1); if(format_volume("/data")!=0) { ui_print("Error formatting /data!\n"); ui_reset_progress(); return; } ui_reset_progress(); set_force_raw_format_enabled(0); ui_print("Done.\n"); // toggle dualboot_set_tdb_enabled(!enable); } #ifndef PHILZ_TOUCH_RECOVERY ui_setMenuTextColor(MENU_TEXT_COLOR); #endif return; }
int nandroid_backup_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) { int ret = 0; char name[PATH_MAX]; strcpy(name, basename(mount_point)); ensure_path_mounted("/sdcard"); struct stat file_info; int callback = stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info) != 0; ui_print("Backing up %s...\n", name); if (0 != (ret = ensure_path_mounted(mount_point) != 0)) { ui_print("Can't mount %s!\n", mount_point); return ret; } compute_directory_stats(mount_point); char tmp[PATH_MAX]; scan_mounted_volumes(); Volume *v = volume_for_path(mount_point); MountedVolume *mv = NULL; if (v != NULL) mv = find_mounted_volume_by_mount_point(v->mount_point); if (mv == NULL || mv->filesystem == NULL) sprintf(tmp, "%s/%s.auto", backup_path, name); else sprintf(tmp, "%s/%s.%s", backup_path, name, mv->filesystem); nandroid_backup_handler backup_handler = get_backup_handler(mount_point); if (backup_handler == NULL) { ui_print("Error finding an appropriate backup handler.\n"); return -2; } ret = backup_handler(mount_point, tmp, callback); if (umount_when_finished) { ensure_path_unmounted(mount_point); } if (0 != ret) { ui_print("Error while making a backup image of %s!\n", mount_point); return ret; } ui_print("Backup of %s completed.\n", name); return 0; }
int replace_device_node(Volume* vol, struct stat* stat) { if(stat==NULL) return -1; ssize_t len; char resolved_path[PATH_MAX]; if((len = readlink(vol->device, resolved_path, sizeof(resolved_path)-1)) != -1) resolved_path[len] = '\0'; else sprintf(resolved_path, "%s", vol->device); if(ensure_path_unmounted(vol->mount_point)!=0) { LOGE("replace_device_node: could not unmount device!\n"); return -1; } if(unlink(resolved_path)!=0) { LOGE("replace_device_node: could not delete node!\n"); return -1; } if(mknod(resolved_path, stat->st_mode, stat->st_rdev)!=0) { LOGE("replace_device_node: could not create node!\n"); return -1; } return 0; }
int ensure_path_unmounted(const char* path) { // if we are using /data/media, do not ever unmount volumes /data or /sdcard if (is_data_media_volume_path(path)) { return ensure_path_unmounted("/data"); } if (strstr(path, "/data") == path && is_data_media() && !ignore_data_media) { return 0; } Volume* v = volume_for_path(path); if (v == NULL) { LOGE("unknown volume for path [%s]\n", path); return -1; } if (strcmp(v->fs_type, "ramdisk") == 0) { // the ramdisk is always mounted; you can't unmount it. return -1; } int result; result = scan_mounted_volumes(); if (result < 0) { LOGE("failed to scan mounted volumes\n"); return -1; } const MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point); if (mv == NULL) { // volume is already unmounted return 0; } if (fs_mgr_is_voldmanaged(volume_for_path(v->mount_point))) return vold_unmount_volume(v->mount_point, 0, 1) == CommandOkay ? 0 : -1; return unmount_mounted_volume(mv); }
int set_active_system(int num) { int i; char* mount_point; Volume* system0 = volume_for_path("/system"); Volume* system1 = volume_for_path("/system1"); Volume* boot0 = volume_for_path("/boot"); Volume* boot1 = volume_for_path("/boot1"); Volume* radio0 = volume_for_path("/radio"); Volume* radio1 = volume_for_path("/radio1"); handle_volume_request(system0, system1, num); handle_volume_request(boot0, boot1, num); handle_volume_request(radio0, radio1, num); if(ensure_path_unmounted("/data")!=0) { LOGE("could not unmount /data!\n"); return -1; } selected_dualsystem_mode = num; return 0; }
static int erase_volume(const char *volume) { ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); /* add by cjcheng start... */ if (strcmp(volume, "/cache") == 0) { ui->SetTipTitle(RecoveryUI::TIP_TITLE_WIPE_CACHE); } else if (strcmp(volume, "/data") == 0) { ui->SetTipTitle(RecoveryUI::TIP_TITLE_WIPE_DATA); } /* add by cjcheng end... */ ui->Print("Formatting %s...\n", volume); ensure_path_unmounted(volume); if (strcmp(volume, "/cache") == 0) { // 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; } return format_volume(volume); }
// clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and // record any intent we were asked to communicate back to the system. // this function is idempotent: call it as many times as you like. static void finish_recovery(const char *send_intent) { // By this point, we're ready to return to the main system... if (send_intent != NULL) { FILE *fp = fopen_path(INTENT_FILE, "w"); if (fp == NULL) { LOGE("Can't open %s\n", INTENT_FILE); } else { fputs(send_intent, fp); check_and_fclose(fp, INTENT_FILE); } } // Copy logs to cache so the system can find out what happened. copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); chmod(LOG_FILE, 0600); chown(LOG_FILE, 1000, 1000); // system user chmod(LAST_LOG_FILE, 0640); chmod(LAST_INSTALL_FILE, 0644); // Reset to mormal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; memset(&boot, 0, sizeof(boot)); set_bootloader_message(&boot); // Remove the command file, so recovery won't repeat indefinitely. if (ensure_path_mounted(COMMAND_FILE) != 0 || (unlink(COMMAND_FILE) && errno != ENOENT)) { LOGW("Can't unlink %s\n", COMMAND_FILE); } ensure_path_unmounted(CACHE_ROOT); sync(); // For good measure. }
static int update_directory(const char* path, const char* unmount_when_done, int* wipe_cache, Device* device) { 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; } const char** headers = prepend_title(MENU_HEADERS); int d_size = 0; int d_alloc = 10; char** dirs = (char**)malloc(d_alloc * sizeof(char*)); int z_size = 1; int z_alloc = 10; char** zips = (char**)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 = (char**)realloc(dirs, d_alloc * sizeof(char*)); } dirs[d_size] = (char*)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 = (char**)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 = (char**)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, device); 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, wipe_cache, device); 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, wipe_cache, TEMPORARY_INSTALL_FILE); 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; }
static int erase_volume(const char *volume) { bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); 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 show_partition_menu() { static char* headers[] = { "Mounts and Storage Menu", "", NULL }; static MountMenuEntry* mount_menu = NULL; static FormatMenuEntry* format_menu = 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_menu = malloc(num_volumes * sizeof(MountMenuEntry)); format_menu = 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) { if (strcmp("datamedia", v->fs_type) != 0) { sprintf(&mount_menu[mountable_volumes].mount, "mount %s", v->mount_point); sprintf(&mount_menu[mountable_volumes].unmount, "unmount %s", v->mount_point); mount_menu[mountable_volumes].v = &device_volumes[i]; ++mountable_volumes; } if (is_safe_to_format(v->mount_point)) { sprintf(&format_menu[formatable_volumes].txt, "format %s", v->mount_point); format_menu[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_menu[formatable_volumes].txt, "format %s", v->mount_point); format_menu[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_menu[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_menu[i]; options[mountable_volumes+i] = e->txt; } if (!is_data_media()) { options[mountable_volumes + formatable_volumes] = "mount USB storage"; options[mountable_volumes + formatable_volumes + 1] = NULL; } else { options[mountable_volumes + formatable_volumes] = "format /data and /data/media (/sdcard)"; 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)) { if (!is_data_media()) { show_mount_usb_storage_menu(); } else { if (!confirm_selection("format /data and /data/media (/sdcard)", confirm)) continue; ignore_data_media_workaround(1); ui_print("Formatting /data...\n"); if (0 != format_volume("/data")) ui_print("Error formatting /data!\n"); else ui_print("Done.\n"); ignore_data_media_workaround(0); } } else if (chosen_item < mountable_volumes) { MountMenuEntry* e = &mount_menu[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_menu[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_menu); free(format_menu); }
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; }
int format_device(const char *device, const char *path, const char *fs_type) { Volume* v = volume_for_path(path); if (v == NULL) { // silent failure for sd-ext if (strcmp(path, "/sd-ext") == 0) return -1; LOGE("unknown volume \"%s\"\n", path); return -1; } if (is_data_media_volume_path(path)) { return format_unknown_device(NULL, path, NULL); } if (strstr(path, "/data") == path && is_data_media()) { return format_unknown_device(NULL, path, NULL); } if (strcmp(fs_type, "ramdisk") == 0) { // you can't format the ramdisk. LOGE("can't format_volume \"%s\"", path); return -1; } if (strcmp(fs_type, "rfs") == 0) { if (ensure_path_unmounted(path) != 0) { LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point); return -1; } if (0 != format_rfs_device(device, path)) { LOGE("format_volume: format_rfs_device failed on %s\n", device); return -1; } return 0; } if (strcmp(v->mount_point, path) != 0) { return format_unknown_device(v->device, path, NULL); } if (ensure_path_unmounted(path) != 0) { LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point); return -1; } if (strcmp(fs_type, "yaffs2") == 0 || strcmp(fs_type, "mtd") == 0) { mtd_scan_partitions(); const MtdPartition* partition = mtd_find_partition_by_name(device); if (partition == NULL) { LOGE("format_volume: no MTD partition \"%s\"\n", device); return -1; } MtdWriteContext *write = mtd_write_partition(partition); if (write == NULL) { LOGW("format_volume: can't open MTD \"%s\"\n", device); return -1; } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { LOGW("format_volume: can't erase MTD \"%s\"\n", device); mtd_write_close(write); return -1; } else if (mtd_write_close(write)) { LOGW("format_volume: can't close MTD \"%s\"\n",device); return -1; } return 0; } if (strcmp(fs_type, "ext4") == 0) { int length = 0; if (strcmp(v->fs_type, "ext4") == 0) { // Our desired filesystem matches the one in fstab, respect v->length length = v->length; } reset_ext4fs_info(); int result = make_ext4fs(device, length, v->mount_point, sehandle); if (result != 0) { LOGE("format_volume: make_extf4fs failed on %s\n", device); return -1; } return 0; } return format_unknown_device(device, path, fs_type); }