summaryrefslogtreecommitdiff
path: root/ubi-utils
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils')
-rw-r--r--ubi-utils/src/eb_chain.c35
-rw-r--r--ubi-utils/src/eb_chain.h4
-rw-r--r--ubi-utils/src/unubi.c401
-rw-r--r--ubi-utils/src/unubi_analyze.c169
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;