int erase_persistent_partition() { Volume *v = volume_for_path(PERSISTENT_PATH); if (v == NULL) { // most devices won't have /persistent, so this is not an error. return 0; } int fd = open(v->blk_device, O_RDWR); uint64_t size = get_file_size(fd); if (size == 0) { LOGE("failed to stat size of /persistent\n"); close(fd); return -1; } char oem_unlock_enabled; lseek(fd, size - 1, SEEK_SET); read(fd, &oem_unlock_enabled, 1); if (oem_unlock_enabled) { if (wipe_block_device(fd, size)) { LOGE("error wiping /persistent: %s\n", strerror(errno)); close(fd); return -1; } lseek(fd, size - 1, SEEK_SET); write(fd, &oem_unlock_enabled, 1); } close(fd); return (int) oem_unlock_enabled; }
int flash_erase(int fd) { int64_t size; size = get_block_device_size(fd); D(DEBUG, "erase %"PRId64" data from %d\n", size, fd); return wipe_block_device(fd, size); }
int main(int argc, char *argv[]) { int secure = 0; char *devname; int fd; u64 len; struct stat statbuf; int ret; if ((argc != 2) && (argc != 3)) { usage(); } if (argc == 3) { if (!strcmp(argv[1], "-s")) { secure = 1; devname = argv[2]; } else { usage(); } } else { devname = argv[1]; } fd = open(devname, O_RDWR); if (fd < 0) { fprintf(stderr, "Cannot open device %s\n", devname); exit(1); } if (fstat(fd, &statbuf) < 0) { fprintf(stderr, "Cannot stat %s\n", devname); exit(1); } if (!S_ISBLK(statbuf.st_mode)) { fprintf(stderr, "%s is not a block device\n", devname); exit(1); } len = get_block_device_size(fd); if (! len) { fprintf(stderr, "Cannot get size of block device %s\n", devname); exit(1); } ret = wipe_block_device(fd, len, secure); close(fd); return ret; }
static int com_android_server_PersistentDataBlockService_wipe(JNIEnv *env, jclass, jstring jpath) { ScopedUtfChars path(env, jpath); int fd = open(path.c_str(), O_WRONLY); if (fd < 0) return 0; const int ret = wipe_block_device(fd); close(fd); return ret; }
int erase_usercalibration_partition() { Volume *v = volume_for_path(USERCALIB_PATH); if (v == NULL) { // most devices won't have /mnt/usercalib, so this is not an error. return 0; } int fd = open(v->blk_device, O_RDWR); uint64_t size = get_file_size(fd); if (size != 0) { if (wipe_block_device(fd, size)) { LOGE("error wiping /mnt/usercalib: %s\n", strerror(errno)); close(fd); return -1; } } close(fd); return 0; }
int make_ext4fs_internal(int fd, const char *directory, char *mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse, int crc, int wipe, int init_itabs, struct selabel_handle *sehnd) { u32 root_inode_num; u16 root_mode; if (setjmp(setjmp_env)) return EXIT_FAILURE; /* Handle a call to longjmp() */ if (info.len <= 0) info.len = get_file_size(fd); if (info.len <= 0) { fprintf(stderr, "Need size of filesystem\n"); return EXIT_FAILURE; } if (info.block_size <= 0) info.block_size = compute_block_size(); /* Round down the filesystem length to be a multiple of the block size */ info.len &= ~((u64)info.block_size - 1); if (info.journal_blocks == 0) info.journal_blocks = compute_journal_blocks(); if (info.no_journal == 0) info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL; else info.journal_blocks = 0; if (info.blocks_per_group <= 0) info.blocks_per_group = compute_blocks_per_group(); if (info.inodes <= 0) info.inodes = compute_inodes(); if (info.inode_size <= 0) info.inode_size = 256; if (info.label == NULL) info.label = ""; info.inodes_per_group = compute_inodes_per_group(); info.feat_compat |= EXT4_FEATURE_COMPAT_RESIZE_INODE; info.feat_ro_compat |= EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | EXT4_FEATURE_RO_COMPAT_LARGE_FILE; info.feat_incompat |= EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_FILETYPE; info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks(); printf("Creating filesystem with parameters:\n"); printf(" Size: %llu\n", info.len); printf(" Block size: %d\n", info.block_size); printf(" Blocks per group: %d\n", info.blocks_per_group); printf(" Inodes per group: %d\n", info.inodes_per_group); printf(" Inode size: %d\n", info.inode_size); printf(" Journal blocks: %d\n", info.journal_blocks); printf(" Label: %s\n", info.label); ext4_create_fs_aux_info(); printf(" Blocks: %llu\n", aux_info.len_blocks); printf(" Block groups: %d\n", aux_info.groups); printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks); info.sparse_file = sparse_file_new(info.block_size, info.len); block_allocator_init(); ext4_fill_in_sb(); MTK_add_mountpoint(aux_info.sb,mountpoint); if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED) error("failed to reserve first 10 inodes"); if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL) ext4_create_journal_inode(); if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE) ext4_create_resize_inode(); #ifdef USE_MINGW // Windows needs only 'create an empty fs image' functionality assert(!directory); root_inode_num = build_default_directory_structure(); #else if (directory) root_inode_num = build_directory_structure(directory, mountpoint, 0, fs_config_func, sehnd); else root_inode_num = build_default_directory_structure(); #endif root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; inode_set_permissions(root_inode_num, root_mode, 0, 0, 0); #ifdef HAVE_SELINUX if (sehnd) { char *sepath = NULL; char *secontext = NULL; if (mountpoint[0] == '/') sepath = strdup(mountpoint); else asprintf(&sepath, "/%s", mountpoint); if (!sepath) critical_error_errno("malloc"); if (selabel_lookup(sehnd, &secontext, sepath, S_IFDIR) < 0) { error("cannot lookup security context for %s", sepath); } if (secontext) { printf("Labeling %s as %s\n", sepath, secontext); inode_set_selinux(root_inode_num, secontext); } free(sepath); freecon(secontext); } #endif ext4_update_free(); if (init_itabs) init_unused_inode_tables(); ext4_queue_sb(); printf("Created filesystem with %d/%d inodes and %d/%d blocks\n", aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, aux_info.sb->s_inodes_count, aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, aux_info.sb->s_blocks_count_lo); if (wipe) wipe_block_device(fd, info.len); write_ext4_image(fd, gzip, sparse, crc); sparse_file_destroy(info.sparse_file); info.sparse_file = NULL; return 0; }
int make_ext4fs_internal(int fd, const char *_directory, fs_config_func_t fs_config_func, int gzip, int sparse, int crc, int wipe, int verbose, time_t fixed_time, FILE* block_list_file) { u32 root_inode_num; u16 root_mode; char *directory = NULL; if (setjmp(setjmp_env)) return EXIT_FAILURE; /* Handle a call to longjmp() */ if (_directory == NULL) { fprintf(stderr, "Need a source directory\n"); return EXIT_FAILURE; } directory = canonicalize_rel_slashes(_directory); if (info.len <= 0) info.len = get_file_size(fd); if (info.len <= 0) { fprintf(stderr, "Need size of filesystem\n"); return EXIT_FAILURE; } if (info.block_size <= 0) info.block_size = compute_block_size(); /* Round down the filesystem length to be a multiple of the block size */ info.len &= ~((u64)info.block_size - 1); if (info.journal_blocks == 0) info.journal_blocks = compute_journal_blocks(); if (info.no_journal == 0) info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL; else info.journal_blocks = 0; if (info.blocks_per_group <= 0) info.blocks_per_group = compute_blocks_per_group(); if (info.inodes <= 0) info.inodes = compute_inodes(); if (info.inode_size <= 0) info.inode_size = 256; if (info.label == NULL) info.label = ""; info.inodes_per_group = compute_inodes_per_group(); info.feat_compat |= EXT4_FEATURE_COMPAT_RESIZE_INODE | EXT4_FEATURE_COMPAT_EXT_ATTR; info.feat_ro_compat |= EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | EXT4_FEATURE_RO_COMPAT_LARGE_FILE | EXT4_FEATURE_RO_COMPAT_GDT_CSUM; info.feat_incompat |= EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_FILETYPE; info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks(); printf("Creating filesystem with parameters:\n"); printf(" Size: %"PRIu64"\n", info.len); printf(" Block size: %d\n", info.block_size); printf(" Blocks per group: %d\n", info.blocks_per_group); printf(" Inodes per group: %d\n", info.inodes_per_group); printf(" Inode size: %d\n", info.inode_size); printf(" Journal blocks: %d\n", info.journal_blocks); printf(" Label: %s\n", info.label); ext4_create_fs_aux_info(); printf(" Blocks: %"PRIu64"\n", aux_info.len_blocks); printf(" Block groups: %d\n", aux_info.groups); printf(" Reserved blocks: %"PRIu64"\n", (aux_info.len_blocks / 100) * info.reserve_pcnt); printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks); ext4_sparse_file = sparse_file_new(info.block_size, info.len); block_allocator_init(); ext4_fill_in_sb(); if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED) error("failed to reserve first 10 inodes"); if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL) ext4_create_journal_inode(); if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE) ext4_create_resize_inode(); root_inode_num = build_directory_structure(directory, "", 0, fs_config_func, verbose, fixed_time); root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; inode_set_permissions(root_inode_num, root_mode, 0, 0, 0); ext4_update_free(); ext4_queue_sb(); if (block_list_file) { size_t dirlen = strlen(directory); struct block_allocation* p = get_saved_allocation_chain(); while (p) { if (strncmp(p->filename, directory, dirlen) == 0) { fprintf(block_list_file, "%s", p->filename + dirlen); } else { fprintf(block_list_file, "%s", p->filename); } print_blocks(block_list_file, p); struct block_allocation* pn = p->next; free_alloc(p); p = pn; } } printf("Created filesystem with %d/%d inodes and %d/%d blocks\n", aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, aux_info.sb->s_inodes_count, aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, aux_info.sb->s_blocks_count_lo); if (wipe && WIPE_IS_SUPPORTED) { wipe_block_device(fd, info.len); } write_ext4_image(fd, gzip, sparse, crc); sparse_file_destroy(ext4_sparse_file); ext4_sparse_file = NULL; free(directory); return 0; }
/* When multiple fstab records share the same mount_point, it will * try to mount each one in turn, and ignore any duplicates after a * first successful mount. * Returns -1 on error, and FS_MGR_MNTALL_* otherwise. */ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode) { int i = 0; int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE; int error_count = 0; int mret = -1; int mount_errno = 0; int attempted_idx = -1; if (!fstab) { return -1; } for (i = 0; i < fstab->num_entries; i++) { /* Don't mount entries that are managed by vold or not for the mount mode*/ if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) || ((mount_mode == MOUNT_MODE_LATE) && !fs_mgr_is_latemount(&fstab->recs[i])) || ((mount_mode == MOUNT_MODE_EARLY) && fs_mgr_is_latemount(&fstab->recs[i]))) { continue; } /* Skip swap and raw partition entries such as boot, recovery, etc */ if (!strcmp(fstab->recs[i].fs_type, "swap") || !strcmp(fstab->recs[i].fs_type, "emmc") || !strcmp(fstab->recs[i].fs_type, "mtd")) { continue; } /* Skip mounting the root partition, as it will already have been mounted */ if (!strcmp(fstab->recs[i].mount_point, "/")) { if ((fstab->recs[i].fs_mgr_flags & MS_RDONLY) != 0) { fs_mgr_set_blk_ro(fstab->recs[i].blk_device); } continue; } /* Translate LABEL= file system labels into block devices */ if (!strcmp(fstab->recs[i].fs_type, "ext2") || !strcmp(fstab->recs[i].fs_type, "ext3") || !strcmp(fstab->recs[i].fs_type, "ext4")) { int tret = translate_ext_labels(&fstab->recs[i]); if (tret < 0) { ERROR("Could not translate label to block device\n"); continue; } } if (fstab->recs[i].fs_mgr_flags & MF_WAIT) { wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT); } if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) { int rc = fs_mgr_setup_verity(&fstab->recs[i]); if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { INFO("Verity disabled"); } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) { ERROR("Could not set up verified partition, skipping!\n"); continue; } } int last_idx_inspected; int top_idx = i; mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx); i = last_idx_inspected; mount_errno = errno; /* Deal with encryptability. */ if (!mret) { int status = handle_encryptable(&fstab->recs[attempted_idx]); if (status == FS_MGR_MNTALL_FAIL) { /* Fatal error - no point continuing */ return status; } if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) { if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) { // Log and continue ERROR("Only one encryptable/encrypted partition supported\n"); } encryptable = status; } /* Success! Go get the next one */ continue; } /* mount(2) returned an error, handle the encryptable/formattable case */ bool wiped = partition_wiped(fstab->recs[top_idx].blk_device); bool crypt_footer = false; if (mret && mount_errno != EBUSY && mount_errno != EACCES && fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) { /* top_idx and attempted_idx point at the same partition, but sometimes * at two different lines in the fstab. Use the top one for formatting * as that is the preferred one. */ ERROR("%s(): %s is wiped and %s %s is formattable. Format it.\n", __func__, fstab->recs[top_idx].blk_device, fstab->recs[top_idx].mount_point, fstab->recs[top_idx].fs_type); if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) && strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) { int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY); if (fd >= 0) { INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc); wipe_block_device(fd, get_file_size(fd)); close(fd); } else { ERROR("%s(): %s wouldn't open (%s)\n", __func__, fstab->recs[top_idx].key_loc, strerror(errno)); } } else if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) && !strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) { crypt_footer = true; } if (fs_mgr_do_format(&fstab->recs[top_idx], crypt_footer) == 0) { /* Let's replay the mount actions. */ i = top_idx - 1; continue; } else { ERROR("%s(): Format failed. Suggest recovery...\n", __func__); encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY; continue; } } if (mret && mount_errno != EBUSY && mount_errno != EACCES && fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) { if (wiped) { ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__, fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY; continue; } else { /* Need to mount a tmpfs at this mountpoint for now, and set * properties that vold will query later for decrypting */ ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__, fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) { ++error_count; continue; } } encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED; } else { if (fs_mgr_is_nofail(&fstab->recs[attempted_idx])) { ERROR("Ignoring failure to mount an un-encryptable or wiped partition on" "%s at %s options: %s error: %s\n", fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_options, strerror(mount_errno)); } else { ERROR("Failed to mount an un-encryptable or wiped partition on" "%s at %s options: %s error: %s\n", fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_options, strerror(mount_errno)); ++error_count; } continue; } } if (error_count) { return -1; } else { return encryptable; } }
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->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. */ if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0 && length < 0) { LOGE("format_volume: crypt footer + negative length (%zd) not supported on %s\n", length, v->fs_type); return -1; } if (length < 0) { LOGE("format_volume: negative length (%zd) not supported on %s\n", length, v->fs_type); return -1; } 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", 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; }
/* When multiple fstab records share the same mount_point, it will * try to mount each one in turn, and ignore any duplicates after a * first successful mount. * Returns -1 on error, and FS_MGR_MNTALL_* otherwise. */ int fs_mgr_mount_all(struct fstab *fstab) { int i = 0; int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED; int error_count = 0; int mret = -1; int mount_errno = 0; int attempted_idx = -1; if (!fstab) { return -1; } for (i = 0; i < fstab->num_entries; i++) { /* Don't mount entries that are managed by vold */ if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) { continue; } /* Skip swap and raw partition entries such as boot, recovery, etc */ if (!strcmp(fstab->recs[i].fs_type, "swap") || !strcmp(fstab->recs[i].fs_type, "emmc") || !strcmp(fstab->recs[i].fs_type, "mtd")) { continue; } if (fstab->recs[i].fs_mgr_flags & MF_WAIT) { wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT); } if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) { int rc = fs_mgr_setup_verity(&fstab->recs[i]); if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { INFO("Verity disabled"); } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) { ERROR("Could not set up verified partition, skipping!\n"); continue; } } int last_idx_inspected; int top_idx = i; mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx); i = last_idx_inspected; mount_errno = errno; /* Deal with encryptability. */ if (!mret) { /* If this is encryptable, need to trigger encryption */ if ( (fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT) || (device_is_force_encrypted() && fs_mgr_is_encryptable(&fstab->recs[attempted_idx]))) { if (umount(fstab->recs[attempted_idx].mount_point) == 0) { if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION; } else { ERROR("Only one encryptable/encrypted partition supported\n"); encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED; } } else { INFO("Could not umount %s - allow continue unencrypted\n", fstab->recs[attempted_idx].mount_point); continue; } } /* Success! Go get the next one */ continue; } /* mount(2) returned an error, handle the encryptable/formattable case */ bool wiped = partition_wiped(fstab->recs[top_idx].blk_device); if (mret && mount_errno != EBUSY && mount_errno != EACCES && fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) { /* top_idx and attempted_idx point at the same partition, but sometimes * at two different lines in the fstab. Use the top one for formatting * as that is the preferred one. */ ERROR("%s(): %s is wiped and %s %s is formattable. Format it.\n", __func__, fstab->recs[top_idx].blk_device, fstab->recs[top_idx].mount_point, fstab->recs[top_idx].fs_type); if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) && strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) { int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY, 0644); if (fd >= 0) { INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc); wipe_block_device(fd, get_file_size(fd)); close(fd); } else { ERROR("%s(): %s wouldn't open (%s)\n", __func__, fstab->recs[top_idx].key_loc, strerror(errno)); } } if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) { /* Let's replay the mount actions. */ i = top_idx - 1; continue; } } if (mret && mount_errno != EBUSY && mount_errno != EACCES && fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) { if (wiped) { ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__, fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY; continue; } else { /* Need to mount a tmpfs at this mountpoint for now, and set * properties that vold will query later for decrypting */ ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__, fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) { ++error_count; continue; } } encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED; } else { ERROR("Failed to mount an un-encryptable or wiped partition on" "%s at %s options: %s error: %s\n", fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_options, strerror(mount_errno)); ++error_count; continue; } } if (error_count) { return -1; } else { return encryptable; } }
int format_volume(const char* volume) { time_t start, end; start = time((time_t *)NULL); printf("format %s start=%u\n", volume, (unsigned int)start); #if defined(CACHE_MERGE_SUPPORT) char *target_volume = (char *)volume; if (strcmp(target_volume, "/cache") == 0) { // we cannot mount data since partition size changed // clear cache folder when data mounted if (part_size_changed) { LOGI("partition size changed, clear cache folder when data mounted...\n"); need_clear_cache = 1; // change format volume name to format actual cache partition target_volume = "/.cache"; } else { // clear DATA_CACHE_ROOT if (ensure_path_mounted(DATA_CACHE_ROOT) != 0) { LOGE("Can't mount %s while clearing cache!\n", DATA_CACHE_ROOT); return -1; } if (remove_dir(DATA_CACHE_ROOT)) { LOGE("remove_dir %s error: %s\n", DATA_CACHE_ROOT, strerror(errno)); return -1; } if (mkdir(DATA_CACHE_ROOT, 0770) != 0) { LOGE("Can't mkdir %s (%s)\n", DATA_CACHE_ROOT, strerror(errno)); return -1; } LOGI("format cache successfully!\n"); end = time((time_t *)NULL); printf("format end=%u duration=%u\n", (unsigned int)end, (unsigned int)(end - start)); return 0; } } Volume* v = volume_for_path(target_volume); if (v == NULL) { LOGE("unknown volume \"%s\"\n", target_volume); return -1; } if (strcmp(v->fs_type, "ramdisk") == 0) { // you can't format the ramdisk. LOGE("can't format_volume \"%s\"", target_volume); return -1; } if (strcmp(v->mount_point, target_volume) != 0) { LOGE("can't give path \"%s\" to format_volume\n", target_volume); return -1; } if (ensure_path_unmounted(target_volume) != 0) { LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point); return -1; } #else 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; } #endif #if defined (UBIFS_SUPPORT) if (strcmp(v->fs_type, "ubifs") == 0) { int ret; ret = ubi_format(v->mount_point); if (!ret) { end = time((time_t *)NULL); printf("format end=%u duration=%u\n", (unsigned int)end, (unsigned int)(end - start)); return 0; } else { LOGE("Ubiformat failed on \"%s\"\n", v->mount_point); } #if 0 int ret; //Remove volume if(ubi_rmvol_user(v->mount_point)!=0){ LOGE("failed to remove %s\n", v->blk_device); return -1; } //Make volume ret = ubi_mkvol_user(v->mount_point); if(!ret){ printf("%s volume made\n", v->blk_device); return 0; } #endif } #endif 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; } end = time((time_t *)NULL); printf("format end=%u duration=%u\n", (unsigned int)end, (unsigned int)(end - start)); return 0; } if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "f2fs") == 0) { if (!mt_is_support_gpt()) { #if defined(HAVE_ANDROID_OS) && !defined(ARCH_X86) //wschen 2012-07-10 int fd; struct msdc_ioctl msdc_io; fd = open("/dev/misc-sd", O_RDONLY); if (fd < 0) { LOGE("open: /dev/misc-sd failed\n"); return -1; } msdc_io.opcode = MSDC_ERASE_PARTITION; #if defined(CACHE_MERGE_SUPPORT) if (!strcmp(target_volume, "/.cache")) { msdc_io.buffer = (unsigned int*) "cache"; msdc_io.total_size = 6; } else if (!strcmp(target_volume, "/data")) { msdc_io.buffer = (unsigned int*) "usrdata"; msdc_io.total_size = 8; } #else if (!strcmp(volume, "/cache")) { msdc_io.buffer = (unsigned int*) "cache"; msdc_io.total_size = 6; } else if (!strcmp(volume, "/data")) { msdc_io.buffer = (unsigned int*) "usrdata"; msdc_io.total_size = 8; } #endif ioctl(fd, 0, &msdc_io); close(fd); #endif } // end of not support_gpt // 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); } #ifndef CRYPT_FOOTER_OFFSET #define CRYPT_FOOTER_OFFSET (0) #endif 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 = 0; if (strcmp(v->fs_type, "ext4") == 0) { #if defined(CACHE_MERGE_SUPPORT) result = make_ext4fs(v->blk_device, length, target_volume, sehandle); #else LOGE("Before make_ext4fs v->blk_device:%s length:%lld volume=%s\n", v->blk_device, length, volume); result = make_ext4fs(v->blk_device, length, volume, sehandle); #endif } else { /* Has to be f2fs because we checked earlier. */ if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0 && length < 0) { LOGE("format_volume: crypt footer + negative length (%zd) not supported on %s\n", length, v->fs_type); return -1; } if (length < 0) { LOGE("format_volume: negative length (%zd) not supported on %s\n", length, v->fs_type); return -1; } 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", 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; } end = time((time_t *)NULL); printf("format end=%u duration=%u\n", (unsigned int)end, (unsigned int)(end - start)); return 0; } LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; }
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 make_ext4fs_internal(int fd, const char *_directory, const char *_target_out_directory, const char *_mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse, int crc, int wipe, int real_uuid, struct selabel_handle *sehnd, int verbose, time_t fixed_time, FILE* block_list_file) { u32 root_inode_num; u16 root_mode; char *mountpoint; char *directory = NULL; char *target_out_directory = NULL; if (setjmp(setjmp_env)) return EXIT_FAILURE; /* Handle a call to longjmp() */ info.block_device = is_block_device_fd(fd); if (info.block_device && (sparse || gzip || crc)) { fprintf(stderr, "No sparse/gzip/crc allowed for block device\n"); return EXIT_FAILURE; } if (_mountpoint == NULL) { mountpoint = strdup(""); } else { mountpoint = canonicalize_abs_slashes(_mountpoint); } if (_directory) { directory = canonicalize_rel_slashes(_directory); } if (_target_out_directory) { target_out_directory = canonicalize_rel_slashes(_target_out_directory); } if (info.len <= 0) info.len = get_file_size(fd); if (info.len <= 0) { fprintf(stderr, "Need size of filesystem\n"); return EXIT_FAILURE; } if (info.block_size <= 0) info.block_size = compute_block_size(); /* Round down the filesystem length to be a multiple of the block size */ info.len &= ~((u64)info.block_size - 1); if (info.journal_blocks == 0) info.journal_blocks = compute_journal_blocks(); if (info.no_journal == 0) info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL; else info.journal_blocks = 0; if (info.blocks_per_group <= 0) info.blocks_per_group = compute_blocks_per_group(); if (info.inodes <= 0) info.inodes = compute_inodes(); if (info.inode_size <= 0) info.inode_size = 256; if (info.label == NULL) info.label = ""; info.inodes_per_group = compute_inodes_per_group(); info.feat_compat |= EXT4_FEATURE_COMPAT_RESIZE_INODE | EXT4_FEATURE_COMPAT_EXT_ATTR; info.feat_ro_compat |= EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | EXT4_FEATURE_RO_COMPAT_LARGE_FILE | EXT4_FEATURE_RO_COMPAT_GDT_CSUM; info.feat_incompat |= EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_FILETYPE; info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks(); printf("Creating filesystem with parameters:\n"); printf(" Size: %"PRIu64"\n", info.len); printf(" Block size: %d\n", info.block_size); printf(" Blocks per group: %d\n", info.blocks_per_group); printf(" Inodes per group: %d\n", info.inodes_per_group); printf(" Inode size: %d\n", info.inode_size); printf(" Journal blocks: %d\n", info.journal_blocks); printf(" Label: %s\n", info.label); ext4_create_fs_aux_info(); printf(" Blocks: %"PRIu64"\n", aux_info.len_blocks); printf(" Block groups: %d\n", aux_info.groups); printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks); ext4_sparse_file = sparse_file_new(info.block_size, info.len); block_allocator_init(); ext4_fill_in_sb(real_uuid); if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED) error("failed to reserve first 10 inodes"); if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL) ext4_create_journal_inode(); if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE) ext4_create_resize_inode(); #ifdef USE_MINGW // Windows needs only 'create an empty fs image' functionality assert(!directory); root_inode_num = build_default_directory_structure(mountpoint, sehnd); #else if (directory) root_inode_num = build_directory_structure(directory, mountpoint, target_out_directory, 0, fs_config_func, sehnd, verbose, fixed_time); else root_inode_num = build_default_directory_structure(mountpoint, sehnd); #endif root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; inode_set_permissions(root_inode_num, root_mode, 0, 0, 0); #ifndef USE_MINGW if (sehnd) { char *secontext = NULL; if (selabel_lookup(sehnd, &secontext, mountpoint, S_IFDIR) < 0) { error("cannot lookup security context for %s", mountpoint); } if (secontext) { if (verbose) { printf("Labeling %s as %s\n", mountpoint, secontext); } inode_set_selinux(root_inode_num, secontext); } freecon(secontext); } #endif ext4_update_free(); if (block_list_file) { size_t dirlen = directory ? strlen(directory) : 0; struct block_allocation* p = get_saved_allocation_chain(); while (p) { if (directory && strncmp(p->filename, directory, dirlen) == 0) { // substitute mountpoint for the leading directory in the filename, in the output file fprintf(block_list_file, "%s%s", mountpoint, p->filename + dirlen); } else { fprintf(block_list_file, "%s", p->filename); } print_blocks(block_list_file, p); struct block_allocation* pn = p->next; free_alloc(p); p = pn; } } printf("Created filesystem with %d/%d inodes and %d/%d blocks\n", aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, aux_info.sb->s_inodes_count, aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, aux_info.sb->s_blocks_count_lo); if (wipe && WIPE_IS_SUPPORTED) { wipe_block_device(fd, info.len); } write_ext4_image(fd, gzip, sparse, crc); sparse_file_destroy(ext4_sparse_file); ext4_sparse_file = NULL; free(mountpoint); free(directory); return 0; }