static int flash_image(const struct mtd_dev_info *mtd, const struct ubigen_info *ui, struct ubi_scan_info *si) { int fd, img_ebs, eb, written_ebs = 0, divisor, ret = -1; off_t st_size; char *buf = NULL; fd = open_file(&st_size); if (fd < 0) return fd; buf = malloc(mtd->eb_size); if (!buf) { sys_errmsg("cannot allocate %d bytes of memory", mtd->eb_size); goto out_close; } img_ebs = st_size / mtd->eb_size; if (img_ebs > si->good_cnt) { sys_errmsg("file \"%s\" is too large (%lld bytes)", args.image, (long long)st_size); goto out_close; } if (st_size % mtd->eb_size) { sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of " "eraseblock size (%d bytes)", args.image, (long long)st_size, mtd->eb_size); goto out_close; } if (st_size == 0) { sys_errmsg("file \"%s\" has size 0 bytes", args.image); goto out_close; } verbose(args.verbose, "will write %d eraseblocks", img_ebs); divisor = img_ebs; for (eb = 0; eb < mtd->eb_cnt; eb++) { int err, new_len; long long ec; if (!args.quiet && !args.verbose) { printf("\r" PROGRAM_NAME ": flashing eraseblock %d -- %2u %% complete ", eb, (eb + 1) * 100 / mtd->eb_cnt); } if (si->ec[eb] == EB_BAD) { divisor += 1; continue; } if (args.verbose) { normsg_cont("eraseblock %d: erase", eb); } err = libmtd_erase(mtd, args.node_fd, eb); if (err) { if (!args.quiet) printf("\n"); sys_errmsg("failed to erase eraseblock %d", eb); if (errno != EIO) goto out_close; if (mark_bad(mtd, si, eb)) goto out_close; continue; } err = read_full(fd, buf, mtd->eb_size); if (err < 0) { sys_errmsg("failed to read eraseblock %d from \"%s\"", written_ebs, args.image); goto out_close; } if (args.override_ec) ec = args.ec; else if (si->ec[eb] <= EC_MAX) ec = si->ec[eb] + 1; else ec = si->mean_ec; if (args.verbose) { printf(", change EC to %lld", ec); } err = change_ech((struct ubi_ec_hdr *)buf, ui->image_seq, ec); if (err) { errmsg("bad EC header at eraseblock %d of \"%s\"", written_ebs, args.image); goto out_close; } if (args.verbose) { printf(", write data\n"); } new_len = drop_ffs(mtd, buf, mtd->eb_size); err = libmtd_write(mtd, args.node_fd, eb, 0, buf, new_len); if (err) { sys_errmsg("cannot write eraseblock %d", eb); if (errno != EIO) goto out_close; err = mtd_torture(mtd, args.node_fd, eb); if (err) { if (mark_bad(mtd, si, eb)) goto out_close; } continue; } if (++written_ebs >= img_ebs) break; } if (!args.quiet && !args.verbose) printf("\n"); ret = eb + 1; out_close: free(buf); close(fd); return ret; }
static int format(const struct mtd_dev_info *mtd, const struct ubigen_info *ui, struct ubi_scan_info *si, int start_eb, int novtbl) { int eb, err, write_size; struct ubi_ec_hdr *hdr; struct ubi_vtbl_record *vtbl; int eb1 = -1, eb2 = -1; long long ec1 = -1, ec2 = -1; write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1; write_size /= mtd->subpage_size; write_size *= mtd->subpage_size; hdr = malloc(write_size); if (!hdr) return sys_errmsg("cannot allocate %d bytes of memory", write_size); memset(hdr, 0xFF, write_size); for (eb = start_eb; eb < mtd->eb_cnt; eb++) { long long ec; if (!args.quiet && !args.verbose) { printf("\r" PROGRAM_NAME ": formatting eraseblock %d -- %2u %% complete ", eb, (eb + 1 - start_eb) * 100 / (mtd->eb_cnt - start_eb)); } if (si->ec[eb] == EB_BAD) continue; if (args.override_ec) ec = args.ec; else if (si->ec[eb] <= EC_MAX) ec = si->ec[eb] + 1; else ec = si->mean_ec; ubigen_init_ec_hdr(ui, hdr, ec); if (args.verbose) { normsg_cont("eraseblock %d: erase", eb); } err = libmtd_erase(mtd, args.node_fd, eb); if (err) { if (!args.quiet) printf("\n"); sys_errmsg("failed to erase eraseblock %d", eb); if (errno != EIO) goto out_free; if (mark_bad(mtd, si, eb)) goto out_free; continue; } if ((eb1 == -1 || eb2 == -1) && !novtbl) { if (eb1 == -1) { eb1 = eb; ec1 = ec; } else if (eb2 == -1) { eb2 = eb; ec2 = ec; } if (args.verbose) printf(", do not write EC, leave for vtbl\n"); continue; } if (args.verbose) { printf(", write EC %lld\n", ec); } err = libmtd_write(mtd, args.node_fd, eb, 0, hdr, write_size); if (err) { if (!args.quiet && !args.verbose) printf("\n"); sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d", write_size, eb); if (errno != EIO) { if (!args.subpage_size != mtd->min_io_size) normsg("may be sub-page size is " "incorrect?"); goto out_free; } err = mtd_torture(mtd, args.node_fd, eb); if (err) { if (mark_bad(mtd, si, eb)) goto out_free; } continue; } } if (!args.quiet && !args.verbose) printf("\n"); if (!novtbl) { if (eb1 == -1 || eb2 == -1) { errmsg("no eraseblocks for volume table"); goto out_free; } verbose(args.verbose, "write volume table to eraseblocks %d and %d", eb1, eb2); vtbl = ubigen_create_empty_vtbl(ui); if (!vtbl) goto out_free; err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl, args.node_fd); free(vtbl); if (err) { errmsg("cannot write layout volume"); goto out_free; } } free(hdr); return 0; out_free: free(hdr); return -1; }
static int flash_image(libmtd_t libmtd, const struct mtd_dev_info *mtd, const struct ubigen_info *ui, struct ubi_scan_info *si) { int fd, img_ebs, eb, written_ebs = 0, divisor, skip_data_read = 0; off_t st_size; fd = open_file(&st_size); if (fd < 0) return fd; img_ebs = st_size / mtd->eb_size; if (img_ebs > si->good_cnt) { sys_errmsg("file \"%s\" is too large (%lld bytes)", args.image, (long long)st_size); goto out_close; } if (st_size % mtd->eb_size) { return sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of ""eraseblock size (%d bytes)", args.image, (long long)st_size, mtd->eb_size); goto out_close; } verbose(args.verbose, "will write %d eraseblocks", img_ebs); divisor = img_ebs; for (eb = 0; eb < mtd->eb_cnt; eb++) { int err, new_len; char buf[mtd->eb_size]; long long ec; if (!args.quiet && !args.verbose) { printf("\r" PROGRAM_NAME ": flashing eraseblock %d -- %2lld %% complete ", eb, (long long)(eb + 1) * 100 / divisor); fflush(stdout); } if (si->ec[eb] == EB_BAD) { divisor += 1; continue; } if (args.verbose) { normsg_cont("eraseblock %d: erase", eb); fflush(stdout); } err = mtd_erase(libmtd, mtd, args.node_fd, eb); if (err) { if (!args.quiet) printf("\n"); sys_errmsg("failed to erase eraseblock %d", eb); if (errno != EIO) goto out_close; if (mark_bad(mtd, si, eb)) goto out_close; continue; } if (!skip_data_read) { err = read_all(fd, buf, mtd->eb_size); if (err) { sys_errmsg("failed to read eraseblock %d from \"%s\"", written_ebs, args.image); goto out_close; } } skip_data_read = 0; if (args.override_ec) ec = args.ec; else if (si->ec[eb] <= EC_MAX) ec = si->ec[eb] + 1; else ec = si->mean_ec; if (args.verbose) { printf(", change EC to %lld", ec); fflush(stdout); } err = change_ech((struct ubi_ec_hdr *)buf, ui->image_seq, ec); if (err) { errmsg("bad EC header at eraseblock %d of \"%s\"", written_ebs, args.image); goto out_close; } if (args.verbose) { printf(", write data\n"); fflush(stdout); } new_len = drop_ffs(mtd, buf, mtd->eb_size); err = mtd_write(libmtd, mtd, args.node_fd, eb, 0, buf, new_len, NULL, 0, 0); if (err) { sys_errmsg("cannot write eraseblock %d", eb); if (errno != EIO) goto out_close; err = mtd_torture(libmtd, mtd, args.node_fd, eb); if (err) { if (mark_bad(mtd, si, eb)) goto out_close; } /* * We have to make sure that we do not read next block * of data from the input image or stdin - we have to * write buf first instead. */ skip_data_read = 1; continue; } if (++written_ebs >= img_ebs) break; } if (!args.quiet && !args.verbose) printf("\n"); close(fd); return eb + 1; out_close: close(fd); return -1; }