summaryrefslogtreecommitdiff
path: root/ubi-utils/src/unubi.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src/unubi.c')
-rw-r--r--ubi-utils/src/unubi.c141
1 files changed, 81 insertions, 60 deletions
diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c
index e0a71a6..6ca9405 100644
--- a/ubi-utils/src/unubi.c
+++ b/ubi-utils/src/unubi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) International Business Machines Corp., 2006, 2007
*
* 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
@@ -17,12 +17,13 @@
*/
/*
- * Authors: Frank Haverkamp, haver@vnet.ibm.com
- * Drake Dowsett, dowsett@de.ibm.com
+ * Authors: Drake Dowsett, dowsett@de.ibm.com
+ * Frank Haverkamp, haver@vnet.ibm.com
*
* 1.2 Removed argp because we want to use uClibc.
* 1.3 Minor cleanups.
* 1.4 Meanwhile Drake had done a lot of changes, syncing those.
+ * 1.5 Bugfixes, simplifications
*/
/*
@@ -44,18 +45,18 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <limits.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <mtd/ubi-header.h>
#include "crc32.h"
-#include "eb_chain.h"
#include "unubi_analyze.h"
#define EXEC "unubi"
#define CONTACT "haver@vnet.ibm.com"
-#define VERSION "1.4"
+#define VERSION "1.5"
static char doc[] = "\nVersion: " VERSION "\n";
static int debug = 0;
@@ -66,7 +67,7 @@ static const char *optionsstr =
"to rebuild all valid complete UBI volumes found within the image.\n"
"\n"
" OPERATIONS\n"
-" -a, --analyze Analyze image\n"
+" -a, --analyze Analyze image and create gnuplot graphs\n"
" -i, --info-table Extract volume information tables\n"
" -r, --rebuild=<volume-id> Extract and rebuild volume\n"
"\n"
@@ -75,8 +76,11 @@ static const char *optionsstr =
" (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"
+" -s, --headersize=<header-size> Specify size reserved for metadata in eraseblock\n"
+ " in bytes (default 2048 Byte)\n"
+ /* the -s option might be insufficient when using different vid
+ offset than what we used when writing this tool ... Better would
+ probably be --vid-hdr-offset or alike */
"\n"
" ADVANCED\n"
" -e, --eb-split Generate individual eraseblock images (all\n"
@@ -138,8 +142,12 @@ struct args {
int analyze;
int itable;
uint32_t *vols;
- size_t bsize;
+
+ size_t vid_hdr_offset;
+ size_t data_offset;
+ size_t bsize; /* FIXME replace by vid_hdr/data offs? */
size_t hsize;
+
char *odir_path;
int eb_split;
int vol_split;
@@ -204,29 +212,30 @@ parse_opt(int argc, char **argv, struct args *args)
break;
switch (key) {
- case 'a':
+ case 'a': /* --analyze */
args->analyze = 1;
break;
- case 'b':
+ case 'b': /* --block-size=<block-size> */
args->bsize = str_to_num(optarg);
break;
- case 's':
+ case 's': /* --header-size=<header-size> */
args->hsize = str_to_num(optarg);
break;
- case 'd':
+ case 'd': /* --dir=<output-dir> */
args->odir_path = optarg;
break;
- case 'D': /* I wanted to use -v but that was
- already used ... */
+ case 'D': /* --debug */
+ /* I wanted to use -v but that was already
+ used ... */
debug = 1;
break;
- case 'e':
+ case 'e': /* --eb-split */
args->eb_split = SPLIT_RAW;
break;
- case 'i':
+ case 'i': /* --info-table */
args->itable = 1;
break;
- case 'r':
+ case 'r': /* --rebuild=<volume-id> */
i = str_to_num(optarg);
if (i < UBI_MAX_VOLUMES)
args->vols[str_to_num(optarg)] = 1;
@@ -235,11 +244,11 @@ parse_opt(int argc, char **argv, struct args *args)
return -1;
}
break;
- case 'v':
+ case 'v': /* --vol-split */
if (args->vol_split != SPLIT_RAW)
args->vol_split = SPLIT_DATA;
break;
- case 'V':
+ case 'V': /* --vol-split! */
args->vol_split = SPLIT_RAW;
break;
case '?': /* help */
@@ -258,6 +267,10 @@ parse_opt(int argc, char **argv, struct args *args)
}
}
+ /* FIXME I suppose hsize should be replaced! */
+ args->vid_hdr_offset = args->hsize - UBI_VID_HDR_SIZE;
+ args->data_offset = args->hsize;
+
if (optind < argc)
args->img_path = argv[optind++];
return 0;
@@ -307,33 +320,6 @@ collapse(uint32_t *full_array, size_t full_len,
return j;
}
-
-/**
- * header_crc: calculate the crc of EITHER a eb_hdr or vid_hdr
- * one of the first two 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;
-}
-
-
/**
* data_crc: save the FILE* position, calculate the crc over a span,
* reset the position
@@ -420,8 +406,8 @@ extract_data(FILE* fpin, size_t len, const char *path)
* failure and 0 on success
**/
static int
-extract_itable(FILE* fpin, eb_info_t cur, size_t bsize, size_t num,
- const char* path)
+extract_itable(FILE *fpin, struct eb_info *cur, size_t bsize, size_t num,
+ const char *path)
{
char filename[MAXPATH + 1];
int rc;
@@ -531,14 +517,14 @@ extract_itable(FILE* fpin, eb_info_t cur, size_t bsize, size_t num,
* 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,
- size_t block_size, size_t header_size)
+rebuild_volume(FILE * fpin, uint32_t *vol_id, struct eb_info **head,
+ const char *path, size_t block_size, size_t header_size)
{
char filename[MAXPATH];
int rc;
uint32_t vol, num, data_size;
FILE* fpout;
- eb_info_t cur;
+ struct eb_info *cur;
rc = 0;
@@ -606,6 +592,7 @@ rebuild_volume(FILE* fpin, uint32_t *vol_id, eb_info_t *head, const char* path,
fseek(fpin, ubi32_to_cpu(cur->ec.data_offset), SEEK_CUR);
if (cur->vid.vol_type == UBI_VID_DYNAMIC)
+ /* FIXME It might be that alignment has influence */
data_size = block_size - header_size;
else
data_size = ubi32_to_cpu(cur->vid.data_size);
@@ -651,8 +638,8 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
/* relations:
* cur ~ head
* next ~ first */
- eb_info_t head, cur, first, next;
- eb_info_t *next_ptr;
+ struct eb_info *head, *cur, *first, *next;
+ struct eb_info **next_ptr;
rc = 0;
count = 0;
@@ -673,6 +660,11 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
const char *raw_path;
uint32_t crc;
+ cur->phys_addr = ftell(fpin);
+ cur->data_crc_ok = 0;
+ cur->ec_crc_ok = 0;
+ cur->vid_crc_ok = 0;
+
memset(filename, 0, MAXPATH + 1);
memset(reason, 0, MAXPATH + 1);
@@ -696,8 +688,8 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
}
/* check erasecounter header crc */
- header_crc(&(cur->ec), NULL, &crc);
-
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->ec),
+ UBI_EC_HDR_SIZE_CRC);
if (ubi32_to_cpu(cur->ec.hdr_crc) != crc) {
snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc");
goto invalid;
@@ -738,13 +730,16 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
snprintf(reason, MAXPATH, ".invalid.vid_magic");
goto invalid;
}
+ cur->ec_crc_ok = 1;
/* check volume id header crc */
- header_crc(NULL, &(cur->vid), &crc);
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->vid),
+ UBI_VID_HDR_SIZE_CRC);
if (ubi32_to_cpu(cur->vid.hdr_crc) != crc) {
snprintf(reason, MAXPATH, ".invalid.vid_hdr_crc");
goto invalid;
}
+ cur->vid_crc_ok = 1;
/* check data crc, but only for a static volume */
if (cur->vid.vol_type == UBI_VID_STATIC) {
@@ -756,6 +751,7 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
snprintf(reason, MAXPATH, ".invalid.data_crc");
goto invalid;
}
+ cur->data_crc_ok = 1;
}
/* enlist this vol, it's valid */
@@ -788,9 +784,22 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
if (rc != 0)
goto err;
+ /*
+ * FIXME For dynamic UBI volumes we must write
+ * the maximum available data. The
+ * vid.data_size field is not used in this
+ * case. The dynamic volume user is
+ * responsible for the content.
+ */
if (a->vol_split == SPLIT_DATA) {
- /* write only data section */
- size = ubi32_to_cpu(cur->vid.data_size);
+ /* Write only data section */
+ if (cur->vid.vol_type == UBI_VID_DYNAMIC) {
+ /* FIXME Formular is not
+ always right ... */
+ size = a->bsize - a->hsize;
+ } else
+ size = ubi32_to_cpu(cur->vid.data_size);
+
fseek(fpin,
ubi32_to_cpu(cur->ec.data_offset),
SEEK_CUR);
@@ -883,9 +892,21 @@ unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
err:
free(cur);
- if (a->analyze)
+ if (a->analyze) {
+ char fname[PATH_MAX];
+ FILE *fp;
+
unubi_analyze(&head, first, a->odir_path);
+ /* prepare output files */
+ memset(fname, 0, PATH_MAX + 1);
+ snprintf(fname, PATH_MAX, "%s/%s", a->odir_path, FN_EH_STAT);
+ fp = fopen(fname, "w");
+ if (fp != NULL) {
+ eb_chain_print(fp, head);
+ fclose(fp);
+ }
+ }
eb_chain_destroy(&head);
eb_chain_destroy(&first);