From 6ccd7242c4c1404dafb64cd937adc3c65ce02385 Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Wed, 21 Jun 2006 14:26:02 +0200 Subject: [MTD] UBI: Removed automake, autoconf, added ubi userspace headers. Signed-off-by: Frank Haverkamp --- ubi-utils/src/unubi.c | 392 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 ubi-utils/src/unubi.c (limited to 'ubi-utils/src/unubi.c') diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c new file mode 100644 index 0000000..6d877e7 --- /dev/null +++ b/ubi-utils/src/unubi.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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. + * + * Author: Frank Haverkamp + * + * An utility to decompose UBI images. Not yet finished ... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crc32.h" +#include + +#define MAXPATH 1024 +#define MIN(x,y) ((x)<(y)?(x):(y)) + +static uint32_t crc32_table[256]; + +struct args { + const char *output_dir; + uint32_t hdr_offs; + uint32_t data_offs; + uint32_t blocksize; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +}; + +static struct args myargs = { + .output_dir = "unubi", + .hdr_offs = 64, + .data_offs = 128, + .blocksize = 128 * 1024, + .arg1 = NULL, + .options = NULL, +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +const char *argp_program_bug_address = + "... uuuh, lets wait until it looks nicer"; + +static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\t" + BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" + "\nWrite to UBI Volume.\n"; + +static struct argp_option options[] = { + { .name = "dir", + .key = 'd', + .arg = "", + .flags = 0, + .doc = "output directory", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "blocksize", + .key = 'b', + .arg = "", + .flags = 0, + .doc = "blocksize", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "data-offs", + .key = 'x', + .arg = "", + .flags = 0, + .doc = "data offset", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "hdr-offs", + .key = 'x', + .arg = "", + .flags = 0, + .doc = "hdr offset", + .group = OPTION_ARG_OPTIONAL }, + + { .name = NULL, .key = 0, .arg = NULL, .flags = 0, + .doc = NULL, .group = 0 }, +}; + +static struct argp argp = { + .options = options, + .parser = parse_opt, + .args_doc = "image-file", + .doc = doc, + .children = NULL, + .help_filter = NULL, + .argp_domain = NULL, +}; + +/* + * str_to_num - Convert string into number and cope with endings like + * k, K, kib, KiB for kilobyte + * m, M, mib, MiB for megabyte + */ +uint32_t str_to_num(char *str) +{ + char *s = str; + ulong num = strtoul(s, &s, 0); + + if (*s != '\0') { + if (strcmp(s, "KiB") == 0) + num *= 1024; + else if (strcmp(s, "MiB") == 0) + num *= 1024*1024; + else { + fprintf(stderr, "WARNING: Wrong number format " + "\"%s\", check your paramters!\n", str); + } + } + return num; +} + +/* + * @brief Parse the arguments passed into the test case. + * + * @param key The parameter. + * @param arg Argument passed to parameter. + * @param state Location to put information on parameters. + * + * @return error + * + * Get the `input' argument from `argp_parse', which we know is a + * pointer to our arguments structure. + */ +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + struct args *args = state->input; + + switch (key) { + case 'b': /* --blocksize */ + args->blocksize = str_to_num(arg); + break; + + case 'x': /* --data-offs= */ + args->data_offs = str_to_num(arg); + break; + + case 'y': /* --hdr-offs= */ + args->hdr_offs = str_to_num(arg); + break; + + case 'd': /* --dir= */ + args->output_dir = arg; + break; + + case ARGP_KEY_NO_ARGS: + /* argp_usage(state); */ + break; + + case ARGP_KEY_ARG: + args->arg1 = arg; + /* Now we consume all the rest of the arguments. + `state->next' is the index in `state->argv' of the + next argument to be parsed, which is the first STRING + we're interested in, so we can just use + `&state->argv[state->next]' as the value for + arguments->strings. + + _In addition_, by setting `state->next' to the end + of the arguments, we can force argp to stop parsing + here and return. */ + + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + + case ARGP_KEY_END: + /* argp_usage(state); */ + break; + + default: + return(ARGP_ERR_UNKNOWN); + } + + return 0; +} + +static inline void +hexdump(FILE *fp, const void *p, ssize_t size) +{ + int k; + const uint8_t *buf = p; + + for (k = 0; k < size; k++) { + fprintf(fp, "%02x ", buf[k]); + if ((k & 15) == 15) + fprintf(fp, "\n"); + } +} + +/* + * This was put together in 1.5 hours and this is exactly how it looks + * like! FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME + * FIXME FIXME FIXME FIXME FIXME FIXME! + */ +static int extract_volume(struct args *args, const uint8_t *buf, + int len, int volume, FILE *fp) +{ + int i, rc; + int nrblocks = len / args->blocksize; + int max_lnum = -1, lnum = 0; + const uint8_t *ptr; + uint8_t **vol_tab; + int *vol_len; + + vol_tab = calloc(nrblocks, sizeof(uint8_t *)); + vol_len = calloc(nrblocks, sizeof(int)); + + if (!buf || !vol_tab || !vol_len) + exit(EXIT_FAILURE); + + for (i = 0, ptr = buf; i < nrblocks; i++, ptr += args->blocksize) { + uint32_t crc; + struct ubi_ec_hdr *ec_hdr = (struct ubi_ec_hdr *)ptr; + struct ubi_vid_hdr *vid_hdr = NULL; + uint8_t *data; + + /* default */ + vol_len[lnum] = args->blocksize - (2 * 1024); + + /* Check UBI EC header */ + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, ec_hdr, + UBI_EC_HDR_SIZE_CRC); + if (crc != ubi32_to_cpu(ec_hdr->hdr_crc)) + continue; + + vid_hdr = (struct ubi_vid_hdr *) + (ptr + ubi32_to_cpu(ec_hdr->vid_hdr_offset)); + data = (uint8_t *)(ptr + ubi32_to_cpu(ec_hdr->data_offset)); + + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, vid_hdr, + UBI_VID_HDR_SIZE_CRC); + if (crc != ubi32_to_cpu(vid_hdr->hdr_crc)) + continue; + + if (volume == (int)ubi32_to_cpu(vid_hdr->vol_id)) { + + printf("****** block %4d volume %2d **********\n", + i, volume); + + hexdump(stdout, ptr, 64); + + printf("--- vid_hdr\n"); + hexdump(stdout, vid_hdr, 64); + + printf("--- data\n"); + hexdump(stdout, data, 64); + + lnum = ubi32_to_cpu(vid_hdr->lnum); + vol_tab[lnum] = data; + if (max_lnum < lnum) + max_lnum = lnum; + if (vid_hdr->vol_type == UBI_VID_STATIC) + vol_len[lnum] = + ubi32_to_cpu(vid_hdr->data_size); + + } + } + + for (lnum = 0; lnum <= max_lnum; lnum++) { + if (vol_tab[lnum]) { + rc = fwrite(vol_tab[lnum], 1, vol_len[lnum], fp); + if (ferror(fp) || (vol_len[lnum] != rc)) { + perror("could not write file"); + exit(EXIT_FAILURE); + } + } else { + /* Fill up empty areas by 0xff, for static + * volumes this means they are broken! + */ + for (i = 0; i < vol_len[lnum]; i++) { + if (fputc(0xff, fp) == EOF) { + perror("could not write char"); + exit(EXIT_FAILURE); + } + } + } + } + + free(vol_tab); + free(vol_len); + return 0; +} + +int +main(int argc, char *argv[]) +{ + int len, rc; + FILE *fp; + struct stat file_info; + uint8_t *buf; + int i; + + init_crc32_table(crc32_table); + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &myargs); + + if (!myargs.arg1) { + fprintf(stderr, "Please specify input file!\n"); + exit(EXIT_FAILURE); + } + + fp = fopen(myargs.arg1, "r"); + if (!fp) { + perror("Cannot open file"); + exit(EXIT_FAILURE); + } + if (fstat(fileno(fp), &file_info) != 0) { + fprintf(stderr, "Cannot fetch file size " + "from input file.\n"); + } + len = file_info.st_size; + buf = malloc(len); + if (!buf) { + perror("out of memory!"); + exit(EXIT_FAILURE); + } + rc = fread(buf, 1, len, fp); + if (ferror(fp) || (len != rc)) { + perror("could not read file"); + exit(EXIT_FAILURE); + } + if (!myargs.output_dir) { + fprintf(stderr, "No output directory specified!\n"); + exit(EXIT_FAILURE); + } + + rc = mkdir(myargs.output_dir, 0777); + if (rc && errno != EEXIST) { + perror("Cannot create output directory"); + exit(EXIT_FAILURE); + } + for (i = 0; i < 32; i++) { + char fname[1024]; + FILE *fpout; + + printf("######### VOLUME %d ############################\n", + i); + + sprintf(fname, "%s/ubivol_%d.bin", myargs.output_dir, i); + fpout = fopen(fname, "w+"); + if (!fpout) { + perror("Cannot open file"); + exit(EXIT_FAILURE); + } + extract_volume(&myargs, buf, len, i, fpout); + fclose(fpout); + } + + fclose(fp); + free(buf); + exit(EXIT_SUCCESS); +} -- cgit v1.2.3 From e820054fd876faa7306d64957c71c9c5c29db78c Mon Sep 17 00:00:00 2001 From: Drake Dowsett Date: Mon, 6 Nov 2006 16:54:10 +0100 Subject: [MTD] UBI: rework of off-line UBI analysis tool The new version can create a gnuplot graph of the erase count statistics. It can also extract UBI volumes and single blocks with a preanalysis of the EC as well as the VID header. It has a manual page too ;-). Signed-off-by: Frank Haverkamp --- ubi-utils/Makefile | 2 +- ubi-utils/doc/unubi.roff | 123 ++++++ ubi-utils/src/eb_chain.c | 287 +++++++++++++ ubi-utils/src/eb_chain.h | 73 ++++ ubi-utils/src/unubi.c | 975 +++++++++++++++++++++++++++++++----------- ubi-utils/src/unubi_analyze.c | 435 +++++++++++++++++++ ubi-utils/src/unubi_analyze.h | 26 ++ 7 files changed, 1659 insertions(+), 262 deletions(-) create mode 100644 ubi-utils/doc/unubi.roff create mode 100644 ubi-utils/src/eb_chain.c create mode 100644 ubi-utils/src/eb_chain.h create mode 100644 ubi-utils/src/unubi_analyze.c create mode 100644 ubi-utils/src/unubi_analyze.h (limited to 'ubi-utils/src/unubi.c') diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile index 2776c07..0818a9b 100644 --- a/ubi-utils/Makefile +++ b/ubi-utils/Makefile @@ -71,7 +71,7 @@ ubigen: ubigen.o libubigen.o crc32.o mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o $(CC) $(LDFLAGS) -o $@ $^ -unubi: unubi.o crc32.o +unubi: unubi.o crc32.o unubi_analyze.o eb_chain.o $(CC) $(LDFLAGS) -o $@ $^ pfi2bin: pfi2bin.o peb.o error.o list.o crc32.o libubigen.o bootenv.o \ diff --git a/ubi-utils/doc/unubi.roff b/ubi-utils/doc/unubi.roff new file mode 100644 index 0000000..6cebc46 --- /dev/null +++ b/ubi-utils/doc/unubi.roff @@ -0,0 +1,123 @@ +.TH UNUBI 1 "NOVEMBER 2006" FSP "FSP Flashutils" +.SH NAME +unubi \- extract volumes/eraseblocks from a raw\-UBI image +.SH SYNOPSIS +\fBunubi [\-aevEV] [\-d \fIout\-dir\fB] [\-r \fIvolume\-id\fB] +[\-b \fIblock\-size\fB] \fIimage\-file +.SH DESCRIPTION +.PP +\fBunubi\fR reads an image file containing blocks of UBI headers and data +(such as produced from \fBnand2bin\fR) and rebuilds the volumes within. +The default operation (when no flags are given) is to rebuild all valid +volumes found in the image. \fBunubi\fR can also read straight from the +onboard MTD device (ex. /dev/mtdblock/NAND). +.SH OPTIONS +.IP "\-a, \-\-analyze" +When flagged, analysis files are generated within the output directory. These +may include tables and or graphs detailing statistics gathered from the +eraseblock data. Files are prefixed `analysis_'. + +See \fBANALYSIS\fR. +.IP "\-b, \-\-blocksize \fIblock\-size\fR" +Specify in bytes the \fIimage\-file\fR eraseblock size. Sizes may be +postfixed with `KiB' or `MiB' to indicate mebibytes or kibibytes +respectively. Default is 128KiB. +.IP "\-d, \-\-dir \fIoutput\-dir\fR" +Specify the output directory. If no directory is specified, the default +is `unubi_\fIimage\-file\fR' within the curent working directory. If the +attempt to create the output directory fails, +.B unubi +will try to create it in /tmp before aborting. +.IP "\-e, \-\-eb\-split" +When flagged, images are created for each eraseblock in \fIimage\-file\fR +regardless of its validity. Each image is the complete eraseblock, including +headers and any space to the end of the eraseblock after where the data may +end. + +Invalid images are named `ebEEEE', where EEEE is the physical index of the +eraseblock in the image. Valid images are named `ebEEEE_VVV_NNN_RRR' where +VVV is the known volume ID, NNN is the logical number and RRR is the version +of the eraseblock data. Note that the version number is in hexadecimal. + +Invalid images may also contain this postfix, if the data in the header +could be valid (ie. the header contains a resonable volume ID, but the +header and/or data CRCs are not valid). If this is the case, images are named +`ebEEEE_VVV_NNN_RRR.reason', so as to distinguish known values from +non\-definite ones. + +See \fBREASON SUFFIXES\fR. +.IP "\-r, \-\-rebuild \fIvolume\-id\fR" +Specify a volume to rebuild. Can be used successively to specify +several volumes to be rebuilt. + +Images are named `volumeVVV' where VVV is the volume ID. For each missing +eraseblock, an error message will be printed. +.IP "\-v, \-\-vol\-split" +When flagged, images are created for each valid eraseblock in +\fIimage\-file\fR. Since a vaild eraseblock will have a defined data start and +data length, only this range will make up the image. + +Images are named `volVVV_NNN_RRR_EEEE', where, for the data in the eraseblock, +VVV is the volume ID, NNN is the logical number, RRR is the version and EEEE +is the phyisical index of the eraseblock in the image. +.IP "\-V, \-\-vol\-split!" +Same as above, only all images are the complete eraseblock (including headers, +and raw data, even past the point where the data is supposed to end). +Overrides \-v when both \-v and \-V are flagged. +.SH ANALYSIS +The following files will be generated during the analysis: +.IP "analysis_ec_hdr.data" +A space delimited table with these two columns for each eraseblock: the +eraseblock's index or physical position in the image, and the eraseblock's +erase count. The third column contains the erase count data sorted. +.IP "analysis_vid_hdr.data" +A space delimited table with these four colums for each eraseblock: the +volume ID, the volume logical number, the leb version, and the data size. +In addition there are a normalized column representing the volume ID and +volume logical number, a normalized column representing the leb version, and +a normalized column representing the data_size. These normalized columns are +used to better draw the the gnuplot image. +.IP "analysis_ec_hdr.plot" +A gnuplot script for quickly viewing a sample output from the respective .data +file. +.IP "analysis_vid_hdr.plot" +A gnuplot script for quickly viewing a sample output from the respective .data +file. +.SH REASONS SUFFIXES +When \-\-eb\-split produces possibly invalid, though usable, eraseblocks, the +known reason suffixes are: +.IP ".ec_magic" +The erase counter header did not contain a valid magic field. +.IP ".ec_hdr_crc" +The erase counter header did not contain a vaild header CRC field. +.IP ".vid_magic" +The volume ID header did not contain a valid magic field. +.IP ".vid_hdr_crc" +The volume ID header did not contain a valid header CRC field. +.IP ".data_crc" +The volume ID header did not contain a valid data CRC field. +.SH EXAMPLES +To extract and rebuild all valid volumes from demo.img (note the output +directory will be /home/user/unubi_demo.img): +.sp 1 +.RS +.B /home/user# unubi demo.img +.sp 1 +.RE +To analyze demo.img as well as extract and rebuild volume 7: +.sp 1 +.RS +.B /home/user# unubi \-a \-r 7 demo.img +.sp 1 +.RE +To split demo.img into raw images for each eraseblock into the folder +/var/eraseblocks: +.sp 1 +.RS +.B /home/user# unubi \-e \-d /var/eraseblocks demo.img +.SH AUTHORS +Frank Haverkamp +.sp 0 +Drake Dowsett +.SH CONTACT +Andreas Arnez diff --git a/ubi-utils/src/eb_chain.c b/ubi-utils/src/eb_chain.c new file mode 100644 index 0000000..501a838 --- /dev/null +++ b/ubi-utils/src/eb_chain.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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. + */ + +/* + * Author: Drake Dowsett, dowsett@de.ibm.com + * Contact: Andreas Arnez, arnez@de.ibm.com + */ + +/* see eb_chain.h */ + +#include +#include +#include +#include "eb_chain.h" + +#define COPY(dst, src) \ + do \ + { \ + dst = malloc(sizeof(*dst)); \ + if (dst == NULL) \ + return -ENOMEM; \ + memcpy(dst, src, sizeof(*dst)); \ + } while (0) + + +/** + * inserts an eb_info into the chain starting at head, then searching + * linearly for the correct position; + * new should contain valid vid and ec headers and the data_crc should + * already have been checked before insertion, otherwise the chain + * could be have un an undesired manner; + * returns -ENOMEM if alloc fails, otherwise SHOULD always return 0, + * if not, the code reached the last line and returned -EAGAIN, + * meaning there is a bug or a case not being handled here; + **/ +int +eb_chain_insert(eb_info_t *head, eb_info_t new) +{ + uint32_t vol, num, ver; + uint32_t new_vol, new_num, new_ver; + eb_info_t prev, cur, hist, ins; + eb_info_t *prev_ptr; + + if ((head == NULL) || (new == NULL)) + return 0; + + if (*head == NULL) + { + COPY(*head, new); + (*head)->next = NULL; + return 0; + } + + new_vol = ubi32_to_cpu(new->inner.vol_id); + new_num = ubi32_to_cpu(new->inner.lnum); + new_ver = ubi32_to_cpu(new->inner.leb_ver); + + /** TRAVERSE HORIZONTALY **/ + + cur = *head; + prev = NULL; + + /* traverse until vol_id/lnum align */ + vol = ubi32_to_cpu(cur->inner.vol_id); + num = ubi32_to_cpu(cur->inner.lnum); + while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) + { + /* insert new at end of chain */ + if (cur->next == NULL) + { + COPY(ins, new); + ins->next = NULL; + cur->next = ins; + return 0; + } + + prev = cur; + cur = cur->next; + vol = ubi32_to_cpu(cur->inner.vol_id); + num = ubi32_to_cpu(cur->inner.lnum); + } + + if (prev == NULL) + prev_ptr = head; + else + prev_ptr = &(prev->next); + + /* insert new into the middle of chain */ + if ((new_vol != vol) || (new_num != num)) + { + COPY(ins, new); + ins->next = cur; + *prev_ptr = ins; + return 0; + } + + /** TRAVERSE VERTICALY **/ + + hist = cur; + prev = NULL; + + /* traverse until versions align */ + ver = ubi32_to_cpu(cur->inner.leb_ver); + while (new_ver < ver) + { + /* insert new at bottom of history */ + if (hist->older == NULL) + { + COPY(ins, new); + ins->next = NULL; + ins->older = NULL; + hist->older = ins; + return 0; + } + + prev = hist; + hist = hist->older; + ver = ubi32_to_cpu(hist->inner.leb_ver); + } + + if (prev == NULL) + { + /* replace active version */ + COPY(ins, new); + ins->next = hist->next; + *prev_ptr = ins; + + /* place cur in vertical histroy */ + ins->older = hist; + hist->next = NULL; + return 0; + } + else + { + /* insert between versions, beneath active version */ + COPY(ins, new); + ins->next = NULL; + ins->older = prev->older; + prev->older = ins; + return 0; + } + + /* logically impossible to reach this point... hopefully */ + return -EAGAIN; +} + + +/** + * sets the pointer at pos to the position of the first entry in the chain + * with of vol_id and, if given, with the same lnum as *lnum; + * if there is no entry in the chain, then *pos is NULL on return; + * always returns 0; + **/ +int +eb_chain_position(eb_info_t *head, uint32_t vol_id, uint32_t *lnum, + eb_info_t *pos) +{ + uint32_t vol, num; + eb_info_t cur; + + if ((head == NULL) || (*head == NULL) || (pos == NULL)) + return 0; + + *pos = NULL; + + cur = *head; + while (cur != NULL) + { + vol = ubi32_to_cpu(cur->inner.vol_id); + num = ubi32_to_cpu(cur->inner.lnum); + + if (vol_id == vol) + if ((lnum == NULL) || (*lnum == num)) + { + *pos = cur; + return 0; + } + + cur = cur->next; + } + + return 0; +} + + +/** + * prints to stream, the vol_id, lnum and leb_ver for each entry in the + * chain, starting at head; + * this is intended for debuging purposes; + * always returns 0; + **/ +int +eb_chain_print(FILE* stream, eb_info_t *head) +{ + eb_info_t cur; + + if (head == NULL) + return 0; + + if (stream == NULL) + stream = stdout; + + if (*head == NULL) + { + fprintf(stream, "EMPTY\n"); + return 0; + } + + cur = *head; + while (cur != NULL) + { + eb_info_t hist; + + fprintf(stream, " VOL %4u-%04u | VER 0x%8x\n", + ubi32_to_cpu(cur->inner.vol_id), + ubi32_to_cpu(cur->inner.lnum), + ubi32_to_cpu(cur->inner.leb_ver)); + + hist = cur->older; + while (hist != NULL) + { + fprintf(stream, "+ VOL %4u-%04u | VER 0x%8x\n", + ubi32_to_cpu(hist->inner.vol_id), + ubi32_to_cpu(hist->inner.lnum), + ubi32_to_cpu(hist->inner.leb_ver)); + + hist = hist->older; + } + + cur = cur->next; + } + + return 0; +} + + +/** + * frees the memory of the entire chain, starting at head; + * head will be NULL on return; + * always returns 0; + **/ +int +eb_chain_destroy(eb_info_t *head) +{ + if (head == NULL) + return 0; + + while (*head != NULL) + { + eb_info_t cur; + eb_info_t hist; + + cur = *head; + *head = (*head)->next; + + hist = cur->older; + while (hist != NULL) + { + eb_info_t temp; + + temp = hist; + hist = hist->older; + + free(temp); + } + + free(cur); + } + + return 0; +} + diff --git a/ubi-utils/src/eb_chain.h b/ubi-utils/src/eb_chain.h new file mode 100644 index 0000000..f640c54 --- /dev/null +++ b/ubi-utils/src/eb_chain.h @@ -0,0 +1,73 @@ +#ifndef __EB_CHAIN_H__ +#define __EB_CHAIN_H__ + +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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. + */ + +/* + * Author: Drake Dowsett + * Contact: Andreas Arnez (arnez@de.ibm.com) + * + * Eraseblock Chain + * + * A linked list structure to order eraseblocks by volume and logical number + * and to update by version number. Doesn't contain actual eraseblock data + * but rather the erasecounter and volume id headers as well as a position + * indicator. + * + * Diagram Example: + * + * [V1.0v0]->[V1.1v2]->[V1.2v1]->[V2.0v2]->[V2.1v0]->[V2.2v1]->NULL + * | | | | | | + * NULL [V1.1v1] [V1.2v0] [V2.0v1] NULL [V2.2v0] + * | | | | + * [V1.1v0] NULL [V2.0v0] NULL + * | | + * NULL NULL + * + * [VA.BvC] represents the eb_info for the eraseblock with the vol_id A, + * lnum B and leb_ver C + * -> represents the `next' pointer + * | represents the `older' pointer + */ + +#include +#include +#include + +typedef struct eb_info *eb_info_t; +struct eb_info { + struct ubi_ec_hdr outer; + struct ubi_vid_hdr inner; + fpos_t eb_top; + uint32_t linear; + + eb_info_t next; + eb_info_t older; +}; + +int eb_chain_insert(eb_info_t *head, eb_info_t item); + +int eb_chain_position(eb_info_t *head, uint32_t vol_id, uint32_t *lnum, + eb_info_t *pos); + +int eb_chain_print(FILE *stream, eb_info_t *head); + +int eb_chain_destroy(eb_info_t *head); + +#endif /* __EB_CHAIN_H__ */ diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c index 6d877e7..4b9ddfd 100644 --- a/ubi-utils/src/unubi.c +++ b/ubi-utils/src/unubi.c @@ -14,13 +14,23 @@ * 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. - * - * Author: Frank Haverkamp - * - * An utility to decompose UBI images. Not yet finished ... */ -#include +/* + * Authors: Frank Haverkamp, haver@vnet.ibm.com + * Drake Dowsett, dowsett@de.ibm.com + */ + +/* + * unubi reads an image file containing blocks of UBI headers and data + * (such as produced from nand2bin) and rebuilds the volumes within. The + * default operation (when no flags are given) is to rebuild all valid + * volumes found in the image. unubi can also read straight from the + * onboard MTD device (ex. /dev/mtdblock/NAND). + */ + +/* TODO: consideration for dynamic vs. static volumes */ + #include #include #include @@ -34,359 +44,802 @@ #include #include #include +#include #include "crc32.h" -#include +#include "eb_chain.h" +#include "unubi_analyze.h" + +#define EXEC "unubi" +#define CONTACT "haver@vnet.ibm.com" +#define VERSION "0.9" + +static char doc[] = "\nVersion: " VERSION "\n\t" + BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" + "\nAnalyze raw flash containing UBI data.\n"; + +#define ERR_MSG(fmt...) \ + fprintf(stderr, EXEC ": " fmt) -#define MAXPATH 1024 -#define MIN(x,y) ((x)<(y)?(x):(y)) +#define SPLIT_DATA 1 +#define SPLIT_RAW 2 + +#define DIR_FMT "unubi_%s" +#define KIB 1024 +#define MIB (KIB * KIB) +#define MAXPATH KIB + +/* filenames */ +#define FN_INVAL "%s/eb%04u%s" /* invalid eraseblock */ +#define FN_NSURE "%s/eb%04u_%03u_%03u_%03x%s" /* unsure eraseblock */ +#define FN_VALID "%s/eb%04u_%03u_%03u_%03x%s" /* valid eraseblock */ +#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04u" /* split volume */ +#define FN_VOLWH "%s/volume%03u" /* whole volume */ static uint32_t crc32_table[256]; +/* struct args: + * bsize int, blocksize of image blocks + * analyze flag, when non-zero produce analysis + * eb_split flag, when non-zero output eb#### + * note: SPLIT_DATA vs. SPLIT_RAW + * vol_split flag, when non-zero output vol###_#### + * note: SPLIT_DATA vs. SPLIT_RAW + * odir_path string, directory to place volumes in + * img_path string, file to read as ubi image + * vols int array of size UBI_MAX_VOLUMES, where a 1 can be + * written for each --rebuild flag in the index specified + * then the array can be counted and collapsed using + * count_set() and collapse() + */ struct args { - const char *output_dir; - uint32_t hdr_offs; - uint32_t data_offs; - uint32_t blocksize; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ + uint32_t bsize; + int analyze; + int eb_split; + int vol_split; + char *odir_path; + char *img_path; + uint32_t *vols; + + char **options; }; -static struct args myargs = { - .output_dir = "unubi", - .hdr_offs = 64, - .data_offs = 128, - .blocksize = 128 * 1024, - .arg1 = NULL, - .options = NULL, -}; +static error_t parse_opt(int key, char *arg, struct argp_state *state); -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -const char *argp_program_bug_address = - "... uuuh, lets wait until it looks nicer"; - -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\t" - BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" - "\nWrite to UBI Volume.\n"; +const char *argp_program_version = VERSION; +const char *argp_program_bug_address = CONTACT; static struct argp_option options[] = { - { .name = "dir", - .key = 'd', - .arg = "", - .flags = 0, - .doc = "output directory", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "blocksize", - .key = 'b', - .arg = "", - .flags = 0, - .doc = "blocksize", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "data-offs", - .key = 'x', - .arg = "", - .flags = 0, - .doc = "data offset", - .group = OPTION_ARG_OPTIONAL }, - - { .name = "hdr-offs", - .key = 'x', - .arg = "", - .flags = 0, - .doc = "hdr offset", - .group = OPTION_ARG_OPTIONAL }, - - { .name = NULL, .key = 0, .arg = NULL, .flags = 0, - .doc = NULL, .group = 0 }, + { + name: NULL, key: 0, arg: NULL, + flags: 0, group: 0, doc: "OPTIONS", + }, + { + name: "rebuild", key: 'r', arg: "", + flags: 0, group: 1, doc: "Extract and rebuild volume", + }, + { + name: "dir", key: 'd', arg: "", + flags: 0, group: 2, doc: "Specify output directory", + }, + { + name: "analyze", key: 'a', arg: NULL, + flags: 0, group: 3, doc: "Analyze image", + }, + { + name: "blocksize", key: 'b', arg: "", + flags: 0, group: 4, doc: "Specify size of eraseblocks " + "in image in bytes (default " + "128KiB)", + }, + { + name: "eb-split", key: 'e', arg: NULL, + flags: 0, group: 5, doc: "Generate individual eraseblock " + "images (all eraseblocks)", + }, + { + name: "vol-split", key: 'v', arg: NULL, + flags: 0, group: 5, doc: "Generate individual eraseblock " + "images (valid eraseblocks only)", + }, + { + name: "vol-split!", key: 'V', arg: NULL, + flags: 0, group: 5, doc: "Raw split by eraseblock " + "(valid eraseblocks only)", + }, + { + name: NULL, key: 0, arg: NULL, + flags: 0, group: 0, doc: NULL, + }, }; static struct argp argp = { .options = options, .parser = parse_opt, .args_doc = "image-file", - .doc = doc, + .doc = doc, .children = NULL, .help_filter = NULL, .argp_domain = NULL, }; -/* - * str_to_num - Convert string into number and cope with endings like - * k, K, kib, KiB for kilobyte - * m, M, mib, MiB for megabyte - */ -uint32_t str_to_num(char *str) + +/** + * parses out a numerical value from a string of numbers followed by: + * k, K, kib, KiB for kibibyte + * m, M, mib, MiB for mebibyte + **/ +static uint32_t +str_to_num(char *str) { - char *s = str; - ulong num = strtoul(s, &s, 0); + char *s; + ulong num; + + s = str; + num = strtoul(s, &s, 0); if (*s != '\0') { - if (strcmp(s, "KiB") == 0) - num *= 1024; - else if (strcmp(s, "MiB") == 0) - num *= 1024*1024; - else { - fprintf(stderr, "WARNING: Wrong number format " - "\"%s\", check your paramters!\n", str); - } + if ((strcmp(s, "KiB") == 0) || (strcmp(s, "K") == 0) || + (strcmp(s, "kib") == 0) || (strcmp(s, "k") == 0)) + num *= KIB; + if ((strcmp(s, "MiB") == 0) || (strcmp(s, "M") == 0) || + (strcmp(s, "mib") == 0) || (strcmp(s, "m") == 0)) + num *= MIB; + else + ERR_MSG("couldn't parse '%s', assuming %lu\n", + s, num); } return num; } -/* - * @brief Parse the arguments passed into the test case. - * - * @param key The parameter. - * @param arg Argument passed to parameter. - * @param state Location to put information on parameters. - * - * @return error - * - * Get the `input' argument from `argp_parse', which we know is a - * pointer to our arguments structure. - */ + +/** + * parses the arguments passed into the program + * get the input argument from argp_parse, which we know is a + * pointer to our arguments structure; + **/ static error_t parse_opt(int key, char *arg, struct argp_state *state) { + uint32_t i; struct args *args = state->input; switch (key) { - case 'b': /* --blocksize */ - args->blocksize = str_to_num(arg); + case 'a': + args->analyze = 1; break; - - case 'x': /* --data-offs= */ - args->data_offs = str_to_num(arg); + case 'b': + args->bsize = str_to_num(arg); break; - - case 'y': /* --hdr-offs= */ - args->hdr_offs = str_to_num(arg); + case 'd': + args->odir_path = arg; break; - - case 'd': /* --dir= */ - args->output_dir = arg; + case 'e': + args->eb_split = SPLIT_RAW; + break; + case 'r': + i = str_to_num(arg); + if (i < UBI_MAX_VOLUMES) + args->vols[str_to_num(arg)] = 1; + else { + ERR_MSG("volume-id out of bounds\n"); + return ARGP_ERR_UNKNOWN; + } + break; + case 'v': + if (args->vol_split != SPLIT_RAW) + args->vol_split = SPLIT_DATA; + break; + case 'V': + args->vol_split = SPLIT_RAW; break; - case ARGP_KEY_NO_ARGS: - /* argp_usage(state); */ break; - case ARGP_KEY_ARG: - args->arg1 = arg; - /* Now we consume all the rest of the arguments. - `state->next' is the index in `state->argv' of the - next argument to be parsed, which is the first STRING - we're interested in, so we can just use - `&state->argv[state->next]' as the value for - arguments->strings. - - _In addition_, by setting `state->next' to the end - of the arguments, we can force argp to stop parsing - here and return. */ - + args->img_path = arg; args->options = &state->argv[state->next]; state->next = state->argc; break; - case ARGP_KEY_END: - /* argp_usage(state); */ break; - default: - return(ARGP_ERR_UNKNOWN); + return ARGP_ERR_UNKNOWN; } return 0; } -static inline void -hexdump(FILE *fp, const void *p, ssize_t size) + +/** + * counts the number of indicies which are flagged in full_array; + * full_array is an array of flags (1/0); + **/ +static size_t +count_set(uint32_t *full_array, size_t full_len) { - int k; - const uint8_t *buf = p; + size_t count, i; - for (k = 0; k < size; k++) { - fprintf(fp, "%02x ", buf[k]); - if ((k & 15) == 15) - fprintf(fp, "\n"); - } + if (full_array == NULL) + return 0; + + for (i = 0, count = 0; i < full_len; i++) + if (full_array[i] != 0) + count++; + + return count; } -/* - * This was put together in 1.5 hours and this is exactly how it looks - * like! FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME - * FIXME FIXME FIXME FIXME FIXME FIXME! - */ -static int extract_volume(struct args *args, const uint8_t *buf, - int len, int volume, FILE *fp) + +/** + * generates coll_array from full_array; + * full_array is an array of flags (1/0); + * coll_array is an array of the indicies in full_array which are flagged (1); + **/ +static size_t +collapse(uint32_t *full_array, size_t full_len, + uint32_t *coll_array, size_t coll_len) { - int i, rc; - int nrblocks = len / args->blocksize; - int max_lnum = -1, lnum = 0; - const uint8_t *ptr; - uint8_t **vol_tab; - int *vol_len; + size_t i, j; - vol_tab = calloc(nrblocks, sizeof(uint8_t *)); - vol_len = calloc(nrblocks, sizeof(int)); + if ((full_array == NULL) || (coll_array == NULL)) + return 0; - if (!buf || !vol_tab || !vol_len) - exit(EXIT_FAILURE); + for (i = 0, j = 0; (i < full_len) && (j < coll_len); i++) + if (full_array[i] != 0) { + coll_array[j] = i; + j++; + } - for (i = 0, ptr = buf; i < nrblocks; i++, ptr += args->blocksize) { - uint32_t crc; - struct ubi_ec_hdr *ec_hdr = (struct ubi_ec_hdr *)ptr; - struct ubi_vid_hdr *vid_hdr = NULL; - uint8_t *data; + return j; +} + + +/** + * header_crc: calculate the crc of EITHER a eb_hdr or vid_hdr + * one of the first to args MUST be NULL, the other is the header + * to caculate the crc on + * always returns 0 + **/ +static int +header_crc(struct ubi_ec_hdr *ebh, struct ubi_vid_hdr *vidh, uint32_t *ret_crc) +{ + uint32_t crc = UBI_CRC32_INIT; + + if (ret_crc == NULL) + return 0; + + if ((ebh != NULL) && (vidh == NULL)) + crc = clc_crc32(crc32_table, crc, ebh, UBI_EC_HDR_SIZE_CRC); + else if ((ebh == NULL) && (vidh != NULL)) + crc = clc_crc32(crc32_table, crc, vidh, UBI_VID_HDR_SIZE_CRC); + else + return 0; + + *ret_crc = crc; + return 0; +} - /* default */ - vol_len[lnum] = args->blocksize - (2 * 1024); - /* Check UBI EC header */ - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, ec_hdr, - UBI_EC_HDR_SIZE_CRC); - if (crc != ubi32_to_cpu(ec_hdr->hdr_crc)) - continue; +/** + * data_crc: save the FILE* position, calculate the crc over a span, + * reset the position + * returns non-zero when EOF encountered + **/ +static int +data_crc(FILE* fpin, size_t length, uint32_t *ret_crc) +{ + int rc; + size_t i; + char buf[length]; + uint32_t crc; + fpos_t start; + + rc = fgetpos(fpin, &start); + if (rc < 0) + return -1; + + for (i = 0; i < length; i++) { + int c = fgetc(fpin); + if (c == EOF) { + ERR_MSG("unexpected EOF\n"); + return -1; + } + buf[i] = (char)c; + } - vid_hdr = (struct ubi_vid_hdr *) - (ptr + ubi32_to_cpu(ec_hdr->vid_hdr_offset)); - data = (uint8_t *)(ptr + ubi32_to_cpu(ec_hdr->data_offset)); + rc = fsetpos(fpin, &start); + if (rc < 0) + return -1; - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, vid_hdr, - UBI_VID_HDR_SIZE_CRC); - if (crc != ubi32_to_cpu(vid_hdr->hdr_crc)) - continue; + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, length); + *ret_crc = crc; + return 0; +} + + +/** + * reads data of size len from fpin and writes it to path + **/ +static int +extract_data(FILE* fpin, size_t len, const char *path) +{ + int rc; + size_t i; + FILE* fpout; + + rc = 0; + fpout = NULL; + + fpout = fopen(path, "wb"); + if (fpout == NULL) { + ERR_MSG("couldn't open file for writing: %s\n", path); + rc = -1; + goto err; + } - if (volume == (int)ubi32_to_cpu(vid_hdr->vol_id)) { + for (i = 0; i < len; i++) { + int c = fgetc(fpin); + if (c == EOF) { + ERR_MSG("unexpected EOF while writing: %s\n", path); + rc = -2; + goto err; + } + c = fputc(c, fpout); + if (c == EOF) { + ERR_MSG("couldn't write: %s\n", path); + rc = -3; + goto err; + } + } - printf("****** block %4d volume %2d **********\n", - i, volume); + err: + if (fpout != NULL) + fclose(fpout); + return rc; +} - hexdump(stdout, ptr, 64); - printf("--- vid_hdr\n"); - hexdump(stdout, vid_hdr, 64); +/** + * using eb chain, tries to rebuild the data of volume at vol_id, or for all + * the known volumes, if vol_id is NULL; + **/ +static int +rebuild_volume(FILE* fpin, uint32_t *vol_id, eb_info_t *head, const char* path) +{ + char filename[MAXPATH]; + int rc; + uint32_t vol, num; + FILE* fpout; + eb_info_t cur; - printf("--- data\n"); - hexdump(stdout, data, 64); + rc = 0; - lnum = ubi32_to_cpu(vid_hdr->lnum); - vol_tab[lnum] = data; - if (max_lnum < lnum) - max_lnum = lnum; - if (vid_hdr->vol_type == UBI_VID_STATIC) - vol_len[lnum] = - ubi32_to_cpu(vid_hdr->data_size); + if ((fpin == NULL) || (head == NULL) || (*head == NULL)) + return 0; + /* when vol_id is null, then do all */ + if (vol_id == NULL) { + cur = *head; + vol = ubi32_to_cpu(cur->inner.vol_id); + } + else { + vol = *vol_id; + eb_chain_position(head, vol, NULL, &cur); + if (cur == NULL) { + ERR_MSG("no valid volume %d was found\n", vol); + return -1; } } - for (lnum = 0; lnum <= max_lnum; lnum++) { - if (vol_tab[lnum]) { - rc = fwrite(vol_tab[lnum], 1, vol_len[lnum], fp); - if (ferror(fp) || (vol_len[lnum] != rc)) { - perror("could not write file"); - exit(EXIT_FAILURE); + num = 0; + snprintf(filename, MAXPATH, FN_VOLWH, path, vol); + fpout = fopen(filename, "wb"); + if (fpout == NULL) { + ERR_MSG("couldn't open file for writing: %s\n", filename); + return -1; + } + + while (cur != NULL) { + size_t i; + + if (ubi32_to_cpu(cur->inner.vol_id) != vol) { + /* close out file */ + fclose(fpout); + + /* only stay around if that was the only volume */ + if (vol_id != NULL) + goto out; + + /* begin with next */ + vol = ubi32_to_cpu(cur->inner.vol_id); + num = 0; + snprintf(filename, MAXPATH, FN_VOLWH, path, vol); + fpout = fopen(filename, "wb"); + if (fpout == NULL) { + ERR_MSG("couldn't open file for writing: %s\n", + filename); + return -1; } - } else { - /* Fill up empty areas by 0xff, for static - * volumes this means they are broken! - */ - for (i = 0; i < vol_len[lnum]; i++) { - if (fputc(0xff, fp) == EOF) { - perror("could not write char"); - exit(EXIT_FAILURE); - } + } + + if (ubi32_to_cpu(cur->inner.lnum) != num) { + ERR_MSG("missing valid block %d for volume %d\n", + num, vol); + } + + rc = fsetpos(fpin, &(cur->eb_top)); + if (rc < 0) + goto out; + fseek(fpin, ubi32_to_cpu(cur->outer.data_offset), SEEK_CUR); + + for (i = 0; i < ubi32_to_cpu(cur->inner.data_size); i++) { + int c = fgetc(fpin); + if (c == EOF) { + ERR_MSG("unexpected EOF while writing: %s\n", + filename); + rc = -2; + goto out; + } + c = fputc(c, fpout); + if (c == EOF) { + ERR_MSG("couldn't write: %s\n", filename); + rc = -3; + goto out; } } + + cur = cur->next; + num++; } - free(vol_tab); - free(vol_len); - return 0; + out: + if (vol_id == NULL) + fclose(fpout); + return rc; } -int -main(int argc, char *argv[]) + +/** + * traverses FILE* trying to load complete, valid and accurate header data + * into the eb chain; + **/ +static int +unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) { - int len, rc; - FILE *fp; - struct stat file_info; - uint8_t *buf; - int i; + char filename[MAXPATH + 1]; + char reason[MAXPATH + 1]; + int rc; + size_t i, count; + /* relations: + * cur ~ head + * next ~ first */ + eb_info_t head, cur, first, next; + eb_info_t *next_ptr; + + rc = 0; + count = 0; + head = NULL; + first = NULL; + next = NULL; + cur = malloc(sizeof(*cur)); + if (cur == NULL) { + ERR_MSG("out of memory\n"); + rc = -ENOMEM; + goto err; + } + memset(cur, 0, sizeof(*cur)); - init_crc32_table(crc32_table); + fgetpos(fpin, &(cur->eb_top)); + while (1) { + const char *raw_path; + uint32_t crc; + + memset(filename, 0, MAXPATH + 1); + memset(reason, 0, MAXPATH + 1); + + /* in case of an incomplete ec header */ + raw_path = FN_INVAL; + + /* read erasecounter header */ + rc = fread(&cur->outer, 1, sizeof(cur->outer), fpin); + if (rc == 0) + goto out; /* EOF */ + if (rc != sizeof(cur->outer)) { + ERR_MSG("reading ec-hdr failed rc=%d\n", rc); + rc = -1; + goto err; + } + + /* check erasecounter header magic */ + if (ubi32_to_cpu(cur->outer.magic) != UBI_EC_HDR_MAGIC) { + snprintf(reason, MAXPATH, ".invalid.ec_magic"); + goto invalid; + } + + /* check erasecounter header crc */ + header_crc(&(cur->outer), NULL, &crc); + + if (ubi32_to_cpu(cur->outer.hdr_crc) != crc) { + snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc"); + goto invalid; + } + + /* read volume id header */ + rc = fsetpos(fpin, &(cur->eb_top)); + if (rc != 0) + goto err; + fseek(fpin, ubi32_to_cpu(cur->outer.vid_hdr_offset), SEEK_CUR); + + /* read erasecounter header */ + rc = fread(&cur->inner, 1, sizeof(cur->inner), fpin); + if (rc == 0) + goto out; /* EOF */ + if (rc != sizeof(cur->inner)) { + ERR_MSG("reading vid-hdr failed rc=%d\n", rc); + rc = -1; + goto err; + } + + /* empty? */ + if (ubi32_to_cpu(cur->inner.magic) == 0xffffffff) { + snprintf(reason, MAXPATH, ".empty"); + goto invalid; + } + + /* vol_id should be in bounds */ + if ((ubi32_to_cpu(cur->inner.vol_id) >= UBI_MAX_VOLUMES) && + (ubi32_to_cpu(cur->inner.vol_id) < + UBI_INTERNAL_VOL_START)) { + snprintf(reason, MAXPATH, ".invalid"); + goto invalid; + } else + raw_path = FN_NSURE; + + /* check volume id header magic */ + if (ubi32_to_cpu(cur->inner.magic) != UBI_VID_HDR_MAGIC) { + snprintf(reason, MAXPATH, ".invalid.vid_magic"); + goto invalid; + } + + /* check volume id header crc */ + header_crc(NULL, &(cur->inner), &crc); + if (ubi32_to_cpu(cur->inner.hdr_crc) != crc) { + snprintf(reason, MAXPATH, ".invalid.vid_hdr_crc"); + goto invalid; + } + + /* check data crc */ + rc = data_crc(fpin, ubi32_to_cpu(cur->inner.data_size), &crc); + if (rc < 0) + goto err; + if (ubi32_to_cpu(cur->inner.data_crc) != crc) { + snprintf(reason, MAXPATH, ".invalid.data_crc"); + goto invalid; + } - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &myargs); + /* enlist this vol, it's valid */ + raw_path = FN_VALID; + cur->linear = count; + rc = eb_chain_insert(&head, cur); + if (rc < 0) { + if (rc == -ENOMEM) { + ERR_MSG("out of memory\n"); + goto err; + } + ERR_MSG("unknown and unexpected error, please contact " + CONTACT "\n"); + goto err; + } + + if (a->vol_split) { + size_t size = 0; - if (!myargs.arg1) { - fprintf(stderr, "Please specify input file!\n"); - exit(EXIT_FAILURE); + rc = fsetpos(fpin, &(cur->eb_top)); + if (rc != 0) + goto err; + + if (a->vol_split == SPLIT_DATA) { + /* write only data section */ + size = ubi32_to_cpu(cur->inner.data_size); + fseek(fpin, + ubi32_to_cpu(cur->outer.data_offset), + SEEK_CUR); + } + else if (a->vol_split == SPLIT_RAW) + /* write entire eraseblock */ + size = a->bsize; + + snprintf(filename, MAXPATH, FN_VOLSP, + a->odir_path, + ubi32_to_cpu(cur->inner.vol_id), + ubi32_to_cpu(cur->inner.lnum), + ubi32_to_cpu(cur->inner.leb_ver), count); + rc = extract_data(fpin, size, filename); + if (rc < 0) + goto err; + } + + invalid: + if (a->eb_split) { + /* jump to top of block */ + rc = fsetpos(fpin, &(cur->eb_top)); + if (rc != 0) + goto err; + + if (strcmp(raw_path, FN_INVAL) == 0) + snprintf(filename, MAXPATH, raw_path, + a->odir_path, count, reason); + else + snprintf(filename, MAXPATH, raw_path, + a->odir_path, + count, + ubi32_to_cpu(cur->inner.vol_id), + ubi32_to_cpu(cur->inner.lnum), + ubi32_to_cpu(cur->inner.leb_ver), + reason); + + rc = extract_data(fpin, a->bsize, filename); + if (rc < 0) + goto err; + } + + /* append to simple linked list */ + if (first == NULL) + next_ptr = &first; + else + next_ptr = &next->next; + + *next_ptr = malloc(sizeof(**next_ptr)); + if (*next_ptr == NULL) { + ERR_MSG("out of memory\n"); + rc = -ENOMEM; + goto err; + } + memset(*next_ptr, 0, sizeof(**next_ptr)); + + next = *next_ptr; + memcpy(next, cur, sizeof(*next)); + next->next = NULL; + + count++; + rc = fsetpos(fpin, &(cur->eb_top)); + if (rc != 0) + goto err; + fseek(fpin, a->bsize, SEEK_CUR); + memset(cur, 0, sizeof(*cur)); + + fgetpos(fpin, &(cur->eb_top)); } - fp = fopen(myargs.arg1, "r"); - if (!fp) { - perror("Cannot open file"); - exit(EXIT_FAILURE); + out: + for (i = 0; i < vc; i++) { + rc = rebuild_volume(fpin, &vols[i], &head, a->odir_path); + if (rc < 0) + goto err; } - if (fstat(fileno(fp), &file_info) != 0) { - fprintf(stderr, "Cannot fetch file size " - "from input file.\n"); + + /* if there were no volumes specified, rebuild them all, + * UNLESS eb_ or vol_ split or analyze was specified */ + if ((vc == 0) && (!a->eb_split) && (!a->vol_split) && (!a->analyze)) { + rc = rebuild_volume(fpin, NULL, &head, a->odir_path); + if (rc < 0) + goto err; } - len = file_info.st_size; - buf = malloc(len); - if (!buf) { - perror("out of memory!"); - exit(EXIT_FAILURE); + + err: + free(cur); + + if (a->analyze) + unubi_analyze(&head, first, a->odir_path); + eb_chain_destroy(&head); + eb_chain_destroy(&first); + + return rc; +} + + +/** + * handles command line arguments, then calls unubi_volumes + **/ +int +main(int argc, char *argv[]) +{ + int rc, free_a_odir; + size_t vols_len; + uint32_t *vols; + FILE* fpin; + struct args a; + + rc = 0; + free_a_odir = 0; + vols_len = 0; + vols = NULL; + fpin = NULL; + init_crc32_table(crc32_table); + + /* setup struct args a */ + memset(&a, 0, sizeof(a)); + a.bsize = 128 * KIB; + a.vols = malloc(sizeof(*a.vols) * UBI_MAX_VOLUMES); + if (a.vols == NULL) { + ERR_MSG("out of memory\n"); + rc = ENOMEM; + goto err; } - rc = fread(buf, 1, len, fp); - if (ferror(fp) || (len != rc)) { - perror("could not read file"); - exit(EXIT_FAILURE); + memset(a.vols, 0, sizeof(*a.vols) * UBI_MAX_VOLUMES); + + /* parse args and check for validity */ + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &a); + if (a.img_path == NULL) { + ERR_MSG("no image file specified\n"); + rc = EINVAL; + goto err; } - if (!myargs.output_dir) { - fprintf(stderr, "No output directory specified!\n"); - exit(EXIT_FAILURE); + else if (a.odir_path == NULL) { + char *ptr; + int len; + + ptr = strrchr(a.img_path, '/'); + if (ptr == NULL) + ptr = a.img_path; + else + ptr++; + + len = strlen(DIR_FMT) + strlen(ptr); + free_a_odir = 1; + a.odir_path = malloc(sizeof(*a.odir_path) * len); + if (a.odir_path == NULL) { + ERR_MSG("out of memory\n"); + rc = ENOMEM; + goto err; + } + snprintf(a.odir_path, len, DIR_FMT, ptr); + } + + fpin = fopen(a.img_path, "rb"); + if (fpin == NULL) { + ERR_MSG("couldn't open file for reading: " + "%s\n", a.img_path); + rc = EINVAL; + goto err; } - rc = mkdir(myargs.output_dir, 0777); - if (rc && errno != EEXIST) { - perror("Cannot create output directory"); - exit(EXIT_FAILURE); + rc = mkdir(a.odir_path, 0777); + if ((rc < 0) && (errno != EEXIST)) { + ERR_MSG("couldn't create ouput directory: " + "%s\n", a.odir_path); + rc = -rc; + goto err; } - for (i = 0; i < 32; i++) { - char fname[1024]; - FILE *fpout; - - printf("######### VOLUME %d ############################\n", - i); - - sprintf(fname, "%s/ubivol_%d.bin", myargs.output_dir, i); - fpout = fopen(fname, "w+"); - if (!fpout) { - perror("Cannot open file"); - exit(EXIT_FAILURE); + + /* fill in vols array */ + vols_len = count_set(a.vols, UBI_MAX_VOLUMES); + if (vols_len > 0) { + vols = malloc(sizeof(*vols) * vols_len); + if (vols == NULL) { + ERR_MSG("out of memory\n"); + rc = ENOMEM; + goto err; } - extract_volume(&myargs, buf, len, i, fpout); - fclose(fpout); + collapse(a.vols, UBI_MAX_VOLUMES, vols, vols_len); + } + + /* unubi volumes */ + rc = unubi_volumes(fpin, vols, vols_len, &a); + if (rc < 0) { + ERR_MSG("error encountered while working on image file: " + "%s\n", a.img_path); + rc = -rc; + goto err; } - fclose(fp); - free(buf); - exit(EXIT_SUCCESS); + err: + free(a.vols); + if (free_a_odir != 0) + free(a.odir_path); + if (fpin != NULL) + fclose(fpin); + if (vols_len > 0) + free(vols); + return rc; } diff --git a/ubi-utils/src/unubi_analyze.c b/ubi-utils/src/unubi_analyze.c new file mode 100644 index 0000000..2e94ca9 --- /dev/null +++ b/ubi-utils/src/unubi_analyze.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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. + */ + +/* + * Authors: Drake Dowsett, dowsett@de.ibm.com + * Contact: Andreas Arnez, arnez@de.ibm.com + * + * unubi uses the following functions to generate analysis output based on + * the header information in a raw-UBI image + */ + +/* + * TODO: use OOB data to check for eraseblock validity in NAND images + */ + +#include +#include +#include +#include +#include +#include + +#include "eb_chain.h" +#include "crc32.h" + +#define MAXPATH 1024 +#define EC_X_INT 50 + +#define FN_STATS "analysis_stats.txt" +#define FN_EH_DATA "analysis_ec_hdr.data" +#define FN_EH_PLOT "analysis_ec_hdr.plot" +#define FN_VH_DATA "analysis_vid_hdr.data" +#define FN_VH_PLOT "analysis_vid_hdr.plot" + + +/** + * intcmp - function needed by qsort to order integers + **/ +int intcmp(const void *a, const void *b) +{ + int A = *(int *)a; + int B = *(int *)b; + return A - B; +} + +int longcmp(const void *a, const void *b) +{ + long long A = *(long long *)a; + long long B = *(long long *)b; + return A - B; +} + + +/** + * unubi_analyze_group_index - finds the normalized index in an array + * item: look for this item in the array + * array: array to search through + * size: length of the array + * array should be sorted for this algorithm to perform properly; + * if the item is not found returns -1, otherwise return value is the + * index in the array (note this contricts the array size to 2^32-1); + **/ +int +norm_index(uint32_t item, uint32_t *array, size_t length) +{ + size_t i, index; + + for (index = 0, i = 0; i < length; i++) { + if ((i != 0) && (array[i] != array[i - 1])) + index++; + + if (item == array[i]) + return index; + } + + return -1; +} + + +/** + * unubi_analyze_ec_hdr - generate data table and plot script + * first: head of simple linked list + * path: folder to write into + * generates a data file containing the eraseblock index in the image + * and the erase counter found in its ec header; + * if the crc check fails, the line is commented out in the data file; + * also generates a simple gnuplot sript for quickly viewing one + * display of the data file; + **/ +int +unubi_analyze_ec_hdr(eb_info_t first, const char *path) +{ + char filename[MAXPATH + 1]; + size_t count, eraseblocks; + uint32_t crc, crc32_table[256]; + uint64_t *erase_counts; + FILE* fpdata; + FILE* fpplot; + eb_info_t cur; + + /* crc check still needed for `first' linked list */ + init_crc32_table(crc32_table); + + /* prepare output files */ + memset(filename, 0, MAXPATH + 1); + snprintf(filename, MAXPATH, "%s/%s", path, FN_EH_DATA); + fpdata = fopen(filename, "w"); + if (fpdata == NULL) + return -1; + + memset(filename, 0, MAXPATH + 1); + snprintf(filename, MAXPATH, "%s/%s", path, FN_EH_PLOT); + fpplot = fopen(filename, "w"); + if (fpplot == NULL) + return -1; + + chmod(filename, 0755); + + /* first run: count elements */ + count = 0; + cur = first; + while (cur != NULL) { + cur = cur->next; + count++; + } + eraseblocks = count; + + erase_counts = malloc(eraseblocks * sizeof(*erase_counts)); + memset(erase_counts, 0, eraseblocks * sizeof(*erase_counts)); + + /* second run: populate array to sort */ + count = 0; + cur = first; + while(cur != NULL) { + erase_counts[count] = ubi64_to_cpu(cur->outer.ec); + cur = cur->next; + count++; + } + qsort(erase_counts, eraseblocks, sizeof(*erase_counts), + (void *)longcmp); + + /* third run: generate data file */ + count = 0; + cur = first; + fprintf(fpdata, "# eraseblock_no actual_erase_count " + "sorted_erase_count\n"); + while (cur != NULL) { + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &cur->outer, + UBI_EC_HDR_SIZE_CRC); + + if ((ubi32_to_cpu(cur->outer.magic) != UBI_EC_HDR_MAGIC) || + (crc != ubi32_to_cpu(cur->outer.hdr_crc))) + fprintf(fpdata, "# "); + + fprintf(fpdata, "%u %llu %llu", count, + ubi64_to_cpu(cur->outer.ec), + erase_counts[count]); + + if (ubi32_to_cpu(cur->outer.magic) != UBI_EC_HDR_MAGIC) + fprintf(fpdata, " ## bad magic: %08x", + ubi32_to_cpu(cur->outer.magic)); + + if (crc != ubi32_to_cpu(cur->outer.hdr_crc)) + fprintf(fpdata, " ## CRC mismatch: given=%08x, " + "calc=%08x", ubi32_to_cpu(cur->outer.hdr_crc), + crc); + + fprintf(fpdata, "\n"); + + cur = cur->next; + count++; + } + fclose(fpdata); + + fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); + fprintf(fpplot, "set xlabel \"eraseblock\"\n"); + + /* fourth run: generate plot file xtics */ + count = 0; + cur = first; + fprintf(fpplot, "set xtics ("); + while (cur != NULL) { + if ((count % EC_X_INT) == 0) { + if (count > 0) + fprintf(fpplot, ", "); + fprintf(fpplot, "%d", count); + } + + cur = cur->next; + count++; + } + fprintf(fpplot, ")\n"); + + fprintf(fpplot, "set ylabel \"erase count\"\n"); + fprintf(fpplot, "set xrange [-1:%u]\n", eraseblocks + 1); + fprintf(fpplot, "# set yrange [-1:%llu]\n", + erase_counts[eraseblocks - 1] + 1); + fprintf(fpplot, "plot \"%s\" u 1:2 t \"unsorted: %s\" with boxes\n", + FN_EH_DATA, FN_EH_DATA); + fprintf(fpplot, "# replot \"%s\" u 1:3 t \"sorted: %s\" with lines\n", + FN_EH_DATA, FN_EH_DATA); + fprintf(fpplot, "pause -1 \"press ENTER\"\n"); + + fclose(fpplot); + + return 0; +} + + +/** + * unubi_analyze_vid_hdr - generate data table and plot script + * head: head of complex linked list (eb_chain) + * path: folder to write into + * generates a data file containing the volume id, logical number, leb version, + * and data size from the vid header; + * all eraseblocks listed in the eb_chain are valid (checked in unubi); + * also generates a simple gnuplot sript for quickly viewing one + * display of the data file; + **/ +int +unubi_analyze_vid_hdr(eb_info_t *head, const char *path) +{ + char filename[MAXPATH + 1]; + int y1, y2; + size_t count, step, breadth; + uint32_t *leb_versions, *data_sizes; + FILE* fpdata; + FILE* fpplot; + eb_info_t cur; + + /* prepare output files */ + memset(filename, 0, MAXPATH + 1); + snprintf(filename, MAXPATH, "%s/%s", path, FN_VH_DATA); + fpdata = fopen(filename, "w"); + if (fpdata == NULL) + return -1; + + memset(filename, 0, MAXPATH + 1); + snprintf(filename, MAXPATH, "%s/%s", path, FN_VH_PLOT); + fpplot = fopen(filename, "w"); + if (fpplot == NULL) + return -1; + + chmod(filename, 0755); + + /* first run: count elements */ + count = 0; + cur = *head; + while (cur != NULL) { + cur = cur->next; + count++; + } + breadth = count; + + leb_versions = malloc(breadth * sizeof(*leb_versions)); + memset(leb_versions, 0, breadth * sizeof(*leb_versions)); + + data_sizes = malloc(breadth * sizeof(*data_sizes)); + memset(data_sizes, 0, breadth * sizeof(*data_sizes)); + + /* second run: populate arrays to sort */ + count = 0; + cur = *head; + while (cur != NULL) { + leb_versions[count] = ubi32_to_cpu(cur->inner.leb_ver); + data_sizes[count] = ubi32_to_cpu(cur->inner.data_size); + cur = cur->next; + count++; + } + qsort(leb_versions, breadth, sizeof(*leb_versions), (void *)intcmp); + qsort(data_sizes, breadth, sizeof(*data_sizes), (void *)intcmp); + + /* third run: generate data file */ + count = 0; + cur = *head; + fprintf(fpdata, "# x_axis vol_id lnum y1_axis leb_ver " + "y2_axis data_size\n"); + while (cur != NULL) { + y1 = norm_index(ubi32_to_cpu(cur->inner.leb_ver), leb_versions, + breadth); + y2 = norm_index(ubi32_to_cpu(cur->inner.data_size), data_sizes, + breadth); + + if ((y1 == -1) || (y2 == -1)) + return -1; + + fprintf(fpdata, "%u %u %u %u %u %u %u\n", + count, + ubi32_to_cpu(cur->inner.vol_id), + ubi32_to_cpu(cur->inner.lnum), + y1, + ubi32_to_cpu(cur->inner.leb_ver), + y2, + ubi32_to_cpu(cur->inner.data_size)); + cur = cur->next; + count++; + } + fclose(fpdata); + + fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); + fprintf(fpplot, "set xlabel \"volume\"\n"); + + /* fourth run: generate plot file xtics */ + count = 0; + step = 0; + cur = *head; + fprintf(fpplot, "set xtics ("); + while (cur != NULL) { + if (count > 0) + fprintf(fpplot, ", "); + if (step != ubi32_to_cpu(cur->inner.vol_id)) { + step = ubi32_to_cpu(cur->inner.vol_id); + fprintf(fpplot, "\"%d\" %d 0", step, count); + } + else + fprintf(fpplot, "\"%d\" %d 1", + ubi32_to_cpu(cur->inner.lnum), count); + cur = cur->next; + count++; + } + fprintf(fpplot, ")\n"); + fprintf(fpplot, "set nox2tics\n"); + + /* fifth run: generate plot file ytics */ + count = 0; + cur = *head; + fprintf(fpplot, "set ylabel \"leb version\"\n"); + fprintf(fpplot, "set ytics ("); + while (cur != NULL) { + y1 = norm_index(ubi32_to_cpu(cur->inner.leb_ver), leb_versions, + breadth); + + if (y1 == -1) + return -1; + + if (count > 0) + fprintf(fpplot, ", "); + + fprintf(fpplot, "\"%u\" %u", ubi32_to_cpu(cur->inner.leb_ver), + y1); + + cur = cur->next; + count++; + } + fprintf(fpplot, ")\n"); + + /* sixth run: generate plot file y2tics */ + count = 0; + cur = *head; + fprintf(fpplot, "set y2label \"data size\"\n"); + fprintf(fpplot, "set y2tics ("); + while (cur != NULL) { + y2 = norm_index(ubi32_to_cpu(cur->inner.data_size), + data_sizes, breadth); + + if (y2 == -1) + return -1; + + if (count > 0) + fprintf(fpplot, ", "); + + fprintf(fpplot, "\"%u\" %u", ubi32_to_cpu(cur->inner.data_size), + y2); + + cur = cur->next; + count++; + } + fprintf(fpplot, ")\n"); + + y1 = norm_index(leb_versions[breadth - 1], leb_versions, breadth); + y2 = norm_index(data_sizes[breadth - 1], data_sizes, breadth); + fprintf(fpplot, "set xrange [-1:%u]\n", count + 1); + fprintf(fpplot, "set yrange [-1:%u]\n", y1 + 1); + fprintf(fpplot, "set y2range [-1:%u]\n", y2 + 1); + fprintf(fpplot, "plot \"%s\" u 1:4 t \"leb version: %s\" " + "axes x1y1 with lp\n", FN_VH_DATA, FN_VH_DATA); + fprintf(fpplot, "replot \"%s\" u 1:6 t \"data size: %s\" " + "axes x1y2 with lp\n", FN_VH_DATA, FN_VH_DATA); + fprintf(fpplot, "pause -1 \"press ENTER\"\n"); + + fclose(fpplot); + + free(data_sizes); + free(leb_versions); + + return 0; +} + + +/** + * unubi_analyze - run all analyses + * head: eb_chain head + * first: simple linked list of eraseblock headers (use .next) + * path: directory (without trailing slash) to output to + * returns 0 upon successful completion, or -1 otherwise + **/ +int +unubi_analyze(eb_info_t *head, eb_info_t first, const char *path) +{ + int rc; + + if (path == NULL) + return -1; + + if (first == NULL) + return -1; + + if ((head == NULL) || (*head == NULL)) + return -1; + + rc = unubi_analyze_ec_hdr(first, path); + if (rc < 0) + return -1; + + rc = unubi_analyze_vid_hdr(head, path); + if (rc < 0) + return -1; + + return 0; +} diff --git a/ubi-utils/src/unubi_analyze.h b/ubi-utils/src/unubi_analyze.h new file mode 100644 index 0000000..ac01a44 --- /dev/null +++ b/ubi-utils/src/unubi_analyze.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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. + */ + +/* + * Authors: Drake Dowsett, dowsett@de.ibm.com + */ + +#include "eb_chain.h" + +int +unubi_analyze(eb_info_t *head, eb_info_t first, const char *path); -- cgit v1.2.3 From c573347818b96a54827a073336838da725b8892e Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 11 Dec 2006 14:34:23 +0100 Subject: [PATCH 12/13] Convert unubi to use getopt option parsing Signed-off-by: Josh Boyer Acked-by: Frank Haverkamp --- ubi-utils/src/unubi.c | 201 ++++++++++++++++++++++++-------------------------- 1 file changed, 98 insertions(+), 103 deletions(-) (limited to 'ubi-utils/src/unubi.c') diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c index 4b9ddfd..f8045d8 100644 --- a/ubi-utils/src/unubi.c +++ b/ubi-utils/src/unubi.c @@ -31,7 +31,6 @@ /* TODO: consideration for dynamic vs. static volumes */ -#include #include #include #include @@ -54,10 +53,40 @@ #define CONTACT "haver@vnet.ibm.com" #define VERSION "0.9" +extern char *optarg; +extern int optind; + static char doc[] = "\nVersion: " VERSION "\n\t" BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" "\nAnalyze raw flash containing UBI data.\n"; +static const char *optionsstr = +" OPTIONS\n" +" -r, --rebuild= Extract and rebuild volume\n" +"\n" +" -d, --dir= Specify output directory\n" +"\n" +" -a, --analyze Analyze image\n" +"\n" +" -b, --blocksize= Specify size of eraseblocks in image in bytes\n" +" (default 128KiB)\n" +"\n" +" -e, --eb-split Generate individual eraseblock images (all\n" +" eraseblocks)\n" +" -v, --vol-split Generate individual eraseblock images (valid\n" +" eraseblocks only)\n" +" -V, --vol-split! Raw split by eraseblock (valid eraseblocks only)\n" +"\n" +" -?, --help Give this help list\n" +" --usage Give a short usage message\n" +" --version Print program version\n"; + +static const char *usage = +"Usage: unubi [-aevV?] [-r ] [-d ] [-b ]\n" +" [--rebuild=] [--dir=] [--analyze]\n" +" [--blocksize=] [--eb-split] [--vol-split]\n" +" [--vol-split!] [--help] [--usage] [--version] image-file\n"; + #define ERR_MSG(fmt...) \ fprintf(stderr, EXEC ": " fmt) @@ -104,66 +133,20 @@ struct args { char **options; }; -static error_t parse_opt(int key, char *arg, struct argp_state *state); - -const char *argp_program_version = VERSION; -const char *argp_program_bug_address = CONTACT; - -static struct argp_option options[] = { - { - name: NULL, key: 0, arg: NULL, - flags: 0, group: 0, doc: "OPTIONS", - }, - { - name: "rebuild", key: 'r', arg: "", - flags: 0, group: 1, doc: "Extract and rebuild volume", - }, - { - name: "dir", key: 'd', arg: "", - flags: 0, group: 2, doc: "Specify output directory", - }, - { - name: "analyze", key: 'a', arg: NULL, - flags: 0, group: 3, doc: "Analyze image", - }, - { - name: "blocksize", key: 'b', arg: "", - flags: 0, group: 4, doc: "Specify size of eraseblocks " - "in image in bytes (default " - "128KiB)", - }, - { - name: "eb-split", key: 'e', arg: NULL, - flags: 0, group: 5, doc: "Generate individual eraseblock " - "images (all eraseblocks)", - }, - { - name: "vol-split", key: 'v', arg: NULL, - flags: 0, group: 5, doc: "Generate individual eraseblock " - "images (valid eraseblocks only)", - }, - { - name: "vol-split!", key: 'V', arg: NULL, - flags: 0, group: 5, doc: "Raw split by eraseblock " - "(valid eraseblocks only)", - }, - { - name: NULL, key: 0, arg: NULL, - flags: 0, group: 0, doc: NULL, - }, -}; - -static struct argp argp = { - .options = options, - .parser = parse_opt, - .args_doc = "image-file", - .doc = doc, - .children = NULL, - .help_filter = NULL, - .argp_domain = NULL, +struct option long_options[] = { + { .name = "rebuild", .has_arg = 1, .flag = NULL, .val = 'r' }, + { .name = "dir", .has_arg = 1, .flag = NULL, .val = 'd' }, + { .name = "analyze", .has_arg = 0, .flag = NULL, .val = 'a' }, + { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' }, + { .name = "eb-split", .has_arg = 0, .flag = NULL, .val = 'e' }, + { .name = "vol-split", .has_arg = 0, .flag = NULL, .val = 'v' }, + { .name = "vol-split!", .has_arg = 0, .flag = NULL, .val = 'e' }, + { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, + { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, + { .name = "version", .has_arg = 0, .flag = NULL, .val = 'J' }, + { NULL, 0, NULL, 0} }; - /** * parses out a numerical value from a string of numbers followed by: * k, K, kib, KiB for kibibyte @@ -198,54 +181,66 @@ str_to_num(char *str) * get the input argument from argp_parse, which we know is a * pointer to our arguments structure; **/ -static error_t -parse_opt(int key, char *arg, struct argp_state *state) +static int +parse_opt(int argc, char **argv, struct args *args) { uint32_t i; - struct args *args = state->input; - - switch (key) { - case 'a': - args->analyze = 1; - break; - case 'b': - args->bsize = str_to_num(arg); - break; - case 'd': - args->odir_path = arg; - break; - case 'e': - args->eb_split = SPLIT_RAW; - break; - case 'r': - i = str_to_num(arg); - if (i < UBI_MAX_VOLUMES) - args->vols[str_to_num(arg)] = 1; - else { - ERR_MSG("volume-id out of bounds\n"); - return ARGP_ERR_UNKNOWN; + + while (1) { + int key; + + key = getopt_long(argc, argv, "r:d:ab:evV?", long_options, NULL); + if (key == -1) + break; + + switch (key) { + case 'a': + args->analyze = 1; + break; + case 'b': + args->bsize = str_to_num(optarg); + break; + case 'd': + args->odir_path = optarg; + break; + case 'e': + args->eb_split = SPLIT_RAW; + break; + case 'r': + i = str_to_num(optarg); + if (i < UBI_MAX_VOLUMES) + args->vols[str_to_num(optarg)] = 1; + else { + ERR_MSG("volume-id out of bounds\n"); + return -1; + } + break; + case 'v': + if (args->vol_split != SPLIT_RAW) + args->vol_split = SPLIT_DATA; + break; + case 'V': + args->vol_split = SPLIT_RAW; + break; + case '?': /* help */ + fprintf(stderr, "Usage: unubi [OPTION...] image-file\n"); + fprintf(stderr, "%s", doc); + fprintf(stderr, "%s", optionsstr); + fprintf(stderr, "\nReport bugs to %s\n", CONTACT); + exit(0); + break; + case 'J': + fprintf(stderr, "%s\n", VERSION); + exit(0); + break; + default: + fprintf(stderr, "%s", usage); + exit(-1); } - break; - case 'v': - if (args->vol_split != SPLIT_RAW) - args->vol_split = SPLIT_DATA; - break; - case 'V': - args->vol_split = SPLIT_RAW; - break; - case ARGP_KEY_NO_ARGS: - break; - case ARGP_KEY_ARG: - args->img_path = arg; - args->options = &state->argv[state->next]; - state->next = state->argc; - break; - case ARGP_KEY_END: - break; - default: - return ARGP_ERR_UNKNOWN; } + if (optind < argc) + args->img_path = argv[optind++]; return 0; } @@ -769,7 +764,7 @@ main(int argc, char *argv[]) memset(a.vols, 0, sizeof(*a.vols) * UBI_MAX_VOLUMES); /* parse args and check for validity */ - argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &a); + parse_opt(argc, argv, &a); if (a.img_path == NULL) { ERR_MSG("no image file specified\n"); rc = EINVAL; -- cgit v1.2.3 From da59698ccf81a1df3a250edb81a91f1b8a3decf0 Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Mon, 11 Dec 2006 14:34:23 +0100 Subject: [MTD] UBI Utils: Tools should have individual version numbers The tools had a mixture of different version numbers. This is changed now. The internal change to move to remove glibc dependencies should be reflected by an increase of the version number, so that we can react if trouble is seen with the new code. Singed-off-by: Frank Haverkamp --- ubi-utils/src/bin2nand.c | 24 +++++++++++++++--------- ubi-utils/src/config.h | 4 ++-- ubi-utils/src/mkbootenv.c | 19 ++++++++++++------- ubi-utils/src/nand2bin.c | 12 +++++++++--- ubi-utils/src/pddcustomize.c | 22 +++++++++++++++------- ubi-utils/src/pfi2bin.c | 9 ++++++--- ubi-utils/src/pfiflash.c | 2 +- ubi-utils/src/ubigen.c | 35 +++++++++++++++++++++-------------- ubi-utils/src/ubimirror.c | 17 ++++++++++++----- ubi-utils/src/ubimkvol.c | 16 ++++++++++------ ubi-utils/src/ubirmvol.c | 11 +++++++---- ubi-utils/src/ubiupdatevol.c | 2 +- ubi-utils/src/unubi.c | 4 +++- 13 files changed, 114 insertions(+), 63 deletions(-) (limited to 'ubi-utils/src/unubi.c') diff --git a/ubi-utils/src/bin2nand.c b/ubi-utils/src/bin2nand.c index df838af..4bab1ad 100644 --- a/ubi-utils/src/bin2nand.c +++ b/ubi-utils/src/bin2nand.c @@ -22,10 +22,11 @@ * Create a flashable NAND image from a binary image * * History: - * 1.0: Initial release (tglx) - * 1.1: Understands hex and dec input parameters (tglx) - * 1.2: Generates separated OOB data, if needed. (oloh) - * 1.3: Padds data/oob to a given size. (oloh) + * 1.0 Initial release (tglx) + * 1.1 Understands hex and dec input parameters (tglx) + * 1.2 Generates separated OOB data, if needed. (oloh) + * 1.3 Padds data/oob to a given size. (oloh) + * 1.4 Removed argp because we want to use uClibc. */ #include @@ -44,6 +45,8 @@ #include "config.h" #include "nandecc.h" +#define PROGRAM_VERSION "1.4" + #define CHECK_ENDP(option, endp) do { \ if (*endp) { \ fprintf(stderr, \ @@ -65,7 +68,7 @@ typedef enum action_t { extern char *optarg; extern int optind; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" "bin2nand - a tool for adding OOB information to a " @@ -153,11 +156,13 @@ parse_opt(int argc, char **argv, myargs *args) switch (key) { case 'p': /* pagesize */ - args->pagesize = (size_t) ustrtoull(optarg, &endp, 0); + args->pagesize = (size_t) + ustrtoull(optarg, &endp, 0); CHECK_ENDP("p", endp); break; case 'j': /* padding */ - args->padding = (size_t) ustrtoull(optarg, &endp, 0); + args->padding = (size_t) + ustrtoull(optarg, &endp, 0); CHECK_ENDP("j", endp); break; case 'o': /* output */ @@ -172,7 +177,7 @@ parse_opt(int argc, char **argv, myargs *args) exit(0); break; case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", PROGRAM_VERSION); exit(0); break; case 'c': @@ -187,7 +192,8 @@ parse_opt(int argc, char **argv, myargs *args) if (optind < argc) { args->fp_in = fopen(argv[optind++], "rb"); if ((args->fp_in) == NULL) { - err_quit("Cannot open file %s for input\n", argv[optind++]); + err_quit("Cannot open file %s for input\n", + argv[optind++]); } } diff --git a/ubi-utils/src/config.h b/ubi-utils/src/config.h index b5bbd5b..8c4dd54 100644 --- a/ubi-utils/src/config.h +++ b/ubi-utils/src/config.h @@ -20,8 +20,8 @@ * Author: Frank Haverkamp */ -#define PACKAGE_VERSION "1.1" -#define PACKAGE_BUGREPORT "haver@vnet.ibm.com, dedekind@linutronix.de, or tglx@linutronix.de" +#define PACKAGE_BUGREPORT \ + "haver@vnet.ibm.com, dedekind@linutronix.de, or tglx@linutronix.de" #define __unused __attribute__((unused)) diff --git a/ubi-utils/src/mkbootenv.c b/ubi-utils/src/mkbootenv.c index a556939..c05f4e2 100644 --- a/ubi-utils/src/mkbootenv.c +++ b/ubi-utils/src/mkbootenv.c @@ -18,6 +18,8 @@ * Author: Oliver Lohmann * * Create boot-parameter/pdd data from an ASCII-text input file. + * + * 1.2 Removed argp because we want to use uClibc. */ #include @@ -32,10 +34,12 @@ #include "bootenv.h" #include "error.h" +#define PROGRAM_VERSION "1.2" + extern char *optarg; extern int optind; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" "mkbootenv - processes bootenv text files and convertes " @@ -91,19 +95,20 @@ parse_opt(int argc, char **argv, myargs *args) case 'o': args->fp_out = fopen(optarg, "wb"); if ((args->fp_out) == NULL) { - fprintf(stderr, - "Cannot open file %s for output\n", optarg); + fprintf(stderr, "Cannot open file %s " + "for output\n", optarg); exit(1); } break; case '?': /* help */ printf("%s", doc); printf("%s", optionsstr); - printf("\nReport bugs to %s\n", PACKAGE_BUGREPORT); + printf("\nReport bugs to %s\n", + PACKAGE_BUGREPORT); exit(0); break; case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", PROGRAM_VERSION); exit(0); break; default: @@ -115,8 +120,8 @@ parse_opt(int argc, char **argv, myargs *args) if (optind < argc) { args->fp_in = fopen(argv[optind++], "rb"); if ((args->fp_in) == NULL) { - fprintf(stderr, - "Cannot open file %s for input\n", argv[optind]); + fprintf(stderr, "Cannot open file %s for input\n", + argv[optind]); exit(1); } } diff --git a/ubi-utils/src/nand2bin.c b/ubi-utils/src/nand2bin.c index a9b68bd..34cce40 100644 --- a/ubi-utils/src/nand2bin.c +++ b/ubi-utils/src/nand2bin.c @@ -18,7 +18,10 @@ * Author: Frank Haverkamp * * An utility to decompose NAND images and strip OOB off. Not yet finished ... + * + * 1.2 Removed argp because we want to use uClibc. */ + #include #include #include @@ -36,6 +39,8 @@ #include "config.h" #include "nandecc.h" +#define PROGRAM_VERSION "1.2" + #define MAXPATH 1024 #define MIN(x,y) ((x)<(y)?(x):(y)) @@ -60,7 +65,7 @@ static struct args myargs = { .options = NULL, }; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\t" +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\t" BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" "\nSplit data and OOB.\n"; @@ -147,12 +152,13 @@ parse_opt(int argc, char **argv, struct args *args) printf("Usage: nand2bin [OPTION...] input.mif\n"); printf("%s", doc); printf("%s", optionsstr); - printf("\nReport bugs to %s\n", PACKAGE_BUGREPORT); + printf("\nReport bugs to %s\n", + PACKAGE_BUGREPORT); exit(0); break; case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", PROGRAM_VERSION); exit(0); break; diff --git a/ubi-utils/src/pddcustomize.c b/ubi-utils/src/pddcustomize.c index 5d1864a..5c2a5f0 100644 --- a/ubi-utils/src/pddcustomize.c +++ b/ubi-utils/src/pddcustomize.c @@ -23,6 +23,8 @@ * if the system is updated and one must be able to modify them when * the system has booted the first time. This tool is intended to do * PDD modification. + * + * 1.3 Removed argp because we want to use uClibc. */ #include @@ -41,6 +43,8 @@ #include "libubi.h" #include "ubimirror.h" +#define PROGRAM_VERSION "1.3" + typedef enum action_t { ACT_NORMAL = 0, ACT_LIST, @@ -59,7 +63,7 @@ typedef enum action_t { extern char *optarg; extern int optind; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" "pddcustomize - customize bootenv and pdd values.\n"; @@ -160,7 +164,8 @@ parse_opt(int argc, char **argv, myargs *args) while (1) { int key; - key = getopt_long(argc, argv, "clbxs:i:o:?V", long_options, NULL); + key = getopt_long(argc, argv, "clbxs:i:o:?V", + long_options, NULL); if (key == -1) break; @@ -182,8 +187,9 @@ parse_opt(int argc, char **argv, myargs *args) args->side = get_update_side(optarg); if (args->side < 0) { err_msg("Unsupported seqnum: %d.\n" - "Supported seqnums are '0' and '1'\n", - args->side, optarg); + "Supported seqnums are " + "'0' and '1'\n", + args->side, optarg); ERR_ARGP; } break; @@ -194,14 +200,16 @@ parse_opt(int argc, char **argv, myargs *args) args->file_out = optarg; break; case '?': /* help */ - err_msg("Usage: pddcustomize.orig [OPTION...] [key=value] [...]"); + err_msg("Usage: pddcustomize.orig [OPTION...] " + "[key=value] [...]"); err_msg("%s", doc); err_msg("%s", optionsstr); - err_msg("\nReport bugs to %s", PACKAGE_BUGREPORT); + err_msg("\nReport bugs to %s", + PACKAGE_BUGREPORT); exit(0); break; case 'V': - err_msg("%s", PACKAGE_VERSION); + err_msg("%s", PROGRAM_VERSION); exit(0); break; default: diff --git a/ubi-utils/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c index 044fa24..9265fd5 100644 --- a/ubi-utils/src/pfi2bin.c +++ b/ubi-utils/src/pfi2bin.c @@ -22,6 +22,8 @@ * chips in a manufacturing step where the flashes are written before * being soldered onto the hardware. For NAND images another step is * required to add the right OOB data to the binary image. + * + * 1.3 Removed argp because we want to use uClibc. */ #include @@ -42,7 +44,7 @@ #include "peb.h" #include "crc32.h" -#define PROGRAM_VERSION "1.2" +#define PROGRAM_VERSION "1.3" #define MAX_FNAME 255 #define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */ @@ -157,12 +159,13 @@ parse_opt(int argc, char **argv, myargs *args) printf("pfi2bin [OPTION...] pfifile\n"); printf("%s", doc); printf("%s", optionsstr); - printf("\nReport bugs to %s\n", PACKAGE_BUGREPORT); + printf("\nReport bugs to %s\n", + PACKAGE_BUGREPORT); exit(0); break; case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", PROGRAM_VERSION); exit(0); break; diff --git a/ubi-utils/src/pfiflash.c b/ubi-utils/src/pfiflash.c index 259a647..63487b9 100644 --- a/ubi-utils/src/pfiflash.c +++ b/ubi-utils/src/pfiflash.c @@ -193,7 +193,7 @@ parse_opt(int argc, char **argv, myargs *args) exit(0); break; case 'V': - err_msg("%s", PACKAGE_VERSION); + err_msg("%s", PROGRAM_VERSION); exit(0); break; default: diff --git a/ubi-utils/src/ubigen.c b/ubi-utils/src/ubigen.c index 226834f..877f469 100644 --- a/ubi-utils/src/ubigen.c +++ b/ubi-utils/src/ubigen.c @@ -21,6 +21,7 @@ * * 1.0 Initial version * 1.1 Different CRC32 start value + * 1.2 Removed argp because we want to use uClibc. */ #include @@ -34,6 +35,8 @@ #include "ubigen.h" #include "config.h" +#define PROGRAM_VERSION "1.2" + typedef enum action_t { ACT_NORMAL = 0x00000001, ACT_BROKEN_UPDATE = 0x00000002, @@ -42,7 +45,7 @@ typedef enum action_t { extern char *optarg; extern int optind; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" "ubigen - a tool for adding UBI information to a binary input file.\n"; @@ -187,16 +190,16 @@ parse_opt(int argc, char **argv, myargs *args) case 'o': /* output */ args->fp_out = fopen(optarg, "wb"); if ((args->fp_out) == NULL) { - fprintf(stderr, "Cannot open file %s for output\n", - optarg); + fprintf(stderr, "Cannot open file %s " + "for output\n", optarg); exit(1); } break; case 'i': /* input */ args->fp_in = fopen(optarg, "rb"); if ((args->fp_in) == NULL) { - fprintf(stderr, "Cannot open file %s for input\n", - optarg); + fprintf(stderr, "Cannot open file %s " + "for input\n", optarg); exit(1); } break; @@ -205,23 +208,26 @@ parse_opt(int argc, char **argv, myargs *args) break; case 'B': /* eb_size */ - args->eb_size = (uint32_t) ustrtoul(optarg, &endp, 0); + args->eb_size = + (uint32_t)ustrtoul(optarg, &endp, 0); CHECK_ENDP("B", endp); break; case 'E': /* erasecount */ - args->ec = (uint64_t) strtoul(optarg, &endp, 0); + args->ec = (uint64_t)strtoul(optarg, &endp, 0); CHECK_ENDP("E", endp); break; case 'I': /* id */ - args->id = (uint16_t) strtoul(optarg, &endp, 0); + args->id = (uint16_t)strtoul(optarg, &endp, 0); CHECK_ENDP("I", endp); break; case 'T': /* type */ - args->type = (uint16_t) strtoul(optarg, &endp, 0); + args->type = + (uint16_t)strtoul(optarg, &endp, 0); CHECK_ENDP("T", endp); break; case 'X': /* versionnr */ - args->version = (uint8_t) strtoul(optarg, &endp, 0); + args->version = + (uint8_t)strtoul(optarg, &endp, 0); CHECK_ENDP("X", endp); break; case 'O': /* offset for volume hdr */ @@ -241,12 +247,13 @@ parse_opt(int argc, char **argv, myargs *args) fprintf(stderr, "Usage: ubigen [OPTION...]\n"); fprintf(stderr, "%s", doc); fprintf(stderr, "%s", optionsstr); - fprintf(stderr, "\nReport bugs to %s\n", PACKAGE_BUGREPORT); + fprintf(stderr, "\nReport bugs to %s\n", + PACKAGE_BUGREPORT); exit(0); break; case 'V': - fprintf(stderr, "%s\n", PACKAGE_VERSION); + fprintf(stderr, "%s\n", PROGRAM_VERSION); exit(0); break; @@ -260,8 +267,8 @@ parse_opt(int argc, char **argv, myargs *args) if (!args->fp_in) { args->fp_in = fopen(argv[optind++], "rb"); if ((args->fp_in) == NULL) { - fprintf(stderr, - "Cannot open file %s for input\n", argv[optind]); + fprintf(stderr, "Cannot open file %s for " + "input\n", argv[optind]); exit(1); } } diff --git a/ubi-utils/src/ubimirror.c b/ubi-utils/src/ubimirror.c index 1b1d0be..533a0ee 100644 --- a/ubi-utils/src/ubimirror.c +++ b/ubi-utils/src/ubimirror.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Author: Oliver Lohmann + * + * 1.2 Removed argp because we want to use uClibc. */ #include @@ -32,6 +34,8 @@ #include "example_ubi.h" #include "ubimirror.h" +#define PROGRAM_VERSION "1.2" + typedef enum action_t { ACT_NORMAL = 0, ACT_ARGP_ABORT, @@ -51,7 +55,7 @@ typedef enum action_t { extern char *optarg; extern int optind; -static char doc[] = "\nVersion: " PACKAGE_VERSION "\n\tBuilt on " +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" "ubimirror - mirrors ubi volumes.\n"; @@ -122,19 +126,22 @@ parse_opt(int argc, char **argv, myargs *args) args->side = get_update_side(optarg); if (args->side < 0) { err_msg("Unsupported seqnum: %s.\n" - "Supported seqnums are '0' and '1'\n", optarg); + "Supported seqnums are '0' " + "and '1'\n", optarg); ERR_ARGP; } break; case '?': /* help */ - err_msg("Usage: ubimirror [OPTION...] \n"); + err_msg("Usage: ubimirror [OPTION...] " + " \n"); err_msg("%s", doc); err_msg("%s", optionsstr); - err_msg("\nReport bugs to %s\n", PACKAGE_BUGREPORT); + err_msg("\nReport bugs to %s\n", + PACKAGE_BUGREPORT); exit(0); break; case 'V': - err_msg("%s", PACKAGE_VERSION); + err_msg("%s", PROGRAM_VERSION); exit(0); break; default: diff --git a/ubi-utils/src/ubimkvol.c b/ubi-utils/src/ubimkvol.c index 7d510eb..e878d70 100644 --- a/ubi-utils/src/ubimkvol.c +++ b/ubi-utils/src/ubimkvol.c @@ -26,6 +26,7 @@ * 1.1 Does not support erase blocks anymore. This is replaced by * the number of bytes. * 1.2 Reworked the user-interface to use argp. + * 1.3 Removed argp because we want to use uClibc. */ #include @@ -38,7 +39,7 @@ #include #include -#define PROGRAM_VERSION "1.2" +#define PROGRAM_VERSION "1.3" extern char *optarg; extern int optind; @@ -179,10 +180,12 @@ parse_opt(int argc, char **argv, struct args *args) break; case 'n': /* --volid= */ args->vol_id = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || - (args->vol_id < 0 && args->vol_id != UBI_DYNAMIC_VOLUME)) { + if (*endp != '\0' || + endp == optarg || + (args->vol_id < 0 && + args->vol_id != UBI_DYNAMIC_VOLUME)) { fprintf(stderr, "Bad volume ID: " - "\"%s\"\n", optarg); + "\"%s\"\n", optarg); goto out; } break; @@ -199,12 +202,13 @@ parse_opt(int argc, char **argv, struct args *args) fprintf(stderr, "Usage: ubimkvol [OPTION...]\n"); fprintf(stderr, "%s", doc); fprintf(stderr, "%s", optionsstr); - fprintf(stderr, "\nReport bugs to %s\n", PACKAGE_BUGREPORT); + fprintf(stderr, "\nReport bugs to %s\n", + PACKAGE_BUGREPORT); exit(0); break; case 'V': - fprintf(stderr, "%s\n", PACKAGE_VERSION); + fprintf(stderr, "%s\n", PROGRAM_VERSION); exit(0); break; diff --git a/ubi-utils/src/ubirmvol.c b/ubi-utils/src/ubirmvol.c index 69e4d0e..04ec085 100644 --- a/ubi-utils/src/ubirmvol.c +++ b/ubi-utils/src/ubirmvol.c @@ -23,6 +23,7 @@ * Frank Haverkamp * * 1.1 Reworked the userinterface to use argp. + * 1.2 Removed argp because we want to use uClibc. */ #include @@ -35,7 +36,7 @@ #include #include -#define PROGRAM_VERSION "1.1" +#define PROGRAM_VERSION "1.2" extern char *optarg; extern int optind; @@ -123,7 +124,8 @@ parse_opt(int argc, char **argv, struct args *args) case 'n': /* --volid= */ args->vol_id = strtoul(optarg, &endp, 0); if (*endp != '\0' || endp == optarg || - (args->vol_id < 0 && args->vol_id != UBI_DYNAMIC_VOLUME)) { + (args->vol_id < 0 && + args->vol_id != UBI_DYNAMIC_VOLUME)) { fprintf(stderr, "Bad volume ID: " "\"%s\"\n", optarg); goto out; @@ -136,11 +138,12 @@ parse_opt(int argc, char **argv, struct args *args) fprintf(stderr, "Usage: ubirmvol [OPTION...]\n"); fprintf(stderr, "%s", doc); fprintf(stderr, "%s", optionsstr); - fprintf(stderr, "\nReport bugs to %s\n", PACKAGE_BUGREPORT); + fprintf(stderr, "\nReport bugs to %s\n", + PACKAGE_BUGREPORT); exit(0); break; case 'V': - fprintf(stderr, "%s\n", PACKAGE_VERSION); + fprintf(stderr, "%s\n", PROGRAM_VERSION); exit(0); break; default: diff --git a/ubi-utils/src/ubiupdatevol.c b/ubi-utils/src/ubiupdatevol.c index 753ad61..011d532 100644 --- a/ubi-utils/src/ubiupdatevol.c +++ b/ubi-utils/src/ubiupdatevol.c @@ -154,7 +154,7 @@ parse_opt(int argc, char **argv, struct args *args) break; case 'V': - fprintf(stderr, "%s\n", PACKAGE_VERSION); + fprintf(stderr, "%s\n", PROGRAM_VERSION); exit(0); break; diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c index f8045d8..0f8945f 100644 --- a/ubi-utils/src/unubi.c +++ b/ubi-utils/src/unubi.c @@ -19,6 +19,8 @@ /* * Authors: Frank Haverkamp, haver@vnet.ibm.com * Drake Dowsett, dowsett@de.ibm.com + * + * 1.2 Removed argp because we want to use uClibc. */ /* @@ -51,7 +53,7 @@ #define EXEC "unubi" #define CONTACT "haver@vnet.ibm.com" -#define VERSION "0.9" +#define VERSION "1.0" extern char *optarg; extern int optind; -- cgit v1.2.3 From d45b87985d5371b2e47458ee0666f7979d5a8c21 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 12 Dec 2006 09:22:48 +0100 Subject: [PATCH] Minor ubi utils cleanups Remove getopt extern declarations Minor whitespace cleanups Remove incorrect program names that snuck in during getopt rewrite Change comments to match reality Signed-off-by: Josh Boyer Acked-by: Frank Haverkamp --- ubi-utils/src/bin2nand.c | 6 ++---- ubi-utils/src/mkbootenv.c | 6 ++---- ubi-utils/src/nand2bin.c | 14 +++++--------- ubi-utils/src/pddcustomize.c | 10 ++++------ ubi-utils/src/pfi2bin.c | 8 +++----- ubi-utils/src/pfiflash.c | 8 +++----- ubi-utils/src/ubigen.c | 8 +++----- ubi-utils/src/ubimirror.c | 6 ++---- ubi-utils/src/ubimkvol.c | 35 ++++++++++++++++++----------------- ubi-utils/src/ubirmvol.c | 25 ++++++++++++------------- ubi-utils/src/ubiupdatevol.c | 7 ++----- ubi-utils/src/unubi.c | 19 +++++++------------ 12 files changed, 63 insertions(+), 89 deletions(-) (limited to 'ubi-utils/src/unubi.c') diff --git a/ubi-utils/src/bin2nand.c b/ubi-utils/src/bin2nand.c index 4bab1ad..20fc90a 100644 --- a/ubi-utils/src/bin2nand.c +++ b/ubi-utils/src/bin2nand.c @@ -27,6 +27,7 @@ * 1.2 Generates separated OOB data, if needed. (oloh) * 1.3 Padds data/oob to a given size. (oloh) * 1.4 Removed argp because we want to use uClibc. + * 1.5 Minor cleanup */ #include @@ -45,7 +46,7 @@ #include "config.h" #include "nandecc.h" -#define PROGRAM_VERSION "1.4" +#define PROGRAM_VERSION "1.5" #define CHECK_ENDP(option, endp) do { \ if (*endp) { \ @@ -65,9 +66,6 @@ typedef enum action_t { #define PADDING 0 /* 0 means, do not adjust anything */ #define BUFSIZE 4096 -extern char *optarg; -extern int optind; - static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" diff --git a/ubi-utils/src/mkbootenv.c b/ubi-utils/src/mkbootenv.c index c05f4e2..4a8cc6a 100644 --- a/ubi-utils/src/mkbootenv.c +++ b/ubi-utils/src/mkbootenv.c @@ -20,6 +20,7 @@ * Create boot-parameter/pdd data from an ASCII-text input file. * * 1.2 Removed argp because we want to use uClibc. + * 1.3 Minor cleanup */ #include @@ -34,10 +35,7 @@ #include "bootenv.h" #include "error.h" -#define PROGRAM_VERSION "1.2" - -extern char *optarg; -extern int optind; +#define PROGRAM_VERSION "1.3" static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" diff --git a/ubi-utils/src/nand2bin.c b/ubi-utils/src/nand2bin.c index 34cce40..636ee6f 100644 --- a/ubi-utils/src/nand2bin.c +++ b/ubi-utils/src/nand2bin.c @@ -20,6 +20,7 @@ * An utility to decompose NAND images and strip OOB off. Not yet finished ... * * 1.2 Removed argp because we want to use uClibc. + * 1.3 Minor cleanup */ #include @@ -39,14 +40,11 @@ #include "config.h" #include "nandecc.h" -#define PROGRAM_VERSION "1.2" +#define PROGRAM_VERSION "1.3" #define MAXPATH 1024 #define MIN(x,y) ((x)<(y)?(x):(y)) -extern char *optarg; -extern int optind; - struct args { const char *oob_file; const char *output_file; @@ -116,14 +114,12 @@ uint32_t str_to_num(char *str) /* * @brief Parse the arguments passed into the test case. * - * @param key The parameter. - * @param arg Argument passed to parameter. - * @param state Location to put information on parameters. + * @param argc The number of arguments + * @param argv The argument list + * @param args Pointer to program args structure * * @return error * - * Get the `input' argument from `argp_parse', which we know is a - * pointer to our arguments structure. */ static int parse_opt(int argc, char **argv, struct args *args) diff --git a/ubi-utils/src/pddcustomize.c b/ubi-utils/src/pddcustomize.c index 5c2a5f0..764f2e7 100644 --- a/ubi-utils/src/pddcustomize.c +++ b/ubi-utils/src/pddcustomize.c @@ -25,6 +25,7 @@ * PDD modification. * * 1.3 Removed argp because we want to use uClibc. + * 1.4 Minor cleanups */ #include @@ -43,7 +44,7 @@ #include "libubi.h" #include "ubimirror.h" -#define PROGRAM_VERSION "1.3" +#define PROGRAM_VERSION "1.4" typedef enum action_t { ACT_NORMAL = 0, @@ -60,9 +61,6 @@ typedef enum action_t { args->action = ACT_ARGP_ERR; \ } while (0) -extern char *optarg; -extern int optind; - static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" @@ -81,7 +79,7 @@ static const char *optionsstr = " -V, --version Print program version\n"; static const char *usage = -"Usage: pddcustomize.orig [-bclx?V] [-i ] [-o ] [-s ]\n" +"Usage: pddcustomize [-bclx?V] [-i ] [-o ] [-s ]\n" " [--both] [--copyright] [--input=] [--list]\n" " [--output=] [--side=] [--host] [--help] [--usage]\n" " [--version] [key=value] [...]\n"; @@ -200,7 +198,7 @@ parse_opt(int argc, char **argv, myargs *args) args->file_out = optarg; break; case '?': /* help */ - err_msg("Usage: pddcustomize.orig [OPTION...] " + err_msg("Usage: pddcustomize [OPTION...] " "[key=value] [...]"); err_msg("%s", doc); err_msg("%s", optionsstr); diff --git a/ubi-utils/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c index 9265fd5..57c4ea5 100644 --- a/ubi-utils/src/pfi2bin.c +++ b/ubi-utils/src/pfi2bin.c @@ -24,6 +24,7 @@ * required to add the right OOB data to the binary image. * * 1.3 Removed argp because we want to use uClibc. + * 1.4 Minor cleanups */ #include @@ -44,7 +45,7 @@ #include "peb.h" #include "crc32.h" -#define PROGRAM_VERSION "1.3" +#define PROGRAM_VERSION "1.4" #define MAX_FNAME 255 #define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */ @@ -52,9 +53,6 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) -extern char *optarg; -extern int optind; - static uint32_t crc32_table[256]; static char err_buf[ERR_BUF_SIZE]; @@ -92,7 +90,7 @@ static const char *optionsstr = " -V, --version Print program version\n"; static const char *usage = -"Usage: pfi2bin.orig [-cv?V] [-j pdd-file] [-o filename] [--copyright]\n" +"Usage: pfi2bin [-cv?V] [-j pdd-file] [-o filename] [--copyright]\n" " [--verbose] [--platform=pdd-file] [--output=filename] [--help]\n" " [--usage] [--version] pfifile\n"; diff --git a/ubi-utils/src/pfiflash.c b/ubi-utils/src/pfiflash.c index 63487b9..0b0da56 100644 --- a/ubi-utils/src/pfiflash.c +++ b/ubi-utils/src/pfiflash.c @@ -25,6 +25,7 @@ * 1.1 fixed output to stderr and stdout in logfile mode. * 1.2 updated. * 1.3 removed argp parsing to be able to use uClib. + * 1.4 Minor cleanups */ #include @@ -41,10 +42,7 @@ #include "error.h" #include "config.h" -#define PROGRAM_VERSION "1.3" - -extern char *optarg; -extern int optind; +#define PROGRAM_VERSION "1.4" static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" @@ -70,7 +68,7 @@ static const char *optionsstr = " -V, --version Print program version\n"; static const char *usage = -"Usage: pfiflash.orig [-cvC?V] [-l ] [-p ] [-r ] [-s ]\n" +"Usage: pfiflash [-cvC?V] [-l ] [-p ] [-r ] [-s ]\n" " [--copyright] [--logfile=] [--verbose] [--complete]\n" " [--pdd-update=] [--raw-flash=] [--side=]\n" " [--help] [--usage] [--version] [pfifile]\n"; diff --git a/ubi-utils/src/ubigen.c b/ubi-utils/src/ubigen.c index 877f469..d99ba2d 100644 --- a/ubi-utils/src/ubigen.c +++ b/ubi-utils/src/ubigen.c @@ -22,6 +22,7 @@ * 1.0 Initial version * 1.1 Different CRC32 start value * 1.2 Removed argp because we want to use uClibc. + * 1.3 Minor cleanups */ #include @@ -35,16 +36,13 @@ #include "ubigen.h" #include "config.h" -#define PROGRAM_VERSION "1.2" +#define PROGRAM_VERSION "1.3" typedef enum action_t { ACT_NORMAL = 0x00000001, ACT_BROKEN_UPDATE = 0x00000002, } action_t; -extern char *optarg; -extern int optind; - static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" @@ -85,7 +83,7 @@ static const char *optionsstr = " -V, --version Print program version\n"; static const char *usage = -"Usage: ubigen.orig [-cdv?V] [-A ] [-B ] [-E ] [-I ]\n" +"Usage: ubigen [-cdv?V] [-A ] [-B ] [-E ] [-I ]\n" " [-O ] [-T ] [-X ] [-i ] [-o ]\n" " [-U ] [--copyright] [--debug] [--verbose] [--alignment=]\n" " [--blocksize=] [--erasecount=] [--id=]\n" diff --git a/ubi-utils/src/ubimirror.c b/ubi-utils/src/ubimirror.c index 533a0ee..eeedb3a 100644 --- a/ubi-utils/src/ubimirror.c +++ b/ubi-utils/src/ubimirror.c @@ -18,6 +18,7 @@ * Author: Oliver Lohmann * * 1.2 Removed argp because we want to use uClibc. + * 1.3 Minor cleanups */ #include @@ -34,7 +35,7 @@ #include "example_ubi.h" #include "ubimirror.h" -#define PROGRAM_VERSION "1.2" +#define PROGRAM_VERSION "1.3" typedef enum action_t { ACT_NORMAL = 0, @@ -52,9 +53,6 @@ typedef enum action_t { #define VOL_ARGS_MAX 2 -extern char *optarg; -extern int optind; - static char doc[] = "\nVersion: " PROGRAM_VERSION "\n\tBuilt on " BUILD_CPU" "BUILD_OS" at "__DATE__" "__TIME__"\n" "\n" diff --git a/ubi-utils/src/ubimkvol.c b/ubi-utils/src/ubimkvol.c index e878d70..879dcb6 100644 --- a/ubi-utils/src/ubimkvol.c +++ b/ubi-utils/src/ubimkvol.c @@ -27,6 +27,7 @@ * the number of bytes. * 1.2 Reworked the user-interface to use argp. * 1.3 Removed argp because we want to use uClibc. + * 1.4 Minor cleanups */ #include @@ -39,10 +40,7 @@ #include #include -#define PROGRAM_VERSION "1.3" - -extern char *optarg; -extern int optind; +#define PROGRAM_VERSION "1.4" /* * The variables below are set by command line arguments. @@ -114,14 +112,12 @@ struct option long_options[] = { /* * @brief Parse the arguments passed into the test case. * - * @param key The parameter. - * @param arg Argument passed to parameter. - * @param state Location to put information on parameters. + * @param argc The number of arguments + * @param argv The list of arguments + * @param args Pointer to argument structure * * @return error * - * Get the `input' argument from `argp_parse', which we know is a - * pointer to our arguments structure. */ static int parse_opt(int argc, char **argv, struct args *args) @@ -142,16 +138,18 @@ parse_opt(int argc, char **argv, struct args *args) else if (!strcmp(optarg, "static")) args->vol_type = UBI_STATIC_VOLUME; else { - fprintf(stderr, "Bad volume type: \"%s\"\n", - optarg); + fprintf(stderr, + "Bad volume type: \"%s\"\n", + optarg); goto out; } break; case 's': args->bytes = strtoull(optarg, &endp, 0); if (endp == optarg || args->bytes < 0) { - fprintf(stderr, "Bad volume size: \"%s\"\n", - optarg); + fprintf(stderr, + "Bad volume size: \"%s\"\n", + optarg); goto out; } if (endp != '\0') { @@ -172,9 +170,11 @@ parse_opt(int argc, char **argv, struct args *args) break; case 'd': /* --devn= */ args->devn = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || args->devn < 0) { - fprintf(stderr, "Bad UBI device number: " - "\"%s\"\n", optarg); + if (*endp != '\0' || endp == optarg || + args->devn < 0) { + fprintf(stderr, + "Bad UBI device number: " + "\"%s\"\n", optarg); goto out; } break; @@ -199,7 +199,8 @@ parse_opt(int argc, char **argv, struct args *args) goto out; case '?': /* help */ - fprintf(stderr, "Usage: ubimkvol [OPTION...]\n"); + fprintf(stderr, + "Usage: ubimkvol [OPTION...]\n"); fprintf(stderr, "%s", doc); fprintf(stderr, "%s", optionsstr); fprintf(stderr, "\nReport bugs to %s\n", diff --git a/ubi-utils/src/ubirmvol.c b/ubi-utils/src/ubirmvol.c index 04ec085..f458e8a 100644 --- a/ubi-utils/src/ubirmvol.c +++ b/ubi-utils/src/ubirmvol.c @@ -24,6 +24,7 @@ * * 1.1 Reworked the userinterface to use argp. * 1.2 Removed argp because we want to use uClibc. + * 1.3 Minor cleanups */ #include @@ -36,10 +37,7 @@ #include #include -#define PROGRAM_VERSION "1.2" - -extern char *optarg; -extern int optind; +#define PROGRAM_VERSION "1.3" /* * The below variables are set by command line options. @@ -91,14 +89,12 @@ struct option long_options[] = { /* * @brief Parse the arguments passed into the test case. * - * @param key The parameter. - * @param arg Argument passed to parameter. - * @param state Location to put information on parameters. + * @param argc The number of arguments + * @param argv The list of arguments + * @param args Pointer to argument structure * * @return error * - * Get the `input' argument from `argp_parse', which we know is a - * pointer to our arguments structure. */ static int parse_opt(int argc, char **argv, struct args *args) @@ -115,9 +111,11 @@ parse_opt(int argc, char **argv, struct args *args) switch (key) { case 'd': /* --devn= */ args->devn = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || args->devn < 0) { - fprintf(stderr, "Bad UBI device number: " - "\"%s\"\n", optarg); + if (*endp != '\0' || endp == optarg || + args->devn < 0) { + fprintf(stderr, + "Bad UBI device number: " + "\"%s\"\n", optarg); goto out; } break; @@ -135,7 +133,8 @@ parse_opt(int argc, char **argv, struct args *args) fprintf(stderr, "Parameter is missing\n"); goto out; case '?': /* help */ - fprintf(stderr, "Usage: ubirmvol [OPTION...]\n"); + fprintf(stderr, + "Usage: ubirmvol [OPTION...]\n"); fprintf(stderr, "%s", doc); fprintf(stderr, "%s", optionsstr); fprintf(stderr, "\nReport bugs to %s\n", diff --git a/ubi-utils/src/ubiupdatevol.c b/ubi-utils/src/ubiupdatevol.c index 011d532..b3c4bf1 100644 --- a/ubi-utils/src/ubiupdatevol.c +++ b/ubi-utils/src/ubiupdatevol.c @@ -24,6 +24,7 @@ * * 1.0 Reworked the userinterface to use argp. * 1.1 Removed argp parsing because we want to use uClib. + * 1.2 Minor cleanups */ #include @@ -42,16 +43,12 @@ #include #include -#define PROGRAM_VERSION "1.1" +#define PROGRAM_VERSION "1.2" #define MAXPATH 1024 #define BUFSIZE 128 * 1024 #define MIN(x,y) ((x)<(y)?(x):(y)) -/* FIXME is this not covered by including getopt.h? */ -extern char *optarg; -extern int optind; - struct args { int devn; int vol_id; diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c index 0f8945f..cade1e1 100644 --- a/ubi-utils/src/unubi.c +++ b/ubi-utils/src/unubi.c @@ -21,6 +21,7 @@ * Drake Dowsett, dowsett@de.ibm.com * * 1.2 Removed argp because we want to use uClibc. + * 1.3 Minor cleanups */ /* @@ -53,10 +54,7 @@ #define EXEC "unubi" #define CONTACT "haver@vnet.ibm.com" -#define VERSION "1.0" - -extern char *optarg; -extern int optind; +#define VERSION "1.3" static char doc[] = "\nVersion: " VERSION "\n\t" BUILD_OS" "BUILD_CPU" at "__DATE__" "__TIME__"\n" @@ -177,12 +175,6 @@ str_to_num(char *str) return num; } - -/** - * parses the arguments passed into the program - * get the input argument from argp_parse, which we know is a - * pointer to our arguments structure; - **/ static int parse_opt(int argc, char **argv, struct args *args) { @@ -225,10 +217,13 @@ parse_opt(int argc, char **argv, struct args *args) args->vol_split = SPLIT_RAW; break; case '?': /* help */ - fprintf(stderr, "Usage: unubi [OPTION...] image-file\n"); + fprintf(stderr, + "Usage: unubi [OPTION...] " + "image-file\n"); fprintf(stderr, "%s", doc); fprintf(stderr, "%s", optionsstr); - fprintf(stderr, "\nReport bugs to %s\n", CONTACT); + fprintf(stderr, + "\nReport bugs to %s\n", CONTACT); exit(0); break; case 'J': -- cgit v1.2.3 From 9fe86e65fb6bd77a02955d07d6f336ace4984e2d Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 12 Feb 2007 20:41:17 -0600 Subject: Fix several issues when compiling for 64bit systems Signed-off-by: Josh Boyer --- ubi-utils/src/hashmap.c | 2 +- ubi-utils/src/libubi.c | 4 ++-- ubi-utils/src/nand2bin.c | 2 +- ubi-utils/src/pfi.c | 2 +- ubi-utils/src/reader.c | 7 ++++--- ubi-utils/src/unubi.c | 2 +- ubi-utils/src/unubi_analyze.c | 20 ++++++++++---------- 7 files changed, 20 insertions(+), 19 deletions(-) (limited to 'ubi-utils/src/unubi.c') diff --git a/ubi-utils/src/hashmap.c b/ubi-utils/src/hashmap.c index 250f71f..3511d56 100644 --- a/ubi-utils/src/hashmap.c +++ b/ubi-utils/src/hashmap.c @@ -323,7 +323,7 @@ hashmap_dump(hashmap_t map) for(i = 0; i < map->maxsize; i++) { if (map->data[i] != NULL) { - printf("[%d]: ", i); + printf("[%zd]: ", i); print_all(map->data[i]); } } diff --git a/ubi-utils/src/libubi.c b/ubi-utils/src/libubi.c index 979f157..7cb74bf 100644 --- a/ubi-utils/src/libubi.c +++ b/ubi-utils/src/libubi.c @@ -698,8 +698,8 @@ ubi_vol_update(int vol_fd, unsigned long long bytes) err = ioctl(vol_fd, UBI_IOCVOLUP, &bytes); if (err) { ubi_err("%s failure calling update ioctl\n" - " IOCTL(%08x) err=%d errno=%d\n", - __func__, UBI_IOCVOLUP, err, errno); + " IOCTL(%08lx) err=%d errno=%d\n", + __func__, (long unsigned int)UBI_IOCVOLUP, err, errno); } return err; } diff --git a/ubi-utils/src/nand2bin.c b/ubi-utils/src/nand2bin.c index 636ee6f..b8e4ea3 100644 --- a/ubi-utils/src/nand2bin.c +++ b/ubi-utils/src/nand2bin.c @@ -203,7 +203,7 @@ process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize) case 2048: oobsize = 64; eccpoi = 64 / 2; break; case 512: oobsize = 16; eccpoi = 16 / 2; break; default: - fprintf(stderr, "Unsupported page size: %d\n", pagesize); + fprintf(stderr, "Unsupported page size: %zd\n", pagesize); return -EINVAL; } memset(oobbuf, 0xff, oobsize); diff --git a/ubi-utils/src/pfi.c b/ubi-utils/src/pfi.c index 7b57559..fa835e2 100644 --- a/ubi-utils/src/pfi.c +++ b/ubi-utils/src/pfi.c @@ -253,7 +253,7 @@ int pfi_header_setvalue (pfi_header head, { int key_id = find_key_by_name(key); - if ((uint32_t)value == (uint32_t)NULL) + if (value == NULL) return PFI_EINSUFF; if ((key_id < 0) || (key_id >= num_keys)) diff --git a/ubi-utils/src/reader.c b/ubi-utils/src/reader.c index 975caa1..7935a15 100644 --- a/ubi-utils/src/reader.c +++ b/ubi-utils/src/reader.c @@ -178,7 +178,8 @@ read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw, } rc = bootenv_list_to_num_vector(raw_start_list, - &(res->starts_size), &(res->starts)); + (void *) &(res->starts_size), + &(res->starts)); if (rc != 0) { EBUF_PFI("Cannot create numeric value array: %s", tmp_str); goto err; @@ -246,7 +247,7 @@ read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, goto err; } - rc = bootenv_list_to_num_vector(ubi_id_list, &(res->ids_size), + rc = bootenv_list_to_num_vector(ubi_id_list, (void *) &(res->ids_size), &(res->ids)); if (rc != 0) { EBUF_PFI("Cannot create numeric value array: %s", tmp_str); @@ -298,7 +299,7 @@ read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, EBUF_PFI("Cannot translate PFI value: %s", tmp_str); goto err; } - rc = bootenv_list_to_vector(ubi_name_list, &(res->names_size), + rc = bootenv_list_to_vector(ubi_name_list, (void *) &(res->names_size), &(tmp_names)); if (rc != 0) { EBUF_PFI("Cannot create string array: %s", tmp_str); diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c index cade1e1..811a6db 100644 --- a/ubi-utils/src/unubi.c +++ b/ubi-utils/src/unubi.c @@ -102,7 +102,7 @@ static const char *usage = #define FN_INVAL "%s/eb%04u%s" /* invalid eraseblock */ #define FN_NSURE "%s/eb%04u_%03u_%03u_%03x%s" /* unsure eraseblock */ #define FN_VALID "%s/eb%04u_%03u_%03u_%03x%s" /* valid eraseblock */ -#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04u" /* split volume */ +#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04zu" /* split volume */ #define FN_VOLWH "%s/volume%03u" /* whole volume */ static uint32_t crc32_table[256]; diff --git a/ubi-utils/src/unubi_analyze.c b/ubi-utils/src/unubi_analyze.c index 2e94ca9..6009fc0 100644 --- a/ubi-utils/src/unubi_analyze.c +++ b/ubi-utils/src/unubi_analyze.c @@ -167,9 +167,9 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) (crc != ubi32_to_cpu(cur->outer.hdr_crc))) fprintf(fpdata, "# "); - fprintf(fpdata, "%u %llu %llu", count, - ubi64_to_cpu(cur->outer.ec), - erase_counts[count]); + fprintf(fpdata, "%zu %llu %llu", count, + (unsigned long long) ubi64_to_cpu(cur->outer.ec), + (unsigned long long) erase_counts[count]); if (ubi32_to_cpu(cur->outer.magic) != UBI_EC_HDR_MAGIC) fprintf(fpdata, " ## bad magic: %08x", @@ -198,7 +198,7 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) if ((count % EC_X_INT) == 0) { if (count > 0) fprintf(fpplot, ", "); - fprintf(fpplot, "%d", count); + fprintf(fpplot, "%zd", count); } cur = cur->next; @@ -207,9 +207,9 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) fprintf(fpplot, ")\n"); fprintf(fpplot, "set ylabel \"erase count\"\n"); - fprintf(fpplot, "set xrange [-1:%u]\n", eraseblocks + 1); + fprintf(fpplot, "set xrange [-1:%zu]\n", eraseblocks + 1); fprintf(fpplot, "# set yrange [-1:%llu]\n", - erase_counts[eraseblocks - 1] + 1); + (unsigned long long) erase_counts[eraseblocks - 1] + 1); fprintf(fpplot, "plot \"%s\" u 1:2 t \"unsorted: %s\" with boxes\n", FN_EH_DATA, FN_EH_DATA); fprintf(fpplot, "# replot \"%s\" u 1:3 t \"sorted: %s\" with lines\n", @@ -299,7 +299,7 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) if ((y1 == -1) || (y2 == -1)) return -1; - fprintf(fpdata, "%u %u %u %u %u %u %u\n", + fprintf(fpdata, "%zu %u %u %u %u %u %u\n", count, ubi32_to_cpu(cur->inner.vol_id), ubi32_to_cpu(cur->inner.lnum), @@ -325,10 +325,10 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) fprintf(fpplot, ", "); if (step != ubi32_to_cpu(cur->inner.vol_id)) { step = ubi32_to_cpu(cur->inner.vol_id); - fprintf(fpplot, "\"%d\" %d 0", step, count); + fprintf(fpplot, "\"%zd\" %zd 0", step, count); } else - fprintf(fpplot, "\"%d\" %d 1", + fprintf(fpplot, "\"%d\" %zd 1", ubi32_to_cpu(cur->inner.lnum), count); cur = cur->next; count++; @@ -384,7 +384,7 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) y1 = norm_index(leb_versions[breadth - 1], leb_versions, breadth); y2 = norm_index(data_sizes[breadth - 1], data_sizes, breadth); - fprintf(fpplot, "set xrange [-1:%u]\n", count + 1); + fprintf(fpplot, "set xrange [-1:%zu]\n", count + 1); fprintf(fpplot, "set yrange [-1:%u]\n", y1 + 1); fprintf(fpplot, "set y2range [-1:%u]\n", y2 + 1); fprintf(fpplot, "plot \"%s\" u 1:4 t \"leb version: %s\" " -- cgit v1.2.3