From b6a0dcf2591e809e929ba60aec72288c7b301356 Mon Sep 17 00:00:00 2001 From: Enrico Scholz Date: Mon, 25 Aug 2008 21:09:51 +0200 Subject: ubi-utils: allow 'ubiformat' to read from stdin This patch allows to read the image from stdin and adds an '--image-size' option to specify its size. 'upiupdatevol' has this feature already and it is useful for 'ubiformat' too. It adds a read_all() function which reads a block of data. Plain 'read(2)' can fail on nc -l -p 1234 | ubiformat -f - -S 25427968 else. Signed-off-by: Enrico Scholz Signed-off-by: Artem Bityutskiy --- ubi-utils/new-utils/src/ubiformat.c | 96 +++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 19 deletions(-) diff --git a/ubi-utils/new-utils/src/ubiformat.c b/ubi-utils/new-utils/src/ubiformat.c index c2888e0..05caed9 100644 --- a/ubi-utils/new-utils/src/ubiformat.c +++ b/ubi-utils/new-utils/src/ubiformat.c @@ -51,6 +51,7 @@ struct args { int subpage_size; int vid_hdr_offs; int ubi_ver; + off_t image_sz; long long ec; const char *image; const char *node; @@ -62,7 +63,7 @@ static struct args args = }; static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION - " - a tool to format MTD devices and flash UBI images"; + " - a tool to format MTD devices and flash UBI images"; static const char *optionsstr = "-s, --sub-page-size= minimum input/output unit used for UBI\n" @@ -75,7 +76,8 @@ static const char *optionsstr = " 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= flash image file\n" +"-f, --flash-image= flash image file, or '-' for stdin\n" +"-S, --image-size= bytes in input, if not reading from file\n" "-e, --erase-counter= use as the erase counter value for all\n" " eraseblocks\n" "-y, --yes assume the answer is \"yes\" for all question\n" @@ -93,7 +95,7 @@ static const char *usage = "\t\t\t[--help] [--version] [--yes] [--verbose] [--quiet]\n" "\t\t\t[--ec=] [--vid-hdr-offset=]\n" "\t\t\t[--ubi-ver=] [--no-volume-table]\n" -"\t\t\t[--flash-image=]\n\n" +"\t\t\t[--flash-image=] [--image-size=]\n\n" "Example 1: " PROGRAM_NAME " /dev/mtd0 -y - format MTD device number 0 and do\n" " not ask questions.\n" @@ -105,6 +107,7 @@ static const struct option long_options[] = { { .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' }, @@ -121,7 +124,7 @@ static int parse_opt(int argc, char * const argv[]) int key; char *endp; - key = getopt_long(argc, argv, "nh?Vyqve:x:s:O:f:", long_options, NULL); + key = getopt_long(argc, argv, "nh?Vyqve:x:s:O:f:S:", long_options, NULL); if (key == -1) break; @@ -153,6 +156,12 @@ static int parse_opt(int argc, char * const argv[]) 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; @@ -284,7 +293,7 @@ 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) + if (((const uint8_t *)buf)[i] != 0xFF) break; /* The resulting length must be aligned to the minimum flash I/O size */ @@ -294,27 +303,75 @@ static int drop_ffs(const struct mtd_info *mtd, const void *buf, int len) 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; - struct stat st; + off_t st_size; - if (stat(args.image, &st)) - return sys_errmsg("cannot open \"%s\"", args.image); + fd = open_file(mtd, si, &st_size); + if (fd < 0) + return fd; - img_ebs = st.st_size / mtd->eb_size; - if (img_ebs > si->good_cnt) - return sys_errmsg("file \"%s\" is too large (%lld bytes)", - args.image, (long long)st.st_size); + img_ebs = st_size / mtd->eb_size; - if (st.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.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; + } - fd = open(args.image, O_RDONLY); - if (fd == -1) - return sys_errmsg("cannot open \"%s\"", args.image); + 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; @@ -345,7 +402,8 @@ static int flash_image(const struct mtd_info *mtd, const struct ubigen_info *ui, goto out_close; } - if (read(fd, buf, mtd->eb_size) != mtd->eb_size) { + 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; -- cgit v1.2.3