diff options
-rw-r--r-- | ubi-utils/src/eb_chain.c | 35 | ||||
-rw-r--r-- | ubi-utils/src/eb_chain.h | 4 | ||||
-rw-r--r-- | ubi-utils/src/unubi.c | 401 | ||||
-rw-r--r-- | ubi-utils/src/unubi_analyze.c | 169 |
4 files changed, 402 insertions, 207 deletions
diff --git a/ubi-utils/src/eb_chain.c b/ubi-utils/src/eb_chain.c index 501a838..22594c5 100644 --- a/ubi-utils/src/eb_chain.c +++ b/ubi-utils/src/eb_chain.c @@ -27,6 +27,7 @@ #include <stdlib.h> #include <string.h> #include "eb_chain.h" +#include "crc32.h" #define COPY(dst, src) \ do \ @@ -66,9 +67,9 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) 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); + new_vol = ubi32_to_cpu(new->vid.vol_id); + new_num = ubi32_to_cpu(new->vid.lnum); + new_ver = ubi32_to_cpu(new->vid.leb_ver); /** TRAVERSE HORIZONTALY **/ @@ -76,8 +77,8 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) prev = NULL; /* traverse until vol_id/lnum align */ - vol = ubi32_to_cpu(cur->inner.vol_id); - num = ubi32_to_cpu(cur->inner.lnum); + vol = ubi32_to_cpu(cur->vid.vol_id); + num = ubi32_to_cpu(cur->vid.lnum); while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) { /* insert new at end of chain */ @@ -91,8 +92,8 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) prev = cur; cur = cur->next; - vol = ubi32_to_cpu(cur->inner.vol_id); - num = ubi32_to_cpu(cur->inner.lnum); + vol = ubi32_to_cpu(cur->vid.vol_id); + num = ubi32_to_cpu(cur->vid.lnum); } if (prev == NULL) @@ -115,7 +116,7 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) prev = NULL; /* traverse until versions align */ - ver = ubi32_to_cpu(cur->inner.leb_ver); + ver = ubi32_to_cpu(cur->vid.leb_ver); while (new_ver < ver) { /* insert new at bottom of history */ @@ -130,7 +131,7 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) prev = hist; hist = hist->older; - ver = ubi32_to_cpu(hist->inner.leb_ver); + ver = ubi32_to_cpu(hist->vid.leb_ver); } if (prev == NULL) @@ -181,8 +182,8 @@ eb_chain_position(eb_info_t *head, uint32_t vol_id, uint32_t *lnum, cur = *head; while (cur != NULL) { - vol = ubi32_to_cpu(cur->inner.vol_id); - num = ubi32_to_cpu(cur->inner.lnum); + vol = ubi32_to_cpu(cur->vid.vol_id); + num = ubi32_to_cpu(cur->vid.lnum); if (vol_id == vol) if ((lnum == NULL) || (*lnum == num)) @@ -227,17 +228,17 @@ eb_chain_print(FILE* stream, eb_info_t *head) 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)); + ubi32_to_cpu(cur->vid.vol_id), + ubi32_to_cpu(cur->vid.lnum), + ubi32_to_cpu(cur->vid.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)); + ubi32_to_cpu(hist->vid.vol_id), + ubi32_to_cpu(hist->vid.lnum), + ubi32_to_cpu(hist->vid.leb_ver)); hist = hist->older; } diff --git a/ubi-utils/src/eb_chain.h b/ubi-utils/src/eb_chain.h index f640c54..4c94058 100644 --- a/ubi-utils/src/eb_chain.h +++ b/ubi-utils/src/eb_chain.h @@ -52,8 +52,8 @@ typedef struct eb_info *eb_info_t; struct eb_info { - struct ubi_ec_hdr outer; - struct ubi_vid_hdr inner; + struct ubi_ec_hdr ec; + struct ubi_vid_hdr vid; fpos_t eb_top; uint32_t linear; diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c index 81db5fa..e0a71a6 100644 --- a/ubi-utils/src/unubi.c +++ b/ubi-utils/src/unubi.c @@ -21,7 +21,8 @@ * Drake Dowsett, dowsett@de.ibm.com * * 1.2 Removed argp because we want to use uClibc. - * 1.3 Minor cleanups + * 1.3 Minor cleanups. + * 1.4 Meanwhile Drake had done a lot of changes, syncing those. */ /* @@ -54,22 +55,30 @@ #define EXEC "unubi" #define CONTACT "haver@vnet.ibm.com" -#define VERSION "1.3" +#define VERSION "1.4" -static char doc[] = "\nVersion: " VERSION "\n" - "unubi - analyze raw flash containing UBI data.\n"; +static char doc[] = "\nVersion: " VERSION "\n"; +static int debug = 0; static const char *optionsstr = -" OPTIONS\n" -" -r, --rebuild=<volume-id> Extract and rebuild volume\n" -"\n" -" -d, --dir=<output-dir> Specify output directory\n" +"Extract volumes and/or analysis information from an UBI data file.\n" +"When no parameters are flagged or given, the default operation is\n" +"to rebuild all valid complete UBI volumes found within the image.\n" "\n" +" OPERATIONS\n" " -a, --analyze Analyze image\n" +" -i, --info-table Extract volume information tables\n" +" -r, --rebuild=<volume-id> Extract and rebuild volume\n" "\n" +" OPTIONS\n" " -b, --blocksize=<block-size> Specify size of eraseblocks in image in bytes\n" " (default 128KiB)\n" +" -d, --dir=<output-dir> Specify output directory\n" +" -D, --debug Enable debug output\n" +" -s, --headersize=<header-size> Specify size of eraseblock header in image\n" +" in bytes (default 2048 Byte)\n" "\n" +" ADVANCED\n" " -e, --eb-split Generate individual eraseblock images (all\n" " eraseblocks)\n" " -v, --vol-split Generate individual eraseblock images (valid\n" @@ -78,13 +87,16 @@ static const char *optionsstr = "\n" " -?, --help Give this help list\n" " --usage Give a short usage message\n" -" --version Print program version\n"; +" --version Print program version\n" +"\n"; static const char *usage = -"Usage: unubi [-aevV?] [-r <volume-id>] [-d <output-dir>] [-b <block-size>]\n" -" [--rebuild=<volume-id>] [--dir=<output-dir>] [--analyze]\n" -" [--blocksize=<block-size>] [--eb-split] [--vol-split]\n" -" [--vol-split!] [--help] [--usage] [--version] image-file\n"; +"Usage: unubi [-aievV?] [-r <volume-id>] [-b <block-size>] [-d <output-dir>]\n" +" [-s <header-size>] [--analyze] [--info-table]\n" +" [--rebuild=<volume-id>] [--blocksize=<block-size>]\n" +" [--dir=<output-dir>] [--headersize=<header-size>] [--eb-split]\n" +" [--vol-split] [--vol-split!] [--help] [--usage] [--version]\n" +" image-file\n"; #define ERR_MSG(fmt...) \ fprintf(stderr, EXEC ": " fmt) @@ -101,13 +113,15 @@ 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_%04zu" /* split volume */ +#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04u" /* split volume */ #define FN_VOLWH "%s/volume%03u" /* whole volume */ +#define FN_VITBL "%s/vol_info_table%u" /* vol info table */ static uint32_t crc32_table[256]; /* struct args: * bsize int, blocksize of image blocks + * hsize int, eraseblock header size * analyze flag, when non-zero produce analysis * eb_split flag, when non-zero output eb#### * note: SPLIT_DATA vs. SPLIT_RAW @@ -121,13 +135,15 @@ static uint32_t crc32_table[256]; * count_set() and collapse() */ struct args { - uint32_t bsize; int analyze; + int itable; + uint32_t *vols; + size_t bsize; + size_t hsize; + char *odir_path; int eb_split; int vol_split; - char *odir_path; char *img_path; - uint32_t *vols; char **options; }; @@ -164,7 +180,7 @@ str_to_num(char *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) || + else if ((strcmp(s, "MiB") == 0) || (strcmp(s, "M") == 0) || (strcmp(s, "mib") == 0) || (strcmp(s, "m") == 0)) num *= MIB; else @@ -182,56 +198,63 @@ parse_opt(int argc, char **argv, struct args *args) while (1) { int key; - key = getopt_long(argc, argv, "r:d:ab:evV?", long_options, NULL); + key = getopt_long(argc, argv, "ab:s:d:Deir:vV?J", + 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); + case 'a': + args->analyze = 1; + break; + case 'b': + args->bsize = str_to_num(optarg); + break; + case 's': + args->hsize = str_to_num(optarg); + break; + case 'd': + args->odir_path = optarg; + break; + case 'D': /* I wanted to use -v but that was + already used ... */ + debug = 1; + break; + case 'e': + args->eb_split = SPLIT_RAW; + break; + case 'i': + args->itable = 1; + 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%s%s\nReport bugs to %s\n", + doc, optionsstr, CONTACT); + exit(0); + break; + case 'J': + fprintf(stderr, "%s\n", VERSION); + exit(0); + break; + default: + fprintf(stderr, "%s", usage); + exit(-1); } } @@ -287,7 +310,7 @@ collapse(uint32_t *full_array, size_t full_len, /** * 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 + * one of the first two args MUST be NULL, the other is the header * to caculate the crc on * always returns 0 **/ @@ -391,15 +414,129 @@ extract_data(FILE* fpin, size_t len, const char *path) /** + * extract volume information table from block. saves and reloads fpin + * position + * returns -1 when a fpos set or get fails, otherwise <= -2 on other + * failure and 0 on success + **/ +static int +extract_itable(FILE* fpin, eb_info_t cur, size_t bsize, size_t num, + const char* path) +{ + char filename[MAXPATH + 1]; + int rc; + size_t i, max; + fpos_t temp; + FILE* fpout = NULL; + struct ubi_vol_tbl_record rec; + + if (fpin == NULL || cur == NULL || path == NULL) + return -2; + + /* remember position */ + rc = fgetpos(fpin, &temp); + if (rc < 0) + return -1; + + /* jump to top of eraseblock, skip to data section */ + fsetpos(fpin, &cur->eb_top); + if (rc < 0) + return -1; + fseek(fpin, ubi32_to_cpu(cur->ec.data_offset), SEEK_CUR); + + /* prepare output file */ + if (ubi32_to_cpu(cur->vid.vol_id) != UBI_LAYOUT_VOL_ID) + return -2; + memset(filename, 0, MAXPATH + 1); + snprintf(filename, MAXPATH, FN_VITBL, path, num); + fpout = fopen(filename, "w"); + if (fpout == NULL) + return -2; + + /* loop through entries */ + fprintf(fpout, + "index\trpebs\talign\ttype\tcrc\t\tname\n"); + max = bsize - ubi32_to_cpu(cur->ec.data_offset); + for (i = 0; i < (max / sizeof(rec)); i++) { + int blank = 1; + char *ptr, *base; + char name[UBI_VOL_NAME_MAX + 1]; + const char *type = "unknown\0"; + uint32_t crc; + + /* read record */ + rc = fread(&rec, 1, sizeof(rec), fpin); + if (rc == 0) + break; + if (rc != sizeof(rec)) { + ERR_MSG("reading volume information " + "table record failed\n"); + rc = -3; + goto exit; + } + + /* check crc */ + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &rec, + UBI_VTBL_RECORD_SIZE_CRC); + if (crc != ubi32_to_cpu(rec.crc)) + continue; + + /* check for empty */ + base = (char *)&rec; + ptr = base; + while (blank && + ((unsigned)(ptr - base) < UBI_VTBL_RECORD_SIZE_CRC)) { + if (*ptr != 0) + blank = 0; + ptr++; + } + + if (blank) + continue; + + /* prep type string */ + if (rec.vol_type == UBI_VID_DYNAMIC) + type = "dynamic\0"; + else if (rec.vol_type == UBI_VID_STATIC) + type = "static\0"; + + /* prep name string */ + rec.name[ubi16_to_cpu(rec.name_len)] = '\0'; + sprintf(name, "%s", rec.name); + + /* print record line to fpout */ + fprintf(fpout, "%u\t%u\t%u\t%s\t0x%08x\t%s\n", + i, + ubi32_to_cpu(rec.reserved_pebs), + ubi32_to_cpu(rec.alignment), + type, + ubi32_to_cpu(rec.crc), + name); + } + + exit: + /* reset position */ + if (fsetpos(fpin, &temp) < 0) + rc = -1; + + if (fpout != NULL) + fclose(fpout); + + return rc; +} + + +/** * 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) +rebuild_volume(FILE* fpin, uint32_t *vol_id, eb_info_t *head, const char* path, + size_t block_size, size_t header_size) { char filename[MAXPATH]; int rc; - uint32_t vol, num; + uint32_t vol, num, data_size; FILE* fpout; eb_info_t cur; @@ -411,13 +548,13 @@ rebuild_volume(FILE* fpin, uint32_t *vol_id, eb_info_t *head, const char* path) /* when vol_id is null, then do all */ if (vol_id == NULL) { cur = *head; - vol = ubi32_to_cpu(cur->inner.vol_id); - } - else { + vol = ubi32_to_cpu(cur->vid.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); + if (debug) + ERR_MSG("no valid volume %d was found\n", vol); return -1; } } @@ -433,7 +570,7 @@ rebuild_volume(FILE* fpin, uint32_t *vol_id, eb_info_t *head, const char* path) while (cur != NULL) { size_t i; - if (ubi32_to_cpu(cur->inner.vol_id) != vol) { + if (ubi32_to_cpu(cur->vid.vol_id) != vol) { /* close out file */ fclose(fpout); @@ -442,7 +579,7 @@ rebuild_volume(FILE* fpin, uint32_t *vol_id, eb_info_t *head, const char* path) goto out; /* begin with next */ - vol = ubi32_to_cpu(cur->inner.vol_id); + vol = ubi32_to_cpu(cur->vid.vol_id); num = 0; snprintf(filename, MAXPATH, FN_VOLWH, path, vol); fpout = fopen(filename, "wb"); @@ -453,17 +590,27 @@ rebuild_volume(FILE* fpin, uint32_t *vol_id, eb_info_t *head, const char* path) } } - if (ubi32_to_cpu(cur->inner.lnum) != num) { - ERR_MSG("missing valid block %d for volume %d\n", - num, vol); + while (num < ubi32_to_cpu(cur->vid.lnum)) { + /* FIXME haver: I hope an empty block is + written out so that the binary has no holes + ... */ + if (debug) + ERR_MSG("missing valid block %d for volume %d\n", + num, vol); + num++; } rc = fsetpos(fpin, &(cur->eb_top)); if (rc < 0) goto out; - fseek(fpin, ubi32_to_cpu(cur->outer.data_offset), SEEK_CUR); + fseek(fpin, ubi32_to_cpu(cur->ec.data_offset), SEEK_CUR); - for (i = 0; i < ubi32_to_cpu(cur->inner.data_size); i++) { + if (cur->vid.vol_type == UBI_VID_DYNAMIC) + data_size = block_size - header_size; + else + data_size = ubi32_to_cpu(cur->vid.data_size); + + for (i = 0; i < data_size; i++) { int c = fgetc(fpin); if (c == EOF) { ERR_MSG("unexpected EOF while writing: %s\n", @@ -500,7 +647,7 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) char filename[MAXPATH + 1]; char reason[MAXPATH + 1]; int rc; - size_t i, count; + size_t i, count, itable_num; /* relations: * cur ~ head * next ~ first */ @@ -509,6 +656,7 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) rc = 0; count = 0; + itable_num = 0; head = NULL; first = NULL; next = NULL; @@ -532,25 +680,25 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) raw_path = FN_INVAL; /* read erasecounter header */ - rc = fread(&cur->outer, 1, sizeof(cur->outer), fpin); + rc = fread(&cur->ec, 1, sizeof(cur->ec), fpin); if (rc == 0) goto out; /* EOF */ - if (rc != sizeof(cur->outer)) { - ERR_MSG("reading ec-hdr failed rc=%d\n", rc); + if (rc != sizeof(cur->ec)) { + ERR_MSG("reading ec-hdr failed\n"); rc = -1; goto err; } /* check erasecounter header magic */ - if (ubi32_to_cpu(cur->outer.magic) != UBI_EC_HDR_MAGIC) { + if (ubi32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) { snprintf(reason, MAXPATH, ".invalid.ec_magic"); goto invalid; } /* check erasecounter header crc */ - header_crc(&(cur->outer), NULL, &crc); + header_crc(&(cur->ec), NULL, &crc); - if (ubi32_to_cpu(cur->outer.hdr_crc) != crc) { + if (ubi32_to_cpu(cur->ec.hdr_crc) != crc) { snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc"); goto invalid; } @@ -559,27 +707,26 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) 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); + fseek(fpin, ubi32_to_cpu(cur->ec.vid_hdr_offset), SEEK_CUR); + rc = fread(&cur->vid, 1, sizeof(cur->vid), fpin); if (rc == 0) goto out; /* EOF */ - if (rc != sizeof(cur->inner)) { - ERR_MSG("reading vid-hdr failed rc=%d\n", rc); + if (rc != sizeof(cur->vid)) { + ERR_MSG("reading vid-hdr failed\n"); rc = -1; goto err; } - /* empty? */ - if (ubi32_to_cpu(cur->inner.magic) == 0xffffffff) { + /* if the magic number is 0xFFFFFFFF, then it's very likely + * that the volume is empty */ + if (ubi32_to_cpu(cur->vid.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) < + if ((ubi32_to_cpu(cur->vid.vol_id) >= UBI_MAX_VOLUMES) && + (ubi32_to_cpu(cur->vid.vol_id) < UBI_INTERNAL_VOL_START)) { snprintf(reason, MAXPATH, ".invalid"); goto invalid; @@ -587,25 +734,28 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) raw_path = FN_NSURE; /* check volume id header magic */ - if (ubi32_to_cpu(cur->inner.magic) != UBI_VID_HDR_MAGIC) { + if (ubi32_to_cpu(cur->vid.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) { + header_crc(NULL, &(cur->vid), &crc); + if (ubi32_to_cpu(cur->vid.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; + /* check data crc, but only for a static volume */ + if (cur->vid.vol_type == UBI_VID_STATIC) { + rc = data_crc(fpin, ubi32_to_cpu(cur->vid.data_size), + &crc); + if (rc < 0) + goto err; + if (ubi32_to_cpu(cur->vid.data_crc) != crc) { + snprintf(reason, MAXPATH, ".invalid.data_crc"); + goto invalid; + } } /* enlist this vol, it's valid */ @@ -622,6 +772,15 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) goto err; } + /* extract info-table */ + if (a->itable && + (ubi32_to_cpu(cur->vid.vol_id) == UBI_LAYOUT_VOL_ID)) { + extract_itable(fpin, cur, a->bsize, + itable_num, a->odir_path); + itable_num++; + } + + /* split volumes */ if (a->vol_split) { size_t size = 0; @@ -631,9 +790,9 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) if (a->vol_split == SPLIT_DATA) { /* write only data section */ - size = ubi32_to_cpu(cur->inner.data_size); + size = ubi32_to_cpu(cur->vid.data_size); fseek(fpin, - ubi32_to_cpu(cur->outer.data_offset), + ubi32_to_cpu(cur->ec.data_offset), SEEK_CUR); } else if (a->vol_split == SPLIT_RAW) @@ -642,15 +801,16 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) 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); + ubi32_to_cpu(cur->vid.vol_id), + ubi32_to_cpu(cur->vid.lnum), + ubi32_to_cpu(cur->vid.leb_ver), count); rc = extract_data(fpin, size, filename); if (rc < 0) goto err; } invalid: + /* split eraseblocks */ if (a->eb_split) { /* jump to top of block */ rc = fsetpos(fpin, &(cur->eb_top)); @@ -664,9 +824,9 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) 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), + ubi32_to_cpu(cur->vid.vol_id), + ubi32_to_cpu(cur->vid.lnum), + ubi32_to_cpu(cur->vid.leb_ver), reason); rc = extract_data(fpin, a->bsize, filename); @@ -704,15 +864,18 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) out: for (i = 0; i < vc; i++) { - rc = rebuild_volume(fpin, &vols[i], &head, a->odir_path); + rc = rebuild_volume(fpin, &vols[i], &head, a->odir_path, + a->bsize, a->hsize); if (rc < 0) goto err; } /* 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 ((vc == 0) && (!a->eb_split) && (!a->vol_split) && + (!a->analyze) && (!a->itable)) { + rc = rebuild_volume(fpin, NULL, &head, a->odir_path, a->bsize, + a->hsize); if (rc < 0) goto err; } @@ -722,6 +885,7 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) if (a->analyze) unubi_analyze(&head, first, a->odir_path); + eb_chain_destroy(&head); eb_chain_destroy(&first); @@ -751,6 +915,7 @@ main(int argc, char *argv[]) /* setup struct args a */ memset(&a, 0, sizeof(a)); a.bsize = 128 * KIB; + a.hsize = 2 * KIB; a.vols = malloc(sizeof(*a.vols) * UBI_MAX_VOLUMES); if (a.vols == NULL) { ERR_MSG("out of memory\n"); @@ -818,8 +983,8 @@ main(int argc, char *argv[]) /* 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); + /* ERR_MSG("error encountered while working on image file: " + "%s\n", a.img_path); */ rc = -rc; goto err; } diff --git a/ubi-utils/src/unubi_analyze.c b/ubi-utils/src/unubi_analyze.c index 6009fc0..e5bbb23 100644 --- a/ubi-utils/src/unubi_analyze.c +++ b/ubi-utils/src/unubi_analyze.c @@ -113,6 +113,9 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) FILE* fpplot; eb_info_t cur; + if (first == NULL) + return -1; + /* crc check still needed for `first' linked list */ init_crc32_table(crc32_table); @@ -126,9 +129,12 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) memset(filename, 0, MAXPATH + 1); snprintf(filename, MAXPATH, "%s/%s", path, FN_EH_PLOT); fpplot = fopen(filename, "w"); - if (fpplot == NULL) + if (fpplot == NULL) { + fclose(fpdata); return -1; + } + /* make executable */ chmod(filename, 0755); /* first run: count elements */ @@ -146,8 +152,8 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) /* second run: populate array to sort */ count = 0; cur = first; - while(cur != NULL) { - erase_counts[count] = ubi64_to_cpu(cur->outer.ec); + while (cur != NULL) { + erase_counts[count] = ubi64_to_cpu(cur->ec.ec); cur = cur->next; count++; } @@ -160,24 +166,24 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) fprintf(fpdata, "# eraseblock_no actual_erase_count " "sorted_erase_count\n"); while (cur != NULL) { - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &cur->outer, + crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &cur->ec, UBI_EC_HDR_SIZE_CRC); - if ((ubi32_to_cpu(cur->outer.magic) != UBI_EC_HDR_MAGIC) || - (crc != ubi32_to_cpu(cur->outer.hdr_crc))) + if ((ubi32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) || + (crc != ubi32_to_cpu(cur->ec.hdr_crc))) fprintf(fpdata, "# "); - fprintf(fpdata, "%zu %llu %llu", count, - (unsigned long long) ubi64_to_cpu(cur->outer.ec), - (unsigned long long) erase_counts[count]); + fprintf(fpdata, "%u %llu %llu", count, + ubi64_to_cpu(cur->ec.ec), + erase_counts[count]); - if (ubi32_to_cpu(cur->outer.magic) != UBI_EC_HDR_MAGIC) + if (ubi32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) fprintf(fpdata, " ## bad magic: %08x", - ubi32_to_cpu(cur->outer.magic)); + ubi32_to_cpu(cur->ec.magic)); - if (crc != ubi32_to_cpu(cur->outer.hdr_crc)) + if (crc != ubi32_to_cpu(cur->ec.hdr_crc)) fprintf(fpdata, " ## CRC mismatch: given=%08x, " - "calc=%08x", ubi32_to_cpu(cur->outer.hdr_crc), + "calc=%08x", ubi32_to_cpu(cur->ec.hdr_crc), crc); fprintf(fpdata, "\n"); @@ -198,7 +204,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, "%zd", count); + fprintf(fpplot, "%d", count); } cur = cur->next; @@ -207,9 +213,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:%zu]\n", eraseblocks + 1); + fprintf(fpplot, "set xrange [-1:%u]\n", eraseblocks + 1); fprintf(fpplot, "# set yrange [-1:%llu]\n", - (unsigned long long) erase_counts[eraseblocks - 1] + 1); + 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", @@ -236,26 +242,40 @@ int unubi_analyze_vid_hdr(eb_info_t *head, const char *path) { char filename[MAXPATH + 1]; - int y1, y2; + int rc, y1, y2; size_t count, step, breadth; uint32_t *leb_versions, *data_sizes; FILE* fpdata; FILE* fpplot; eb_info_t cur; + if (head == NULL || *head == NULL) + return -1; + + rc = 0; + fpdata = NULL; + fpplot = NULL; + data_sizes = NULL; + leb_versions = NULL; + /* 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; + if (fpdata == NULL) { + rc = -1; + goto exit; + } memset(filename, 0, MAXPATH + 1); snprintf(filename, MAXPATH, "%s/%s", path, FN_VH_PLOT); fpplot = fopen(filename, "w"); - if (fpplot == NULL) - return -1; + if (fpplot == NULL) { + rc = -1; + goto exit; + } + /* make executable */ chmod(filename, 0755); /* first run: count elements */ @@ -267,18 +287,26 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) } breadth = count; - leb_versions = malloc(breadth * sizeof(*leb_versions)); - memset(leb_versions, 0, breadth * sizeof(*leb_versions)); + leb_versions = malloc(breadth * sizeof(uint32_t)); + if (leb_versions == NULL) { + rc = -1; + goto exit; + } + memset(leb_versions, 0, breadth * sizeof(uint32_t)); - data_sizes = malloc(breadth * sizeof(*data_sizes)); + data_sizes = malloc(breadth * sizeof(uint32_t)); + if (data_sizes == NULL) { + rc = -1; + goto exit; + } 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); + leb_versions[count] = ubi32_to_cpu(cur->vid.leb_ver); + data_sizes[count] = ubi32_to_cpu(cur->vid.data_size); cur = cur->next; count++; } @@ -291,26 +319,27 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) 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, + y1 = norm_index(ubi32_to_cpu(cur->vid.leb_ver), leb_versions, breadth); - y2 = norm_index(ubi32_to_cpu(cur->inner.data_size), data_sizes, + y2 = norm_index(ubi32_to_cpu(cur->vid.data_size), data_sizes, breadth); - if ((y1 == -1) || (y2 == -1)) - return -1; + if ((y1 == -1) || (y2 == -1)) { + rc = -1; + goto exit; + } - fprintf(fpdata, "%zu %u %u %u %u %u %u\n", + fprintf(fpdata, "%u %u %u %u %u %u %u\n", count, - ubi32_to_cpu(cur->inner.vol_id), - ubi32_to_cpu(cur->inner.lnum), + ubi32_to_cpu(cur->vid.vol_id), + ubi32_to_cpu(cur->vid.lnum), y1, - ubi32_to_cpu(cur->inner.leb_ver), + ubi32_to_cpu(cur->vid.leb_ver), y2, - ubi32_to_cpu(cur->inner.data_size)); + ubi32_to_cpu(cur->vid.data_size)); cur = cur->next; count++; } - fclose(fpdata); fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); fprintf(fpplot, "set xlabel \"volume\"\n"); @@ -323,13 +352,13 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) 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, "\"%zd\" %zd 0", step, count); + if (step != ubi32_to_cpu(cur->vid.vol_id)) { + step = ubi32_to_cpu(cur->vid.vol_id); + fprintf(fpplot, "\"%d\" %d 0", step, count); } else - fprintf(fpplot, "\"%d\" %zd 1", - ubi32_to_cpu(cur->inner.lnum), count); + fprintf(fpplot, "\"%d\" %d 1", + ubi32_to_cpu(cur->vid.lnum), count); cur = cur->next; count++; } @@ -341,17 +370,19 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) 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, + while (cur->next != NULL) { + y1 = norm_index(ubi32_to_cpu(cur->vid.leb_ver), leb_versions, breadth); - if (y1 == -1) - return -1; + if (y1 == -1) { + rc = -1; + goto exit; + } if (count > 0) fprintf(fpplot, ", "); - fprintf(fpplot, "\"%u\" %u", ubi32_to_cpu(cur->inner.leb_ver), + fprintf(fpplot, "\"%u\" %u", ubi32_to_cpu(cur->vid.leb_ver), y1); cur = cur->next; @@ -365,16 +396,18 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) fprintf(fpplot, "set y2label \"data size\"\n"); fprintf(fpplot, "set y2tics ("); while (cur != NULL) { - y2 = norm_index(ubi32_to_cpu(cur->inner.data_size), + y2 = norm_index(ubi32_to_cpu(cur->vid.data_size), data_sizes, breadth); - if (y2 == -1) - return -1; + if (y2 == -1) { + rc = -1; + goto exit; + } if (count > 0) fprintf(fpplot, ", "); - fprintf(fpplot, "\"%u\" %u", ubi32_to_cpu(cur->inner.data_size), + fprintf(fpplot, "\"%u\" %u", ubi32_to_cpu(cur->vid.data_size), y2); cur = cur->next; @@ -384,7 +417,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:%zu]\n", count + 1); + 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\" " @@ -393,12 +426,17 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) "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; + exit: + if (fpdata != NULL) + fclose(fpdata); + if (fpplot != NULL) + fclose(fpplot); + if (data_sizes != NULL) + free(data_sizes); + if (leb_versions != NULL) + free(leb_versions); + + return rc; } @@ -412,23 +450,14 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) int unubi_analyze(eb_info_t *head, eb_info_t first, const char *path) { - int rc; + int ec_rc, vid_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) + ec_rc = unubi_analyze_ec_hdr(first, path); + vid_rc = unubi_analyze_vid_hdr(head, path); + if (ec_rc < 0 || vid_rc < 0) return -1; return 0; |