From 26c965bc654d67881fc54f4b24a552600752dadd Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Sat, 24 Nov 2007 11:04:51 +0100 Subject: ubi-utils: various fixes in unubi The extraction of data from blocks used for dynamic volumes was totally broken. The data size was calculated wrong. This fix is not perfect, the alignment is still ignored. The parameter "header-size" is very misleading. It does not reflect the vid hdr offset properly. I assume therefor that it only works for the layout I am using where the vid hdr is at the _end_ of the 1st NAND page (2048). I added the generation of a textfile with information about the blocks which are going into the internal graph representation. Instead of a graph I think that a simple array will simplify the code very much. The array must than be sorted properly to cope with older and newer block-copies but that should not be a problem. discussed the tool with my coleage Andreas Arnez and we found that it might be a good idea to replace it even with a perl program for the same purpose since that would offer the flexibility to change it on the fly when needed. The tool is mainly used for crash analysis so it could be an advantage to change it without needing a C-compiler. Signed-off-by: Frank Haverkamp --- ubi-utils/scripts/unubi_test.sh | 82 +++++++++++++++++------ ubi-utils/src/eb_chain.c | 135 ++++++++++++++++++-------------------- ubi-utils/src/eb_chain.h | 73 --------------------- ubi-utils/src/unubi.c | 141 +++++++++++++++++++++++----------------- ubi-utils/src/unubi_analyze.c | 48 +++++++------- ubi-utils/src/unubi_analyze.h | 70 ++++++++++++++++++-- 6 files changed, 294 insertions(+), 255 deletions(-) delete mode 100644 ubi-utils/src/eb_chain.h diff --git a/ubi-utils/scripts/unubi_test.sh b/ubi-utils/scripts/unubi_test.sh index 1cbe426..40dc2e2 100644 --- a/ubi-utils/scripts/unubi_test.sh +++ b/ubi-utils/scripts/unubi_test.sh @@ -6,56 +6,100 @@ # 2007 Frank Haverkamp # -version=1.0 +version=1.1 image=data.mif oob=oob.bin data=data.bin pagesize=2048 volmax=31 -datadir=unubi_data.bin +datadir=unubi_data -echo "Testcase: ${0} Version: ${version}" -echo - -if [ -f $1 ]; then - image=${1} -fi +# general arguments e.g. debug enablement +# unubi_args="-D" +echo "------------------------------------------------------------------------" +echo "Testcase: ${0} Version: ${version}" +echo "------------------------------------------------------------------------" echo "Testing nand2bin ..." echo " Input: ${image}" echo " Data: ${data}" echo " OOB: ${oob}" echo " Pagesize: ${pagesize}" - nand2bin --pagesize ${pagesize} -o ${data} -O ${oob} ${image} echo +echo "------------------------------------------------------------------------" echo "Testing unubi ..." +echo "------------------------------------------------------------------------" unubi --version +echo +echo "------------------------------------------------------------------------" echo "Trying to extract first ${volmax} volumes ..." +echo "------------------------------------------------------------------------" +mkdir -p ${datadir}/volumes for v in `seq 0 ${volmax}` ; do - unubi -r${v} ${data} + unubi ${unubi_args} -r${v} -d${datadir}/volumes ${data} echo -n "." done echo "ok" +ls -l ${datadir}/volumes +echo -ls -l unubi_data.bin/ - +echo "------------------------------------------------------------------------" echo "Extracting graphics ..." -unubi -a ${data} +echo "------------------------------------------------------------------------" +unubi -a -d${datadir} ${data} +echo "Use gnuplot to display:" +ls ${datadir}/*.plot +ls ${datadir}/*.data +echo +echo "------------------------------------------------------------------------" +echo "eb-split" +echo "------------------------------------------------------------------------" +unubi -e -d${datadir}/eb-split ${data} +ls -l ${datadir}/eb-split +echo -echo "Extracting volume info table ..." -unubi -i ${data} +echo "------------------------------------------------------------------------" +echo "vol-split" +echo "------------------------------------------------------------------------" +unubi -v -d${datadir}/vol-split ${data} +ls -l ${datadir}/vol-split +echo +echo "The generated images contain only the data (126KiB in our " +echo "case) not including the UBI erase count and volume info " +echo "header. For dynamic volumes the data should be the full " +echo "126KiB. Unubi cannot know how much of the data is valid. " +echo + +echo "------------------------------------------------------------------------" +echo "!vol-split" +echo "------------------------------------------------------------------------" +unubi -V -d${datadir}/vol-split! ${data} +ls -l ${datadir}/vol-split\! +echo +echo "The generated images contain the full block data of 128KiB " +echo "including the UBI erase count and volume information header." +echo +echo "------------------------------------------------------------------------" +echo "Extracting volume info table ..." +echo "------------------------------------------------------------------------" +unubi -i -d${datadir} ${data} +echo "I strongly hope that empty ubi blocks are filled with 0xff! " echo + +echo "------------------------------------------------------------------------" echo "Table 0" -echo "-------" +echo "------------------------------------------------------------------------" cat ${datadir}/vol_info_table0 - echo + +echo "------------------------------------------------------------------------" echo "Table 1" -echo "-------" -cat ${datadir}/vol_info_table1 \ No newline at end of file +echo "------------------------------------------------------------------------" +cat ${datadir}/vol_info_table1 +echo diff --git a/ubi-utils/src/eb_chain.c b/ubi-utils/src/eb_chain.c index 22594c5..8f6e327 100644 --- a/ubi-utils/src/eb_chain.c +++ b/ubi-utils/src/eb_chain.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 @@ -26,12 +26,11 @@ #include #include #include -#include "eb_chain.h" +#include "unubi_analyze.h" #include "crc32.h" #define COPY(dst, src) \ - do \ - { \ + do { \ dst = malloc(sizeof(*dst)); \ if (dst == NULL) \ return -ENOMEM; \ @@ -50,18 +49,17 @@ * meaning there is a bug or a case not being handled here; **/ int -eb_chain_insert(eb_info_t *head, eb_info_t new) +eb_chain_insert(struct eb_info **head, struct eb_info *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; + struct eb_info *prev, *cur, *hist, *ins; + struct eb_info **prev_ptr; if ((head == NULL) || (new == NULL)) return 0; - if (*head == NULL) - { + if (*head == NULL) { COPY(*head, new); (*head)->next = NULL; return 0; @@ -79,11 +77,9 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) /* traverse until vol_id/lnum align */ 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))) - { + while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) { /* insert new at end of chain */ - if (cur->next == NULL) - { + if (cur->next == NULL) { COPY(ins, new); ins->next = NULL; cur->next = ins; @@ -102,8 +98,7 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) prev_ptr = &(prev->next); /* insert new into the middle of chain */ - if ((new_vol != vol) || (new_num != num)) - { + if ((new_vol != vol) || (new_num != num)) { COPY(ins, new); ins->next = cur; *prev_ptr = ins; @@ -117,11 +112,9 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) /* traverse until versions align */ ver = ubi32_to_cpu(cur->vid.leb_ver); - while (new_ver < ver) - { + while (new_ver < ver) { /* insert new at bottom of history */ - if (hist->older == NULL) - { + if (hist->older == NULL) { COPY(ins, new); ins->next = NULL; ins->older = NULL; @@ -134,8 +127,7 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) ver = ubi32_to_cpu(hist->vid.leb_ver); } - if (prev == NULL) - { + if (prev == NULL) { /* replace active version */ COPY(ins, new); ins->next = hist->next; @@ -146,18 +138,13 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) 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; + /* insert between versions, beneath active version */ + COPY(ins, new); + ins->next = NULL; + ins->older = prev->older; + prev->older = ins; + return 0; } @@ -168,11 +155,11 @@ eb_chain_insert(eb_info_t *head, eb_info_t new) * always returns 0; **/ int -eb_chain_position(eb_info_t *head, uint32_t vol_id, uint32_t *lnum, - eb_info_t *pos) +eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum, + struct eb_info **pos) { uint32_t vol, num; - eb_info_t cur; + struct eb_info *cur; if ((head == NULL) || (*head == NULL) || (pos == NULL)) return 0; @@ -180,17 +167,14 @@ eb_chain_position(eb_info_t *head, uint32_t vol_id, uint32_t *lnum, *pos = NULL; cur = *head; - while (cur != NULL) - { + while (cur != NULL) { vol = ubi32_to_cpu(cur->vid.vol_id); num = ubi32_to_cpu(cur->vid.lnum); - if (vol_id == vol) - if ((lnum == NULL) || (*lnum == num)) - { - *pos = cur; - return 0; - } + if ((vol_id == vol) && ((lnum == NULL) || (*lnum == num))) { + *pos = cur; + return 0; + } cur = cur->next; } @@ -206,43 +190,53 @@ eb_chain_position(eb_info_t *head, uint32_t vol_id, uint32_t *lnum, * always returns 0; **/ int -eb_chain_print(FILE* stream, eb_info_t *head) +eb_chain_print(FILE* stream, struct eb_info *head) { - eb_info_t cur; - - if (head == NULL) - return 0; + struct eb_info *cur; if (stream == NULL) stream = stdout; - if (*head == NULL) - { + if (head == NULL) { fprintf(stream, "EMPTY\n"); return 0; } + /* 012345678012345678012345678012301230123 01234567 0123457 01234567*/ + fprintf(stream, "VOL_ID LNUM LEB_VER EC VID DAT PADDR DSIZE EC\n"); + cur = head; + while (cur != NULL) { + struct eb_info *hist; - cur = *head; - while (cur != NULL) - { - eb_info_t hist; - - fprintf(stream, " VOL %4u-%04u | VER 0x%8x\n", + fprintf(stream, "%08x %-8u %-8u %-4s%-4s", ubi32_to_cpu(cur->vid.vol_id), ubi32_to_cpu(cur->vid.lnum), - ubi32_to_cpu(cur->vid.leb_ver)); + ubi32_to_cpu(cur->vid.leb_ver), + cur->ec_crc_ok ? "ok":"bad", + cur->vid_crc_ok ? "ok":"bad"); + if (cur->vid.vol_type == UBI_VID_STATIC) + fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"bad"); + else fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"ign"); + fprintf(stream, " %08x %-8u %-8llu\n", cur->phys_addr, + ubi32_to_cpu(cur->vid.data_size), + ubi64_to_cpu(cur->ec.ec)); hist = cur->older; - while (hist != NULL) - { - fprintf(stream, "+ VOL %4u-%04u | VER 0x%8x\n", + while (hist != NULL) { + fprintf(stream, "%08x %-8u %-8u %-4s%-4s", ubi32_to_cpu(hist->vid.vol_id), ubi32_to_cpu(hist->vid.lnum), - ubi32_to_cpu(hist->vid.leb_ver)); + ubi32_to_cpu(hist->vid.leb_ver), + hist->ec_crc_ok ? "ok":"bad", + hist->vid_crc_ok ? "ok":"bad"); + if (hist->vid.vol_type == UBI_VID_STATIC) + fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"bad"); + else fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"ign"); + fprintf(stream, " %08x %-8u %-8llu (*)\n", hist->phys_addr, + ubi32_to_cpu(hist->vid.data_size), + ubi64_to_cpu(hist->ec.ec)); hist = hist->older; } - cur = cur->next; } @@ -256,33 +250,28 @@ eb_chain_print(FILE* stream, eb_info_t *head) * always returns 0; **/ int -eb_chain_destroy(eb_info_t *head) +eb_chain_destroy(struct eb_info **head) { if (head == NULL) return 0; - while (*head != NULL) - { - eb_info_t cur; - eb_info_t hist; + while (*head != NULL) { + struct eb_info *cur; + struct eb_info *hist; cur = *head; *head = (*head)->next; hist = cur->older; - while (hist != NULL) - { - eb_info_t temp; + while (hist != NULL) { + struct eb_info *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 deleted file mode 100644 index 4c94058..0000000 --- a/ubi-utils/src/eb_chain.h +++ /dev/null @@ -1,73 +0,0 @@ -#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 ec; - struct ubi_vid_hdr vid; - 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 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 #include #include +#include #include #include #include #include #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= Extract and rebuild volume\n" "\n" @@ -75,8 +76,11 @@ static const char *optionsstr = " (default 128KiB)\n" " -d, --dir= Specify output directory\n" " -D, --debug Enable debug output\n" -" -s, --headersize= Specify size of eraseblock header in image\n" -" in bytes (default 2048 Byte)\n" +" -s, --headersize= 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= */ args->bsize = str_to_num(optarg); break; - case 's': + case 's': /* --header-size= */ args->hsize = str_to_num(optarg); break; - case 'd': + case 'd': /* --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= */ 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); diff --git a/ubi-utils/src/unubi_analyze.c b/ubi-utils/src/unubi_analyze.c index e5bbb23..c2fbe47 100644 --- a/ubi-utils/src/unubi_analyze.c +++ b/ubi-utils/src/unubi_analyze.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 @@ -32,22 +32,15 @@ #include #include #include +#include #include #include -#include "eb_chain.h" +#include "unubi_analyze.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 **/ @@ -103,15 +96,15 @@ norm_index(uint32_t item, uint32_t *array, size_t length) * display of the data file; **/ int -unubi_analyze_ec_hdr(eb_info_t first, const char *path) +unubi_analyze_ec_hdr(struct eb_info *first, const char *path) { - char filename[MAXPATH + 1]; + char filename[PATH_MAX + 1]; size_t count, eraseblocks; uint32_t crc, crc32_table[256]; uint64_t *erase_counts; FILE* fpdata; FILE* fpplot; - eb_info_t cur; + struct eb_info *cur; if (first == NULL) return -1; @@ -120,14 +113,14 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) init_crc32_table(crc32_table); /* prepare output files */ - memset(filename, 0, MAXPATH + 1); - snprintf(filename, MAXPATH, "%s/%s", path, FN_EH_DATA); + memset(filename, 0, PATH_MAX + 1); + snprintf(filename, PATH_MAX, "%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); + memset(filename, 0, PATH_MAX + 1); + snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_PLOT); fpplot = fopen(filename, "w"); if (fpplot == NULL) { fclose(fpdata); @@ -147,6 +140,11 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) eraseblocks = count; erase_counts = malloc(eraseblocks * sizeof(*erase_counts)); + if (!erase_counts) { + perror("out of memory"); + exit(EXIT_FAILURE); + } + memset(erase_counts, 0, eraseblocks * sizeof(*erase_counts)); /* second run: populate array to sort */ @@ -239,15 +237,15 @@ unubi_analyze_ec_hdr(eb_info_t first, const char *path) * display of the data file; **/ int -unubi_analyze_vid_hdr(eb_info_t *head, const char *path) +unubi_analyze_vid_hdr(struct eb_info **head, const char *path) { - char filename[MAXPATH + 1]; + char filename[PATH_MAX + 1]; int rc, y1, y2; size_t count, step, breadth; uint32_t *leb_versions, *data_sizes; FILE* fpdata; FILE* fpplot; - eb_info_t cur; + struct eb_info *cur; if (head == NULL || *head == NULL) return -1; @@ -259,16 +257,16 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) leb_versions = NULL; /* prepare output files */ - memset(filename, 0, MAXPATH + 1); - snprintf(filename, MAXPATH, "%s/%s", path, FN_VH_DATA); + memset(filename, 0, PATH_MAX + 1); + snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_DATA); fpdata = fopen(filename, "w"); if (fpdata == NULL) { rc = -1; goto exit; } - memset(filename, 0, MAXPATH + 1); - snprintf(filename, MAXPATH, "%s/%s", path, FN_VH_PLOT); + memset(filename, 0, PATH_MAX + 1); + snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_PLOT); fpplot = fopen(filename, "w"); if (fpplot == NULL) { rc = -1; @@ -448,7 +446,7 @@ unubi_analyze_vid_hdr(eb_info_t *head, const char *path) * returns 0 upon successful completion, or -1 otherwise **/ int -unubi_analyze(eb_info_t *head, eb_info_t first, const char *path) +unubi_analyze(struct eb_info **head, struct eb_info *first, const char *path) { int ec_rc, vid_rc; diff --git a/ubi-utils/src/unubi_analyze.h b/ubi-utils/src/unubi_analyze.h index ac01a44..243ea58 100644 --- a/ubi-utils/src/unubi_analyze.h +++ b/ubi-utils/src/unubi_analyze.h @@ -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 @@ -16,11 +16,71 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef __UNUBI_ANALYZE_H__ +#define __UNUBI_ANALYZE_H__ + /* - * Authors: Drake Dowsett, dowsett@de.ibm.com + * 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 "eb_chain.h" +#include +#include +#include + +#define FN_EH_STAT "analysis_blocks.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" + +struct eb_info { + struct ubi_ec_hdr ec; + struct ubi_vid_hdr vid; + + fpos_t eb_top; + uint32_t linear; + int ec_crc_ok; + int vid_crc_ok; + int data_crc_ok; + uint32_t phys_addr; + + struct eb_info *next; + struct eb_info *older; +}; + +int eb_chain_insert(struct eb_info **head, struct eb_info *item); + +int eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum, + struct eb_info **pos); + +int eb_chain_print(FILE *stream, struct eb_info *head); + +int eb_chain_destroy(struct eb_info **head); + +int unubi_analyze(struct eb_info **head, struct eb_info *first, + const char *path); -int -unubi_analyze(eb_info_t *head, eb_info_t first, const char *path); +#endif /* __UNUBI_ANALYZE_H__ */ -- cgit v1.2.3