📄 ubiformat.c
字号:
/* * Copyright (C) 2008 Nokia Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* * An utility to format MTD devices into UBI and flash UBI images. * * Author: Artem Bityutskiy */#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <stdint.h>#include <stdlib.h>#include <getopt.h>#include <fcntl.h>#include <libubi.h>#include <libmtd.h>#include <libscan.h>#include <libubigen.h>#include <mtd_swab.h>#include "crc32.h"#include "common.h"#define PROGRAM_VERSION "1.0"#define PROGRAM_NAME "ubiformat"/* The variables below are set by command line arguments */struct args { unsigned int yes:1; unsigned int quiet:1; unsigned int verbose:1; unsigned int override_ec:1; unsigned int novtbl:1; int subpage_size; int vid_hdr_offs; int ubi_ver; off_t image_sz; long long ec; const char *image; const char *node;};static struct args args ={ .ubi_ver = 1,};static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION " - a tool to format MTD devices and flash UBI images";static const char *optionsstr ="-s, --sub-page-size=<bytes> minimum input/output unit used for UBI\n"" headers, e.g. sub-page size in case of NAND\n"" flash (equivalent to the minimum input/output\n"" unit size by default)\n""-O, --vid-hdr-offset=<offs> offset if the VID header from start of the\n"" physical eraseblock (default is the next\n"" minimum I/O unit or sub-page after the EC\n"" header)\n""-n, --no-volume-table only erase all eraseblock and preserve erase\n"" counters, do not write empty volume table\n""-f, --flash-image=<file> flash image file, or '-' for stdin\n""-S, --image-size=<bytes> bytes in input, if not reading from file\n""-e, --erase-counter=<value> use <value> as the erase counter value for all\n"" eraseblocks\n""-y, --yes assume the answer is \"yes\" for all question\n"" this program would otherwise ask\n""-q, --quiet suppress progress percentage information\n""-v, --verbose be verbose\n""-x, --ubi-ver=<num> UBI version number to put to EC headers\n"" (default is 1)\n""-h, -?, --help print help message\n""-V, --version print program version\n";static const char *usage ="Usage: " PROGRAM_NAME " <MTD device node file name> [-h] [-V] [-y] [-q] [-v]\n""\t\t\t[-x <num>] [-E <value>] [-s <bytes>] [-O <offs>] [-n]\n""\t\t\t[--help] [--version] [--yes] [--verbose] [--quiet]\n""\t\t\t[--ec=<value>] [--vid-hdr-offset=<offs>]\n""\t\t\t[--ubi-ver=<num>] [--no-volume-table]\n""\t\t\t[--flash-image=<file>] [--image-size=<bytes>]\n\n""Example 1: " PROGRAM_NAME " /dev/mtd0 -y - format MTD device number 0 and do\n"" not ask questions.\n""Example 2: " PROGRAM_NAME " /dev/mtd0 -q -e 0 - format MTD device number 0,\n"" be quiet and force erase counter value 0.";static const struct option long_options[] = { { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, { .name = "no-volume-table", .has_arg = 0, .flag = NULL, .val = 'n' }, { .name = "flash-image", .has_arg = 1, .flag = NULL, .val = 'f' }, { .name = "image-size", .has_arg = 1, .flag = NULL, .val = 'S' }, { .name = "yes", .has_arg = 0, .flag = NULL, .val = 'y' }, { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, { .name = "quiet", .has_arg = 0, .flag = NULL, .val = 'q' }, { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, { NULL, 0, NULL, 0},};static int parse_opt(int argc, char * const argv[]){ while (1) { int key; char *endp; key = getopt_long(argc, argv, "nh?Vyqve:x:s:O:f:S:", long_options, NULL); if (key == -1) break; switch (key) { case 's': args.subpage_size = ubiutils_get_bytes(optarg); if (args.subpage_size <= 0) return errmsg("bad sub-page size: \"%s\"", optarg); if (!is_power_of_2(args.subpage_size)) return errmsg("sub-page size should be power of 2"); break; case 'O': args.vid_hdr_offs = strtoul(optarg, &endp, 0); if (args.vid_hdr_offs <= 0 || *endp != '\0' || endp == optarg) return errmsg("bad VID header offset: \"%s\"", optarg); break; case 'e': args.ec = strtoull(optarg, &endp, 0); if (args.ec <= 0 || *endp != '\0' || endp == optarg) return errmsg("bad erase counter value: \"%s\"", optarg); if (args.ec >= EC_MAX) return errmsg("too high erase %llu, counter, max is %u", args.ec, EC_MAX); args.override_ec = 1; break; case 'f': args.image = optarg; break; case 'S': args.image_sz = ubiutils_get_bytes(optarg); if (args.image_sz <= 0) return errmsg("bad image-size: \"%s\"", optarg); break; case 'n': args.novtbl = 1; break; case 'y': args.yes = 1; break; case 'q': args.quiet = 1; break; case 'x': args.ubi_ver = strtoul(optarg, &endp, 0); if (args.ubi_ver < 0 || *endp != '\0' || endp == optarg) return errmsg("bad UBI version: \"%s\"", optarg); break; case 'v': args.verbose = 1; break; case 'V': fprintf(stderr, "%s\n", PROGRAM_VERSION); exit(EXIT_SUCCESS); case 'h': case '?': fprintf(stderr, "%s\n\n", doc); fprintf(stderr, "%s\n\n", usage); fprintf(stderr, "%s\n", optionsstr); exit(EXIT_SUCCESS); case ':': return errmsg("parameter is missing"); default: fprintf(stderr, "Use -h for help\n"); return -1; } } if (args.quiet && args.verbose) return errmsg("using \"-q\" and \"-v\" at the same time does not make sense"); if (optind == argc) return errmsg("MTD device name was not specified (use -h for help)"); else if (optind != argc - 1) return errmsg("more then one MTD device specified (use -h for help)"); if (args.image && args.novtbl) return errmsg("-n cannot be used together with -f"); args.node = argv[optind]; return 0;}static int want_exit(void){ char buf[4]; while (1) { normsg_cont("continue? (yes/no) "); scanf("%3s", buf); if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1)) return 0; if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1)) return 1; }}static int answer_is_yes(void){ char buf[4]; while (1) { scanf("%3s", buf); if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1)) return 1; if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1)) return 0; }}static void print_bad_eraseblocks(const struct mtd_info *mtd, const struct ubi_scan_info *si){ int first = 1, eb; if (si->bad_cnt == 0) return; normsg_cont("bad eraseblocks: "); for (eb = 0; eb < mtd->eb_cnt; eb++) { if (si->ec[eb] != EB_BAD) continue; if (first) { printf("%d", eb); first = 0; } else printf(", %d", eb); } printf("\n");}static int change_ec(struct ubi_ec_hdr *hdr, long long ec){ uint32_t crc; /* Check the EC header */ if (be32_to_cpu(hdr->magic) != UBI_EC_HDR_MAGIC) return errmsg("bad UBI magic %#08x, should be %#08x", be32_to_cpu(hdr->magic), UBI_EC_HDR_MAGIC); crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); if (be32_to_cpu(hdr->hdr_crc) != crc) return errmsg("bad CRC %#08x, should be %#08x\n", crc, be32_to_cpu(hdr->hdr_crc)); hdr->ec = cpu_to_be64(ec); crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); hdr->hdr_crc = cpu_to_be32(crc); return 0;}static int drop_ffs(const struct mtd_info *mtd, const void *buf, int len){ int i; for (i = len - 1; i >= 0; i--) if (((const uint8_t *)buf)[i] != 0xFF) break; /* The resulting length must be aligned to the minimum flash I/O size */ len = i + 1; len = (len + mtd->min_io_size - 1) / mtd->min_io_size; len *= mtd->min_io_size; return len;}static int open_file(const struct mtd_info *mtd, struct ubi_scan_info *si, off_t *sz){ int fd; if (!strcmp(args.image, "-")) { if (args.image_sz == 0) return errmsg("must use '-S' with non-zero value when reading from stdin"); *sz = args.image_sz; fd = dup(STDIN_FILENO); if (fd < 0) return sys_errmsg("failed to dup stdin"); } else { struct stat st; if (stat(args.image, &st)) return sys_errmsg("cannot open \"%s\"", args.image); *sz = st.st_size; fd = open(args.image, O_RDONLY); if (fd == -1) return sys_errmsg("cannot open \"%s\"", args.image); } return fd;}static int read_all(int fd, void *buf, size_t len){ while (len > 0) { ssize_t l = read(fd, buf, len); if (l == 0) return errmsg("eof reached; %d bytes remaining", len); else if (l > 0) { buf += l; len -= l; } else if (errno == EINTR || errno == EAGAIN) continue; else return sys_errmsg("reading failed; %d bytes remaining", len); } return 0;}static int flash_image(const struct mtd_info *mtd, const struct ubigen_info *ui, struct ubi_scan_info *si){ int fd, img_ebs, eb, written_ebs = 0, divisor; off_t st_size; fd = open_file(mtd, si, &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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -