int nandroid_backup_system(const char* backup_path) { ui_set_background(BACKGROUND_ICON_INSTALLING); 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) { if (strstr(backup_path, "/sdcard") == backup_path && is_data_media()) volume = volume_for_path("/data"); else return print_and_error("Unable to find volume for backup path.\n"); } 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]; sprintf(tmp, "mkdir -p %s", backup_path); __system(tmp); if (0 != (ret = nandroid_backup_partition(backup_path, "/system"))) return ret; sync(); ui_set_background(BACKGROUND_ICON_NONE); ui_reset_progress(); ui_print("\nBackup complete!\n"); 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 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); }
static nandroid_backup_handler get_backup_handler(const char *backup_path) { Volume *v = volume_for_path(backup_path); if (v == NULL) { #ifndef USE_CHINESE_FONT ui_print("Unable to find volume.\n"); #else ui_print("无法找到卷。\n"); #endif return NULL; } const MountedVolume *mv = find_mounted_volume_by_mount_point(v->mount_point); if (mv == NULL) { #ifndef USE_CHINESE_FONT ui_print("Unable to find mounted volume: %s\n", v->mount_point); #else ui_print("无法挂载卷: %s\n", v->mount_point); #endif return NULL; } if (strcmp(backup_path, "/data") == 0 && is_data_media()) { return default_backup_handler; } if (strlen(forced_backup_format) > 0) return default_backup_handler; // Disable tar backups of yaffs2 by default char prefer_tar[PROPERTY_VALUE_MAX]; property_get("ro.cwm.prefer_tar", prefer_tar, "false"); if (strcmp("yaffs2", mv->filesystem) == 0 && strcmp("false", prefer_tar) == 0) { return mkyaffs2image_wrapper; } return default_backup_handler; }
void show_nandroid_menu() { static char* headers[] = { "Nandroid", "", NULL }; static char* list[] = { "backup to internal sdcard", "restore from internal sdcard", "advanced restore from internal sdcard", "backup to external sdcard", "restore from external sdcard", "advanced restore from external sdcard", NULL }; if (volume_for_path("/emmc") == NULL || volume_for_path("/sdcard") == NULL && is_data_media()) list[3] = NULL; int chosen_item = get_menu_selection(headers, list, 0, 0); switch (chosen_item) { case 0: { char backup_path[PATH_MAX]; time_t t = time(NULL); struct tm *tmp = localtime(&t); if (tmp == NULL) { struct timeval tp; gettimeofday(&tp, NULL); sprintf(backup_path, "/emmc/clockworkmod/backup/%d", tp.tv_sec); } else { strftime(backup_path, sizeof(backup_path), "/emmc/clockworkmod/backup/%F.%H.%M.%S", tmp); } nandroid_backup(backup_path); } break; case 1: show_nandroid_restore_menu("/emmc"); break; case 2: show_nandroid_advanced_restore_menu("/emmc"); break; case 3: { char backup_path[PATH_MAX]; time_t t = time(NULL); struct tm *tmp = localtime(&t); if (tmp == NULL) { struct timeval tp; gettimeofday(&tp, NULL); sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec); } else { strftime(backup_path, sizeof(backup_path), "/sdcard/clockworkmod/backup/%F.%H.%M.%S", tmp); } nandroid_backup(backup_path); } break; case 4: show_nandroid_restore_menu("/sdcard"); break; case 5: show_nandroid_advanced_restore_menu("/sdcard"); break; } }
int format_volume(const char* volume) { Volume* v = volume_for_path(volume); if (v == NULL) { // no /sdcard? let's assume /data/media if (strstr(volume, "/sdcard") == volume && is_data_media()) { return format_unknown_device(NULL, volume, NULL); } // silent failure for sd-ext if (strcmp(volume, "/sd-ext") == 0) return -1; 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) { #if 0 LOGE("can't give path \"%s\" to format_volume\n", volume); return -1; #endif return format_unknown_device(v->device, volume, NULL); } 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); // MtdWriteContext *write = mtd_write_partition(v->device); 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; } #if 0 LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; #endif return format_unknown_device(v->device, volume, v->fs_type); }
int check_backup_size(const char* backup_path) { // these are the size stats for backup_path we previously refreshed by calling Get_Size_Via_statfs() int total_mb = (int)(Total_Size / 1048576LLU); int used_mb = (int)(Used_Size / 1048576LLU); int free_mb = (int)(Free_Size / 1048576LLU); int free_percent = free_mb * 100 / total_mb; Before_Used_Size = Used_Size; // save Used_Size to refresh data written stats later Backup_Size = 0; // supported nandroid partitions char* Base_Partitions_List[BASE_PARTITIONS_NUM] = { "/recovery", BOOT_PARTITION_MOUNT_POINT, "/wimax", "/modem", "/radio", "/efs", "/misc", "/system", "/preload", "/data", "/datadata", "/cache", "/sd-ext" }; int items_num = BASE_PARTITIONS_NUM + MAX_EXTRA_NANDROID_PARTITIONS + 1; char* Partitions_List[items_num]; int i; for (i = 0; i < BASE_PARTITIONS_NUM; ++i) { Partitions_List[i] = Base_Partitions_List[i]; } int extra_partitions_num = get_extra_partitions_state(); for (i = 0; i < extra_partitions_num; ++i) { Partitions_List[BASE_PARTITIONS_NUM + i] = extra_partition[i].mount_point; } Partitions_List[BASE_PARTITIONS_NUM + extra_partitions_num] = NULL; int preload_status = 0; if ((is_custom_backup && backup_preload) || (!is_custom_backup && nandroid_add_preload.value)) preload_status = 1; int Base_Partitions_Backup_Status[] = { backup_recovery, backup_boot, backup_wimax, backup_modem, backup_radio, backup_efs, backup_misc, backup_system, preload_status, backup_data, backup_data, backup_cache, backup_sdext, }; LOGI("Checking needed space for backup '%s'\n", backup_path); // calculate needed space for backup // assume recovery and wimax always use a raw backup mode (Is_Image() = 0) char skipped_parts[1024] = ""; int ret = 0; Volume* vol; for (i = 0; Partitions_List[i] != NULL; ++i) { if (i >= BASE_PARTITIONS_NUM) { if (!extra_partition[i - BASE_PARTITIONS_NUM].backup_state) continue; } else if (!Base_Partitions_Backup_Status[i]) { continue; } // size of /data will be calculated later for /data/media devices to subtract sdcard size from it if (strcmp(Partitions_List[i], "/data") == 0 && is_data_media()) continue; // redundant but keep for compatibility: // has_datadata() does a volume_for_path() != NULL check if (strcmp(Partitions_List[i], "/datadata") == 0 && !has_datadata()) continue; vol = volume_for_path(Partitions_List[i]); if (vol == NULL) continue; if (Is_Image(Partitions_List[i]) == 0) { if (Find_Partition_Size(Partitions_List[i]) == 0) { Backup_Size += Total_Size; LOGI("%s backup size (/proc)=%lluMb\n", Partitions_List[i], Total_Size / 1048576LLU); // debug } else { ret++; strcat(skipped_parts, " - "); strcat(skipped_parts, Partitions_List[i]); } } else if (Is_File_System(Partitions_List[i]) == 0) { // Get_Size_Via_statfs() will ensure vol->mount_point != NULL if (0 == ensure_path_mounted(vol->mount_point) && 0 == Get_Size_Via_statfs(vol->mount_point)) { Backup_Size += Used_Size; LOGI("%s backup size (stat)=%lluMb\n", Partitions_List[i], Used_Size / 1048576LLU); // debug } else { ret++; strcat(skipped_parts, " - "); strcat(skipped_parts, Partitions_List[i]); } } else { ret++; strcat(skipped_parts, " - Unknown file system: "); strcat(skipped_parts, Partitions_List[i]); } } // handle special partitions and folders: // handle /data and /data/media partitions size for /data/media devices unsigned long long data_backup_size = 0; unsigned long long data_used_bytes = 0; unsigned long long data_media_size = 0; if (is_data_media() && (backup_data || backup_data_media)) { if (0 == ensure_path_mounted("/data") && 0 == Get_Size_Via_statfs("/data")) { data_media_size = Get_Folder_Size("/data/media"); data_used_bytes = Get_Folder_Size("/data"); data_backup_size = data_used_bytes - data_media_size; LOGI("/data: tot size=%lluMb, free=%lluMb, backup size=%lluMb, used=%lluMb, media=%lluMb\n", Total_Size/1048576LLU, Free_Size/1048576LLU, data_backup_size/1048576LLU, data_used_bytes/1048576LLU, data_media_size/1048576LLU); } else { if (backup_data) { strcat(skipped_parts, " - /data"); ret++; } if (backup_data_media) { strcat(skipped_parts, " - /data/media"); ret++; } } } if (backup_data) Backup_Size += data_backup_size; // check if we are also backing up /data/media // if backup_path is same as /data/media, ignore this as it will not be processed by nandroid_backup_datamedia() if (backup_data_media && !is_data_media_volume_path(backup_path)) { Backup_Size += data_media_size; LOGI("included /data/media size\n"); // debug } // .android_secure size calculation // set_android_secure_path() will mount tmp so no need to remount before calling Get_Folder_Size(tmp) char tmp[PATH_MAX]; set_android_secure_path(tmp); if (backup_data && android_secure_ext) { unsigned long long andsec_size; andsec_size = Get_Folder_Size(tmp); Backup_Size += andsec_size; LOGI("%s backup size=%lluMb\n", tmp, andsec_size / 1048576LLU); // debug } // check if we have the needed space int backup_size_mb = (int)(Backup_Size / 1048576LLU); ui_print("\n>> Free space: %dMb (%d%%)\n", free_mb, free_percent); ui_print(">> Needed space: %dMb\n", backup_size_mb); if (ret) ui_print(">> Unknown partitions size (%d):%s\n", ret, skipped_parts); // dedupe wrapper needs less space than actual backup size (incremental backups) // only check free space in Mb if we use tar or tar.gz as a default format // also, add extra 50 Mb for security measures if (free_percent < 3 || (default_backup_handler != dedupe_compress_wrapper && free_mb < backup_size_mb + 50)) { LOGW("Low space for backup!\n"); if (!ui_is_initialized()) { // do not prompt when it is an "adb shell nandroid backup" command LOGW("\n>>> Backup could fail with I/O error!! <<<\n\n"); } else if (nand_prompt_on_low_space.value && !confirm_selection("Low free space! Continue anyway?", "Yes - Continue Nandroid Job")) return -1; } return 0; }
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); }
static void compute_directory_stats(const char* directory) { char tmp[PATH_MAX]; sprintf(tmp, "find %s | %s wc -l > /tmp/dircount", directory, strcmp(directory, "/data") == 0 && is_data_media() ? "grep -v /data/media |" : ""); __system(tmp); char count_text[100]; FILE* f = fopen("/tmp/dircount", "r"); fread(count_text, 1, sizeof(count_text), f); fclose(f); nandroid_files_count = 0; nandroid_files_total = atoi(count_text); ui_reset_progress(); ui_show_progress(1, 0); }
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 (backup_boot && 0 != (ret = nandroid_backup_partition(backup_path, "/boot"))) return ret; if (backup_recovery && 0 != (ret = nandroid_backup_partition(backup_path, "/recovery"))) return ret; Volume *vol = volume_for_path("/wimax"); if (backup_wimax && 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"); } //2 copies of efs are made: tarball and raw backup if (backup_efs) { //first backup in raw format, returns 0 on success (or if skipped), else 1 if (0 != custom_backup_raw_handler(backup_path, "/efs")) { ui_print("EFS raw image backup failed! Trying tar backup...\n"); } //second backup in tar format sprintf(tmp, "%s/efs_tar", backup_path); ensure_directory(tmp); if (0 != (ret = nandroid_backup_partition(tmp, "/efs"))) return ret; } if (backup_modem) { if (0 != (ret = nandroid_backup_partition(backup_path, "/modem"))) return ret; } if (backup_system && 0 != (ret = nandroid_backup_partition(backup_path, "/system"))) return ret; if (is_custom_backup && backup_preload) { if (0 != (ret = nandroid_backup_partition(backup_path, "/preload"))) { ui_print("Failed to backup /preload!\n"); return ret; } } else if (!is_custom_backup #ifdef PHILZ_TOUCH_RECOVERY && nandroid_add_preload #endif ) { if (0 != (ret = nandroid_backup_partition(backup_path, "/preload"))) { ui_print("Failed to backup preload! Try to disable it.\n"); ui_print("Skipping /preload...\n"); //return ret; } } if (backup_data && 0 != (ret = nandroid_backup_partition(backup_path, "/data"))) return ret; if (has_datadata()) { if (backup_data && 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 (backup_data && 0 != (ret = nandroid_backup_partition_extended(backup_path, "/sdcard/.android_secure", 0))) return ret; } if (backup_cache && 0 != (ret = nandroid_backup_partition_extended(backup_path, "/cache", 0))) return ret; if (backup_sdext) { 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; } } #ifdef PHILZ_TOUCH_RECOVERY if (enable_md5sum) #endif { 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, "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 format_volume(const char* volume) { if (is_data_media_volume_path(volume)) { return format_unknown_device(NULL, volume, NULL); } // check to see if /data is being formatted, and if it is /data/media // Note: the /sdcard check is redundant probably, just being safe. if (strstr(volume, "/data") == volume && is_data_media() && !ignore_data_media) { return format_unknown_device(NULL, volume, NULL); } Volume* v = volume_for_path(volume); if (v == NULL) { // silent failure for sd-ext if (strcmp(volume, "/sd-ext") != 0) LOGE("unknown volume '%s'\n", volume); return -1; } // silent failure to format non existing sd-ext when defined in recovery.fstab if (strcmp(volume, "/sd-ext") == 0) { struct stat s; if (0 != stat(v->blk_device, &s)) { LOGI("Skipping format of sd-ext\n"); return -1; } } // Only use vold format for exact matches otherwise /sdcard will be // formatted instead of /storage/sdcard0/.android_secure if (fs_mgr_is_voldmanaged(v) && strcmp(volume, v->mount_point) == 0) { if (ensure_path_unmounted(volume) != 0) { LOGE("format_volume failed to unmount %s", v->mount_point); } return vold_format_volume(v->mount_point, 1) == CommandOkay ? 0 : -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) { #if 0 LOGE("can't give path \"%s\" to format_volume\n", volume); return -1; #endif return format_unknown_device(v->blk_device, volume, NULL); } 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->blk_device); if (partition == NULL) { LOGE("format_volume: no MTD partition \"%s\"\n", v->blk_device); return -1; } MtdWriteContext *write = mtd_write_partition(partition); if (write == NULL) { LOGW("format_volume: can't open MTD \"%s\"\n", v->blk_device); return -1; } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { LOGW("format_volume: can't erase MTD \"%s\"\n", v->blk_device); mtd_write_close(write); return -1; } else if (mtd_write_close(write)) { LOGW("format_volume: can't close MTD \"%s\"\n", v->blk_device); return -1; } return 0; } if (strcmp(v->fs_type, "ext4") == 0) { int result = make_ext4fs(v->blk_device, v->length, volume, sehandle); if (result != 0) { LOGE("format_volume: make_extf4fs failed on %s\n", v->blk_device); return -1; } return 0; } #ifdef USE_F2FS if (strcmp(v->fs_type, "f2fs") == 0) { int result = make_f2fs_main(v->blk_device, v->mount_point); if (result != 0) { LOGE("format_volume: mkfs.f2f2 failed on %s\n", v->blk_device); return -1; } return 0; } #endif #if 0 LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; #endif return format_unknown_device(v->blk_device, volume, v->fs_type); }
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("无法挂载备份时需要的存储器.\n"); } Volume* volume = volume_for_path(backup_path); if (NULL == volume) return print_and_error("找不到备份需要的存储器.\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("找不到备份路径,因此无法开始.\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("可能是你的机器空间不足了,继续中...\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("正在备份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("打包或生成WiMAX镜像失败\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("没找到 /sdcard/.android_secure. 跳过外部程序备份.\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("没找到SD-EXT,因此跳过该处备份.\n"); } else { if (0 != ensure_path_mounted("/sd-ext")) ui_print("没法挂载SD-EXT,可能是你的机器不支持该选项,跳过该部分的备份\n"); else if (0 != (ret = nandroid_backup_partition(backup_path, "/sd-ext"))) return ret; } ui_print("生成md5 校验值...\n"); sprintf(tmp, "nandroid-md5.sh %s", backup_path); if (0 != (ret = __system(tmp))) { ui_print("MD5校验值生成失败\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("\n备份完成!\n"); return 0; }
static void compute_directory_stats(const char* directory) { char tmp[PATH_MAX]; char count_text[100]; // reset file count if we ever return before setting it nandroid_files_count = 0; nandroid_files_total = 0; sprintf(tmp, "find %s | %s wc -l > /tmp/dircount", directory, strcmp(directory, "/data") == 0 && is_data_media() ? "grep -v /data/media |" : ""); __system(tmp); FILE* f = fopen("/tmp/dircount", "r"); if (f == NULL) return; if (fgets(count_text, sizeof(count_text), f) == NULL) { fclose(f); return; } size_t len = strlen(count_text); if (count_text[len - 1] == '\n') count_text[len - 1] = '\0'; fclose(f); nandroid_files_total = atoi(count_text); ui_reset_progress(); ui_show_progress(1, 0); }
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) { #ifndef USE_CHINESE_FONT return print_and_error("Can't mount backup path.\n"); #else return print_and_error("无法挂载备份路径。\n"); #endif } Volume* volume; if (is_data_media_volume_path(backup_path)) volume = volume_for_path("/data"); else volume = volume_for_path(backup_path); if (NULL == volume) #ifndef USE_CHINESE_FONT return print_and_error("Unable to find volume for backup path.\n"); #else return print_and_error("无法找到备份路径所在卷。\n"); #endif int ret; struct statfs sfs; struct stat s; if (NULL != volume) { if (0 != (ret = statfs(volume->mount_point, &sfs))) #ifndef USE_CHINESE_FONT return print_and_error("Unable to stat backup path.\n"); #else return print_and_error("无法统计备份路径。\n"); #endif uint64_t bavail = sfs.f_bavail; uint64_t bsize = sfs.f_bsize; uint64_t sdcard_free = bavail * bsize; uint64_t sdcard_free_mb = sdcard_free / (uint64_t)(1024 * 1024); #ifndef USE_CHINESE_FONT ui_print("SD Card space free: %lluMB\n", sdcard_free_mb); #else ui_print("SD 卡剩余空间: %lluMB\n", sdcard_free_mb); #endif if (sdcard_free_mb < 150) #ifndef USE_CHINESE_FONT ui_print("There may not be enough free space to complete backup... continuing...\n"); #else ui_print("可能没有足够的空间完成备份... 继续...\n"); #endif } 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, "/recovery"))) return ret; Volume *vol = volume_for_path("/wimax"); if (vol != NULL && 0 == stat(vol->blk_device, &s)) { char serialno[PROPERTY_VALUE_MAX]; #ifndef USE_CHINESE_FONT ui_print("Backing up WiMAX...\n"); #else ui_print("正在备份 WiMAX...\n"); #endif 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->blk_device, tmp); if (0 != ret) #ifndef USE_CHINESE_FONT return print_and_error("Error while dumping WiMAX image!\n"); #else return print_and_error("导出 WiMAX 镜像时出错!\n"); #endif } 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(get_android_secure_path(), &s)) { #ifndef USE_CHINESE_FONT ui_print("No .android_secure found. Skipping backup of applications on external storage.\n"); #else ui_print("未找到 .android_secure。跳过备份安装在外置存储卡上的应用程序。\n"); #endif } else { if (0 != (ret = nandroid_backup_partition_extended(backup_path, get_android_secure_path(), 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->blk_device, &s)) { #ifndef USE_CHINESE_FONT LOGI("No sd-ext found. Skipping backup of sd-ext.\n"); #else LOGI("未找到 sd-ext。跳过对 sd-ext 的备份。\n"); #endif } else { if (0 != ensure_path_mounted("/sd-ext")) #ifndef USE_CHINESE_FONT LOGI("Could not mount sd-ext. sd-ext backup may not be supported on this device. Skipping backup of sd-ext.\n"); #else LOGI("无法挂载 sd-ext。此设备可能不支持对 sd-ext 进行备份,跳过对sd-ext的备份。\n"); #endif else if (0 != (ret = nandroid_backup_partition(backup_path, "/sd-ext"))) return ret; }
static void build_configuration_path(char *path_buf, const char *file) { sprintf(path_buf, "%s%s%s", get_primary_storage_path(), (is_data_media() ? "/0/" : "/"), file); }
static int tar_gzip_compress_wrapper(const char* backup_path, const char* backup_file_image, int callback) { char tmp[PATH_MAX]; sprintf(tmp, "cd $(dirname %s) ; touch %s.tar.gz ; (tar cv --exclude=data/data/com.google.android.music/files/* %s $(basename %s) | pigz -c | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.gz.) 2> /proc/self/fd/1 ; exit $?", backup_path, backup_file_image, strcmp(backup_path, "/data") == 0 && is_data_media() ? "--exclude 'media'" : "", backup_path, backup_file_image); return do_tar_compress(tmp, callback); }
int nandroid_backup(const char* backup_path) { ui_set_background(BACKGROUND_ICON_INSTALLING); 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) { if (strstr(backup_path, "/sdcard") == backup_path && is_data_media()) volume = volume_for_path("/data"); else return print_and_error("Unable to find volume for backup path.\n"); } 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]; sprintf(tmp, "mkdir -p %s", backup_path); __system(tmp); if (0 != (ret = nandroid_backup_partition(backup_path, "/boot"))) 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 (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; } sync(); ui_set_background(BACKGROUND_ICON_NONE); ui_reset_progress(); ui_print("\nBackup complete!\n"); return 0; }
static int tar_compress_wrapper(const char* backup_path, const char* backup_file_image, int callback) { char tmp[PATH_MAX]; sprintf(tmp, "cd $(dirname %s) ; touch %s.tar ; (tar cv %s $(basename %s) | split -a 1 -b 1000000000 /proc/self/fd/0 %s.tar.) 2> /proc/self/fd/1 ; exit $?", backup_path, backup_file_image, strcmp(backup_path, "/data") == 0 && is_data_media() ? "--exclude 'media'" : "", backup_path, backup_file_image); FILE *fp = __popen(tmp, "r"); if (fp == NULL) { ui_print("Unable to execute tar.\n"); return -1; } while (fgets(tmp, PATH_MAX, fp) != NULL) { tmp[PATH_MAX - 1] = NULL; if (callback) nandroid_callback(tmp); } return __pclose(fp); }
static int tar_dump_wrapper(const char* backup_path, const char* backup_file_image, int callback) { char tmp[PATH_MAX]; sprintf(tmp, "cd $(dirname %s); tar cv --exclude=data/data/com.google.android.music/files/* %s $(basename %s) 2> /dev/null | cat", backup_path, strcmp(backup_path, "/data") == 0 && is_data_media() ? "--exclude 'media'" : "", backup_path); return __system(tmp); }
int format_volume(const char* volume, bool force) { if (strcmp(volume, "media") == 0) { if (!is_data_media()) { return 0; } if (ensure_path_mounted("/data") != 0) { LOGE("format_volume failed to mount /data\n"); return -1; } int rc = 0; rc = rmtree_except("/data/media", NULL); ensure_path_unmounted("/data"); return rc; } fstab_rec* 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 (strcmp(volume, "/data") == 0 && is_data_media() && !force) { if (ensure_path_mounted("/data") == 0) { // Preserve .layout_version to avoid "nesting bug" LOGI("Preserving layout version\n"); unsigned char layout_buf[256]; ssize_t layout_buflen = -1; int fd; fd = open("/data/.layout_version", O_RDONLY); if (fd != -1) { layout_buflen = read(fd, layout_buf, sizeof(layout_buf)); close(fd); } int rc = rmtree_except("/data", "media"); // Restore .layout_version if (layout_buflen > 0) { LOGI("Restoring layout version\n"); fd = open("/data/.layout_version", O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd != -1) { write(fd, layout_buf, layout_buflen); close(fd); } } ensure_path_unmounted(volume); return rc; } LOGE("format_volume failed to mount /data, formatting instead\n"); } if (ensure_path_unmounted(volume) != 0) { LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point); return -1; } // Only use vold format for exact matches otherwise /sdcard will be // formatted instead of /storage/sdcard0/.android_secure if (fs_mgr_is_voldmanaged(v) && strcmp(volume, v->mount_point) == 0) { if (ensure_path_unmounted(volume) != 0) { LOGE("format_volume failed to unmount %s", v->mount_point); } return vold_format_volume(v->mount_point, 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->blk_device); if (partition == NULL) { LOGE("format_volume: no MTD partition \"%s\"\n", v->blk_device); return -1; } MtdWriteContext *write = mtd_write_partition(partition); if (write == NULL) { LOGW("format_volume: can't open MTD \"%s\"\n", v->blk_device); return -1; } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { LOGW("format_volume: can't erase MTD \"%s\"\n", v->blk_device); mtd_write_close(write); return -1; } else if (mtd_write_close(write)) { LOGW("format_volume: can't close MTD \"%s\"\n", v->blk_device); return -1; } return 0; } if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "f2fs") == 0) { // if there's a key_loc that looks like a path, it should be a // block device for storing encryption metadata. wipe it too. if (v->key_loc != NULL && v->key_loc[0] == '/') { LOGI("wiping %s\n", v->key_loc); int fd = open(v->key_loc, O_WRONLY | O_CREAT, 0644); if (fd < 0) { LOGE("format_volume: failed to open %s\n", v->key_loc); return -1; } wipe_block_device(fd, get_file_size(fd)); close(fd); } ssize_t length = 0; if (v->length != 0) { length = v->length; } else if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0) { length = -CRYPT_FOOTER_OFFSET; } int result; if (strcmp(v->fs_type, "ext4") == 0) { result = make_ext4fs(v->blk_device, length, volume, sehandle); } else { /* Has to be f2fs because we checked earlier. */ char bytes_reserved[10] = {0}; if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0) { snprintf(bytes_reserved, sizeof(bytes_reserved), "%d", CRYPT_FOOTER_OFFSET); } char *num_sectors; if (asprintf(&num_sectors, "%zd", length / 512) <= 0) { LOGE("format_volume: failed to create %s command for %s\n", v->fs_type, v->blk_device); return -1; } const char *f2fs_path = "/sbin/mkfs.f2fs"; const char* const f2fs_argv[] = {"mkfs.f2fs", "-t", "-d1", "-r", bytes_reserved, v->blk_device, num_sectors, NULL}; result = exec_cmd(f2fs_path, (char* const*)f2fs_argv); free(num_sectors); } if (result != 0) { LOGE("format_volume: make %s failed on %s with %d(%s)\n", v->fs_type, v->blk_device, result, strerror(errno)); return -1; } return 0; } LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; }
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("找不到默认\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.镜像没找到,因此跳过该处恢复. %s.\n", name, mount_point); return 0; } else { printf("找到新的可恢复镜像: %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("正在恢复 %s...\n", name); if (backup_filesystem == NULL) { if (0 != (ret = format_volume(mount_point))) { ui_print("格式化下列分区失败 %s!\n", mount_point); return ret; } } else if (0 != (ret = format_device(device, mount_point, backup_filesystem))) { 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 (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("找不到合适的方案\n"); return -2; } if (0 != (ret = restore_handler(tmp, mount_point, callback))) { ui_print("恢复失败: %s!\n", mount_point); return ret; } if (umount_when_finished) { ensure_path_unmounted(mount_point); } return 0; }
void wipe_data(int confirm) { if (confirm) { static char** title_headers = NULL; if (title_headers == NULL) { char* headers[] = { "Confirm wipe of all user data?", " THIS CAN NOT BE UNDONE.", "", NULL }; title_headers = prepend_title((const char**)headers); } char* items[] = { " No", #if TARGET_BOOTLOADER_BOARD_NAME == otter " Yes -- delete all user data", // [1] #else " No", " No", " No", " No", " No", " No", " Yes -- delete all user data", // [7] " No", " No", " No", #endif NULL }; int chosen_item = get_menu_selection(title_headers, items, 1, 0); #if TARGET_BOOTLOADER_BOARD_NAME == otter if (chosen_item != 1) { #else if (chosen_itme != 7) { #endif return; } } ui_print("\n-- Wiping data...\n"); device_wipe_data(); erase_volume("/data"); erase_volume("/cache"); if (has_datadata()) { erase_volume("/datadata"); } #if TARGET_BOOTLOADER_BOARD_NAME != otter // ToDo: make this check for the partition rather then the device erase_volume("/sd-ext"); #endif erase_volume("/sdcard/.android_secure"); ui_print("%s\n", datawipecomplete); } void erase_cache(int orscallback) { if(orscallback) { if(orswipeprompt && !confirm_selection("Confirm wipe?","Yes - Wipe Cache")) { ui_print("Skipping cache wipe...\n"); return; } } else if (!confirm_selection("Confirm wipe?", "Yes - Wipe Cache")) { return; } ui_print("\n-- Wiping cache...\n"); erase_volume("/cache"); ui_print("%s\n", cachewipecomplete); if (!ui_text_visible()) return; } void erase_dalvik_cache(int orscallback) { if(orscallback) { if(orswipeprompt && !confirm_selection("Confirm wipe?", "Yes - Wipe Dalvik Cache")) { ui_print("Skipping dalvik cache wipe...\n"); return; } } else if (!confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache")) { return; } if (0 != ensure_path_mounted("/data")) { return; } #if TARGET_BOOTLOADER_BOARD_NAME != otter ensure_path_mounted("/sd-ext"); #endif ensure_path_mounted("/cache"); __system("rm -r /data/dalvik-cache"); __system("rm -r /cache/dalvik-cache"); #if TARGET_BOOTLOADER_BOARD_NAME != otter __system("rm -r /sd-ext/dalvik-cache"); #endif ui_print("Dalvik Cache wiped.\n"); ensure_path_unmounted("/data"); } void wipe_all(int orscallback) { if(orscallback) { if(orswipeprompt && !confirm_selection("Confirm wipe all?", "Yes - Wipe All")) { ui_print("Skipping full wipe...\n"); return; } } else if (!confirm_selection("Confirm wipe all?", "Yes - Wipe All")) { return; } ui_print("\n-- Wiping system, data, cache...\n"); erase_volume("/system"); erase_volume("/data"); erase_volume("/cache"); ui_print("\nFull wipe complete!\n"); if (!ui_text_visible()) return; } int format_device(const char *device, const char *path, const char *fs_type) { 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 format_unknown_device(NULL, path, NULL); } // silent failure for sd-ext if (strcmp(path, "/sd-ext") == 0) return -1; LOGE("unknown volume \"%s\"\n", path); return -1; } 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); }
static int dedupe_compress_wrapper(const char* backup_path, const char* backup_file_image, int callback) { char tmp[PATH_MAX]; char blob_dir[PATH_MAX]; strcpy(blob_dir, backup_file_image); char *d = dirname(blob_dir); strcpy(blob_dir, d); d = dirname(blob_dir); strcpy(blob_dir, d); d = dirname(blob_dir); strcpy(blob_dir, d); strcat(blob_dir, "/blobs"); ensure_directory(blob_dir); if (!(nandroid_backup_bitfield & NANDROID_FIELD_DEDUPE_CLEARED_SPACE)) { nandroid_backup_bitfield |= NANDROID_FIELD_DEDUPE_CLEARED_SPACE; nandroid_dedupe_gc(blob_dir); } sprintf(tmp, "dedupe c %s %s %s.dup %s", backup_path, blob_dir, backup_file_image, strcmp(backup_path, "/data") == 0 && is_data_media() ? "./media" : ""); FILE *fp = __popen(tmp, "r"); if (fp == NULL) { ui_print("Unable to execute dedupe.\n"); return -1; } while (fgets(tmp, PATH_MAX, fp) != NULL) { tmp[PATH_MAX - 1] = NULL; if (callback) nandroid_callback(tmp); } return __pclose(fp); }
int format_volume(const char* volume) { Volume* v = volume_for_path(volume); if (v == NULL) { // silent failure for sd-ext if (strcmp(volume, "/sd-ext") == 0) return -1; LOGE("unknown volume \"%s\"\n", volume); return -1; } if (is_data_media_volume_path(volume)) { return format_unknown_device(NULL, volume, NULL); } // check to see if /data is being formatted, and if it is /data/media // Note: the /sdcard check is redundant probably, just being safe. if (strstr(volume, "/data") == volume && is_data_media() && !handle_data_media) { return format_unknown_device(NULL, volume, NULL); } 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) { #if 0 LOGE("can't give path \"%s\" to format_volume\n", volume); return -1; #endif return format_unknown_device(v->device, volume, NULL); } 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) { int result = make_ext4fs(v->device, v->length, volume, sehandle); if (result != 0) { LOGE("format_volume: make_extf4fs failed on %s\n", v->device); return -1; } return 0; } #if 0 LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; #endif return format_unknown_device(v->device, volume, v->fs_type); }
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 (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 old .img format\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); ui_print("No %s backup found(img, tar, dup). 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; compute_archive_stats(tmp); 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); 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; }
int main(int argc, char **argv) { time_t start = time(NULL); // If this binary is started with the single argument "--adbd", // instead of being the normal recovery binary, it turns into kind // of a stripped-down version of adbd that only supports the // 'sideload' command. Note this must be a real argument, not // anything in the command file or bootloader control block; the // only way recovery should be run with this argument is when it // starts a copy of itself from the apply_from_adb() function. if (argc == 2 && strcmp(argv[1], "--adbd") == 0) { adb_main(); return 0; } // Handle alternative invocations 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 (strstr(argv[0], "start")) { property_set("ctl.start", argv[1]); return 0; } if (strstr(argv[0], "stop")) { property_set("ctl.stop", argv[1]); return 0; } return busybox_driver(argc, argv); } // devices can run specific tasks on recovery start __system("/sbin/postrecoveryboot.sh"); // Clear umask for packages that copy files out to /tmp and then over // to /system without properly setting all permissions (eg. gapps). umask(0); // 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)); load_volume_table(); setup_data_media(1); vold_client_start(&v_callbacks, 0); vold_set_automount(1); setup_legacy_storage_paths(); ensure_path_mounted(LAST_LOG_FILE); rotate_last_logs(10); get_args(&argc, &argv); const char *send_intent = NULL; const char *update_package = NULL; int wipe_data = 0, wipe_cache = 0, wipe_media = 0, show_text = 0, sideload = 0; bool just_exit = false; bool shutdown_after = false; printf("Checking arguments.\n"); int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { switch (arg) { case 's': send_intent = optarg; break; case 'u': update_package = optarg; break; case 'w': wipe_data = wipe_cache = 1; break; case 'm': wipe_media = 1; break; case 'c': wipe_cache = 1; break; case 't': show_text = 1; break; case 'x': just_exit = true; break; case 'a': sideload = 1; break; case 'p': shutdown_after = true; break; case 'g': { if (stage == NULL || *stage == '\0') { char buffer[20] = "1/"; strncat(buffer, optarg, sizeof(buffer)-3); stage = strdup(buffer); } break; } case '?': LOGE("Invalid command argument\n"); continue; } } printf("stage is [%s]\n", stage); device_ui_init(&ui_parameters); ui_init(); ui_print(EXPAND(RECOVERY_MOD_VERSION_BUILD) "\n"); ui_print("ClockworkMod " EXPAND(CWM_BASE_VERSION) "\n"); LOGI("Device target: " EXPAND(TARGET_COMMON_NAME) "\n"); #ifdef PHILZ_TOUCH_RECOVERY print_libtouch_version(0); #endif int st_cur, st_max; if (stage != NULL && sscanf(stage, "%d/%d", &st_cur, &st_max) == 2) { ui_SetStage(st_cur, st_max); } // ui_SetStage(5, 8); // debug if (show_text) ui_ShowText(true); struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "/file_contexts" } }; sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { 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 = (char*)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.\n"); } } if (status != INSTALL_SUCCESS) { ui_print("Installation aborted.\n"); // If this is an eng or userdebug build, then automatically // turn the text display on if the script fails so the error // message is visible. char buffer[PROPERTY_VALUE_MAX+1]; property_get("ro.build.fingerprint", buffer, ""); if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) { ui_ShowText(true); } } } 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 if (wipe_media) { if (is_data_media() && erase_volume("/data/media")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui_print("Media wipe failed.\n"); } else if (sideload) { status = enter_sideload_mode(status); } else if (!just_exit) { // let's check recovery start up scripts (openrecoveryscript and ROM Manager extendedcommands) status = INSTALL_NONE; // No command specified, it is a normal recovery boot unless we find a boot script to run LOGI("Checking for extendedcommand & OpenRecoveryScript...\n"); // we need show_text to show boot scripts log bool text_visible = ui_IsTextVisible(); ui_SetShowText(true); if (0 == check_boot_script_file(EXTENDEDCOMMAND_SCRIPT)) { LOGI("Running extendedcommand...\n"); status = INSTALL_ERROR; if (0 == run_and_remove_extendedcommand()) status = INSTALL_SUCCESS; } if (0 == check_boot_script_file(ORS_BOOT_SCRIPT_FILE)) { LOGI("Running openrecoveryscript....\n"); status = INSTALL_ERROR; if (0 == run_ors_boot_script()) status = INSTALL_SUCCESS; } ui_SetShowText(text_visible); } if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) { copy_logs(); // ui_set_background(BACKGROUND_ICON_ERROR); // will be set in prompt_and_wait() after recovery lock check handle_failure(); } if (status != INSTALL_SUCCESS || ui_IsTextVisible()) { ui_SetShowText(true); #ifdef PHILZ_TOUCH_RECOVERY check_recovery_lock(); #endif prompt_and_wait(status); } // We reach here when in main menu we choose reboot main system or on success install of boot scripts and recovery commands finish_recovery(send_intent); if (shutdown_after) { ui_print("Shutting down...\n"); reboot_main_system(ANDROID_RB_POWEROFF, 0, 0); } else { ui_print("Rebooting...\n"); reboot_main_system(ANDROID_RB_RESTART, 0, 0); } return EXIT_SUCCESS; }
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); }
int ensure_path_mounted(const char* path) { Volume* v = volume_for_path(path); if (v == NULL) { // no /sdcard? let's assume /data/media if (strstr(path, "/sdcard") == path && is_data_media()) { LOGW("using /data/media, no /sdcard found.\n"); int ret; if (0 != (ret = ensure_path_mounted("/data"))) return ret; setup_data_media(); return 0; } LOGE("unknown volume for path [%s]\n", path); return -1; } if (strcmp(v->fs_type, "ramdisk") == 0) { // the ramdisk is always mounted. return 0; } 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) { // volume is already mounted return 0; } mkdir(v->mount_point, 0755); // in case it doesn't already exist if (strcmp(v->fs_type, "yaffs2") == 0) { // mount an MTD partition as a YAFFS2 filesystem. mtd_scan_partitions(); const MtdPartition* partition; partition = mtd_find_partition_by_name(v->device); if (partition == NULL) { LOGE("failed to find \"%s\" partition to mount at \"%s\"\n", v->device, v->mount_point); return -1; } return mtd_mount_partition(partition, v->mount_point, v->fs_type, 0); } else if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "ext3") == 0 || strcmp(v->fs_type, "rfs") == 0 || strcmp(v->fs_type, "vfat") == 0) { if ((result = try_mount(v->device, v->mount_point, v->fs_type, v->fs_options)) == 0) return 0; if ((result = try_mount(v->device2, v->mount_point, v->fs_type, v->fs_options)) == 0) return 0; if ((result = try_mount(v->device, v->mount_point, v->fs_type2, v->fs_options2)) == 0) return 0; if ((result = try_mount(v->device2, v->mount_point, v->fs_type2, v->fs_options2)) == 0) return 0; return result; } else { // let's try mounting with the mount binary and hope for the best. char mount_cmd[PATH_MAX]; sprintf(mount_cmd, "mount %s", path); return __system(mount_cmd); } LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, v->mount_point); return -1; }
void write_recovery_version() { if ( is_data_media() ) { write_string_to_file("/sdcard/0/clockworkmod/.recovery_version",EXPAND(RECOVERY_VERSION) "\n" EXPAND(TARGET_DEVICE)); } write_string_to_file("/sdcard/clockworkmod/.recovery_version",EXPAND(RECOVERY_VERSION) "\n" EXPAND(TARGET_DEVICE)); }
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; if (is_data_media_volume_path(backup_path)) volume = volume_for_path("/data"); else volume = volume_for_path(backup_path); if (NULL == volume) return print_and_error("Unable to find volume for backup path.\n"); int ret; struct statfs sfs; struct stat s; if (NULL != volume) { if (0 != (ret = statfs(volume->mount_point, &sfs))) return print_and_error("Unable to stat backup path.\n"); uint64_t bavail = sfs.f_bavail; uint64_t bsize = sfs.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, "/recovery"))) return ret; Volume *vol = volume_for_path("/wimax"); if (vol != NULL && 0 == stat(vol->blk_device, &s)) { char serialno[PROPERTY_VALUE_MAX]; ui_print("正在备份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->blk_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 (volume_for_path("/preload") != NULL) { if (0 != (ret = nandroid_backup_partition(backup_path, "/preload"))) 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(get_android_secure_path(), &s)) { ui_print("没发现.android_secure目录. 跳过备份安装到扩展卡上的程序.\n"); } else { if (0 != (ret = nandroid_backup_partition_extended(backup_path, get_android_secure_path(), 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->blk_device, &s)) { LOGI("没有sd-ext分区. 跳过.\n"); } else { if (0 != ensure_path_mounted("/sd-ext")) LOGI("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("创建md5校验文件...\n"); sprintf(tmp, "nandroid-md5.sh %s", backup_path); if (0 != (ret = __system(tmp))) { ui_print("创建md5校验文件出错!\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("\n备份完毕!\n"); return 0; }