int ubifs_exist(const char *part_name) { const MtdPartition *partition; MtdReadContext *mtd_read; char buf[64] = {0}; __u32 *magic; mtd_scan_partitions(); partition = mtd_find_partition_by_name(part_name); if (partition == NULL) { fprintf(stderr,"1. failed to find \"%s\" partition\n", part_name); return 0; } mtd_read = mtd_read_partition(partition); if (mtd_read == NULL) { fprintf(stderr,"2. failed to open \"%s\" partition\n", part_name); return 0; } if (64 != mtd_read_data(mtd_read, buf, 64)) { fprintf(stderr,"3. failed to read \"%s\" partition\n", part_name); mtd_read_close(mtd_read); return 0; } mtd_read_close(mtd_read); magic = (__u32 *)buf; if (*magic == UBI_EC_HDR_MAGIC) { return 1; } return 0; }
int get_bootloader_message_mtd_name(struct bootloader_message *out) { size_t write_size; mtd_scan_partitions(); const MtdPartition *part = mtd_find_partition_by_name(device_name); if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { LOGE("Can't find %s\n", device_name); return -1; } MtdReadContext *read = mtd_read_partition(part); if (read == NULL) { LOGE("Can't open %s\n(%s)\n", device_name, strerror(errno)); return -1; } const ssize_t size = write_size * MISC_PAGES; char data[size]; ssize_t r = mtd_read_data(read, data, size); if (r != size) LOGE("Can't read %s\n(%s)\n", device_name, strerror(errno)); mtd_read_close(read); if (r != size) return -1; memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out)); return 0; }
int ensure_path_mounted(const char* path) { 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. 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("/mnt", 0755); // in case it doesn't already exist 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, "vfat") == 0) { result = mount(v->device, v->mount_point, v->fs_type, MS_NOATIME | MS_NODEV | MS_NODIRATIME, ""); if (result == 0) return 0; if (v->device2) { LOGW("failed to mount %s (%s); trying %s\n", v->device, strerror(errno), v->device2); result = mount(v->device2, v->mount_point, v->fs_type, MS_NOATIME | MS_NODEV | MS_NODIRATIME, ""); if (result == 0) return 0; } LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno)); return -1; } LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, v->mount_point); return -1; }
bool TWPartition::Wipe_MTD() { if (!UnMount(true)) return false; ui_print("MTD Formatting \"%s\"\n", MTD_Name.c_str()); mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(MTD_Name.c_str()); if (mtd == NULL) { LOGE("No mtd partition named '%s'", MTD_Name.c_str()); return false; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { LOGE("Can't write '%s', failed to format.", MTD_Name.c_str()); return false; } if (mtd_erase_blocks(ctx, -1) == -1) { mtd_write_close(ctx); LOGE("Failed to format '%s'", MTD_Name.c_str()); return false; } if (mtd_write_close(ctx) != 0) { LOGE("Failed to close '%s'", MTD_Name.c_str()); return false; } Recreate_AndSec_Folder(); ui_print("Done.\n"); return true; }
int format_volume(const char* volume) { Volume* v = volume_for_path(volume); char value[PROPERTY_VALUE_MAX]; if (v == NULL) { LOGE("unknown volume \"%s\"\n", volume); return -1; } if (strcmp(v->fs_type, "ramdisk") == 0) { // you can't format the ramdisk. LOGE("can't format_volume \"%s\"", volume); return -1; } if (strcmp(v->mount_point, volume) != 0) { LOGE("can't give path \"%s\" to format_volume\n", volume); return -1; } if (ensure_path_unmounted(volume) != 0) { LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point); return -1; } if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) { mtd_scan_partitions(); const MtdPartition* partition = mtd_find_partition_by_name(v->device); if (partition == NULL) { LOGE("format_volume: no MTD partition \"%s\"\n", v->device); return -1; } MtdWriteContext *write = mtd_write_partition(partition); if (write == NULL) { LOGE("format_volume: can't open MTD \"%s\"\n", v->device); return -1; } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { LOGE("format_volume: can't erase MTD \"%s\"\n", v->device); mtd_write_close(write); return -1; } else if (mtd_write_close(write)) { LOGE("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, NULL); if (result != 0) { // If v->length is <= 0 the fs is not created by make_ext4fs. LOGE("format_volume: make_extf4fs failed on %s\n", v->device); return -1; } return 0; } LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; }
int ensure_volume_mounted(fstab_rec* v) { if (v == NULL) { LOGE("cannot mount unknown volume\n"); 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; } if (!fs_mgr_is_voldmanaged(v)) { const MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point); if (mv) { // volume is already mounted return 0; } } mkdir_p(v->mount_point, 0755); // in case it doesn't already exist if (fs_mgr_is_voldmanaged(v)) { if (!strcmp(v->mount_point, "auto")) { return vold_mount_auto_volume(v->label, 1); } return vold_mount_volume(v->mount_point, 1); } else 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->blk_device); if (partition == NULL) { LOGE("failed to find \"%s\" partition to mount at \"%s\"\n", v->blk_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, "f2fs") == 0 || strcmp(v->fs_type, "vfat") == 0) { result = mount(v->blk_device, v->mount_point, v->fs_type, MS_NOATIME | MS_NODEV | MS_NODIRATIME, ""); if (result == 0) return 0; LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno)); return -1; } LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, v->mount_point); return -1; }
static int set_bootloader_message_mtd (const struct bootloader_message *in, const Volume * v) { size_t write_size; mtd_scan_partitions (); const MtdPartition *part = mtd_find_partition_by_name (v->device); if (part == NULL || mtd_partition_info (part, NULL, NULL, &write_size)) { LOGE ("Can't find %s\n", v->device); return -1; } MtdReadContext *read = mtd_read_partition (part); if (read == NULL) { LOGE ("Can't open %s\n(%s)\n", v->device, strerror (errno)); return -1; } ssize_t size = write_size * MISC_PAGES; char data[size]; ssize_t r = mtd_read_data (read, data, size); if (r != size) LOGE ("Can't read %s\n(%s)\n", v->device, strerror (errno)); mtd_read_close (read); if (r != size) return -1; memcpy (&data[write_size * MISC_COMMAND_PAGE], in, sizeof (*in)); MtdWriteContext *write = mtd_write_partition (part); if (write == NULL) { LOGE ("Can't open %s\n(%s)\n", v->device, strerror (errno)); return -1; } if (mtd_write_data (write, data, size) != size) { LOGE ("Can't write %s\n(%s)\n", v->device, strerror (errno)); mtd_write_close (write); return -1; } if (mtd_write_close (write)) { LOGE ("Can't finish %s\n(%s)\n", v->device, strerror (errno)); return -1; } LOGI ("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : ""); return 0; }
int cmd_mtd_get_partition_device(const char *partition, char *device) { mtd_scan_partitions(); MtdPartition *p = mtd_find_partition_by_name(partition); if (p == NULL) return -1; sprintf(device, "/dev/block/mtdblock%d", p->device_index); return 0; }
// Mount the volume specified by path at the given mount_point. int ensure_path_mounted_at(const char* path, const char* mount_point) { 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. return 0; } int result; result = scan_mounted_volumes(); if (result < 0) { LOGE("failed to scan mounted volumes\n"); return -1; } if (!mount_point) { mount_point = v->mount_point; } const MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point); if (mv) { // volume is already mounted return 0; } mkdir(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->blk_device); if (partition == NULL) { LOGE("failed to find \"%s\" partition to mount at \"%s\"\n", v->blk_device, mount_point); return -1; } return mtd_mount_partition(partition, mount_point, v->fs_type, 0); } else if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "squashfs") == 0 || strcmp(v->fs_type, "vfat") == 0) { result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options); if (result == 0) return 0; LOGE("failed to mount %s (%s)\n", mount_point, strerror(errno)); return -1; } LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, mount_point); return -1; }
int cmd_mtd_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only) { mtd_scan_partitions(); const MtdPartition *p; p = mtd_find_partition_by_name(partition); if (p == NULL) { return -1; } return mtd_mount_partition(p, mount_point, filesystem, read_only); }
// Write a memory buffer to target_mtd partition, a string of the form // "MTD:<partition>[:...]". Return 0 on success. int WriteToMTDPartition(unsigned char* data, size_t len, const char* target_mtd) { char* partition = strchr(target_mtd, ':'); if (partition == NULL) { fprintf(stderr, "bad MTD target name \"%s\"\n", target_mtd); return -1; } ++partition; // Trim off anything after a colon, eg "MTD:boot:blah:blah:blah...". // We want just the partition name "boot". partition = strdup(partition); char* end = strchr(partition, ':'); if (end != NULL) *end = '\0'; if (!mtd_partitions_scanned) { mtd_scan_partitions(); mtd_partitions_scanned = 1; } const MtdPartition* mtd = mtd_find_partition_by_name(partition); if (mtd == NULL) { fprintf(stderr, "mtd partition \"%s\" not found for writing\n", partition); return -1; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { fprintf(stderr, "failed to init mtd partition \"%s\" for writing\n", partition); return -1; } size_t written = mtd_write_data(ctx, (char*)data, len); if (written != len) { fprintf(stderr, "only wrote %d of %d bytes to MTD %s\n", written, len, partition); mtd_write_close(ctx); return -1; } if (mtd_erase_blocks(ctx, -1) < 0) { fprintf(stderr, "error finishing mtd write of %s\n", partition); mtd_write_close(ctx); return -1; } if (mtd_write_close(ctx)) { fprintf(stderr, "error closing mtd write of %s\n", partition); return -1; } free(partition); return 0; }
const MtdPartition * get_root_mtd_partition(const char *root_path) { const RootInfo *info = get_root_info_for_path(root_path); if (info == NULL || info->device != g_mtd_device || info->partition_name == NULL) { return NULL; } mtd_scan_partitions(); return mtd_find_partition_by_name(info->partition_name); }
int ensure_root_path_mounted(const char *root_path) { const RootInfo *info = get_root_info_for_path(root_path); if (info == NULL) { return -1; } int ret = internal_root_mounted(info); if (ret >= 0) { /* It's already mounted. */ return 0; } /* It's not mounted. */ if (info->device == g_mtd_device) { if (info->partition_name == NULL) { return -1; } //TODO: make the mtd stuff scan once when it needs to mtd_scan_partitions(); const MtdPartition *partition; partition = mtd_find_partition_by_name(info->partition_name); if (partition == NULL) { return -1; } return mtd_mount_partition(partition, info->mount_point, info->filesystem, 0); } if (info->device == NULL || info->mount_point == NULL || info->filesystem == NULL || info->filesystem == g_raw || info->filesystem == g_package_file) { return -1; } mkdir(info->mount_point, 0755); // in case it doesn't already exist if (mount_internal(info->device, info->mount_point, info->filesystem, info->filesystem_options)) { if (info->device2 == NULL) { LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno)); return -1; } else if (mount(info->device2, info->mount_point, info->filesystem, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) { LOGE("Can't mount %s (or %s)\n(%s)\n", info->device, info->device2, strerror(errno)); return -1; } } return 0; }
// write_raw_image(file, partition) Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; char* partition; char* filename; if (ReadArgs(state, argv, 2, &filename, &partition) < 0) { return NULL; } if (strlen(partition) == 0) { ErrorAbort(state, "partition argument to %s can't be empty", name); goto done; } if (strlen(filename) == 0) { ErrorAbort(state, "file argument to %s can't be empty", name); goto done; } mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(partition); if (mtd == NULL) { fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition); result = strdup(""); goto done; } char mtddevname[32]=""; sprintf(mtddevname, "/dev/mtd/mtd%d", mtd_get_partition_index((MtdPartition*)mtd)); bool success; FILE* f = fopen(filename, "rb"); if (f == NULL) { fprintf(stderr, "%s: can't open %s: %s\n", name, filename, strerror(errno)); result = strdup(""); goto done; } success = !write_recovery(filename, partition); printf("%s %s partition from %s\n", success ? "wrote" : "failed to write", partition, filename); result = success ? partition : strdup(""); done: if (result != partition) free(partition); free(filename); return StringValue(result); }
// FOTA cookie indicates that an android or modem image package // is available for delta update int set_fota_cookie_mtd(void) { size_t write_size; mtd_scan_partitions(); const MtdPartition *part = mtd_find_partition_by_name("FOTA"); if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { LOGE("Can't find FOTA\n"); return -1; } MtdReadContext *read = mtd_read_partition(part); if (read == NULL) { LOGE("Can't open FOTA\n(%s)\n", strerror(errno)); return -1; } ssize_t size = write_size; //writing 1 page is enough char data[size]; ssize_t r = mtd_read_data(read, data, size); if (r != size) LOGE("Can't read FOTA\n(%s)\n", strerror(errno)); mtd_read_close(read); if (r != size) return -1; //setting FOTA cookie value, 0x64645343 memset(data, 0x0, sizeof(data)); data[0] = 0x43; data[1] = 0x53; data[2] = 0x64; data[3] = 0x64; MtdWriteContext *write = mtd_write_partition(part); if (write == NULL) { LOGE("Can't open FOTA\n(%s)\n", strerror(errno)); return -1; } if (mtd_write_data(write, data, size) != size) { LOGE("Can't write FOTA\n(%s)\n", strerror(errno)); mtd_write_close(write); return -1; } if (mtd_write_close(write)) { LOGE("Can't finish FOTA\n(%s)\n", strerror(errno)); return -1; } LOGI("Set FOTA cookie done.\n"); return 0; }
const MtdPartition * get_root_mtd_partition(const char *root_path) { const RootInfo *info = get_root_info_for_path(root_path); if (info == NULL || info->device != g_mtd_device || info->partition_name == NULL) { #ifdef BOARD_HAS_MTD_CACHE if (strcmp(root_path, "CACHE:") != 0) return NULL; #else return NULL; #endif } mtd_scan_partitions(); return mtd_find_partition_by_name(info->partition_name); }
int install_firmware_update(const char *update_type, const char *update_data, size_t update_length, int width, int height, int bpp, const char* busy_image, const char* fail_image, const char *log_filename) { if (update_data == NULL || update_length == 0) return 0; mtd_scan_partitions(); /* We destroy the cache partition to pass the update image to the * bootloader, so all we can really do afterwards is wipe cache and reboot. * Set up this instruction now, in case we're interrupted while writing. */ struct bootloader_message boot; memset(&boot, 0, sizeof(boot)); strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command)); if (set_bootloader_message(&boot)) return -1; if (write_update_for_bootloader( update_data, update_length, width, height, bpp, busy_image, fail_image, log_filename)) { LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno)); return -1; } /* The update image is fully written, so now we can instruct the bootloader * to install it. (After doing so, it will come back here, and we will * wipe the cache and reboot into the system.) */ snprintf(boot.command, sizeof(boot.command), "update-%s", update_type); if (set_bootloader_message(&boot)) { return -1; } reboot(RB_AUTOBOOT); // Can't reboot? WTF? LOGE("Can't reboot\n"); return -1; }
int cmd_mtd_erase_raw_partition (const char *partition_name) { MtdWriteContext *out; size_t erased; size_t total_size; size_t erase_size; if (mtd_scan_partitions () <= 0) { printf ("error scanning partitions"); return -1; } const MtdPartition *p = mtd_find_partition_by_name (partition_name); if (p == NULL) { printf ("can't find %s partition", partition_name); return -1; } out = mtd_write_partition (p); if (out == NULL) { printf ("could not estabilish write context for %s", partition_name); return -1; } // do the actual erase, -1 = full partition erase erased = mtd_erase_blocks (out, -1); // erased = bytes erased, if zero, something borked if (!erased) { printf ("error erasing %s", partition_name); return -1; } return 0; }
static int phx_format_mtd(const char* device) { char* location = (char*) device; Volume* v = volume_for_device(device); if (v) { // We may not have the right "name" for it... Let's flip it location = v->device; } LOGI("%s: Formatting \"%s\"\n", __FUNCTION__, location); mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(location); if (mtd == NULL) { LOGE("%s: no mtd partition named \"%s\"", __FUNCTION__, location); return -1; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { LOGE("%s: can't write \"%s\"", __FUNCTION__, location); return -1; } if (mtd_erase_blocks(ctx, -1) == -1) { mtd_write_close(ctx); LOGE("%s: failed to erase \"%s\"", __FUNCTION__, location); return -1; } if (mtd_write_close(ctx) != 0) { LOGE("%s: failed to close \"%s\"", __FUNCTION__, location); return -1; } return 0; }
int format_volume(const char* volume) { if (PartitionManager.Wipe_By_Path(volume)) return 0; else return -1; Volume* v = volume_for_path(volume); if (v == NULL) { LOGE("unknown volume \"%s\"\n", volume); return -1; } if (strcmp(v->fs_type, "ramdisk") == 0) { // you can't format the ramdisk. LOGE("can't format_volume \"%s\"", volume); return -1; } if (strcmp(v->mount_point, volume) != 0) { LOGE("can't give path \"%s\" to format_volume\n", volume); return -1; } if (ensure_path_unmounted(volume) != 0) { LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point); return -1; } if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) { mtd_scan_partitions(); const MtdPartition* partition = mtd_find_partition_by_name(v->device); if (partition == NULL) { LOGE("format_volume: no MTD partition \"%s\"\n", v->device); return -1; } MtdWriteContext *write = mtd_write_partition(partition); if (write == NULL) { LOGW("format_volume: can't open MTD \"%s\"\n", v->device); return -1; } else if (mtd_erase_blocks(write, -1) == (off_t) -1) { LOGW("format_volume: can't erase MTD \"%s\"\n", v->device); mtd_write_close(write); return -1; } else if (mtd_write_close(write)) { LOGW("format_volume: can't close MTD \"%s\"\n", v->device); return -1; } return 0; } if (strcmp(v->fs_type, "ext4") == 0) { #ifdef USE_EXT4 /* int result = make_ext4fs(v->device, v->length, volume, sehandle); */ int result = 0; #else int result = 0; #endif if (result != 0) { LOGE("format_volume: make_extf4fs failed on %s\n", v->device); return -1; } return 0; } LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; }
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); }
// format(fs_type, partition_type, location, fs_size, mount_point) // // fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes> mount_point=<location> // fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location> // if fs_size == 0, then make_ext4fs uses the entire partition. // if fs_size > 0, that is the size to use // if fs_size < 0, then reserve that many bytes at the end of the partition Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; if (argc != 5) { return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc); } char* fs_type; char* partition_type; char* location; char* fs_size; char* mount_point; if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) { return NULL; } if (strlen(fs_type) == 0) { ErrorAbort(state, "fs_type argument to %s() can't be empty", name); goto done; } if (strlen(partition_type) == 0) { ErrorAbort(state, "partition_type argument to %s() can't be empty", name); goto done; } if (strlen(location) == 0) { ErrorAbort(state, "location argument to %s() can't be empty", name); goto done; } if (strlen(mount_point) == 0) { ErrorAbort(state, "mount_point argument to %s() can't be empty", name); goto done; } if (strcmp(partition_type, "MTD") == 0) { mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(location); if (mtd == NULL) { fprintf(stderr, "%s: no mtd partition named \"%s\"", name, location); result = strdup(""); goto done; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { fprintf(stderr, "%s: can't write \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_erase_blocks(ctx, -1) == -1) { mtd_write_close(ctx); fprintf(stderr, "%s: failed to erase \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_write_close(ctx) != 0) { fprintf(stderr, "%s: failed to close \"%s\"", name, location); result = strdup(""); goto done; } result = location; #ifdef USE_EXT4 } else if (strcmp(fs_type, "ext4") == 0) { int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle); if (status != 0) { fprintf(stderr, "%s: make_ext4fs failed (%d) on %s", name, status, location); result = strdup(""); goto done; } result = location; #endif } else { fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"", name, fs_type, partition_type); } done: free(fs_type); free(partition_type); if (result != location) free(location); return StringValue(result); }
// mount(fs_type, partition_type, location, mount_point) // // fs_type="yaffs2" partition_type="MTD" location=partition // fs_type="ext4" partition_type="EMMC" location=device Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; if (argc != 4) { return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc); } char* fs_type; char* partition_type; char* location; char* mount_point; if (ReadArgs(state, argv, 4, &fs_type, &partition_type, &location, &mount_point) < 0) { return NULL; } if (strlen(fs_type) == 0) { ErrorAbort(state, "fs_type argument to %s() can't be empty", name); goto done; } if (strlen(partition_type) == 0) { ErrorAbort(state, "partition_type argument to %s() can't be empty", name); goto done; } if (strlen(location) == 0) { ErrorAbort(state, "location argument to %s() can't be empty", name); goto done; } if (strlen(mount_point) == 0) { ErrorAbort(state, "mount_point argument to %s() can't be empty", name); goto done; } #ifdef HAVE_SELINUX char *secontext = NULL; if (sehandle) { selabel_lookup(sehandle, &secontext, mount_point, 0755); setfscreatecon(secontext); } #endif mkdir(mount_point, 0755); #ifdef HAVE_SELINUX if (secontext) { freecon(secontext); setfscreatecon(NULL); } #endif if (strcmp(partition_type, "MTD") == 0) { mtd_scan_partitions(); const MtdPartition* mtd; mtd = mtd_find_partition_by_name(location); if (mtd == NULL) { fprintf(stderr, "%s: no mtd partition named \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) { fprintf(stderr, "mtd mount of %s failed: %s\n", location, strerror(errno)); result = strdup(""); goto done; } result = mount_point; } else { if (mount(location, mount_point, fs_type, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { fprintf(stderr, "%s: failed to mount %s at %s: %s\n", name, location, mount_point, strerror(errno)); result = strdup(""); } else { result = mount_point; } } done: free(fs_type); free(partition_type); free(location); if (result != mount_point) free(mount_point); return StringValue(result); }
static int LoadPartitionContents(const char* filename, FileContents* file) { char* copy = strdup(filename); const char* magic = strtok(copy, ":"); enum PartitionType type; if (strcmp(magic, "MTD") == 0) { type = MTD; } else if (strcmp(magic, "EMMC") == 0) { type = EMMC; } else { printf("LoadPartitionContents called with bad filename (%s)\n", filename); return -1; } const char* partition = strtok(NULL, ":"); int i; int colons = 0; for (i = 0; filename[i] != '\0'; ++i) { if (filename[i] == ':') { ++colons; } } if (colons < 3 || colons%2 == 0) { printf("LoadPartitionContents called with bad filename (%s)\n", filename); } int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename int* index = malloc(pairs * sizeof(int)); size_t* size = malloc(pairs * sizeof(size_t)); char** sha1sum = malloc(pairs * sizeof(char*)); for (i = 0; i < pairs; ++i) { const char* size_str = strtok(NULL, ":"); size[i] = strtol(size_str, NULL, 10); if (size[i] == 0) { printf("LoadPartitionContents called with bad size (%s)\n", filename); return -1; } sha1sum[i] = strtok(NULL, ":"); index[i] = i; } // sort the index[] array so it indexes the pairs in order of // increasing size. size_array = size; qsort(index, pairs, sizeof(int), compare_size_indices); MtdReadContext* ctx = NULL; FILE* dev = NULL; switch (type) { case MTD: if (!mtd_partitions_scanned) { mtd_scan_partitions(); mtd_partitions_scanned = 1; } const MtdPartition* mtd = mtd_find_partition_by_name(partition); if (mtd == NULL) { printf("mtd partition \"%s\" not found (loading %s)\n", partition, filename); return -1; } ctx = mtd_read_partition(mtd); if (ctx == NULL) { printf("failed to initialize read of mtd partition \"%s\"\n", partition); return -1; } break; case EMMC: dev = fopen(partition, "rb"); if (dev == NULL) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; } } SHA_CTX sha_ctx; SHA_init(&sha_ctx); uint8_t parsed_sha[SHA_DIGEST_SIZE]; // allocate enough memory to hold the largest size. file->data = malloc(size[index[pairs-1]]); char* p = (char*)file->data; file->size = 0; // # bytes read so far for (i = 0; i < pairs; ++i) { // Read enough additional bytes to get us up to the next size // (again, we're trying the possibilities in order of increasing // size). size_t next = size[index[i]] - file->size; size_t read = 0; if (next > 0) { switch (type) { case MTD: read = mtd_read_data(ctx, p, next); break; case EMMC: read = fread(p, 1, next, dev); break; } if (next != read) { printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition); free(file->data); file->data = NULL; return -1; } SHA_update(&sha_ctx, p, read); file->size += read; } // Duplicate the SHA context and finalize the duplicate so we can // check it against this pair's expected hash. SHA_CTX temp_ctx; memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX)); const uint8_t* sha_so_far = SHA_final(&temp_ctx); if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) { printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]], filename); free(file->data); file->data = NULL; return -1; } if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) { // we have a match. stop reading the partition; we'll return // the data we've read so far. printf("partition read matched size %zu sha %s\n", size[index[i]], sha1sum[index[i]]); break; } p += read; } switch (type) { case MTD: mtd_read_close(ctx); break; case EMMC: fclose(dev); break; } if (i == pairs) { // Ran off the end of the list of (size,sha1) pairs without // finding a match. printf("contents of partition \"%s\" didn't match %s\n", partition, filename); free(file->data); file->data = NULL; return -1; } const uint8_t* sha_final = SHA_final(&sha_ctx); for (i = 0; i < SHA_DIGEST_SIZE; ++i) { file->sha1[i] = sha_final[i]; } // Fake some stat() info. file->st.st_mode = 0644; file->st.st_uid = 0; file->st.st_gid = 0; free(copy); free(index); free(size); free(sha1sum); return 0; }
// Write a memory buffer to 'target' partition, a string of the form // "MTD:<partition>[:...]" or "EMMC:<partition_device>:". Return 0 on // success. int WriteToPartition(unsigned char* data, size_t len, const char* target) { char* copy = strdup(target); const char* magic = strtok(copy, ":"); enum PartitionType type; if (strcmp(magic, "MTD") == 0) { type = MTD; } else if (strcmp(magic, "EMMC") == 0) { type = EMMC; } else { printf("WriteToPartition called with bad target (%s)\n", target); return -1; } const char* partition = strtok(NULL, ":"); if (partition == NULL) { printf("bad partition target name \"%s\"\n", target); return -1; } switch (type) { case MTD: if (!mtd_partitions_scanned) { mtd_scan_partitions(); mtd_partitions_scanned = 1; } const MtdPartition* mtd = mtd_find_partition_by_name(partition); if (mtd == NULL) { printf("mtd partition \"%s\" not found for writing\n", partition); return -1; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { printf("failed to init mtd partition \"%s\" for writing\n", partition); return -1; } size_t written = mtd_write_data(ctx, (char*)data, len); if (written != len) { printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition); mtd_write_close(ctx); return -1; } if (mtd_erase_blocks(ctx, -1) < 0) { printf("error finishing mtd write of %s\n", partition); mtd_write_close(ctx); return -1; } if (mtd_write_close(ctx)) { printf("error closing mtd write of %s\n", partition); return -1; } break; case EMMC: { size_t start = 0; int success = 0; int fd = open(partition, O_RDWR); if (fd < 0) { printf("failed to open %s: %s\n", partition, strerror(errno)); return -1; } int attempt; for (attempt = 0; attempt < 2; ++attempt) { lseek(fd, start, SEEK_SET); while (start < len) { size_t to_write = len - start; if (to_write > 1<<20) to_write = 1<<20; ssize_t written = write(fd, data+start, to_write); if (written < 0) { if (errno == EINTR) { written = 0; } else { printf("failed write writing to %s (%s)\n", partition, strerror(errno)); return -1; } } start += written; } fsync(fd); // drop caches so our subsequent verification read // won't just be reading the cache. sync(); int dc = open("/proc/sys/vm/drop_caches", O_WRONLY); write(dc, "3\n", 2); close(dc); sleep(1); printf(" caches dropped\n"); // verify lseek(fd, 0, SEEK_SET); unsigned char buffer[4096]; start = len; size_t p; for (p = 0; p < len; p += sizeof(buffer)) { size_t to_read = len - p; if (to_read > sizeof(buffer)) to_read = sizeof(buffer); size_t so_far = 0; while (so_far < to_read) { ssize_t read_count = read(fd, buffer+so_far, to_read-so_far); if (read_count < 0) { if (errno == EINTR) { read_count = 0; } else { printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); return -1; } } if ((size_t)read_count < to_read) { printf("short verify read %s at %zu: %zd %zu %s\n", partition, p, read_count, to_read, strerror(errno)); } so_far += read_count; } if (memcmp(buffer, data+p, to_read)) { printf("verification failed starting at %zu\n", p); start = p; break; } } if (start == len) { printf("verification read succeeded (attempt %d)\n", attempt+1); success = true; break; } } if (!success) { printf("failed to verify after all attempts\n"); return -1; } if (close(fd) != 0) { printf("error closing %s (%s)\n", partition, strerror(errno)); return -1; } sync(); break; } } free(copy); return 0; }
// Write a memory buffer to 'target' partition, a string of the form // "MTD:<partition>[:...]" or "EMMC:<partition_device>:". Return 0 on // success. int WriteToPartition(unsigned char* data, size_t len, const char* target) { char* copy = strdup(target); const char* magic = strtok(copy, ":"); enum PartitionType type; #if 0 //wschen 2012-05-24 if (strcmp(magic, "MTD") == 0) { type = MTD; } else if (strcmp(magic, "EMMC") == 0) { type = EMMC; } else { printf("WriteToPartition called with bad target (%s)\n", target); free(copy); return -1; } #else switch (phone_type()) { case NAND_TYPE: type = MTD; break; case EMMC_TYPE: type = EMMC; break; default: printf("WriteToPartition called with bad target (%s)\n", target); free(copy); return -1; } #endif const char* partition = strtok(NULL, ":"); if (partition == NULL) { printf("bad partition target name \"%s\"\n", target); free(copy); return -1; } switch (type) { case MTD: if (!mtd_partitions_scanned) { mtd_scan_partitions(); mtd_partitions_scanned = 1; } const MtdPartition* mtd = mtd_find_partition_by_name(partition); if (mtd == NULL) { printf("mtd partition \"%s\" not found for writing\n", partition); free(copy); return -1; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { printf("failed to init mtd partition \"%s\" for writing\n", partition); free(copy); return -1; } size_t written = mtd_write_data(ctx, (char*)data, len); if (written != len) { printf("only wrote %d of %d bytes to MTD %s\n", written, len, partition); mtd_write_close(ctx); free(copy); return -1; } if (mtd_erase_blocks(ctx, -1) < 0) { printf("error finishing mtd write of %s\n", partition); mtd_write_close(ctx); free(copy); return -1; } if (mtd_write_close(ctx)) { printf("error closing mtd write of %s\n", partition); free(copy); return -1; } break; case EMMC: ; #if 0 //wschen 2011-11-29 FILE* f = fopen(partition, "wb"); if (fwrite(data, 1, len, f) != len) { printf("short write writing to %s (%s)\n", partition, strerror(errno)); free(copy); return -1; } if (fclose(f) != 0) { printf("error closing %s (%s)\n", partition, strerror(errno)); free(copy); return -1; } #else int dev; if (!strcmp(partition, "boot")) { dev = open("/dev/bootimg", O_RDWR | O_SYNC); if (dev == -1) { printf("failed to open emmc partition \"/dev/bootimg\": %s\n", strerror(errno)); free(copy); return -1; } } else { char dev_name[32]; snprintf(dev_name, sizeof(dev_name), "/dev/%s", partition); dev = open(dev_name, O_RDWR | O_SYNC); if (dev == -1) { printf("failed to open emmc partition \"%s\": %s\n", dev_name, strerror(errno)); free(copy); return -1; } } if (write(dev, data, len) != len) { printf("short write writing to %s (%s)\n", partition, strerror(errno)); close(dev); free(copy); return -1; } close(dev); sync(); #endif break; } free(copy); return 0; }
int format_root_device(const char *root) { /* See if this root is already mounted. */ const MountedVolume *volume; char *filesystem; char *device; int ret = scan_mounted_volumes(); if (ret < 0) { LOGD(TAG "format_root_device: load mount info fail\n", root); return false; } volume = find_mounted_volume_by_mount_point(root); if (volume == NULL) { LOGD(TAG "The path %s is unmounted\n", root); return 0; } filesystem = strdup(volume->filesystem); device = strdup(volume->device); ret = unmount_mounted_volume(volume); if (ret < 0) { LOGD(TAG "format_root_device: can't unmount \"%s\"\n", root); return false; } LOGD(TAG "format_root_device : unmount %s scucess, type is %s\n", root, filesystem); if (!strcmp(filesystem, "yaffs2")) { LOGD(TAG "format yaffs2 partitions\n", root); /* Format the device. */ mtd_scan_partitions(); const MtdPartition *partition = NULL; if(!strcmp(root, DATA_PARTITION)) { LOGD(TAG "find the partition name is %s", root); partition = mtd_find_partition_by_name("userdata"); } if (partition == NULL) { LOGD(TAG "format_root_device: can't find mtd partition \"%s\"\n", root); return false; } MtdWriteContext *write = mtd_write_partition(partition); if (write == NULL) { LOGD(TAG "format_root_device: can't open \"%s\"\n", root); return false; } else if (mtd_erase_blocks(write, -1) == (off_t) - 1) { LOGD(TAG "format_root_device: can't erase \"%s\"\n", root); mtd_write_close(write); return false; } else if (mtd_write_close(write)) { LOGD(TAG "format_root_device: can't close \"%s\"\n", root); return false; } else { ret= true; } } else { if (!strcmp(filesystem, "ubifs")) { int ubi_num = -1, ubi_dev; int mtd_num = -1; char path[128]; char mtd_dev_name[128]; const char *binary_path = "/system/bin/ubiformat"; sscanf(device, "/dev/ubi%d_0", &ubi_num); if (ubi_num >= 0 && ubi_num <= 32) { LOGD(TAG "format_root_device: detach ubi device /dev/ubi%d_0\n", ubi_num); } else { LOGD(TAG "Can not find parse ubi num :%s\n", device); return false; } sprintf(path, "/sys/class/ubi/ubi%d/mtd_num", ubi_num); ubi_dev = open(path, O_RDONLY); if (ubi_dev != -1) { ret = read(ubi_dev, path, sizeof(path)); close(ubi_dev); if (ret > 0) { mtd_num = atoi(path); LOGD(TAG " %s mtd_num is %d \n", device, mtd_num); sprintf(mtd_dev_name, "/dev/mtd/mtd%d", mtd_num); } else { LOGD(TAG " read %s fail! \n", path); return false; } } else { LOGD(TAG " open %s fail! \n", path); return false; } ret = ubi_detach_dev(ubi_num); if (ret != 0) { LOGD(TAG "format_root_device: detach ubi device /dev/ubi%d_0 fail!ret=%d\n", ubi_num, ret); return false; } //int check; //check = chmod(binary_path, 0777); //printf("chmod = %d\n", check); const char **args = (const char **)malloc(sizeof(char *) * 3); args[0] = binary_path; args[1] = mtd_dev_name; args[2] = NULL; pid_t pid = fork(); if (pid == 0) { execv(binary_path, (char *const *)args); fprintf(stdout, "E:Can't run %s (%s)\n", binary_path, strerror(errno)); _exit(-1); } int status; waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { LOGE("Error in ubiformat\n(Status %d)\n", WEXITSTATUS(status)); return false; } ret=true; } else { LOGD(TAG "format_root_device : unsupport filesystem %s\n", filesystem); return false; } } free(filesystem); free(device); return ret; }
// write_raw_image(filename_or_blob, partition) Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; Value* partition_value; Value* contents; if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) { return NULL; } char* partition = NULL; if (partition_value->type != VAL_STRING) { ErrorAbort(state, "partition argument to %s must be string", name); goto done; } partition = partition_value->data; if (strlen(partition) == 0) { ErrorAbort(state, "partition argument to %s can't be empty", name); goto done; } if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) { ErrorAbort(state, "file argument to %s can't be empty", name); goto done; } mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(partition); if (mtd == NULL) { fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition); result = strdup(""); goto done; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { fprintf(stderr, "%s: can't write mtd partition \"%s\"\n", name, partition); result = strdup(""); goto done; } bool success; if (contents->type == VAL_STRING) { // we're given a filename as the contents char* filename = contents->data; FILE* f = fopen(filename, "rb"); if (f == NULL) { fprintf(stderr, "%s: can't open %s: %s\n", name, filename, strerror(errno)); result = strdup(""); goto done; } success = true; char* buffer = malloc(BUFSIZ); int read; while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { int wrote = mtd_write_data(ctx, buffer, read); success = success && (wrote == read); } free(buffer); fclose(f); } else { // we're given a blob as the contents ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size); success = (wrote == contents->size); } if (!success) { fprintf(stderr, "mtd_write_data to %s failed: %s\n", partition, strerror(errno)); } if (mtd_erase_blocks(ctx, -1) == -1) { fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition); } if (mtd_write_close(ctx) != 0) { fprintf(stderr, "%s: error closing write of %s\n", name, partition); } printf("%s %s partition\n", success ? "wrote" : "failed to write", partition); result = success ? partition : strdup(""); done: if (result != partition) FreeValue(partition_value); FreeValue(contents); return StringValue(result); }
int cmd_mtd_restore_raw_partition(const char *partition_name, const char *filename) { const MtdPartition *ptn; MtdWriteContext *write; void *data; FILE* f = fopen(filename, "rb"); if (f == NULL) { fprintf(stderr, "error opening %s", filename); return -1; } if (mtd_scan_partitions() <= 0) { fprintf(stderr, "error scanning partitions"); return -1; } const MtdPartition *mtd = mtd_find_partition_by_name(partition_name); if (mtd == NULL) { fprintf(stderr, "can't find %s partition", partition_name); return -1; } int fd = open(filename, O_RDONLY); if (fd < 0) { printf("error opening %s", filename); return -1; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { printf("error writing %s", partition_name); return -1; } int success = 1; char* buffer = malloc(BUFSIZ); int read; while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { int wrote = mtd_write_data(ctx, buffer, read); success = success && (wrote == read); } free(buffer); fclose(f); if (!success) { fprintf(stderr, "error writing %s", partition_name); return -1; } if (mtd_erase_blocks(ctx, -1) == -1) { fprintf(stderr, "error erasing blocks of %s\n", partition_name); } if (mtd_write_close(ctx) != 0) { fprintf(stderr, "error closing write of %s\n", partition_name); } printf("%s %s partition\n", success ? "wrote" : "failed to write", partition_name); return 0; }
int cmd_mtd_backup_raw_partition(const char *partition_name, const char *filename) { MtdReadContext *in; const MtdPartition *partition; char buf[BLOCK_SIZE + SPARE_SIZE]; size_t partition_size; size_t read_size; size_t total; int fd; int wrote; int len; if (mtd_scan_partitions() <= 0) { printf("error scanning partitions"); return -1; } partition = mtd_find_partition_by_name(partition_name); if (partition == NULL) { printf("can't find %s partition", partition_name); return -1; } if (mtd_partition_info(partition, &partition_size, NULL, NULL)) { printf("can't get info of partition %s", partition_name); return -1; } if (!strcmp(filename, "-")) { fd = fileno(stdout); } else { fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); } if (fd < 0) { printf("error opening %s", filename); return -1; } in = mtd_read_partition(partition); if (in == NULL) { close(fd); unlink(filename); printf("error opening %s: %s\n", partition_name, strerror(errno)); return -1; } total = 0; while ((len = mtd_read_data(in, buf, BLOCK_SIZE)) > 0) { wrote = write(fd, buf, len); if (wrote != len) { close(fd); unlink(filename); printf("error writing %s", filename); return -1; } total += BLOCK_SIZE; } mtd_read_close(in); if (close(fd)) { unlink(filename); printf("error closing %s", filename); return -1; } return 0; }