diff options
Diffstat (limited to 'ubi-utils')
81 files changed, 2312 insertions, 17713 deletions
diff --git a/ubi-utils/LICENSE.libiniparser b/ubi-utils/LICENSE.libiniparser new file mode 100644 index 0000000..dbfa45d --- /dev/null +++ b/ubi-utils/LICENSE.libiniparser @@ -0,0 +1,21 @@ +Copyright (c) 2000-2007 by Nicolas Devillard. +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile index 1f8e543..8d4412d 100644 --- a/ubi-utils/Makefile +++ b/ubi-utils/Makefile @@ -10,65 +10,53 @@ MANDIR=/usr/man INCLUDEDIR=/usr/include CC := $(CROSS)gcc -CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror -Wall -O0 -g +CFLAGS := -Iinclude -Isrc -I$(KERNELHDR) $(OPTFLAGS) -Werror -Wall -PERLPROGS = mkpfi -TARGETS = ubiupdate ubimkvol ubirmvol ubicrc32 ubinfo ubiattach ubidetach \ - unubi pfi2bin +LIBS = libubi libubigen libiniparser +UTILS = ubiupdate ubimkvol ubirmvol ubicrc32 ubinfo ubiattach ubidetach ubinize -vpath %.c ./src +vpath %.c src -%: %.o - $(CC) $(LDFLAGS) -g -o $@ $^ +all: $(UTILS) -%.o: %.c - $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,.$(shell basename $<).dep - -all: $(TARGETS) libubi.a - -IGNORE=${wildcard .*.c.dep} --include ${IGNORE} - -clean: - rm -rf *.o $(TARGETS) .*.c.dep libubi.a - -libubi.a: libubi.o - ar cr $@ $^ +# The below cancels existing implicite rule to make programs from .c files, +# in order to force make using our rule defined below +%: %.c -ubidetach: ubidetach.o common.o libubi.o - $(CC) $(LDFLAGS) -o $@ $^ +# The below is the rule to get an .o file from a .c file +%.o: %.c + $(CC) $(CFLAGS) $< -c -o $@ -ubiattach: ubiattach.o common.o libubi.o - $(CC) $(LDFLAGS) -o $@ $^ +# And the below is the rule to get final executable from its .o and common.o +%: libubi %.o common.o + $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lubi -o $@ -ubinfo: ubinfo.o common.o libubi.o - $(CC) $(LDFLAGS) -o $@ $^ +ubicrc32: ubicrc32.o crc32.o + $(CC) $(CFLAGS) -o $@ $^ -ubiupdate: ubiupdate.o common.o libubi.o - $(CC) $(LDFLAGS) -o $@ $^ +ubinize: ubinize.o common.o crc32.o libiniparser libubigen + $(CC) $(CFLAGS) $(filter %.o, $^) -L. -liniparser -lubigen -o $@ -ubimkvol: ubimkvol.o common.o libubi.o - $(CC) $(LDFLAGS) -o $@ $^ +libubi: libubi.o + $(AR) crv $@.a $^ + ranlib $@.a -ubirmvol: ubirmvol.o common.o libubi.o - $(CC) $(LDFLAGS) -o $@ $^ +libubigen: libubigen.o + $(AR) crv $@.a $^ + ranlib $@.a -ubicrc32: ubicrc32.o crc32.o - $(CC) $(LDFLAGS) -o $@ $^ +libiniparser: libiniparser.o dictionary.o + $(AR) crv $@.a $^ + ranlib $@.a -unubi: unubi.o crc32.o unubi_analyze.o eb_chain.o - $(CC) $(LDFLAGS) -o $@ $^ - -pfi2bin: pfi2bin.o common.o list.o crc32.o libubigen.o bootenv.o \ - hashmap.o libpfi.o common.o - $(CC) $(LDFLAGS) -o $@ $^ +clean: + rm -rf *.o $(addsuffix .a, $(LIBS)) $(UTILS) .*.c.dep -install: ${TARGETS} +install: ${UTILS} mkdir -p ${DESTDIR}/${SBINDIR} - install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/ - (cd perl && install ${PERLPROGS} ${DESTDIR}/${SBINDIR}/) + install -m0755 ${UTILS} ${DESTDIR}/${SBINDIR}/ uninstall: - for file in ${TARGETS} ${PERLPROGS}; do \ + for file in ${UTILS}; do \ $(RM) ${DESTDIR}/${SBINDIR}/$$file; \ done diff --git a/ubi-utils/inc/libpfi.h b/ubi-utils/inc/libpfi.h deleted file mode 100644 index 6aca4be..0000000 --- a/ubi-utils/inc/libpfi.h +++ /dev/null @@ -1,257 +0,0 @@ -#ifndef __pfi_h -#define __pfi_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. - */ - -/** - * @file pfi.h - * - * @author Oliver Lohmann <oliloh@de.ibm.com> - * Andreas Arnez <arnez@de.ibm.com> - * Joern Engel <engeljoe@de.ibm.com> - * Frank Haverkamp <haverkam@de.ibm.com> - * - * @brief libpfi will hold all code to create and process pfi - * images. Definitions made in this file are equaly usable for the - * development host and the target system. - * - * @note This header additionally holds the official definitions for - * the pfi headers. - */ - -#include <stdio.h> /* FILE */ -#include "list.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct pfi_ubi { - long long data_offs; - uint32_t data_size; - uint32_t alignment; - uint32_t *ids; - uint32_t ids_size; - char **names; - uint32_t names_size; - uint32_t size; - int vol_type; - int curr_seqnum; /* specifies the seqnum taken in an update, - default: 0 (used by pfiflash, ubimirror) */ - uint32_t crc; -}; - -int read_pfi_headers(struct list_entry **ubi_list, FILE *fp_pfi); -int free_pfi_ubi(struct pfi_ubi **pfi_ubi); - -/* Definitions. */ - -#define PFI_HDRVERSION 1 /* current header version */ - -#define PFI_ENOVERSION 1 /* unknown version */ -#define PFI_ENOHEADER 2 /* not a pfi header */ -#define PFI_EINSUFF 3 /* insufficient information */ -#define PFI_EUNDEF 4 /* key not defined */ -#define PFI_ENOMEM 5 /* out of memory */ -#define PFI_EBADTYPE 6 /* bad data type */ -#define PFI_EFILE 7 /* file I/O error: see errno */ -#define PFI_EFILEINVAL 8 /* file format not valid */ -#define PFI_EINVAL 9 /* invalid parameter */ -#define PFI_ERANGE 10 /* invalid range */ -#define PFI_EMODE 11 /* expecting other mode in this header */ -#define PFI_DATA_START 12 /* data section starts */ -#define PFI_EMAX 13 /* should be always larger as the largest - error code */ - -#define PFI_LABEL_LEN 64 /* This is the maximum length for a - PFI header label */ -#define PFI_KEYWORD_LEN 32 /* This is the maximum length for an - entry in the mode and type fields */ - -#define PFI_UBI_MAX_VOLUMES 128 -#define PFI_UBI_VOL_NAME_LEN 127 - -/** - * @brief The pfi header allows to set flags which influence the flashing - * behaviour. - */ -#define PFI_FLAG_PROTECTED 0x00000001 - -struct pfi_header; - -/** - * @brief Initialize a pfi header object. - * - * @param head Pointer to handle. This function allocates memory - * for this data structure. - * @return 0 on success, otherwise: - * PFI_ENOMEM : no memory available for the handle. - */ -int pfi_header_init (struct pfi_header **head); - - -/** - * @brief Destroy a pfi header object. - * - * @param head handle. head is invalid after calling this function. - * @return 0 always. - */ -int pfi_header_destroy (struct pfi_header **head); - - -/** - * @brief Add a key/value pair to a pfi header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value string. Must be 0 terminated. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_ENOMEM : no memory available for the handle. - * PFI_EBADTYPE : value is not an hex string. This happens - * when the key stores an integer and the - * new value is not convertable e.g. not in - * 0xXXXXXXXX format. - */ -int pfi_header_setvalue (struct pfi_header *head, - const char *key, const char *value); - - -/** - * @brief Add a key/value pair to a pfi header object. Provide the - * value as a number. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value value to set. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : value is not a string. This happens - * when the key stores a string. - */ -int pfi_header_setnumber (struct pfi_header *head, - const char *key, uint32_t value); - - -/** - * @brief For a given key, return the numerical value stored in a - * pfi header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : stored value is not an integer but a string. - */ -int pfi_header_getnumber (struct pfi_header *head, - const char *key, uint32_t *value); - - -static inline uint32_t -pfi_getnumber(struct pfi_header *head, const char *key) -{ - uint32_t value; - pfi_header_getnumber(head, key, &value); - return value; -} - -/** - * @brief For a given key, return the string value stored in a pfi - * header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value string. Memory must be allocated by the user. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : stored value is not a string but an integer. - */ -int pfi_header_getstring (struct pfi_header *head, - const char *key, char *value, size_t size); - - -/** - * @brief Write a pfi header object into a given file. - * - * @param out output stream. - * @param head handle. - * @return 0 on success, error values otherwise: - * PFI_EINSUFF : not all mandatory fields are filled. - * PFI_ENOHEADER : wrong header version or magic number. - * -E* : see <asm/errno.h>. - */ -int pfi_header_write (FILE *out, struct pfi_header *head); - - -/** - * @brief Read a pfi header object from a given file. - * - * @param in input stream. - * @param head handle. - * @return 0 on success, error values otherwise: - * PFI_ENOVERSION: unknown header version. - * PFI_EFILE : cannot read enough data. - * PFI_ENOHEADER : wrong header version or magic number. - * -E* : see <asm/errno.h>. - * - * If the header verification returned success the user can assume that - * all mandatory fields for a particular version are accessible. Checking - * the return code when calling the get-function for those keys is not - * required in those cases. For optional fields the checking must still be - * done. - */ -int pfi_header_read (FILE *in, struct pfi_header *head); - - -/** - * @brief Display a pfi header in human-readable form. - * - * @param out output stream. - * @param head handle. - * @return always 0. - * - * @note Prints out that it is not implemented and whom you should - * contact if you need it urgently!. - */ -int pfi_header_dump (FILE *out, struct pfi_header *head); - - -/* - * @brief Iterates over a stream of pfi files. The iterator function - * must advance the file pointer in FILE *in to the next pfi - * header. Function exists on feof(in). - * - * @param in input file descriptor, must be open and valid. - * @param func iterator function called when pfi header could be - * read and was validated. The function must return 0 on - * success. - * @return See pfi_header_init and pfi_header_read. - * PFI_EINVAL : func is not valid - * 0 ok. - */ -typedef int (* pfi_read_func)(FILE *in, struct pfi_header *hdr, void *priv_data); - -int pfi_read (FILE *in, pfi_read_func func, void *priv_data); - - -#ifdef __cplusplus -} -#endif - -#endif /* __pfi_h */ diff --git a/ubi-utils/include/libiniparser.h b/ubi-utils/include/libiniparser.h new file mode 100644 index 0000000..be3c667 --- /dev/null +++ b/ubi-utils/include/libiniparser.h @@ -0,0 +1,280 @@ + +/*-------------------------------------------------------------------------*/ +/** + @file iniparser.h + @author N. Devillard + @date Sep 2007 + @version 3.0 + @brief Parser for ini files. +*/ +/*--------------------------------------------------------------------------*/ + +/* + $Id: iniparser.h,v 1.24 2007-11-23 21:38:19 ndevilla Exp $ + $Revision: 1.24 $ +*/ + +#ifndef _INIPARSER_H_ +#define _INIPARSER_H_ + +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* + * The following #include is necessary on many Unixes but not Linux. + * It is not needed for Windows platforms. + * Uncomment it if needed. + */ +/* #include <unistd.h> */ + +#include "dictionary.h" + +/*--------------------------------------------------------------------------- + Macros + ---------------------------------------------------------------------------*/ +/** For backwards compatibility only */ +#define iniparser_getstr(d, k) iniparser_getstring(d, k, NULL) +#define iniparser_setstr iniparser_setstring + +/*-------------------------------------------------------------------------*/ +/** + @brief Get number of sections in a dictionary + @param d Dictionary to examine + @return int Number of sections found in dictionary + + This function returns the number of sections found in a dictionary. + The test to recognize sections is done on the string stored in the + dictionary: a section name is given as "section" whereas a key is + stored as "section:key", thus the test looks for entries that do not + contain a colon. + + This clearly fails in the case a section name contains a colon, but + this should simply be avoided. + + This function returns -1 in case of error. + */ +/*--------------------------------------------------------------------------*/ + +int iniparser_getnsec(dictionary * d); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Get name for section n in a dictionary. + @param d Dictionary to examine + @param n Section number (from 0 to nsec-1). + @return Pointer to char string + + This function locates the n-th section in a dictionary and returns + its name as a pointer to a string statically allocated inside the + dictionary. Do not free or modify the returned string! + + This function returns NULL in case of error. + */ +/*--------------------------------------------------------------------------*/ + +char * iniparser_getsecname(dictionary * d, int n); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary to a loadable ini file + @param d Dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given dictionary into a loadable ini file. + It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ + +void iniparser_dump_ini(dictionary * d, FILE * f); + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump. + @param f Opened file pointer to dump to. + @return void + + This function prints out the contents of a dictionary, one element by + line, onto the provided file pointer. It is OK to specify @c stderr + or @c stdout as output files. This function is meant for debugging + purposes mostly. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_dump(dictionary * d, FILE * f); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key + @param d Dictionary to search + @param key Key string to look for + @param def Default value to return if key not found. + @return pointer to statically allocated character string + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the pointer passed as 'def' is returned. + The returned char pointer is pointing to a string allocated in + the dictionary, do not free or modify it. + */ +/*--------------------------------------------------------------------------*/ +char * iniparser_getstring(dictionary * d, const char * key, char * def); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + - "42" -> 42 + - "042" -> 34 (octal -> decimal) + - "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + + Credits: Thanks to A. Becker for suggesting strtol() + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getint(dictionary * d, const char * key, int notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a double + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return double + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + */ +/*--------------------------------------------------------------------------*/ +double iniparser_getdouble(dictionary * d, char * key, double notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a boolean + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + A true boolean is found if one of the following is matched: + + - A string starting with 'y' + - A string starting with 'Y' + - A string starting with 't' + - A string starting with 'T' + - A string starting with '1' + + A false boolean is found if one of the following is matched: + + - A string starting with 'n' + - A string starting with 'N' + - A string starting with 'f' + - A string starting with 'F' + - A string starting with '0' + + The notfound value returned if no boolean is identified, does not + necessarily have to be 0 or 1. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getboolean(dictionary * d, const char * key, int notfound); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Set an entry in a dictionary. + @param ini Dictionary to modify. + @param entry Entry to modify (entry name) + @param val New value to associate to the entry. + @return int 0 if Ok, -1 otherwise. + + If the given entry can be found in the dictionary, it is modified to + contain the provided value. If it cannot be found, -1 is returned. + It is Ok to set val to NULL. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_setstring(dictionary * ini, char * entry, char * val); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete an entry in a dictionary + @param ini Dictionary to modify + @param entry Entry to delete (entry name) + @return void + + If the given entry can be found, it is deleted from the dictionary. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_unset(dictionary * ini, char * entry); + +/*-------------------------------------------------------------------------*/ +/** + @brief Finds out if a given entry exists in a dictionary + @param ini Dictionary to search + @param entry Name of the entry to look for + @return integer 1 if entry exists, 0 otherwise + + Finds out if a given entry exists in the dictionary. Since sections + are stored as keys with NULL associated values, this is the only way + of querying for the presence of sections in a dictionary. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_find_entry(dictionary * ini, char * entry) ; + +/*-------------------------------------------------------------------------*/ +/** + @brief Parse an ini file and return an allocated dictionary object + @param ininame Name of the ini file to read. + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the name of the file to be read. It returns a dictionary object that + should not be accessed directly, but through accessor functions + instead. + + The returned dictionary must be freed using iniparser_freedict(). + */ +/*--------------------------------------------------------------------------*/ +dictionary * iniparser_load(const char * ininame); + +/*-------------------------------------------------------------------------*/ +/** + @brief Free all memory associated to an ini dictionary + @param d Dictionary to free + @return void + + Free all memory associated to an ini dictionary. + It is mandatory to call this function before the dictionary object + gets out of the current context. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_freedict(dictionary * d); + +#endif diff --git a/ubi-utils/inc/libubi.h b/ubi-utils/include/libubi.h index 0cdb67c..0cdb67c 100644 --- a/ubi-utils/inc/libubi.h +++ b/ubi-utils/include/libubi.h diff --git a/ubi-utils/inc/libubigen.h b/ubi-utils/include/libubigen.h index 5315a72..66f5fb1 100644 --- a/ubi-utils/inc/libubigen.h +++ b/ubi-utils/include/libubigen.h @@ -41,6 +41,8 @@ extern "C" { * @data_offs: data offset * @ubi_ver: UBI version * @ec: initial erase counter + * @vtbl_size: volume table size + * @max_volumes: maximum amount of volumes */ struct ubigen_info { @@ -51,6 +53,8 @@ struct ubigen_info int data_offs; int ubi_ver; long long ec; + int vtbl_size; + int max_volumes; }; /** @@ -87,10 +91,11 @@ struct ubigen_vol_info void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size, int subpage_size, int vid_hdr_offs, int ubi_ver, long long ec); -struct ubi_vtbl_record *ubigen_create_empty_vtbl(int *size); -void ubigen_add_volume(const struct ubigen_info *ui, - const struct ubigen_vol_info *vi, - struct ubi_vtbl_record *vtbl); +struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui); +int ubigen_get_vtbl_size(const struct ubigen_info *ui); +int ubigen_add_volume(const struct ubigen_info *ui, + const struct ubigen_vol_info *vi, + struct ubi_vtbl_record *vtbl); int ubigen_write_volume(const struct ubigen_info *ui, const struct ubigen_vol_info *vi, long long bytes, FILE *in, FILE *out); diff --git a/ubi-utils/scripts/mkdevs.pl b/ubi-utils/scripts/mkdevs.pl deleted file mode 100755 index 46d47c5..0000000 --- a/ubi-utils/scripts/mkdevs.pl +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/perl -w - -# -# Author: Artem B. Bityutskiy <dedekind@oktetlabs.ru> -# -# A small scrip which creates UBI device nodes in /dev. UBI allocates -# major number dynamically, so the script looks at /proc/devices to find -# out UBI's major number. -# - -# Create the control device as well if this UBI version supports them (were -# added sice Linux kernel 2.6.24) -my $ctrl = "/sys/class/misc/ubi_ctrl/dev"; - -if (-e "$ctrl") { - open FILE, "<", $ctrl or die "Cannot open $ctrl file: $!\n"; - my $devnums = <FILE>; - close FILE; - - $devnums =~ m/(\d+):(\d+)/; - system("mknod /dev/ubi_ctrl c $1 $2"); -} - -my $proc = '/proc/devices'; -my $regexp = '(\d+) (ubi\d+)$'; - -open FILE, "<", $proc or die "Cannot open $proc file: $!\n"; -my @file = <FILE>; -close FILE; - -foreach (@file) { - next if not m/$regexp/g; - print "found $2\n"; - - system("rm -rf /dev/$2"); - system("mknod /dev/$2 c $1 0"); - - for (my $i = 0; $i < 128; $i += 1) { - system("rm -rf /dev/$2_$i"); - my $j = $i + 1; - system("mknod /dev/$2_$i c $1 $j"); - } -} - diff --git a/ubi-utils/scripts/mkpfi b/ubi-utils/scripts/mkpfi deleted file mode 100755 index 5cc69d9..0000000 --- a/ubi-utils/scripts/mkpfi +++ /dev/null @@ -1,708 +0,0 @@ -#!/usr/bin/perl -# -# 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. -# - -# -# mkpfi -# -# This perl program is assembles PFI files from a config file. -# -# Author: Oliver Lohmann (oliloh@de.ibm.com) -# -use warnings; -use strict; -use lib "/usr/lib/perl5"; # Please change this path as you need it, or - # make a proposal how this could be done - # nicer. -use Getopt::Long; -use Pod::Usage; -use Config::IniFiles; -use File::Temp; - -# ---------------------------------------------------------------------------- -# Versions -our $version : unique = "0.1"; -our $pfi_version : unique = "0x1"; - -# ---------------------------------------------------------------------------- -# Globals -my $verbose = 0; -my $cfg; - -my $err_prefix = "mkpfi error"; - -my %opts = (); -my %files = (config => ""); -my @tmp_files; - -my %tools = (ubicrc32 => "ubicrc32"); - -# ---------------------------------------------------------------------------- -# Processing the input sections -# -# The idea is to combine each section entry with a function -# in order to allow some kind of preprocessing for the values -# before they are written into the PFI file. -# This is especially useful to be more verbose and -# user-friendly in the layout file. -# -# All key-function hashes are applied after the general -# validation of the configuration file. -# If any mandatory key is missing in a section the user -# will be informed and the PFI creation process is aborted. -# -# Default keys will be checked for their presence inside the config -# file. If they are missing, they will be generated with appr. values. - -# Mandatory keys for UBI volumes. -my %ubi_keys = ("ubi_ids" => \&check_id_list, - "ubi_size" => \&replace_num, - "ubi_type" => \&replace_type, - "ubi_names" => \&remove_spaces, - "ubi_alignment" => \&replace_num); - -# Mandatory keys for RAW sections. -my %raw_keys = ("raw_starts" => \&expand_starts, - "raw_total_size" => \&replace_num); - -# Common default keys for documentation and control purposes. -my %common_keys = ("flags" => \&replace_num, - "label" => \&do_nothing); - -# Define any defaults here. Values which maintained in this default -# region need not to be specified by the user explicitly. -my %def_ubi_keys = ("ubi_alignment" => [\&set_default, "0x1"]); -my %def_raw_keys = (); -my %def_common_keys = ("flags" => [\&set_default, "0x0"], - "label" => [\&generate_label, ""]); - -# ---------------------------------------------------------------------------- -# Input keys, actually the path to the input data. - -my %input_keys = ("image" => \&do_nothing); - -# Placeholder keys allow the replacement via a special -# purpose function. E.g. the bootenv_file key will be used -# to generate bootenv binary data from an text file and -# replace the bootenv_file key with an image key to handle it -# in the same way in the further creation process. -my %input_placeholder_keys = ("bootenv_file" => \&create_bootenv_image); - -# ---------------------------------------------------------------------------- -# Helper - -# @brief Get current time string. -sub get_date { - my $tmp = scalar localtime; - $tmp =~ s/ /_/g; - return $tmp; -} - -# @brief Print an info message to stdout. -sub infomsg($) { - my $str = shift; - - print "mkpfi: $str\n" if $verbose; -} - -# @brief Print an error message to stderr. -sub errmsg($) { - my $str = shift; - print STDERR "$err_prefix: $str\n"; -} - -# @brief Print a warning message to stderr. -sub warnmsg($) { - my $str = shift; - print STDERR "mkpfi warning: $str\n"; -} - -sub parse_command_line($) { - my $opt = shift; - my $result = GetOptions( "help" => \$$opt{'help'}, - "man" => \$$opt{'man'}, - "verbose" => \$$opt{'verbose'}, - "config=s" => \$$opt{'config'}, - ) or pod2usage(2); - pod2usage(1) if defined ($$opt{help}); - pod2usage(-verbose => 2) if defined ($$opt{man}); - - $verbose = $$opt{verbose} if defined $$opt{verbose}; - - if (!defined $$opt{config}) { - errmsg("no config file specified (use --help)"); - exit 1; - } -} - -# @brief Check if all needed tools are in PATH. -sub check_tools { - my $err = 0; - my $key; - - foreach $key (keys %tools) { - if (`which $tools{$key}` eq "") { - errmsg("\"$tools{$key}\" not found, add it to your path"); - $err = 1; - } - } - die "$err_prefix: cannot not find all needed tools\n" if $err; -} - -sub open_cfg_file($) { - my $fname = shift; - my $res = new Config::IniFiles(-file => $fname); - - die "$err_prefix: cannot load config file \"$fname\"\n" if (!defined $res); - return $res; -} - -sub set_default($$$$) { - my ($cfg, $section, $parameter, $def_value) = @_; - $cfg->newval($section, $parameter, $def_value); - return; -} - -sub generate_label($$$$) { - my ($cfg, $section, $parameter, $def_value) = @_; - my $new_label = $def_value . $section; - $new_label .= "_" . get_date; - $cfg->newval($section, $parameter, $new_label); - return; -} - -# @brief Converts any num to a unified hex string, i.e the resulting value -# always starts with "0x" and is aligned to 8 hexdigits. -# @return Returns 0 on success, otherwise an error occured. -# -sub any_num_to_hex($$) { - my $val = shift; - my $res = shift; - - # M(iB) - if ($val =~ m/([0-9]+)[Mm][i]?[Bb]?/g) { - $$res = sprintf("0x%08x", $1 * 1024 * 1024); - } - # k(iB) - elsif ($val =~ m/([0-9]+)[kK][i]?[Bb]?/g) { - $$res = sprintf("0x%08x", $1 * 1024); - } - # hex - elsif ($val =~ m/0x?([0-9a-fA-F]+)/g) { - $$res = sprintf("0x%08x", hex $1); - } - # decimal - elsif ($val =~ m/^([0-9]+)$/g) { - $$res = sprintf("0x%08x", $1); - } - else { - $$res = ""; - return -1; - } - - return 0; -} - -sub remove_spaces($$$) { - my ($cfg, $section, $parameter) = @_; - my ($start, @starts, @new_starts); - my $val = $cfg->val($section, $parameter); - my $res; - - $val =~ s/ //g; # spaces - $cfg->newval($section, $parameter, $val); -} - -sub expand_starts($$$) { - my ($cfg, $section, $parameter) = @_; - my ($start, @starts, @new_starts); - my $val = $cfg->val($section, $parameter); - my $res; - - $val =~ s/ //g; # spaces - @starts = split(/,/, $val); - - foreach $start (@starts) { - if (any_num_to_hex($start, \$res) != 0) { - errmsg("section [$section]: expecting a list of numeric " . - "values for parameter \"$parameter\""); - exit 1; - } - push (@new_starts, $res); - } - $res = join(',', @starts); - - $cfg->newval($section, $parameter, $res); -} - -sub check_id_list($$$) { - my ($cfg, $section, $parameter) = @_; - my $val = $cfg->val($section, $parameter); - my $res; - - if (!($val =~ m/^[0-9]+[,0-9]*/)) { - errmsg("syntax error in 'ubi_ids' in " . - "section \"$section\": $val"); - exit 1; - } -} - -sub replace_type($$$) { - my ($cfg, $section, $parameter) = @_; - my $val = $cfg->val($section, $parameter); - my $res; - - $res = lc($val); - grep {$res eq $_} ('static', 'dynamic') - or die "$err_prefix: unknown UBI Volume type in section" . - "[$section]: $val\n"; - - $cfg->newval($section, $parameter, $res); -} - - -sub replace_num($$$) { - my ($cfg, $section, $parameter) = @_; - my $val = $cfg->val($section, $parameter); - my $res = ""; - - if (any_num_to_hex($val, \$res) != 0) { - errmsg("section [$section]: expecting a numeric value " . - "for parameter: $parameter"); - exit 1; - } - $cfg->newval($section, $parameter, $res); -} - -sub do_nothing($$$) { - my ($cfg, $section, $parameter) = @_; - return; -} - -sub bootenv_sanity_check($) { - my $env = shift; # hash array containing bootenv - my %pdd = (); - - defined($$env{'pdd'}) or return "'pdd' not defined"; - foreach (split /,/, $$env{'pdd'}) { - defined($$env{$_}) or return "undefined '$_' in pdd"; - $pdd{$_} = 1; - } - - defined $$env{'pdd_preserve'} or - return ""; - foreach (split /,/, $$env{'pdd_preserve'}) { - defined($pdd{$_}) - or return "pdd_preserve field '$_' not in pdd"; - } - return ""; -} - -sub create_bootenv_image($$$) { - my ($cfg, $section, $parameter) = @_; - my $txt_fn = $cfg->val($section, "bootenv_file"); - my $in; - - my %value = (); - my @key = (); - - open $in, "<", $txt_fn - or die "$err_prefix: can't open bootenv file '$txt_fn'.\n"; - while (<$in>) { - next if (/^\s*(\#.*)?$/); # Skip comments/whitespace. - - if (/^(\S+?)\+\=(.*)$/) { - defined($value{$1}) or - die "$err_prefix: $txt_fn:$.: appending to" . - " non-existent '$1'\n"; - $value{$1} .= $2; - } elsif (/^(\S+?)\=(.*)$/) { - not defined($value{$1}) or - die "$err_prefix: $txt_fn:$.: trying to" . - " redefine '$1'\n"; - push @key, $1; - $value{$1} = $2; - } else { - die "$err_prefix: $txt_fn:$.: unrecognized syntax\n"; - } - } - close $in; - - $_ = &bootenv_sanity_check(\%value) - and die "$err_prefix: $txt_fn: $_\n"; - - my $tmp_file = new File::Temp(); - push (@tmp_files, $tmp_file); - - foreach (@key) { - print $tmp_file "$_=", $value{$_}, "\0"; - } - close $tmp_file; - - $cfg->newval($section, "image", $tmp_file-> filename); -} - -sub process_keys($$$) { - my ($cfg, $section, $keys) = @_; - my @parameters = $cfg->Parameters($section); - my $i; - - for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { - if (defined($$keys{$parameters[$i]})) { - $$keys{$parameters[$i]}->($cfg, $section, - $parameters[$i]); - } - } - -} - -sub is_in_keylist($$) { - my ($key, $keys) = @_; - my $i; - - for ($i = 0; $i < scalar(@$keys); $i++) { - if ($$keys[$i] eq $key) { - return 1; - } - } - - return 0; -} - -sub check_default_keys($$$) { - my ($cfg, $section, $keys) = @_; - my @parameters = $cfg->Parameters($section); - my $key; - - foreach $key (keys %$keys) { - if (!is_in_keylist($key, \@parameters)) { - $$keys{$key}[0]-> - ($cfg, $section, $key, $$keys{$key}[1]); - } - } - -} - - - -sub check_keys($$$) { - my ($cfg, $section, $keys) = @_; - my @parameters = $cfg->Parameters($section); - my ($i, $key, $err); - - $err = 0; - for ($i = 0 ; $i < scalar(@$keys) ; $i++ ) { - if (!is_in_keylist($$keys[$i], \@parameters)) { - errmsg("section [$section]: missing key \"$$keys[$i]\""); - $err = 1; - } - } - - exit 1 if $err; -} - -sub push_pfi_data($$$$$) { - my ($cfg, $section, $pfi_infos, $keys, $mode) = @_; - my ($tmp, $i, $hdr); - - my %pfi_info = (); - $pfi_info{'mode'} = $mode; - $pfi_info{'image'} = $cfg->val($section, "image"); - - # Build the PFI header - $hdr = sprintf("PFI!\n"); - $hdr .= sprintf("version=0x%08x\n", hex $pfi_version); - $hdr .= sprintf("mode=$mode\n"); - - # Calculate the size of the binary data part - $tmp = -s $cfg->val($section, "image"); - if (!defined $tmp) { - errmsg("section [$section]: missing input image \"" . - $cfg->val($section, "image") . "\""); - exit 1; - } - - # Check for the image to fit into the given space - my $quota; - if ($mode eq 'raw') { - $quota = oct $cfg->val($section, "raw_total_size"); - } elsif ($mode eq 'ubi') { - $quota = oct $cfg->val($section, "ubi_size"); - } - $tmp <= $quota - or die "$err_prefix: image file too big: " . - $cfg->val($section, "image") . "\n"; - $pfi_info{'size'} = $tmp; - - $hdr .= sprintf("size=0x%08x\n", $tmp); - - my $img_file = $cfg->val($section, "image"); - my $crc32 = `$tools{'ubicrc32'} $img_file 2>&1`; - if (any_num_to_hex($crc32, \$tmp) != 0) { - die "$err_prefix: $tools{'ubicrc32'} returned an error\n"; - } - $hdr .= sprintf("crc=$tmp\n"); - - # Process all remaining keys - for ($i = 0; $i < scalar (@$keys); $i++) { - if ($$keys[$i] eq "image") { # special case image input file - if (! -e ($tmp = $cfg->val($section, "image"))) { - errmsg("section [$section]: cannot find " . - "input file $tmp"); - exit 1; - } - next; - } - $hdr .= sprintf("%s=%s\n", $$keys[$i], - $cfg->val($section, $$keys[$i])); - } - - $hdr .= sprintf("\n"); # end marker for PFI-header - - $pfi_info{'header'} = $hdr; - - # store in the header list - push @$pfi_infos, \%pfi_info; -} - -sub process_section($$$$$$) { - my ($cfg, $section, $pfi_infos, $custom_keys, - $def_custom_keys, $mode) = @_; - my @keys = (keys %common_keys, keys %$custom_keys); - my @complete_keys = (@keys, keys %input_keys); - - # set defaults if necessary - check_default_keys($cfg, $section, $def_custom_keys); - check_default_keys($cfg, $section, \%def_common_keys); - - # check for placeholders... - process_keys($cfg, $section, \%input_placeholder_keys); - - # VALIDATE layout.cfg entries - check_keys($cfg, $section, \@complete_keys); - - # execute linked functions (if any) - process_keys($cfg, $section, \%common_keys); - process_keys($cfg, $section, $custom_keys); - - push_pfi_data($cfg, $section, $pfi_infos, \@keys, $mode); -} - -sub get_section_info($$) { - my ($cfg, $section) = @_; - my @parameters = $cfg->Parameters($section); - my ($ubi, $raw, $i, @res); - - $ubi = $raw = 0; - for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { - if ($parameters[$i] =~ m/ubi_/gi) { - $ubi = 1; - @res = (\%ubi_keys, \%def_ubi_keys, "ubi"); - } - if ($parameters[$i] =~ m/raw_/gi) { - $raw = 1; - @res = (\%raw_keys, \%def_raw_keys, "raw"); - } - } - - if (($ubi + $raw) != 1) { # double definition in section - errmsg("layout error in section [$section]"); - exit 1; - } - - return @res; -} - -sub mk_target_list($$) { - my $val = shift; - my $tmp = shift; - my $complete = 0; - - if ($val =~ m/\((.*)\)/g) { - $val = $1; - $complete = 1; - } - $val =~ s/ //g; # spaces - - @$tmp = split(/,/, $val); - - return $complete; -} - -sub copy_bytes($$$) { - my ($in, $out, $to_copy) = @_; - - while ($to_copy) { - my $buf; - my $bufsize = 1024*1024; - - $bufsize < $to_copy or $bufsize = $to_copy; - read($in, $buf, $bufsize) == $bufsize - or die "$err_prefix: image file shrunk during operation\n"; - print $out $buf; - $to_copy -= $bufsize; - } -} - -sub write_target($$) { - my ($pfi_infos, $target) = @_; - my ($pfi_info); - - infomsg("writting target pfi file \"$target.pfi\""); - if (-e "$target.pfi") { - `rm -f $target.pfi`; - } - open(FILE, ">", "$target.pfi") - or die "$err_prefix: cannot create output file: $target.pfi\n"; - binmode(FILE); - - # @FIXME sort by mode (first raw, then ubi) - # Currently this ordering is based on a string comparism. :-) - @$pfi_infos = sort {(lc $$a{'mode'}) cmp (lc $$b{'mode'})} @$pfi_infos; - - # Print all headers first - foreach $pfi_info (@$pfi_infos) { - print FILE $$pfi_info{'header'}; - } - - # Print the linked data sections - print FILE "DATA\n"; - foreach $pfi_info (@$pfi_infos) { - open(IMAGE, "<", $$pfi_info{'image'}) - or die "$err_prefix: cannot open input image: " . - "$$pfi_info{'image'}\n"; - binmode(IMAGE); - ©_bytes(\*IMAGE, \*FILE, $$pfi_info{'size'}); - close(IMAGE) or die "$err_prefix: cannot close input image: " . - "$$pfi_info{'image'}\n"; - } - - close(FILE) or die "$err_prefix: cannot close output file: $target.pfi\n"; -} - -sub process_config($) { - my $cfg = shift; - my @sections = $cfg->Sections; - my ($i, $j, $keylist, $def_keylist, $mode, $tmp, - @tlist, $complete, @pfi_infos); - - my @parameters = $cfg->Parameters("targets") or - die "$err_prefix: config file has no [targets] section\n"; - - for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { - infomsg("processing target \"$parameters[$i]\""); - @pfi_infos = (); - - # get a list of subtargets - $complete = mk_target_list($cfg->val("targets", - $parameters[$i]), \@tlist); - # build all subtargets - for ($j = 0 ; $j < scalar(@tlist) ; $j++ ) { - ($keylist, $def_keylist, $mode) - = get_section_info($cfg, $tlist[$j]); - process_section($cfg, $tlist[$j], - \@pfi_infos, - $keylist, $def_keylist, $mode); - } - - write_target(\@pfi_infos, $parameters[$i]); - } - - infomsg("success"); -} - -sub clear_files() { - # @FIXME: - # Works implicitly and Fedora seems to have removed - # the cleanup call. Thus for now, inactive. - # File::Temp::cleanup(); -} - -require 5.008_000; # Tested with version 5.8.0. -select STDOUT; $| = 1; # make STDOUT output unbuffered -select STDERR; $| = 1; # make STDERR output unbuffered - -parse_command_line(\%opts); -check_tools; -$cfg = open_cfg_file($opts{config}); -process_config($cfg); -clear_files; - -__END__ - - -=head1 NAME - -mkpfi - Using GetOpt::Long, Pod::Usage, Config::IniFiles - - -=head1 SYNOPSIS - -mkpfi [OPTIONS ...] - - - OPTION - - [--config] [--help] [--man] - - -=head1 ABSTRACT - -Perl script for generating pdd pfi files from given config files. - -=head1 OPTIONS - -=over - -=item B<--help> - -Print out brief help message. - -=item B<--usage> - -Print usage. - -=item B<--config> - -Config input file. - -=item B<--man> - -Print manual page, same as 'perldoc mkpfi'. - -=item B<--verbose> - -Be verbose. - -=back - -=head1 BUGS - -Report via MTD mailing list - - -=head1 SEE ALSO - -http://www.linux-mtd.infradead.org/ - - -=head1 AUTHOR - -Oliver Lohmann (oliloh@de.ibm.com) - -=cut diff --git a/ubi-utils/sort-me-out/Makefile b/ubi-utils/sort-me-out/Makefile deleted file mode 100644 index b8e3c96..0000000 --- a/ubi-utils/sort-me-out/Makefile +++ /dev/null @@ -1,91 +0,0 @@ -# -# Makefile -# -# Testcase for UBI pfi update. -# -# Author: Frank Haverkamp <haverkam@de.ibm.com> -# - -card = test -mkpfi_cfg = test.cfg - -# -# Some default values you might want to overwrite. Try it if you need -# it and add more if needed. Note that no real sanity checking is done -# on those values. If you do it wrong your card has no valid PDD data. -# - -PATH := $(PATH):/opt/ppc/usr/bin:../perl:.. - -dd = dd -sed = sed -bin2nand = bin2nand -ubigen = ubigen -mkpfi = mkpfi -v -pfi2bin = pfi2bin -v - -vmlinux_bin ?= test_vmlinux.bin -rootfs_bin ?= test_rootfs.bin -spl_bin ?= test_u-boot.bin -pdd_txt ?= pdd.txt - -flashtype ?= nand -pagesize ?= 2048 - -compl ?= $(card)_complete -compl_pfi ?= $(compl).pfi -compl_img ?= $(compl).img - -compl_nand2048_mif=$(compl).$(flashtype)$(pagesize).mif -compl_nand2048_img=$(compl).$(flashtype)$(pagesize).img - -all: help - -help: - @echo "Testcases for the UBI/NAND manufacturing tool-chain" - @echo "---------------------------------------------------------------" - @echo " make mif_test - Generate a mif (manufacturing " - @echo " image file)." - @echo " make bin2nand2bin_test - Create binary with ECC information" - @echo " in the OOB area. Test ECC generation" - @echo " and correction." - -mif_test: $(compl_pfi) $(compl_nand2048_mif) - -bin2nand2bin_test: - chmod a+x ./bin2nand2bin_test.sh - chmod a+x ./inject_biterror.pl - ./bin2nand2bin_test.sh - -$(compl_pfi): $(vmlinux_bin) $(rootfs_bin) $(spl_bin) - $(mkpfi) -c $(mkpfi_cfg) - -# Binary data and out of band data (OOB) -# -$(compl_nand2048_mif): $(compl_img) - $(bin2nand) -p $(pagesize) -o $(compl_nand2048_mif) $< - -# Binary data only -# -$(compl_img): $(compl_pfi) - $(pfi2bin) -j $(pdd_txt) -o $@ $< - -# -# Default data -# -# If the binary data is not available in the current working directory -# we try to create symlinks to our test data. -# -$(vmlinux_bin) $(rootfs_bin) $(spl_bin): - @echo - @echo "No $@ found, will use defaults !" - @echo - @echo "OR press CTRL-C to provide your own $@" && \ - sleep 1 && \ - $(dd) if=/dev/urandom of=$@ bs=1M count=1 - -clean: - $(RM) *.pfi *~ testblock* oob.bin - -distclean: clean - $(RM) *.bin *.mif *.oob *.img diff --git a/ubi-utils/sort-me-out/README b/ubi-utils/sort-me-out/README deleted file mode 100644 index 384322b..0000000 --- a/ubi-utils/sort-me-out/README +++ /dev/null @@ -1,68 +0,0 @@ -This directory contains various stuff that has to be cleaned up and sorted out. - -* jffs2_test.sh: this has nothing to do to UBI. And the test is quite trivial, - so it is questionable if it should not be deleted. Anyway, if we want this, - it has to be moved to mtd-utils.git/tests/fs-tests. - -* ubigen.c: this utility adds UBI headers to an image file, but does not - generate the volume table. It is probably useless, but one might find it - interesting, so we do not drop it so far and keep here. - -* bin2nand2bin_test.sh: tests nand2bin and bin2nand utilities. Should probably - go to some tests/tools-tests or something. the nand2bin and bin2nand - utilities themselves have nothing to do to UBI in general and should not sit - in ubi-utils. Should be moved somewhere like mtd-utils.git/nand-tools/ - -* f64_nor_sample.cfg, f128_nand_sample.cfg: just exampe of configuration files - for the mkpfi utility. Not too useful without any documentation. Some pfi - configuration file format documentation has to be added to mkpfi man page and - these files should probably be added there. - -* pdd.txt: not sure what is it, this is probably something specific to the - setup which is used by IBM guys (Frank, Andreas, Josh). This is probably not - of general interest and should go away. - -* run_all.sh: runns "all" test. - -* ubicrc32.pl: probably redundand as we already have a C ubicrc32 utility. - -* ubi_test.sh: some UBI testing script, should go to - mtd-utils.git/tests/ubi-tests. - -* unubi_test.sh: tests the "unubi" utility, should go somewhere like - tests/tools-tests - -* inject_biterror.pl: injects a bit error to a binary image. Does not relate to - UBI and should go to mtd-utils.git/nand-tools/ or something - -* Makefile: previously was sitting at ubi-tools/scripts and prepared fake image - files for test scripts. - -* test.cfg: mkpfi configuration file for ubi_tools_test.sh - -* ubi_tools_test.sh: similar to unubi_test.sh - -* nand2bin.c, bin2nand.c: useful utilities which should go to - mtd-utils.git/nand-tools/ - -* nandecc.c, nandecc.h: needed to compile nand2bin and bin2nand - -* nandcorr.c: seems to be unused - -* mkbootenv.c: no idea what is this about. Looks like something specific to IBM - guys's setup. - -* pfiflash*: an utility to update UBI volumes described by a pfi file on - target. Nothing wrong with it, but it seems to be rather specific to IBM - guys' environment and it should be cleaned-up. It also should be documented - better. - -* pddcustomize: not sure what is this for, seems to be IBM-specific. - -* ubimirror: not exactly sure what is this for - if it is neede, it should be - cleaned-up and moved to src/ - -* error.[ch]: strange and rather IBM-specific error messages output infrastructure. - -* libubigen-old.c: old ubigen library other tools in this directory should be - compiled with diff --git a/ubi-utils/sort-me-out/bin2nand.c b/ubi-utils/sort-me-out/bin2nand.c deleted file mode 100644 index 83f50cc..0000000 --- a/ubi-utils/sort-me-out/bin2nand.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 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 - * 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: Oliver Lohmann - */ - -/* - * Create a flashable NAND image from a binary image - * - * History: - * 1.0 Initial release (tglx) - * 1.1 Understands hex and dec input parameters (tglx) - * 1.2 Generates separated OOB data, if needed. (oloh) - * 1.3 Padds data/oob to a given size. (oloh) - * 1.4 Removed argp because we want to use uClibc. - * 1.5 Minor cleanup - * 1.6 Written variable not initialized (-j did not work) (haver) - * 1.7 Made NAND ECC layout configurable (haver) - */ - -#include <unistd.h> -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <getopt.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> - -#include "error.h" -#include "config.h" -#include "nandecc.h" -#include "ecclayouts.h" - -#define PROGRAM_VERSION "1.7" - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -#define CHECK_ENDP(option, endp) do { \ - if (*endp) { \ - fprintf(stderr, \ - "Parse error option \'%s\'. " \ - "No correct numeric value.\n" \ - , option); \ - exit(EXIT_FAILURE); \ - } \ -} while(0) - -typedef enum action_t { - ACT_NORMAL = 0x00000001, -} action_t; - -#define PAGESIZE 2048 -#define PADDING 0 /* 0 means, do not adjust anything */ -#define BUFSIZE 4096 - -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "bin2nand - a tool for adding OOB information to a " - "binary input file.\n"; - -static const char *optionsstr = -" -c, --copyright Print copyright informatoin.\n" -" -j, --padding=<num> Padding in Byte/Mi/ki. Default = no padding\n" -" -l, --ecc-placement=<MTD,IBM> OOB placement scheme (default is IBM).\n" -" -p, --pagesize=<num> Pagesize in Byte/Mi/ki. Default = 2048\n" -" -o, --output=<fname> Output filename. Interleaved Data/OOB if\n" -" output-oob not specified.\n" -" -q, --output-oob=<fname> Write OOB data in separate file.\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" -V, --version Print program version\n"; - -static const char *usage = -"Usage: bin2nand [-c?V] [-j <num>] [-p <num>] [-o <fname>] [-q <fname>]\n" -" [--copyright] [--padding=<num>] [--pagesize=<num>]\n" -" [--output=<fname>] [--output-oob=<fname>] [--help] [--usage]\n" -" [--version]\n"; - -struct option long_options[] = { - { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, - { .name = "padding", .has_arg = 1, .flag = NULL, .val = 'j' }, - { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' }, - { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, - { .name = "output-oob", .has_arg = 1, .flag = NULL, .val = 'q' }, - { .name = "ecc-layout", .has_arg = 1, .flag = NULL, .val = 'l' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -#define __unused __attribute__((unused)) -static const char copyright [] __unused = "Copyright IBM Corp. 2007"; - -struct args { - action_t action; - - size_t pagesize; - size_t oobsize; - size_t padding; - - FILE* fp_in; - const char *file_out_data; /* Either: Data and OOB interleaved - or plain data */ - const char *file_out_oob; /* OOB Data only. */ - struct nand_ecclayout *nand_oob; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -}; - - -static int ustrtoull(const char *cp, char **endp, unsigned int base) -{ - unsigned long long res = strtoull(cp, endp, base); - - switch (**endp) { - case 'G': - res *= 1024; - case 'M': - res *= 1024; - case 'k': - case 'K': - res *= 1024; - /* "Ki", "ki", "Mi" or "Gi" are to be used. */ - if ((*endp)[1] == 'i') - (*endp) += 2; - } - return res; -} - -static int -parse_opt(int argc, char **argv, struct args *args) -{ - const char *ecc_layout = NULL; - unsigned int i, oob_idx = 0; - char* endp; - - while (1) { - int key; - - key = getopt_long(argc, argv, "cj:l:p:o:q:?V", long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'p': /* pagesize */ - args->pagesize = (size_t) - ustrtoull(optarg, &endp, 0); - CHECK_ENDP("p", endp); - break; - case 'j': /* padding */ - args->padding = (size_t) - ustrtoull(optarg, &endp, 0); - CHECK_ENDP("j", endp); - break; - case 'o': /* output */ - args->file_out_data = optarg; - break; - case 'q': /* output oob */ - args->file_out_oob = optarg; - break; - case 'l': /* --ecc-layout=<...> */ - ecc_layout = optarg; - break; - case '?': /* help */ - printf("%s%s", doc, optionsstr); - exit(0); - break; - case 'V': - printf("%s\n", PROGRAM_VERSION); - exit(0); - break; - case 'c': - printf("%s\n", copyright); - exit(0); - default: - printf("%s", usage); - exit(-1); - } - } - - if (optind < argc) { - args->fp_in = fopen(argv[optind++], "rb"); - if ((args->fp_in) == NULL) { - err_quit("Cannot open file %s for input\n", - argv[optind++]); - } - } - - switch (args->pagesize) { - case 512: args->oobsize = 16; oob_idx = 0; break; - case 2048: args->oobsize = 64; oob_idx = 1; break; - default: - err_msg("Unsupported page size: %d\n", args->pagesize); - return -EINVAL; - } - - /* Figure out correct oob layout if it differs from default */ - if (ecc_layout) { - for (i = 0; i < ARRAY_SIZE(oob_placement); i++) - if (strcmp(ecc_layout, oob_placement[i].name) == 0) - args->nand_oob = - oob_placement[i].nand_oob[oob_idx]; - } - return 0; -} - -static int -process_page(struct args *args, uint8_t *buf, FILE *fp_data, FILE *fp_oob, - size_t *written) -{ - int eccpoi; - size_t i; - uint8_t oobbuf[64]; - uint8_t ecc_code[3] = { 0, }; /* temp */ - - /* Calculate ECC for each subpage of 256 bytes */ - memset(oobbuf, 0xff, sizeof(oobbuf)); - for (eccpoi = 0, i = 0; i < args->pagesize; i += 256, eccpoi += 3) { - int j; - nand_calculate_ecc(&buf[i], ecc_code); - for (j = 0; j < 3; j++) - oobbuf[args->nand_oob->eccpos[eccpoi + j]] = ecc_code[j]; - } - - /* write data */ - *written += fwrite(buf, 1, args->pagesize, fp_data); - - /* either separate oob or interleave with data */ - if (fp_oob) { - i = fwrite(oobbuf, 1, args->oobsize, fp_oob); - if (ferror(fp_oob)) { - err_msg("IO error\n"); - return -EIO; - } - } - else { - i = fwrite(oobbuf, 1, args->oobsize, fp_data); - if (ferror(fp_data)) { - err_msg("IO error\n"); - return -EIO; - } - } - - return 0; -} - -int main (int argc, char** argv) -{ - int rc = -1; - int res = 0; - size_t written = 0, read; - struct args args = { - .action = ACT_NORMAL, - .pagesize = PAGESIZE, - .padding = PADDING, - .fp_in = NULL, - .file_out_data = NULL, - .file_out_oob = NULL, - .nand_oob = &ibm_nand_oob_64, - }; - - FILE* fp_out_data = stdout; - FILE* fp_out_oob = NULL; - - parse_opt(argc, argv, &args); - - uint8_t* buf = calloc(1, BUFSIZE); - if (!buf) { - err_quit("Cannot allocate page buffer.\n"); - } - - if (!args.fp_in) { - err_msg("No input image specified!\n"); - goto err; - } - - if (args.file_out_data) { - fp_out_data = fopen(args.file_out_data, "wb"); - if (fp_out_data == NULL) { - err_sys("Cannot open file %s for output\n", - args.file_out_data); - goto err; - } - } - - if (args.file_out_oob) { - fp_out_oob = fopen(args.file_out_oob, "wb"); - if (fp_out_oob == NULL) { - err_sys("Cannot open file %s for output\n", - args.file_out_oob); - goto err; - } - } - - - while(1) { - read = fread(buf, 1, args.pagesize, args.fp_in); - if (feof(args.fp_in) && read == 0) - break; - - if (read < args.pagesize) { - err_msg("Image not page aligned\n"); - goto err; - } - - if (ferror(args.fp_in)) { - err_msg("Read error\n"); - goto err; - } - - res = process_page(&args, buf, fp_out_data, fp_out_oob, - &written); - if (res != 0) - goto err; - } - - while (written < args.padding) { - memset(buf, 0xff, args.pagesize); - res = process_page(&args, buf, fp_out_data, fp_out_oob, - &written); - if (res != 0) - goto err; - } - - rc = 0; -err: - free(buf); - - if (args.fp_in) - fclose(args.fp_in); - - if (fp_out_oob) - fclose(fp_out_oob); - - if (fp_out_data && fp_out_data != stdout) - fclose(fp_out_data); - - if (rc != 0) { - err_msg("Error during conversion. rc: %d\n", rc); - if (args.file_out_data) - remove(args.file_out_data); - if (args.file_out_oob) - remove(args.file_out_oob); - } - return rc; -} diff --git a/ubi-utils/sort-me-out/bin2nand2bin_test.sh b/ubi-utils/sort-me-out/bin2nand2bin_test.sh deleted file mode 100755 index 51f048c..0000000 --- a/ubi-utils/sort-me-out/bin2nand2bin_test.sh +++ /dev/null @@ -1,216 +0,0 @@ -#!/bin/sh -# -# Version: 1.1 -# Author: Frank Haverkamp <haver@vnet.ibm.com> -# -# Testcase for nand2bin and bin2nand. Generate testdata and inject -# biterrors. Convert data back and compare with original data. -# -# Conversion: -# bin -> bin2nand -> mif -> nand2bin -> img -# - -inject_biterror=./inject_biterror.pl -pagesize=2048 -oobsize=64 - -# Create test data -dd if=/dev/urandom of=testblock.bin bs=131072 count=1 - -for layout in IBM MTD ; do - echo "*** Simple test with $layout layout ..." - - echo -n "Convert bin to mif ... " - bin2nand -l$layout --pagesize=${pagesize} -o testblock.mif testblock.bin - if [ $? -ne "0" ]; then - echo "failed!" - exit 1 - else - echo "ok" - fi - - echo -n "Convert mif to bin ... " - nand2bin -l$layout --pagesize=${pagesize} -o testblock.img testblock.mif - if [ $? -ne "0" ]; then - echo "failed!" - exit 1 - else - echo "ok" - fi - - echo -n "Comparing data ... " - diff testblock.bin testblock.img - if [ $? -ne "0" ]; then - echo "failed!" - exit 1 - else - echo "ok" - fi -done - -echo "*** Test conversion without bitflips ..." - -echo -n "Convert bin to mif ... " -bin2nand --pagesize=${pagesize} -o testblock.mif testblock.bin -if [ $? -ne "0" ]; then - echo "failed!" - exit 1 -else - echo "ok" -fi - -echo -n "Convert mif to bin ... " -nand2bin --pagesize=${pagesize} -o testblock.img testblock.mif -if [ $? -ne "0" ]; then - echo "failed!" - exit 1 -else - echo "ok" -fi - -echo -n "Comparing data ... " -diff testblock.bin testblock.img -if [ $? -ne "0" ]; then - echo "failed!" - exit 1 -else - echo "ok" -fi - -echo "*** Test conversion with uncorrectable ECC erors ..." -echo -n "Inject biterror at offset $ioffs ... " -${inject_biterror} --offset=0 --bitmask=0x81 \ - --input=testblock.mif \ - --output=testblock_bitflip.mif -if [ $? -ne "0" ]; then - echo "failed!" - exit 1 -else - echo "ok" -fi - -echo "Convert mif to bin ... " -rm testblock.img -nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ - testblock_bitflip.mif -if [ $? -ne "0" ]; then - echo "failed!" - exit 1 -else - echo "ok" -fi - -echo -n "Comparing data, must fail due to uncorrectable ECC ... " -diff testblock.bin testblock.img -if [ $? -ne "0" ]; then - echo "ok" # Must fail! -else - echo "failed!" - exit 1 -fi - -echo "*** Test bitflips in data ... " -for offs in `seq 0 255` ; do - - cp testblock.mif testblock_bitflip.mif - - for xoffs in 0 256 512 768 ; do - let ioffs=$offs+$xoffs - - cp testblock_bitflip.mif testblock_bitflip_tmp.mif - echo -n "Inject biterror at offset $ioffs ... " - ${inject_biterror} --offset=${ioffs} --bitmask=0x01 \ - --input=testblock_bitflip_tmp.mif \ - --output=testblock_bitflip.mif - if [ $? -ne "0" ]; then - echo "failed!" - exit 1 - else - echo "ok" - fi - done - - echo "Convert mif to bin ... " - rm testblock.img - nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ - testblock_bitflip.mif - if [ $? -ne "0" ]; then - echo "failed!" - exit 1 - else - echo "ok" - fi - - echo -n "Comparing data ... " - diff testblock.bin testblock.img - if [ $? -ne "0" ]; then - hexdump testblock.bin > testblock.bin.txt - hexdump testblock.img > testblock.img.txt - echo "Use tkdiff testblock.bin.txt testblock.img.txt to compare" - echo "failed!" - exit 1 - else - echo "ok" - fi - - # Without correction - echo "Convert mif to bin ... " - rm testblock.img - nand2bin --pagesize=${pagesize} -o testblock.img \ - testblock_bitflip.mif - if [ $? -ne "0" ]; then - echo "failed!" - exit 1 - else - echo "ok" - fi - - echo -n "Comparing data must differ, correction is disabled ... " - diff testblock.bin testblock.img - if [ $? -ne "0" ]; then - echo "ok" # must fail - else - echo "failed!" - exit 1 - fi -done - -echo "*** Test bitflips in OOB data ... " -for offs in `seq 0 $oobsize` ; do - - let ioffs=$pagesize+$offs - - echo -n "Inject biterror at offset $ioffs ... " - ${inject_biterror} --offset=${ioffs} --bitmask=0x01 \ - --input=testblock.mif \ - --output=testblock_bitflip.mif - if [ $? -ne "0" ]; then - echo "failed!" - exit 1 - else - echo "ok" - fi - - echo "Convert mif to bin ... " - rm testblock.img - nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ - testblock_bitflip.mif - if [ $? -ne "0" ]; then - echo "failed!" - exit 1 - else - echo "ok" - fi - - echo -n "Comparing data ... " - diff testblock.bin testblock.img - if [ $? -ne "0" ]; then - hexdump testblock.bin > testblock.bin.txt - hexdump testblock.img > testblock.img.txt - echo "Use tkdiff testblock.bin.txt testblock.img.txt to compare" - echo "failed!" - exit 1 - else - echo "ok" - fi -done diff --git a/ubi-utils/sort-me-out/bootenv.c b/ubi-utils/sort-me-out/bootenv.c deleted file mode 100644 index a6dd4de..0000000 --- a/ubi-utils/sort-me-out/bootenv.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * 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: Oliver Lohmann - */ - -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <netinet/in.h> -#include <sys/stat.h> -#include <bootenv.h> - -#include "hashmap.h" -#include "error.h" - -#include <mtd/ubi-header.h> -#include "crc32.h" - -#define ubi_unused __attribute__((unused)) - -#define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */ - -/* Structures */ -struct bootenv { - hashmap_t map; ///< Pointer to hashmap which holds data structure. -}; - -struct bootenv_list { - hashmap_t head; ///< Pointer to list which holds the data structure. -}; - -/** - * @brief Remove the '\n' from a given line. - * @param line Input/Output line. - * @param size Size of the line. - * @param fp File Pointer. - * @return 0 - * @return or error - */ -static int -remove_lf(char *line, size_t size, FILE* fp) -{ - size_t i; - - for (i = 0; i < size; i++) { - if (line[i] == '\n') { - line[i] = '\0'; - return 0; - } - } - - if (!feof(fp)) { - return BOOTENV_EINVAL; - } - - return 0; -} - -/** - * @brief Determine if a line contains only WS. - * @param line The line to process. - * @param size Size of input line. - * @return 1 Yes, only WS. - * @return 0 No, contains data. - */ -static int -is_ws(const char *line, size_t size) -{ - size_t i = 0; - - while (i < size) { - switch (line[i]) { - case '\n': - return 1; - case '#': - return 1; - case ' ': - i++; - continue; - case '\t': - i++; - continue; - default: /* any other char -> no cmnt */ - return 0; - } - } - - return 0; -} - - -/* ------------------------------------------------------------------------- */ - -/** - * @brief Build a list from a comma seperated value string. - * @param list Pointer to hashmap structure which shall store - * the list. - * @param value Comma seperated value string. - * @return 0 - * @return or error. - */ -static int -build_list_definition(hashmap_t list, const char *value) -{ - int rc = 0; - char *str = NULL; - char *ptr = NULL; - size_t len, i, j; - - /* str: val1,val2 , val4,...,valN */ - len = strlen(value); - str = (char*) malloc((len+1) * sizeof(char)); - - /* 1. reformat string: remove spaces */ - for (i = 0, j = 0; i < len; i++) { - if (value[i] == ' ') - continue; - - str[j] = value[i]; - j++; - } - str[j] = '\0'; - - /* str: val1,val2,val4,...,valN\0*/ - /* 2. replace ',' seperator with '\0' */ - len = strlen(str); - for (i = 0; i < len; i++) { - if (str[i] == ',') { - str[i] = '\0'; - } - } - - /* str: val1\0val2\0val4\0...\0valN\0*/ - /* 3. insert definitions into a hash map, using it like a list */ - i = j = 0; - ptr = str; - while (((i = strlen(ptr)) > 0) && (j < len)) { - rc = hashmap_add(list, ptr, ""); - if (rc != 0) { - free(str); - return rc; - } - j += i+1; - if (j < len) - ptr += i+1; - } - - free(str); - return rc; -} - -/** - * @brief Extract a key value pair and add it to a hashmap - * @param str Input string which contains a key value pair. - * @param env The updated handle which contains the new pair. - * @return 0 - * @return or error - * @note The input string format is: "key=value" - */ -static int -extract_pair(const char *str, bootenv_t env) -{ - int rc = 0; - char *key = NULL; - char *val = NULL; - - key = strdup(str); - if (key == NULL) - return -ENOMEM; - - val = strstr(key, "="); - if (val == NULL) { - rc = BOOTENV_EBADENTRY; - goto err; - } - - *val = '\0'; /* split strings */ - val++; - - rc = bootenv_set(env, key, val); - - err: - free(key); - return rc; -} - -int -bootenv_destroy(bootenv_t* env) -{ - int rc = 0; - - if (env == NULL || *env == NULL) - return -EINVAL; - - bootenv_t tmp = *env; - - rc = hashmap_free(tmp->map); - if (rc != 0) - return rc; - - free(tmp); - return rc; -} - -int -bootenv_create(bootenv_t* env) -{ - bootenv_t res; - res = (bootenv_t) calloc(1, sizeof(struct bootenv)); - - if (res == NULL) - return -ENOMEM; - - res->map = hashmap_new(); - - if (res->map == NULL) { - free(res); - return -ENOMEM; - } - - *env = res; - - return 0; -} - - -/** - * @brief Read a formatted buffer and scan it for valid bootenv - * key/value pairs. Add those pairs into a hashmap. - * @param env Hashmap which shall be used to hold the data. - * @param buf Formatted buffer. - * @param size Size of the buffer. - * @return 0 - * @return or error - */ -static int -rd_buffer(bootenv_t env, const char *buf, size_t size) -{ - const char *curr = buf; /* ptr to current key/value pair */ - uint32_t i, j; /* current length, chars processed */ - - if (buf[size - 1] != '\0') /* must end in '\0' */ - return BOOTENV_EFMT; - - for (j = 0; j < size; j += i, curr += i) { - /* strlen returns the size of the string upto - but not including the null terminator; - adding 1 to account for '\0' */ - i = strlen(curr) + 1; - - if (i == 1) - return 0; /* no string found */ - - if (extract_pair(curr, env) != 0) - return BOOTENV_EINVAL; - } - - return 0; -} - - -int -bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc) -{ - int rc; - char *buf = NULL; - size_t i = 0; - uint32_t crc32_table[256]; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - /* allocate temp buffer */ - buf = (char*) calloc(1, size * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - /* FIXME Andreas, please review this I removed size-1 and - * replaced it by just size, I saw the kernel image starting - * with a 0x0060.... and not with the 0x60.... what it should - * be. Is this a tools problem or is it a problem here where - * fp is moved not to the right place due to the former size-1 - * here. - */ - while((i < size) && (!feof(fp))) { - int c = fgetc(fp); - if (c == EOF) { - /* FIXME isn't this dangerous, to update - the boot envs with incomplete data? */ - buf[i++] = '\0'; - break; /* we have enough */ - } - if (ferror(fp)) { - rc = -EIO; - goto err; - } - - buf[i++] = (char)c; - } - - /* calculate crc to return */ - if (ret_crc != NULL) { - init_crc32_table(crc32_table); - *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); - } - - /* transfer to hashmap */ - rc = rd_buffer(env, buf, size); - -err: - free(buf); - return rc; -} - - -/** - * If we have a single file containing the boot-parameter size should - * be specified either as the size of the file or as BOOTENV_MAXSIZE. - * If the bootparameter are in the middle of a file we need the exact - * length of the data. - */ -int -bootenv_read(FILE* fp, bootenv_t env, size_t size) -{ - return bootenv_read_crc(fp, env, size, NULL); -} - - -int -bootenv_read_txt(FILE* fp, bootenv_t env) -{ - int rc = 0; - char *buf = NULL; - char *line = NULL; - char *lstart = NULL; - char *curr = NULL; - size_t len; - size_t size; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - size = BOOTENV_MAXSIZE; - - /* allocate temp buffers */ - buf = (char*) calloc(1, size * sizeof(char)); - lstart = line = (char*) calloc(1, size * sizeof(char)); - if ((buf == NULL) || (line == NULL)) { - rc = -ENOMEM; - goto err; - } - - curr = buf; - while ((line = fgets(line, size, fp)) != NULL) { - if (is_ws(line, size)) { - continue; - } - rc = remove_lf(line, BOOTENV_MAXSIZE, fp); - if (rc != 0) { - goto err; - } - - /* copy new line to binary buffer */ - len = strlen(line); - if (len > size) { - rc = -EFBIG; - goto err; - } - size -= len; /* track remaining space */ - - memcpy(curr, line, len); - curr += len + 1; /* for \0 seperator */ - } - - rc = rd_buffer(env, buf, BOOTENV_MAXSIZE); -err: - if (buf != NULL) - free(buf); - if (lstart != NULL) - free(lstart); - return rc; -} - -static int -fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max ubi_unused, - size_t *written) -{ - int rc = 0; - size_t keys_size, i; - size_t wr = 0; - const char **keys = NULL; - const char *val = NULL; - - rc = bootenv_get_key_vector(env, &keys_size, 1, &keys); - if (rc != 0) - goto err; - - for (i = 0; i < keys_size; i++) { - if (wr > BOOTENV_MAXSIZE) { - rc = -ENOSPC; - goto err; - } - - rc = bootenv_get(env, keys[i], &val); - if (rc != 0) - goto err; - - wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr, - "%s=%s", keys[i], val); - wr++; /* for \0 */ - } - - *written = wr; - -err: - if (keys != NULL) - free(keys); - - return rc; -} - -int -bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc) -{ - int rc = 0; - size_t size = 0; - char *buf = NULL; - uint32_t crc32_table[256]; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - - rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size); - if (rc != 0) - goto err; - - /* calculate crc to return */ - if (ret_crc != NULL) { - init_crc32_table(crc32_table); - *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); - } - - if (fwrite(buf, size, 1, fp) != 1) { - rc = -EIO; - goto err; - } - -err: - if (buf != NULL) - free(buf); - return rc; -} - -int -bootenv_write(FILE* fp, bootenv_t env) -{ - return bootenv_write_crc(fp, env, NULL); -} - -int -bootenv_compare(bootenv_t first, bootenv_t second) -{ - int rc; - size_t written_first, written_second; - char *buf_first, *buf_second; - - if (first == NULL || second == NULL) - return -EINVAL; - - buf_first = malloc(BOOTENV_MAXSIZE); - if (!buf_first) - return -ENOMEM; - buf_second = malloc(BOOTENV_MAXSIZE); - if (!buf_second) { - rc = -ENOMEM; - goto err; - } - - rc = fill_output_buffer(first, buf_first, BOOTENV_MAXSIZE, - &written_first); - if (rc < 0) - goto err; - rc = fill_output_buffer(second, buf_second, BOOTENV_MAXSIZE, - &written_second); - if (rc < 0) - goto err; - - if (written_first != written_second) { - rc = 1; - goto err; - } - - rc = memcmp(buf_first, buf_second, written_first); - if (rc != 0) { - rc = 2; - goto err; - } - -err: - if (buf_first) - free(buf_first); - if (buf_second) - free(buf_second); - - return rc; -} - -int -bootenv_size(bootenv_t env, size_t *size) -{ - int rc = 0; - char *buf = NULL; - - if (env == NULL) - return -EINVAL; - - buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, size); - if (rc != 0) - goto err; - -err: - if (buf != NULL) - free(buf); - return rc; -} - -int -bootenv_write_txt(FILE* fp, bootenv_t env) -{ - int rc = 0; - size_t size, wr, i; - const char **keys = NULL; - const char *key = NULL; - const char *val = NULL; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - rc = bootenv_get_key_vector(env, &size, 1, &keys); - if (rc != 0) - goto err; - - for (i = 0; i < size; i++) { - key = keys[i]; - rc = bootenv_get(env, key, &val); - if (rc != 0) - goto err; - - wr = fprintf(fp, "%s=%s\n", key, val); - if (wr != strlen(key) + strlen(val) + 2) { - rc = -EIO; - goto err; - } - } - -err: - if (keys != NULL) - free(keys); - return rc; -} - -int -bootenv_valid(bootenv_t env ubi_unused) -{ - /* @FIXME No sanity check implemented. */ - return 0; -} - -int -bootenv_copy_bootenv(bootenv_t in, bootenv_t *out) -{ - int rc = 0; - const char *tmp = NULL; - const char **keys = NULL; - size_t vec_size, i; - - if ((in == NULL) || (out == NULL)) - return -EINVAL; - - /* purge output var for sure... */ - rc = bootenv_destroy(out); - if (rc != 0) - return rc; - - /* create the new map */ - rc = bootenv_create(out); - if (rc != 0) - goto err; - - /* get the key list from the input map */ - rc = bootenv_get_key_vector(in, &vec_size, 0, &keys); - if (rc != 0) - goto err; - - if (vec_size != hashmap_size(in->map)) { - rc = BOOTENV_ECOPY; - goto err; - } - - /* make a deep copy of the hashmap */ - for (i = 0; i < vec_size; i++) { - rc = bootenv_get(in, keys[i], &tmp); - if (rc != 0) - goto err; - - rc = bootenv_set(*out, keys[i], tmp); - if (rc != 0) - goto err; - } - -err: - if (keys != NULL) - free(keys); - - return rc; -} - -/* ------------------------------------------------------------------------- */ - - -int -bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, - int *warnings, char *err_buf ubi_unused, - size_t err_buf_size ubi_unused) -{ - bootenv_list_t l_old = NULL; - bootenv_list_t l_new = NULL; - const char *pdd_old = NULL; - const char *pdd_new = NULL; - const char *tmp = NULL; - const char **vec_old = NULL; - const char **vec_new = NULL; - const char **pdd_up_vec = NULL; - size_t vec_old_size, vec_new_size, pdd_up_vec_size, i; - int rc = 0; - - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - /* get the pdd strings, e.g.: - * pdd_old=a,b,c - * pdd_new=a,c,d,e */ - rc = bootenv_get(env_old, "pdd", &pdd_old); - if (rc != 0) - goto err; - rc = bootenv_get(env_new, "pdd", &pdd_new); - if (rc != 0) - goto err; - - /* put it into a list and then convert it to an vector */ - rc = bootenv_list_create(&l_old); - if (rc != 0) - goto err; - rc = bootenv_list_create(&l_new); - if (rc != 0) - goto err; - - rc = bootenv_list_import(l_old, pdd_old); - if (rc != 0) - goto err; - - rc = bootenv_list_import(l_new, pdd_new); - if (rc != 0) - goto err; - - rc = bootenv_list_to_vector(l_old, &vec_old_size, &vec_old); - if (rc != 0) - goto err; - - rc = bootenv_list_to_vector(l_new, &vec_new_size, &vec_new); - if (rc != 0) - goto err; - - rc = bootenv_copy_bootenv(env_new, env_res); - if (rc != 0) - goto err; - - /* calculate the update vector between the old and new pdd */ - pdd_up_vec = hashmap_get_update_key_vector(vec_old, vec_old_size, - vec_new, vec_new_size, &pdd_up_vec_size); - - if (pdd_up_vec == NULL) { - rc = -ENOMEM; - goto err; - } - - if (pdd_up_vec_size != 0) { - /* need to warn the user about the unset of - * some pdd/bootenv values */ - *warnings = BOOTENV_WPDD_STRING_DIFFERS; - - /* remove all entries in the new bootenv load */ - for (i = 0; i < pdd_up_vec_size; i++) { - bootenv_unset(*env_res, pdd_up_vec[i]); - } - } - - /* generate the keep array and copy old pdd values to new bootenv */ - for (i = 0; i < vec_old_size; i++) { - rc = bootenv_get(env_old, vec_old[i], &tmp); - if (rc != 0) { - rc = BOOTENV_EPDDINVAL; - goto err; - } - rc = bootenv_set(*env_res, vec_old[i], tmp); - if (rc != 0) { - goto err; - } - } - /* put the old pdd string into the result map */ - rc = bootenv_set(*env_res, "pdd", pdd_old); - if (rc != 0) { - goto err; - } - - -err: - if (vec_old != NULL) - free(vec_old); - if (vec_new != NULL) - free(vec_new); - if (pdd_up_vec != NULL) - free(pdd_up_vec); - - bootenv_list_destroy(&l_old); - bootenv_list_destroy(&l_new); - return rc; -} - - -int -bootenv_pdd_overwrite(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings ubi_unused, - char *err_buf ubi_unused, size_t err_buf_size ubi_unused) -{ - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - return bootenv_copy_bootenv(env_new, env_res); -} - -int -bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, - int *warnings ubi_unused, char *err_buf, size_t err_buf_size) -{ - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - snprintf(err_buf, err_buf_size, "The PDD merge operation is not " - "implemented. Contact: <oliloh@de.ibm.com>"); - - return BOOTENV_ENOTIMPL; -} - -/* ------------------------------------------------------------------------- */ - -int -bootenv_get(bootenv_t env, const char *key, const char **value) -{ - if (env == NULL) - return -EINVAL; - - *value = hashmap_lookup(env->map, key); - if (*value == NULL) - return BOOTENV_ENOTFOUND; - - return 0; -} - -int -bootenv_get_num(bootenv_t env, const char *key, uint32_t *value) -{ - char *endptr = NULL; - const char *str; - - if (env == NULL) - return 0; - - str = hashmap_lookup(env->map, key); - if (!str) - return -EINVAL; - - *value = strtoul(str, &endptr, 0); - - if (*endptr == '\0') { - return 0; - } - - return -EINVAL; -} - -int -bootenv_set(bootenv_t env, const char *key, const char *value) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_add(env->map, key, value); -} - -int -bootenv_unset(bootenv_t env, const char *key) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_remove(env->map, key); -} - -int -bootenv_get_key_vector(bootenv_t env, size_t* size, int sort, - const char ***vector) -{ - if ((env == NULL) || (size == NULL)) - return -EINVAL; - - *vector = hashmap_get_key_vector(env->map, size, sort); - - if (*vector == NULL) - return -EINVAL; - - return 0; -} - -int -bootenv_dump(bootenv_t env) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_dump(env->map); -} - -int -bootenv_list_create(bootenv_list_t *list) -{ - bootenv_list_t res; - res = (bootenv_list_t) calloc(1, sizeof(struct bootenv_list)); - - if (res == NULL) - return -ENOMEM; - - res->head = hashmap_new(); - - if (res->head == NULL) { - free(res); - return -ENOMEM; - } - - *list = res; - return 0; -} - -int -bootenv_list_destroy(bootenv_list_t *list) -{ - int rc = 0; - - if (list == NULL) - return -EINVAL; - - bootenv_list_t tmp = *list; - if (tmp == 0) - return 0; - - rc = hashmap_free(tmp->head); - if (rc != 0) - return rc; - - free(tmp); - *list = NULL; - return 0; -} - -int -bootenv_list_import(bootenv_list_t list, const char *str) -{ - if (list == NULL) - return -EINVAL; - - return build_list_definition(list->head, str); -} - -int -bootenv_list_export(bootenv_list_t list, char **string) -{ - size_t size, i, j, bufsize, tmp, rc = 0; - const char **items; - - if (list == NULL) - return -EINVAL; - - bufsize = BOOTENV_MAXLINE; - char *res = (char*) malloc(bufsize * sizeof(char)); - if (res == NULL) - return -ENOMEM; - - rc = bootenv_list_to_vector(list, &size, &items); - if (rc != 0) { - goto err; - } - - j = 0; - for (i = 0; i < size; i++) { - tmp = strlen(items[i]); - if (j >= bufsize) { - bufsize += BOOTENV_MAXLINE; - res = (char*) realloc(res, bufsize * sizeof(char)); - if (res == NULL) { - rc = -ENOMEM; - goto err; - } - } - memcpy(res + j, items[i], tmp); - j += tmp; - if (i < (size - 1)) { - res[j] = ','; - j++; - } - } - j++; - res[j] = '\0'; - free(items); - *string = res; - return 0; -err: - free(items); - return rc; -} - -int -bootenv_list_add(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_add(list->head, item, ""); -} - -int -bootenv_list_remove(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_remove(list->head, item); -} - -int -bootenv_list_is_in(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_lookup(list->head, item) != NULL ? 1 : 0; -} - -int -bootenv_list_to_vector(bootenv_list_t list, size_t *size, const char ***vector) -{ - if ((list == NULL) || (size == NULL)) - return -EINVAL; - - *vector = hashmap_get_key_vector(list->head, size, 1); - if (*vector == NULL) - return -ENOMEM; - - return 0; -} - -int -bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, - uint32_t **vector) -{ - int rc = 0; - size_t i; - uint32_t* res = NULL; - char *endptr = NULL; - const char **a = NULL; - - rc = bootenv_list_to_vector(list, size, &a); - if (rc != 0) - goto err; - - res = (uint32_t*) malloc (*size * sizeof(uint32_t)); - if (!res) - goto err; - - for (i = 0; i < *size; i++) { - res[i] = strtoul(a[i], &endptr, 0); - if (*endptr != '\0') - goto err; - } - - if (a) - free(a); - *vector = res; - return 0; - -err: - if (a) - free(a); - if (res) - free(res); - return rc; -} diff --git a/ubi-utils/sort-me-out/bootenv.h b/ubi-utils/sort-me-out/bootenv.h deleted file mode 100644 index 8fecdbf..0000000 --- a/ubi-utils/sort-me-out/bootenv.h +++ /dev/null @@ -1,434 +0,0 @@ -#ifndef __BOOTENV_H__ -#define __BOOTENV_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. - */ - -#include <stdio.h> /* FILE */ -#include <stdint.h> -#include <pfiflash.h> - -/* DOXYGEN DOCUMENTATION */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @file bootenv.h - * @author oliloh@de.ibm.com - * @version 1.3 - * - * 1.3 Some renaming - */ - -/** - * @mainpage Usage - * - * @section intro Introduction - * This library provides all functionality to handle with the so-called - * platform description data (PDD) and the bootparameters defined in - * U-Boot. It is able to apply the defined PDD operations in PDD update - * scenarios. For more information about the PDD and bootparameter - * environment "bootenv" confer the PDD documentation. - * - * @section ret Return codes - * This library defines some return codes which will be delivered classified - * as warnings or errors. See the "Defines" section for details and numeric - * values. - * - * @section benv Bootenv format description - * There are two different input formats: - * - text files - * - binary files - * - * @subsection txt Text Files - * Text files have to be specified like: - * @verbatim key1=value1,value2,value7\n key2=value55,value1\n key4=value1\n@endverbatim - * - * @subsection bin Binary files - * Binary files have to be specified like: - * @verbatim<CRC32-bit>key1=value1,value2,value7\0key2=value55,value1\0... @endverbatim - * You can confer the U-Boot documentation for more details. - * - * @section benvlists Bootenv lists format description. - * Values referenced in the preceeding subsection can be - * defined like lists: - * @verbatim value1,value2,value3 @endverbatim - * There are some situation where a conversion of a comma - * seperated list can be useful, e.g. to get a list - * of defined PDD entries. - */ - -#define BOOTENV_MAXSIZE (1024 * 100) /* max 100kiB space for bootenv */ - -/** - * @def BOOTENV_ECRC - * @brief Given binary file is to large. - * @def BOOTENV_EFMT - * @brief Given bootenv section has an invalid format - * @def BOOTENV_EBADENTRY - * @brief Bad entry in the bootenv section. - * @def BOOTENV_EINVAL - * @brief Invalid bootenv defintion. - * @def BOOTENV_ENOPDD - * @brief Given bootenv sectoin has no PDD defintion string (pdd=...). - * @def BOOTENV_EPDDINVAL - * @brief Given bootenv section has an invalid PDD defintion. - * @def BOOTENV_ENOTIMPL - * @brief Functionality not implemented. - * @def BOOTENV_ECOPY - * @brief Bootenv memory copy error - * @def BOOTENV_ENOTFOUND - * @brief Given key has has no value. - * @def BOOTENV_EMAX - * @brief Highest error value. - */ -#define BOOTENV_ETOOBIG 1 -#define BOOTENV_EFMT 2 -#define BOOTENV_EBADENTRY 3 -#define BOOTENV_EINVAL 4 -#define BOOTENV_ENOPDD 5 -#define BOOTENV_EPDDINVAL 6 -#define BOOTENV_ENOTIMPL 7 -#define BOOTENV_ECOPY 8 -#define BOOTENV_ENOTFOUND 9 -#define BOOTENV_EMAX 10 - -/** - * @def BOOTENV_W - * @brief A warning which is handled internally as an error - * but can be recovered by manual effort. - * @def BOOTENV_WPDD_STRING_DIFFERS - * @brief The PDD strings of old and new PDD differ and - * can cause update problems, because new PDD values - * are removed from the bootenv section completely. - */ -#define BOOTENV_W 20 -#define BOOTENV_WPDD_STRING_DIFFERS 21 -#define BOOTENV_WMAX 22 /* highest warning value */ - - -typedef struct bootenv *bootenv_t; - /**< A bootenv library handle. */ - -typedef struct bootenv_list *bootenv_list_t; - /**< A handle for a value list. */ - -typedef int(*pdd_func_t)(bootenv_t, bootenv_t, bootenv_t*, - int*, char*, size_t); - - -/** - * @brief Get a new handle. - * @return 0 - * @return or error - * */ -int bootenv_create(bootenv_t *env); - -/** - * @brief Cleanup structure. - * @param env Bootenv structure which shall be destroyed. - * @return 0 - * @return or error - */ -int bootenv_destroy(bootenv_t *env); - -/** - * @brief Copy a bootenv handle. - * @param in The input bootenv. - * @param out The copied output bootenv. Discards old data. - * @return 0 - * @return or error - */ -int bootenv_copy_bootenv(bootenv_t in, bootenv_t *out); - -/** - * @brief Looks for a value inside the bootenv data. - * @param env Handle to a bootenv structure. - * @param key The key. - * @return NULL key not found - * @return !NULL ptr to value - */ -int bootenv_get(bootenv_t env, const char *key, const char **value); - - -/** - * @brief Looks for a value inside the bootenv data and converts it to num. - * @param env Handle to a bootenv structure. - * @param key The key. - * @param value A pointer to the resulting numerical value - * @return NULL key not found - * @return !NULL ptr to value - */ -int bootenv_get_num(bootenv_t env, const char *key, uint32_t *value); - -/** - * @brief Set a bootenv value by key. - * @param env Handle to a bootenv structure. - * @param key Key. - * @param value Value to set. - * @return 0 - * @return or error - */ -int bootenv_set(bootenv_t env, const char *key, const char *value); - -/** - * @brief Remove the given key (and its value) from a bootenv structure. - * @param env Handle to a bootenv structure. - * @param key Key. - * @return 0 - * @return or error - */ -int bootenv_unset(bootenv_t env, const char *key); - - -/** - * @brief Get a vector of all keys which are currently set - * within a bootenv handle. - * @param env Handle to a bootenv structure. - * @param size The size of the allocated array structure. - * @param sort Flag, if set the vector is sorted ascending. - * @return NULL on error. - * @return !NULL a pointer to the first element the allocated vector. - * @warning Free the allocate memory yourself! - */ -int bootenv_get_key_vector(bootenv_t env, size_t *size, int sort, - const char ***vector); - -/** - * @brief Calculate the size in bytes which are necessary to write the - * current bootenv section in a *binary file. - * @param env bootenv handle. - * @param size The size in bytes of the bootenv handle. - * @return 0 - * @return or ERROR. - */ -int bootenv_size(bootenv_t env, size_t *size); - -/** - * @brief Read a binary bootenv file. - * @param fp File pointer to input stream. - * @param env bootenv handle. - * @param size maximum data size. - * @return 0 - * @return or ERROR. - */ -int bootenv_read(FILE* fp, bootenv_t env, size_t size); - -/** - * @param ret_crc return value of crc of read data - */ -int bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t *ret_crc); - -/** - * @brief Read bootenv data from an text/ascii file. - * @param fp File pointer to ascii PDD file. - * @param env bootenv handle - * @return 0 - * @return or ERROR. - */ -int bootenv_read_txt(FILE* fp, bootenv_t env); - -/** - * @brief Write a bootenv structure to the given location (binary). - * @param fp Filepointer to binary file. - * @param env Bootenv structure which shall be written. - * @return 0 - * @return or error - */ -int bootenv_write(FILE* fp, bootenv_t env); - -/** - * @param ret_crc return value of crc of read data - */ -int bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc); - -/** - * @brief Write a bootenv structure to the given location (text). - * @param fp Filepointer to text file. - * @param env Bootenv structure which shall be written. - * @return 0 - * @return or error - */ -int bootenv_write_txt(FILE* fp, bootenv_t env); - -/** - * @brief Compare bootenvs using memcmp(). - * @param first First bootenv. - * @param second Second bootenv. - * @return 0 if bootenvs are equal - * @return < 0 if error - * @return > 0 if unequal - */ -int bootenv_compare(bootenv_t first, bootenv_t second); - -/** - * @brief Prototype for a PDD handling funtion - */ - -/** - * @brief The PDD keep operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of PDD keep. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - - -/** - * @brief The PDD merge operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of merge-pdd. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - -/** - * @brief The PDD overwrite operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of overwrite-pdd. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_overwrite(bootenv_t env_new, - bootenv_t env_old, bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - -/** - * @brief Dump a bootenv structure to stdout. (Debug) - * @param env Handle to a bootenv structure. - * @return 0 - * @return or error - */ -int bootenv_dump(bootenv_t env); - -/** - * @brief Validate a bootenv structure. - * @param env Handle to a bootenv structure. - * @return 0 - * @return or error - */ -int bootenv_valid(bootenv_t env); - -/** - * @brief Create a new bootenv list structure. - * @return NULL on error - * @return or a new list handle. - * @note This structure is used to store values in a list. - * A useful addition when handling PDD strings. - */ -int bootenv_list_create(bootenv_list_t *list); - -/** - * @brief Destroy a bootenv list structure - * @param list Handle to a bootenv list structure. - * @return 0 - * @return or error - */ -int bootenv_list_destroy(bootenv_list_t *list); - -/** - * @brief Import a list from a comma seperated string - * @param list Handle to a bootenv list structure. - * @param str Comma seperated string list. - * @return 0 - * @return or error - */ -int bootenv_list_import(bootenv_list_t list, const char *str); - -/** - * @brief Export a list to a string of comma seperated values. - * @param list Handle to a bootenv list structure. - * @return NULL one error - * @return or pointer to a newly allocated string. - * @warning Free the allocated memory by yourself! - */ -int bootenv_list_export(bootenv_list_t list, char **string); - -/** - * @brief Add an item to the list. - * @param list A handle of a list structure. - * @param item An item. - * @return 0 - * @return or error - */ -int bootenv_list_add(bootenv_list_t list, const char *item); - -/** - * @brief Remove an item from the list. - * @param list A handle of a list structure. - * @param item An item. - * @return 0 - * @return or error - */ -int bootenv_list_remove(bootenv_list_t list, const char *item); - -/** - * @brief Check if a given item is in a given list. - * @param list A handle of a list structure. - * @param item An item. - * @return 1 Item is in list. - * @return 0 Item is not in list. - */ -int bootenv_list_is_in(bootenv_list_t list, const char *item); - - -/** - * @brief Convert a list into a vector of all values inside the list. - * @param list Handle to a bootenv structure. - * @param size The size of the allocated vector structure. - * @return 0 - * @return or error - * @warning Free the allocate memory yourself! - */ -int bootenv_list_to_vector(bootenv_list_t list, size_t *size, - const char ***vector); - -/** - * @brief Convert a list into a vector of all values inside the list. - * @param list Handle to a bootenv structure. - * @param size The size of the allocated vector structure. - * @return 0 - * @return or error - * @warning Free the allocate memory yourself! - */ -int bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, - uint32_t **vector); - -#ifdef __cplusplus -} -#endif -#endif /*__BOOTENV_H__ */ diff --git a/ubi-utils/sort-me-out/config.h b/ubi-utils/sort-me-out/config.h deleted file mode 100644 index 55e60f3..0000000 --- a/ubi-utils/sort-me-out/config.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __CONFIG_H__ -#define __CONFIG_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: Frank Haverkamp - */ - -#define PACKAGE_BUGREPORT \ - "haver@vnet.ibm.com, dedekind@linutronix.de, or tglx@linutronix.de" - -#define ubi_unused __attribute__((unused)) - -#endif diff --git a/ubi-utils/sort-me-out/crc32.c b/ubi-utils/sort-me-out/crc32.c deleted file mode 100644 index 666e217..0000000 --- a/ubi-utils/sort-me-out/crc32.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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: Thomas Gleixner - */ - -/* - * CRC32 functions - * - * Can be compiled as seperate object, but is included into the ipl source - * so gcc can inline the functions. We optimize for size so the omission of - * the function frame is helpful. - * - */ - -#include <stdint.h> -#include <crc32.h> - -/* CRC polynomial */ -#define CRC_POLY 0xEDB88320 - -/** - * init_crc32_table - Initialize crc table - * - * @table: pointer to the CRC table which must be initialized - * - * Create CRC32 table for given polynomial. The table is created with - * the lowest order term in the highest order bit. So the x^32 term - * has to implied in the crc calculation function. - */ -void init_crc32_table(uint32_t *table) -{ - uint32_t crc; - int i, j; - - for (i = 0; i < 256; i++) { - crc = i; - for (j = 8; j > 0; j--) { - if (crc & 1) - crc = (crc >> 1) ^ CRC_POLY; - else - crc >>= 1; - } - table[i] = crc; - } -} - -/** - * clc_crc32 - Calculate CRC32 over a buffer - * - * @table: pointer to the CRC table - * @crc: initial crc value - * @buf: pointer to the buffer - * @len: number of bytes to calc - * - * Returns the updated crc value. - * - * The algorithm resembles a hardware shift register, but calculates 8 - * bit at once. - */ -uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, - int len) -{ - const unsigned char *p = buf; - - while(--len >= 0) - crc = table[(crc ^ *p++) & 0xff] ^ (crc >> 8); - return crc; -} diff --git a/ubi-utils/sort-me-out/crc32.h b/ubi-utils/sort-me-out/crc32.h deleted file mode 100644 index 31362b0..0000000 --- a/ubi-utils/sort-me-out/crc32.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __CRC32_H__ -#define __CRC32_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: Thomas Gleixner - * - * CRC32 functions - * - * Can be compiled as seperate object, but is included into the ipl source - * so gcc can inline the functions. We optimize for size so the omission of - * the function frame is helpful. - * - */ -#include <stdint.h> - -void init_crc32_table(uint32_t *table); -uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len); - -#endif /* __CRC32_H__ */ diff --git a/ubi-utils/sort-me-out/eb_chain.c b/ubi-utils/sort-me-out/eb_chain.c deleted file mode 100644 index a018ae6..0000000 --- a/ubi-utils/sort-me-out/eb_chain.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Author: Drake Dowsett, dowsett@de.ibm.com - * Contact: Andreas Arnez, arnez@de.ibm.com - */ - -/* see eb_chain.h */ - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include "unubi_analyze.h" -#include "crc32.h" - -#define COPY(dst, src) \ - do { \ - dst = malloc(sizeof(*dst)); \ - if (dst == NULL) \ - return -ENOMEM; \ - memcpy(dst, src, sizeof(*dst)); \ - } while (0) - - -/** - * inserts an eb_info into the chain starting at head, then searching - * linearly for the correct position; - * new should contain valid vid and ec headers and the data_crc should - * already have been checked before insertion, otherwise the chain - * could be have un an undesired manner; - * returns -ENOMEM if alloc fails, otherwise SHOULD always return 0, - * if not, the code reached the last line and returned -EAGAIN, - * meaning there is a bug or a case not being handled here; - **/ -int -eb_chain_insert(struct eb_info **head, struct eb_info *new) -{ - uint32_t vol, num, ver; - uint32_t new_vol, new_num, new_ver; - struct eb_info *prev, *cur, *hist, *ins; - struct eb_info **prev_ptr; - - if ((head == NULL) || (new == NULL)) - return 0; - - if (*head == NULL) { - COPY(*head, new); - (*head)->next = NULL; - return 0; - } - - new_vol = __be32_to_cpu(new->vid.vol_id); - new_num = __be32_to_cpu(new->vid.lnum); - new_ver = __be32_to_cpu(new->vid.leb_ver); - - /** TRAVERSE HORIZONTALY **/ - - cur = *head; - prev = NULL; - - /* traverse until vol_id/lnum align */ - vol = __be32_to_cpu(cur->vid.vol_id); - num = __be32_to_cpu(cur->vid.lnum); - while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) { - /* insert new at end of chain */ - if (cur->next == NULL) { - COPY(ins, new); - ins->next = NULL; - cur->next = ins; - return 0; - } - - prev = cur; - cur = cur->next; - vol = __be32_to_cpu(cur->vid.vol_id); - num = __be32_to_cpu(cur->vid.lnum); - } - - if (prev == NULL) - prev_ptr = head; - else - prev_ptr = &(prev->next); - - /* insert new into the middle of chain */ - if ((new_vol != vol) || (new_num != num)) { - COPY(ins, new); - ins->next = cur; - *prev_ptr = ins; - return 0; - } - - /** TRAVERSE VERTICALY **/ - - hist = cur; - prev = NULL; - - /* traverse until versions align */ - ver = __be32_to_cpu(cur->vid.leb_ver); - while (new_ver < ver) { - /* insert new at bottom of history */ - if (hist->older == NULL) { - COPY(ins, new); - ins->next = NULL; - ins->older = NULL; - hist->older = ins; - return 0; - } - - prev = hist; - hist = hist->older; - ver = __be32_to_cpu(hist->vid.leb_ver); - } - - if (prev == NULL) { - /* replace active version */ - COPY(ins, new); - ins->next = hist->next; - *prev_ptr = ins; - - /* place cur in vertical histroy */ - ins->older = hist; - hist->next = NULL; - return 0; - } - - /* insert between versions, beneath active version */ - COPY(ins, new); - ins->next = NULL; - ins->older = prev->older; - prev->older = ins; - return 0; -} - - -/** - * sets the pointer at pos to the position of the first entry in the chain - * with of vol_id and, if given, with the same lnum as *lnum; - * if there is no entry in the chain, then *pos is NULL on return; - * always returns 0; - **/ -int -eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum, - struct eb_info **pos) -{ - uint32_t vol, num; - struct eb_info *cur; - - if ((head == NULL) || (*head == NULL) || (pos == NULL)) - return 0; - - *pos = NULL; - - cur = *head; - while (cur != NULL) { - vol = __be32_to_cpu(cur->vid.vol_id); - num = __be32_to_cpu(cur->vid.lnum); - - if ((vol_id == vol) && ((lnum == NULL) || (*lnum == num))) { - *pos = cur; - return 0; - } - - cur = cur->next; - } - - return 0; -} - - -/** - * prints to stream, the vol_id, lnum and leb_ver for each entry in the - * chain, starting at head; - * this is intended for debuging purposes; - * always returns 0; - * - * FIXME I do not like the double list traversion ... - **/ -int -eb_chain_print(FILE* stream, struct eb_info *head) -{ - struct eb_info *cur; - - if (stream == NULL) - stream = stdout; - - if (head == NULL) { - fprintf(stream, "EMPTY\n"); - return 0; - } - /* 012345678012345678012345678012301230123 0123 01234567 0123457 01234567*/ - fprintf(stream, "VOL_ID LNUM LEB_VER EC VID DAT PBLK PADDR DSIZE EC\n"); - cur = head; - while (cur != NULL) { - struct eb_info *hist; - - fprintf(stream, "%08x %-8u %08x %-4s%-4s", - __be32_to_cpu(cur->vid.vol_id), - __be32_to_cpu(cur->vid.lnum), - __be32_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, " %-4d %08x %-8u %-8llu\n", cur->phys_block, - cur->phys_addr, __be32_to_cpu(cur->vid.data_size), - __be64_to_cpu(cur->ec.ec)); - - hist = cur->older; - while (hist != NULL) { - fprintf(stream, "%08x %-8u %08x %-4s%-4s", - __be32_to_cpu(hist->vid.vol_id), - __be32_to_cpu(hist->vid.lnum), - __be32_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, " %-4d %08x %-8u %-8llu (*)\n", - hist->phys_block, hist->phys_addr, - __be32_to_cpu(hist->vid.data_size), - __be64_to_cpu(hist->ec.ec)); - - hist = hist->older; - } - cur = cur->next; - } - - return 0; -} - - -/** - * frees the memory of the entire chain, starting at head; - * head will be NULL on return; - * always returns 0; - **/ -int -eb_chain_destroy(struct eb_info **head) -{ - if (head == NULL) - return 0; - - while (*head != NULL) { - struct eb_info *cur; - struct eb_info *hist; - - cur = *head; - *head = (*head)->next; - - hist = cur->older; - while (hist != NULL) { - struct eb_info *temp; - - temp = hist; - hist = hist->older; - free(temp); - } - free(cur); - } - return 0; -} - diff --git a/ubi-utils/sort-me-out/ecclayouts.h b/ubi-utils/sort-me-out/ecclayouts.h deleted file mode 100644 index a1c7823..0000000 --- a/ubi-utils/sort-me-out/ecclayouts.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __ECCLAYOUTS_H__ -#define __ECCLAYOUTS_H__ -/* - * Copyright (c) International Business Machines Corp., 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 - * 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. - */ - -#include <stdint.h> -#include <mtd/mtd-abi.h> - -/* Define default oob placement schemes for large and small page devices */ -static struct nand_ecclayout mtd_nand_oob_16 = { - .eccbytes = 6, - .eccpos = { 0, 1, 2, 3, 6, 7 }, - .oobfree = {{ .offset = 8, .length = 8 }} -}; - -static struct nand_ecclayout mtd_nand_oob_64 = { - .eccbytes = 24, - .eccpos = { 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63 }, - .oobfree = {{ .offset = 2, .length = 38 }} -}; - -/* Define IBM oob placement schemes */ -static struct nand_ecclayout ibm_nand_oob_16 = { - .eccbytes = 6, - .eccpos = { 9, 10, 11, 13, 14, 15 }, - .oobfree = {{ .offset = 8, .length = 8 }} -}; - -static struct nand_ecclayout ibm_nand_oob_64 = { - .eccbytes = 24, - .eccpos = { 33, 34, 35, 37, 38, 39, 41, 42, - 43, 45, 46, 47, 49, 50, 51, 53, - 54, 55, 57, 58, 59, 61, 62, 63 }, - .oobfree = {{ .offset = 2, .length = 30 }} -}; - -struct oob_placement { - const char *name; - struct nand_ecclayout *nand_oob[2]; -}; - -static struct oob_placement oob_placement[] = { - { .name = "IBM", - .nand_oob = { &ibm_nand_oob_16, &ibm_nand_oob_64 }}, - { .name = "MTD", - .nand_oob = { &mtd_nand_oob_16, &mtd_nand_oob_64 }}, -}; - -#endif diff --git a/ubi-utils/sort-me-out/error.c b/ubi-utils/sort-me-out/error.c deleted file mode 100644 index 4aaedad..0000000 --- a/ubi-utils/sort-me-out/error.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * 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. - */ - -#include <stdio.h> -#include <stdarg.h> -#include <syslog.h> -#include <stdlib.h> -#include <sys/errno.h> -#include <string.h> -#include "error.h" - -#define MAXLINE 4096 -#define MAXWIDTH 80 - -static FILE *logfp = NULL; - -static void err_doit(int, int, const char *, va_list); - -int -read_procfile(FILE *fp_out, const char *procfile) -{ - FILE *fp; - - if (!fp_out) - return -ENXIO; - - fp = fopen(procfile, "r"); - if (!fp) - return -ENOENT; - - while(!feof(fp)) { - int c = fgetc(fp); - - if (c == EOF) - return 0; - - if (putc(c, fp_out) == EOF) - return -EIO; - - if (ferror(fp)) - return -EIO; - } - return fclose(fp); -} - -void -error_initlog(const char *logfile) -{ - if (!logfile) - return; - - logfp = fopen(logfile, "a+"); - read_procfile(logfp, "/proc/cpuinfo"); -} - -void -info_msg(const char *fmt, ...) -{ - FILE* fpout; - char buf[MAXLINE + 1]; - va_list ap; - int n; - - fpout = stdout; - - va_start(ap, fmt); - vsnprintf(buf, MAXLINE, fmt, ap); - n = strlen(buf); - strcat(buf, "\n"); - - fputs(buf, fpout); - fflush(fpout); - if (fpout != stdout) - fclose(fpout); - - va_end(ap); - return; -} - -void -__err_ret(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_INFO, fmt, ap); - va_end(ap); - return; -} - -void -__err_sys(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_ERR, fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - - -void -__err_msg(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(0, LOG_INFO, fmt, ap); - va_end(ap); - - return; -} - -void -__err_quit(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(0, LOG_ERR, fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -void -__err_dump(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(1, LOG_ERR, fmt, ap); - va_end(ap); - abort(); /* dump core and terminate */ - exit(EXIT_FAILURE); /* shouldn't get here */ -} - -/** - * If a logfile is used we must not print on stderr and stdout - * anymore. Since pfilfash might be used in a server context, it is - * even dangerous to write to those descriptors. - */ -static void -err_doit(int errnoflag, int level __attribute__((unused)), - const char *fmt, va_list ap) -{ - FILE* fpout; - int errno_save, n; - char buf[MAXLINE + 1]; - fpout = stderr; - - errno_save = errno; /* value caller might want printed */ - - vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ - - n = strlen(buf); - - if (errnoflag) - snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); - strcat(buf, "\n"); - - if (logfp) { - fputs(buf, logfp); - fflush(logfp); - return; /* exit when logging completes */ - } - - if (fpout == stderr) { - /* perform line wrap when outputting to stderr */ - int word_len, post_len, chars; - char *buf_ptr; - const char *frmt = "%*s%n %n"; - - chars = 0; - buf_ptr = buf; - while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) { - int i; - char word[word_len + 1]; - char post[post_len + 1]; - - strncpy(word, buf_ptr, word_len); - word[word_len] = '\0'; - buf_ptr += word_len; - post_len -= word_len; - - if (chars + word_len > MAXWIDTH) { - fputc('\n', fpout); - chars = 0; - } - fputs(word, fpout); - chars += word_len; - - if (post_len > 0) { - strncpy(post, buf_ptr, post_len); - post[post_len] = '\0'; - buf_ptr += post_len; - } - for (i = 0; i < post_len; i++) { - int inc = 1, chars_new; - - if (post[i] == '\t') - inc = 8; - if (post[i] == '\n') { - inc = 0; - chars_new = 0; - } else - chars_new = chars + inc; - - if (chars_new > MAXWIDTH) { - fputc('\n', fpout); - chars_new = inc; - } - fputc(post[i], fpout); - chars = chars_new; - } - } - } - else - fputs(buf, fpout); - fflush(fpout); - if (fpout != stderr) - fclose(fpout); - - return; -} diff --git a/ubi-utils/sort-me-out/error.h b/ubi-utils/sort-me-out/error.h deleted file mode 100644 index 05d8078..0000000 --- a/ubi-utils/sort-me-out/error.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef __ERROR_H__ -#define __ERROR_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. - */ - -#include <stdio.h> - -void error_initlog(const char *logfile); -int read_procfile(FILE *fp_out, const char *procfile); - -void __err_ret(const char *fmt, ...); -void __err_sys(const char *fmt, ...); -void __err_msg(const char *fmt, ...); -void __err_quit(const char *fmt, ...); -void __err_dump(const char *fmt, ...); - -void info_msg(const char *fmt, ...); - -#ifdef DEBUG -#define __loc_msg(str) do { \ - __err_msg("[%s. FILE: %s FUNC: %s LINE: %d]\n", \ - str, __FILE__, __FUNCTION__, __LINE__); \ -} while (0) -#else -#define __loc_msg(str) -#endif - - -#define err_dump(fmt, ...) do { \ - __loc_msg("ErrDump"); \ - __err_dump(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_quit(fmt, ...) do { \ - __loc_msg("ErrQuit"); \ - __err_quit(fmt, ##__VA_ARGS__); \ -} while (0) - - -#define err_ret(fmt, ...) do { \ - __loc_msg("ErrRet"); \ - __err_ret(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_sys(fmt, ...) do { \ - __loc_msg("ErrSys"); \ - __err_sys(fmt, ##__VA_ARGS__); \ -} while (0) - -#define err_msg(fmt, ...) do { \ - __loc_msg("ErrMsg"); \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) - -#define log_msg(fmt, ...) do { \ - /* __loc_msg("LogMsg"); */ \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) - -#ifdef DEBUG -#define dbg_msg(fmt, ...) do { \ - __loc_msg("DbgMsg"); \ - __err_msg(fmt, ##__VA_ARGS__); \ -} while (0) -#else -#define dbg_msg(fmt, ...) do {} while (0) -#endif - -#endif /* __ERROR_H__ */ diff --git a/ubi-utils/sort-me-out/example_ubi.h b/ubi-utils/sort-me-out/example_ubi.h deleted file mode 100644 index 23c7b54..0000000 --- a/ubi-utils/sort-me-out/example_ubi.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __EXAMPLE_UBI_H__ -#define __EXAMPLE_UBI_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. - */ - -/** - * Defaults for our cards. - */ -#define EXAMPLE_UBI_DEVICE 0 -#define EXAMPLE_BOOTENV_VOL_ID_1 4 -#define EXAMPLE_BOOTENV_VOL_ID_2 5 - -#endif /* __EXAMPLE_UBI_H__ */ diff --git a/ubi-utils/sort-me-out/f128_nand_sample.cfg b/ubi-utils/sort-me-out/f128_nand_sample.cfg deleted file mode 100644 index bb62600..0000000 --- a/ubi-utils/sort-me-out/f128_nand_sample.cfg +++ /dev/null @@ -1,38 +0,0 @@ -[targets] -complete=ipl,spl,bootenv,kernel,rootfs -bootcode=spl,bootenv - -# Build sections -[ipl] -image=ipl.bin -raw_starts=0x00000000 -raw_total_size=128kiB - -[spl] -image=u-boot.bin -ubi_ids=2,3 -ubi_size=2MiB -ubi_type=static -ubi_names=spl_0,spl_1 - -[bootenv] -bootenv_file=bootenv_complete.txt -ubi_ids=4,5 -ubi_size=128kiB -ubi_type=static -ubi_names=bootenv_0,bootenv_1 - -[kernel] -image=vmlinux.bin -ubi_ids=6,7 -ubi_size=6MiB -ubi_type=static -ubi_names=kernel_0,kernel_1 - -[rootfs] -image=rootfs.bin -ubi_ids=8,9 -ubi_alignment=2kiB -ubi_size=16MiB -ubi_type=dynamic -ubi_names=rootfs_0,rootfs_1 diff --git a/ubi-utils/sort-me-out/f64_nor_sample.cfg b/ubi-utils/sort-me-out/f64_nor_sample.cfg deleted file mode 100644 index 889d4c2..0000000 --- a/ubi-utils/sort-me-out/f64_nor_sample.cfg +++ /dev/null @@ -1,39 +0,0 @@ -[targets] -complete=ipl,spl,bootenv,kernel,rootfs -bootcode=spl,bootenv -rootfs=rootfs - -# Build sections -[ipl] -image=ipl.bin -raw_starts=0x02FE0000, 0x03FE0000 -raw_total_size=128kiB - -[spl] -image=u-boot.bin -ubi_ids=2,3 -ubi_size=2MiB -ubi_type=static -ubi_names=spl_0,spl_1 - -[bootenv] -bootenv_file=bootenv_complete.txt -ubi_ids=4,5 -ubi_size=128kiB -ubi_type=static -ubi_names=bootenv_0,bootenv_1 - -[kernel] -image=vmlinux.bin -ubi_ids=6,7 -ubi_size=6MiB -ubi_type=static -ubi_names=kernel_0,kernel_1 - -[rootfs] -image=rootfs.bin -ubi_ids=8,9 -ubi_alignment=2kiB -ubi_size=16128kiB -ubi_type=dynamic -ubi_names=rootfs_0,rootfs_1 diff --git a/ubi-utils/sort-me-out/hashmap.c b/ubi-utils/sort-me-out/hashmap.c deleted file mode 100644 index 3511d56..0000000 --- a/ubi-utils/sort-me-out/hashmap.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * 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: Oliver Lohmann - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include "error.h" -#include "hashmap.h" -#define DEFAULT_BUCKETS 4096 - -#if 0 -#define INFO_MSG(fmt...) do { \ - info_msg(fmt); \ -} while (0) -#else -#define INFO_MSG(fmt...) -#endif - -struct hashentry { - char* key; /* key '0' term. str */ - char* value; /* payload '0' term. str */ - - hashentry_t next; -}; - -struct hashmap { - size_t entries; /* current #entries */ - size_t maxsize; /* no. of hash buckets */ - hashentry_t* data; /* array of buckets */ -}; - -static int -is_empty(hashentry_t l) -{ - return l == NULL ? 1 : 0; -} - -hashmap_t -hashmap_new(void) -{ - hashmap_t res; - res = (hashmap_t) calloc(1, sizeof(struct hashmap)); - - if (res == NULL) - return NULL; - - res->maxsize = DEFAULT_BUCKETS; - res->entries = 0; - - res->data = (hashentry_t*) - calloc(1, res->maxsize * sizeof(struct hashentry)); - - if (res->data == NULL) - return NULL; - - return res; -} - -static hashentry_t -new_entry(const char* key, const char* value) -{ - hashentry_t res; - - res = (hashentry_t) calloc(1, sizeof(struct hashentry)); - - if (res == NULL) - return NULL; - - /* allocate key and value and copy them */ - res->key = strdup(key); - if (res->key == NULL) { - free(res); - return NULL; - } - - res->value = strdup(value); - if (res->value == NULL) { - free(res->key); - free(res); - return NULL; - } - - res->next = NULL; - - return res; -} - -static hashentry_t -free_entry(hashentry_t e) -{ - if (!is_empty(e)) { - if(e->key != NULL) { - free(e->key); - } - if(e->value != NULL) - free(e->value); - free(e); - } - - return NULL; -} - -static hashentry_t -remove_entry(hashentry_t l, const char* key, size_t* entries) -{ - hashentry_t lnext; - if (is_empty(l)) - return NULL; - - if(strcmp(l->key,key) == 0) { - lnext = l->next; - l = free_entry(l); - (*entries)--; - return lnext; - } - - l->next = remove_entry(l->next, key, entries); - - return l; -} - -static hashentry_t -insert_entry(hashentry_t l, hashentry_t e, size_t* entries) -{ - if (is_empty(l)) { - (*entries)++; - return e; - } - - /* check for update */ - if (strcmp(l->key, e->key) == 0) { - e->next = l->next; - l = free_entry(l); - return e; - } - - l->next = insert_entry(l->next, e, entries); - return l; -} - -static hashentry_t -remove_all(hashentry_t l, size_t* entries) -{ - hashentry_t lnext; - if (is_empty(l)) - return NULL; - - lnext = l->next; - free_entry(l); - (*entries)--; - - return remove_all(lnext, entries); -} - -static const char* -value_lookup(hashentry_t l, const char* key) -{ - if (is_empty(l)) - return NULL; - - if (strcmp(l->key, key) == 0) - return l->value; - - return value_lookup(l->next, key); -} - -static void -print_all(hashentry_t l) -{ - if (is_empty(l)) { - printf("\n"); - return; - } - - printf("%s=%s", l->key, l->value); - if (!is_empty(l->next)) { - printf(","); - } - - print_all(l->next); -} - -static void -keys_to_array(hashentry_t l, const char** a, size_t* i) -{ - if (is_empty(l)) - return; - - a[*i] = l->key; - (*i)++; - - keys_to_array(l->next, a, i); -} - -uint32_t -hash_str(const char* str, uint32_t mapsize) -{ - uint32_t hash = 0; - uint32_t x = 0; - uint32_t i = 0; - size_t len = strlen(str); - - for(i = 0; i < len; str++, i++) { - hash = (hash << 4) + (*str); - if((x = hash & 0xF0000000L) != 0) { - hash ^= (x >> 24); - hash &= ~x; - } - } - - return (hash & 0x7FFFFFFF) % mapsize; -} - - -int -hashmap_is_empty(hashmap_t map) -{ - if (map == NULL) - return -EINVAL; - - return map->entries > 0 ? 1 : 0; -} - -const char* -hashmap_lookup(hashmap_t map, const char* key) -{ - uint32_t i; - - if ((map == NULL) || (key == NULL)) - return NULL; - - i = hash_str(key, map->maxsize); - - return value_lookup(map->data[i], key); -} - -int -hashmap_add(hashmap_t map, const char* key, const char* value) -{ - uint32_t i; - hashentry_t entry; - - if ((map == NULL) || (key == NULL) || (value == NULL)) - return -EINVAL; - - i = hash_str(key, map->maxsize); - entry = new_entry(key, value); - if (entry == NULL) - return -ENOMEM; - - map->data[i] = insert_entry(map->data[i], - entry, &map->entries); - - INFO_MSG("HASH_ADD: chain[%d] key:%s val:%s",i, key, value); - return 0; -} - -int -hashmap_remove(hashmap_t map, const char* key) -{ - uint32_t i; - - if ((map == NULL) || (key == NULL)) - return -EINVAL; - - i = hash_str(key, map->maxsize); - map->data[i] = remove_entry(map->data[i], key, &map->entries); - - return 0; -} - -size_t -hashmap_size(hashmap_t map) -{ - if (map != NULL) - return map->entries; - else - return 0; -} - -int -hashmap_free(hashmap_t map) -{ - size_t i; - - if (map == NULL) - return -EINVAL; - - /* "children" first */ - for(i = 0; i < map->maxsize; i++) { - map->data[i] = remove_all(map->data[i], &map->entries); - } - free(map->data); - free(map); - - return 0; -} - -int -hashmap_dump(hashmap_t map) -{ - size_t i; - if (map == NULL) - return -EINVAL; - - for(i = 0; i < map->maxsize; i++) { - if (map->data[i] != NULL) { - printf("[%zd]: ", i); - print_all(map->data[i]); - } - } - - return 0; -} - -static const char** -sort_key_vector(const char** a, size_t size) -{ - /* uses bubblesort */ - size_t i, j; - const char* tmp; - - if (size <= 0) - return a; - - for (i = size - 1; i > 0; i--) { - for (j = 0; j < i; j++) { - if (strcmp(a[j], a[j+1]) > 0) { - tmp = a[j]; - a[j] = a[j+1]; - a[j+1] = tmp; - } - } - } - return a; -} - -const char** -hashmap_get_key_vector(hashmap_t map, size_t* size, int sort) -{ - const char** res; - size_t i, j; - *size = map->entries; - - res = (const char**) malloc(*size * sizeof(char*)); - if (res == NULL) - return NULL; - - j = 0; - for(i=0; i < map->maxsize; i++) { - keys_to_array(map->data[i], res, &j); - } - - if (sort) - res = sort_key_vector(res, *size); - - return res; -} - -int -hashmap_key_is_in_vector(const char** vec, size_t size, const char* key) -{ - size_t i; - for (i = 0; i < size; i++) { - if (strcmp(vec[i], key) == 0) /* found */ - return 1; - } - - return 0; -} - -const char** -hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, - const char** vec2, size_t vec2_size, size_t* res_size) -{ - const char** res; - size_t i, j; - - *res_size = vec2_size; - - res = (const char**) malloc(*res_size * sizeof(char*)); - if (res == NULL) - return NULL; - - /* get all keys from vec2 which are not set in vec1 */ - j = 0; - for (i = 0; i < vec2_size; i++) { - if (!hashmap_key_is_in_vector(vec1, vec1_size, vec2[i])) - res[j++] = vec2[i]; - } - - *res_size = j; - return res; -} diff --git a/ubi-utils/sort-me-out/hashmap.h b/ubi-utils/sort-me-out/hashmap.h deleted file mode 100644 index 1b13e95..0000000 --- a/ubi-utils/sort-me-out/hashmap.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __HASHMAP_H__ -#define __HASHMAP_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: Oliver Lohmann - */ - -#include <stdlib.h> -#include <stdint.h> - -typedef struct hashentry *hashentry_t; -typedef struct hashmap *hashmap_t; - -hashmap_t hashmap_new(void); -int hashmap_free(hashmap_t map); - -int hashmap_add(hashmap_t map, const char* key, const char* value); -int hashmap_update(hashmap_t map, const char* key, const char* value); -int hashmap_remove(hashmap_t map, const char* key); -const char* hashmap_lookup(hashmap_t map, const char* key); - -const char** hashmap_get_key_vector(hashmap_t map, size_t* size, int sort); -int hashmap_key_is_in_vector(const char** vec, size_t size, const char* key); -const char** hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, - const char** vec2, size_t vec2_size, size_t* res_size); - -int hashmap_dump(hashmap_t map); - -int hashmap_is_empty(hashmap_t map); -size_t hashmap_size(hashmap_t map); - -uint32_t hash_str(const char* str, uint32_t mapsize); - -#endif /* __HASHMAP_H__ */ diff --git a/ubi-utils/sort-me-out/inject_biterror.pl b/ubi-utils/sort-me-out/inject_biterror.pl deleted file mode 100755 index b4a862a..0000000 --- a/ubi-utils/sort-me-out/inject_biterror.pl +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/perl -w -# -# 2007 Frank Haverkamp <haver@vnet.ibm.com> -# -# Program for bit-error injection. I am sure that perl experts do it -# in 1 line. Please let me know how it is done right ;-). -# - -use strict; -use warnings; -use Getopt::Long; -use Pod::Usage; - -my $i; -my $help; -my $result; -my $offset = 0; -my $bitmask = 0x01; -my $in = "input.mif"; -my $out = "output.mif"; - -$result = GetOptions ("offset=i" => \$offset, # numeric - "bitmask=o" => \$bitmask, # numeric - "input=s" => \$in, # string - "output=s" => \$out, # string - "help|?" => \$help) or pod2usage(2); - -pod2usage(1) if $help; - -my $buf; - -open(my $in_fh, "<", $in) - or die "Cannot open file $in: $!"; -binmode $in_fh; - -open(my $out_fh, ">", $out) or - die "Cannot open file $out: $!"; -binmode $out_fh; - -$i = 0; -while (sysread($in_fh, $buf, 1)) { - - $buf = pack('C', unpack('C', $buf) ^ $bitmask) if ($i == $offset); - syswrite($out_fh, $buf, 1) or - die "Cannot write to offset $offset: $!"; - $i++; -} - -close $in_fh; -close $out_fh; - -__END__ - -=head1 NAME - -inject_biterrors.pl - -=head1 SYNOPSIS - -inject_biterror.pl [options] - -=head1 OPTIONS - -=over 8 - -=item B<--help> - -Print a brief help message and exits. - -=item B<--offset>=I<offset> - -Byte-offset where bit-error should be injected. - -=item B<--bitmask>=I<bitmask> - -Bit-mask where to inject errors in the byte. - -=item B<--input>=I<input-file> - -Input file. - -=item B<--output>=I<output-file> - -Output file. - -=back - -=head1 DESCRIPTION - -B<inject_biterrors.pl> will read the given input file and inject -biterrors at the I<offset> specified. The location of the biterrors -are defined by the I<bitmask> parameter. - -=cut diff --git a/ubi-utils/sort-me-out/jffs2_test.sh b/ubi-utils/sort-me-out/jffs2_test.sh deleted file mode 100755 index 0cc9f0c..0000000 --- a/ubi-utils/sort-me-out/jffs2_test.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/sh -# -# Testcase for JFFS2 verification. We do not want to see any -# kernel errors occuring when this is executed. -# -# -# To have a standardized output I define the following function to be -# used when a test was ok or when it failed. -# -failed () -{ - echo "FAILED" -} - -passed () -{ - echo "PASSED" -} - -# -# Print sucess message. Consider to exit with zero as return code. -# -exit_success () -{ - echo "SUCCESS" - exit 0 -} - -# -# Print failure message. Consider to exit with non zero return code. -# -exit_failure () -{ - echo "FAILED" - exit 1 -} - -echo "***********************************************************************" -echo "* jffs2 testing ... *" -echo "***********************************************************************" - -ulimit -c unlimited - -for i in `seq 5000`; do - echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " - dd if=/dev/urandom of=test.bin bs=$i count=1; - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - - echo "Copy to different file ... " - dd if=test.bin of=new.bin bs=$i count=1; - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - - echo "Comparing files ... " - cmp test.bin new.bin - dd if=test.bin of=new.bin bs=$i count=1; - if [ $? -ne "0" ] ; then - exit_failure - fi - passed -done - -for i in `seq 5000`; do - echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " - dd if=/dev/urandom of=foo bs=$i count=1; - if [ $? -ne "0" ] ; then - exit_failure - fi - passed -done - -for i in `seq 5000`; do - echo "Testing $i byte (dd if=/dev/zero of=foo bs=$i count=1) ... " - dd if=/dev/zero of=foo bs=$i count=1; - if [ $? -ne "0" ] ; then - exit_failure - fi - passed -done - -echo "***********************************************************************" -echo "* Congratulations, no errors found! *" -echo "* Have fun with your cool JFFS2 using system! *" -echo "***********************************************************************" - -exit_success diff --git a/ubi-utils/sort-me-out/libpfiflash.c b/ubi-utils/sort-me-out/libpfiflash.c deleted file mode 100644 index 7e3d3b3..0000000 --- a/ubi-utils/sort-me-out/libpfiflash.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* - * Copyright 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Authors: Oliver Lohmann <oliloh@de.ibm.com> - * Drake Dowsett <dowsett@de.ibm.com> - * Contact: Andreas Arnez <anrez@de.ibm.com> - */ - -/* TODO Compare data before writing it. This implies that the volume - * parameters are compared first: size, alignment, name, type, ..., - * this is the same, compare the data. Volume deletion is deffered - * until the difference has been found out. - */ - -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#define __USE_GNU -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include <sys/ioctl.h> - -#include <libubi.h> -#include <pfiflash.h> - -#include <mtd/ubi-user.h> /* FIXME Is this ok here? */ -#include <mtd/mtd-user.h> - -#include "pfiflash_error.h" -#include "ubimirror.h" -#include "error.h" -#include "reader.h" -#include "example_ubi.h" -#include "bootenv.h" - -/* ubi-header.h and crc32.h needed for CRC checking */ -#include <mtd/ubi-header.h> /* FIXME Is this ok here? */ -#include "crc32.h" - -#define ubi_unused __attribute__((unused)) - -#define COMPARE_BUFFER_SIZE 2048 - -#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" - -static const char copyright [] ubi_unused = - "Copyright International Business Machines Corp., 2006, 2007"; - -/* simply clear buffer, then write into front of it */ -#define EBUF(fmt...) \ - snprintf(err_buf, err_buf_size, fmt); - -/* make a history of buffer and then prepend something in front */ -#define EBUF_PREPEND(fmt) \ - do { \ - int EBUF_HISTORY_LENGTH = strlen(err_buf); \ - char EBUF_HISTORY[EBUF_HISTORY_LENGTH + 1]; \ - strncpy(EBUF_HISTORY, err_buf, EBUF_HISTORY_LENGTH + 1);\ - EBUF(fmt ": %s", EBUF_HISTORY); \ - } while (0) - -/* An array of PDD function pointers indexed by the algorithm. */ -static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] = - { - &bootenv_pdd_keep, - &bootenv_pdd_merge, - &bootenv_pdd_overwrite - }; - -typedef enum ubi_update_process_t { - UBI_REMOVE = 0, - UBI_WRITE, - UBI_COMPARE, -} ubi_update_process_t; - - -/** - * skip_raw_volumes - reads data from pfi to advance fp past raw block - * @pfi: fp to pfi data - * @pfi_raws: header information - * - * Error handling): - * when early EOF in pfi data - * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err - * when file I/O error - * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err - **/ -static int -skip_raw_volumes(FILE* pfi, list_t pfi_raws, - char* err_buf, size_t err_buf_size) -{ - int rc; - void *i; - list_t ptr; - - if (is_empty(pfi_raws)) - return 0; - - rc = 0; - foreach(i, ptr, pfi_raws) { - size_t j; - pfi_raw_t raw; - - raw = (pfi_raw_t)i; - for(j = 0; j < raw->data_size; j++) { - int c; - - c = fgetc(pfi); - if (c == EOF) - rc = -PFIFLASH_ERR_EOF; - else if (ferror(pfi)) - rc = -PFIFLASH_ERR_FIO; - - if (rc != 0) - goto err; - } - } - - err: - EBUF(PFIFLASH_ERRSTR[-rc]); - return rc; -} - - -/** - * my_ubi_mkvol - wraps the ubi_mkvol functions and impl. bootenv update hook - * @devno: UBI device number. - * @s: Current seqnum. - * @u: Information about the UBI volume from the PFI. - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when UBI system couldn't create a volume - * - returns -PFIFLASH_ERR_UBI_MKVOL, err_buf matches text to err - **/ -static int -my_ubi_mkvol(int devno, int s, pfi_ubi_t u, - char *err_buf, size_t err_buf_size) -{ - int rc, type; - char path[PATH_MAX]; - libubi_t ulib; - struct ubi_mkvol_request req; - - rc = 0; - ulib = NULL; - - log_msg("[ ubimkvol id=%d, size=%d, data_size=%d, type=%d, " - "alig=%d, nlen=%d, name=%s", - u->ids[s], u->size, u->data_size, u->type, u->alignment, - strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]); - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - switch (u->type) { - case pfi_ubi_static: - type = UBI_STATIC_VOLUME; break; - case pfi_ubi_dynamic: - default: - type = UBI_DYNAMIC_VOLUME; - } - - snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno); - - req.vol_id = u->ids[s]; - req.alignment = u->alignment; - req.bytes = u->size; - req.vol_type = type; - req.name = u->names[s]; - - rc = ubi_mkvol(ulib, path, &req); - if (rc != 0) { - rc = -PFIFLASH_ERR_UBI_MKVOL; - EBUF(PFIFLASH_ERRSTR[-rc], u->ids[s]); - goto err; - } - - err: - if (ulib != NULL) - libubi_close(ulib); - - return rc; -} - - -/** - * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol - * @devno UBI device number - * @id UBI volume id to remove - * - * If the volume does not exist, the function will return success. - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when UBI system couldn't update (truncate) a volume - * - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err - * when UBI system couldn't remove a volume - * - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err - **/ -static int -my_ubi_rmvol(int devno, uint32_t id, - char *err_buf, size_t err_buf_size) -{ - int rc, fd; - char path[PATH_MAX]; - libubi_t ulib; - - rc = 0; - ulib = NULL; - - log_msg("[ ubirmvol id=%d", id); - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - /* truncate whether it exist or not */ - fd = open(path, O_RDWR); - if (fd < 0) { - libubi_close(ulib); - return 0; /* not existent, return 0 */ - } - - rc = ubi_update_start(ulib, fd, 0); - close(fd); - if (rc < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; /* if EBUSY than empty device, continue */ - } - - snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno); - - rc = ubi_rmvol(ulib, path, id); - if (rc != 0) { -#ifdef DEBUG - int rc_old = rc; - dbg_msg("Remove UBI volume %d returned with error: %d " - "errno=%d", id, rc_old, errno); -#endif - - rc = -PFIFLASH_ERR_UBI_RMVOL; - EBUF(PFIFLASH_ERRSTR[-rc], id); - - /* TODO Define a ubi_rmvol return value which says - * sth like EUBI_NOSUCHDEV. In this case, a failed - * operation is acceptable. Everything else has to be - * classified as real error. But talk to Andreas Arnez - * before defining something odd... - */ - /* if ((errno == EINVAL) || (errno == ENODEV)) - return 0; */ /* currently it is EINVAL or ENODEV */ - - goto err; - } - - err: - if (ulib != NULL) - libubi_close(ulib); - - return rc; -} - - -/** - * read_bootenv_volume - reads the current bootenv data from id into be_old - * @devno UBI device number - * @id UBI volume id to remove - * @bootenv_old to hold old boot_env data - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when UBI system couldn't open a volume to read - * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err - * when couldn't read bootenv data - * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err - **/ -static int -read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, - char *err_buf, size_t err_buf_size) -{ - int rc; - FILE* fp_in; - char path[PATH_MAX]; - libubi_t ulib; - - rc = 0; - fp_in = NULL; - ulib = NULL; - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - fp_in = fopen(path, "r"); - if (!fp_in) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - - log_msg("[ reading old bootenvs ..."); - - /* Save old bootenvs for reference */ - rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_READ; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - err: - if (fp_in) - fclose(fp_in); - if (ulib) - libubi_close(ulib); - - return rc; -} - - -/** - * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume - * @devno UBI device number - * @id UBI volume id - * @bootend_old old PDD data from machine - * @pdd_f function to handle PDD with - * @fp_in new pdd data contained in PFI - * @fp_in_size data size of new pdd data in PFI - * @pfi_crc crc value from PFI header - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when bootenv can't be created - * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err - * when bootenv can't be read - * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err - * when PDD handling function returns and error - * - passes rc and err_buf data - * when CRC check fails - * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err - * when bootenv can't be resized - * - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err - * when UBI system couldn't open a volume - * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err - * when couldn't write bootenv data - * - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err - **/ -static int -write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, - pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size, - uint32_t pfi_crc, - char *err_buf, size_t err_buf_size) -{ - int rc, warnings, fd_out; - uint32_t crc; - char path[PATH_MAX]; - size_t update_size; - FILE *fp_out; - bootenv_t bootenv_new, bootenv_res; - libubi_t ulib; - - rc = 0; - warnings = 0; - crc = 0; - update_size = 0; - fp_out = NULL; - bootenv_new = NULL; - bootenv_res = NULL; - ulib = NULL; - - log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in); - - /* Workflow: - * 1. Apply PDD operation and get the size of the returning - * bootenv_res section. Without the correct size it wouldn't - * be possible to call UBI update vol. - * 2. Call UBI update vol - * 3. Get FILE* to vol dev - * 4. Write to FILE* - */ - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - rc = bootenv_create(&bootenv_new); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - EBUF(PFIFLASH_ERRSTR[-rc], " 'new'"); - goto err; - } - - rc = bootenv_create(&bootenv_res); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - EBUF(PFIFLASH_ERRSTR[-rc], " 'res'"); - goto err; - } - - rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_READ; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } else if (crc != pfi_crc) { - rc = -PFIFLASH_ERR_CRC_CHECK; - EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); - goto err; - } - - rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("handling PDD"); - goto err; - } - else if (warnings) - /* TODO do something with warnings */ - dbg_msg("A warning in the PDD operation occured: %d", - warnings); - - rc = bootenv_size(bootenv_res, &update_size); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_SIZE; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - fd_out = open(path, O_RDWR); - if (fd_out < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - fp_out = fdopen(fd_out, "r+"); - if (!fp_out) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - rc = ubi_update_start(ulib, fd_out, update_size); - if (rc < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - - rc = bootenv_write(fp_out, bootenv_res); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_WRITE; - EBUF(PFIFLASH_ERRSTR[-rc], devno, id); - goto err; - } - - err: - if (ulib != NULL) - libubi_close(ulib); - if (bootenv_new != NULL) - bootenv_destroy(&bootenv_new); - if (bootenv_res != NULL) - bootenv_destroy(&bootenv_res); - if (fp_out) - fclose(fp_out); - - return rc; -} - - -/** - * write_normal_volume - writes data from PFI file int to regular UBI volume - * @devno UBI device number - * @id UBI volume id - * @update_size size of data stream - * @fp_in PFI data file pointer - * @pfi_crc CRC data from PFI header - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - * when UBI system couldn't open a volume - * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err - * when unexpected EOF is encountered - * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err - * when file I/O error - * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err - * when CRC check fails - * - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err - **/ -static int -write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, - uint32_t pfi_crc, - char *err_buf, size_t err_buf_size) -{ - int rc, fd_out; - uint32_t crc, crc32_table[256]; - char path[PATH_MAX]; - size_t bytes_left; - FILE* fp_out; - libubi_t ulib; - - rc = 0; - crc = UBI_CRC32_INIT; - bytes_left = update_size; - fp_out = NULL; - ulib = NULL; - - log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p", - id, update_size, fp_in); - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - fd_out = open(path, O_RDWR); - if (fd_out < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - fp_out = fdopen(fd_out, "r+"); - if (!fp_out) { - rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - rc = ubi_update_start(ulib, fd_out, update_size); - if (rc < 0) { - rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; - EBUF(PFIFLASH_ERRSTR[-rc], id); - goto err; - } - - init_crc32_table(crc32_table); - while (bytes_left) { - char buf[1024]; - size_t to_rw = sizeof buf > bytes_left ? - bytes_left : sizeof buf; - if (fread(buf, 1, to_rw, fp_in) != to_rw) { - rc = -PFIFLASH_ERR_EOF; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - crc = clc_crc32(crc32_table, crc, buf, to_rw); - if (fwrite(buf, 1, to_rw, fp_out) != to_rw) { - rc = -PFIFLASH_ERR_FIO; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - bytes_left -= to_rw; - } - - if (crc != pfi_crc) { - rc = -PFIFLASH_ERR_CRC_CHECK; - EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); - goto err; - } - - err: - if (fp_out) - fclose(fp_out); - if (ulib) - libubi_close(ulib); - - return rc; -} - -static int compare_bootenv(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size, - uint32_t data_size, pdd_func_t pdd_f, char *err_buf, - size_t err_buf_size) -{ - int rc, warnings = 0; - unsigned int i; - bootenv_t bootenv_pfi, bootenv_res = NULL, bootenv_flash = NULL; - - rc = bootenv_create(&bootenv_pfi); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - goto err; - } - - rc = bootenv_create(&bootenv_res); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - goto err; - } - - rc = bootenv_read(fp_pfi, bootenv_pfi, data_size); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_READ; - goto err; - } - - for (i = 0; i < ids_size; i++) { - rc = bootenv_create(&bootenv_flash); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - goto err; - } - - rc = bootenv_read(fp_flash[i], bootenv_flash, BOOTENV_MAXSIZE); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_READ; - goto err; - } - - rc = pdd_f(bootenv_flash, bootenv_pfi, &bootenv_res, - &warnings, err_buf, err_buf_size); - if (rc != 0) { - rc = -PFIFLASH_ERR_PDD_UNKNOWN; - goto err; - } - - rc = bootenv_compare(bootenv_flash, bootenv_res); - if (rc > 0) { - rc = -PFIFLASH_CMP_DIFF; - goto err; - } else if (rc < 0) { - rc = -PFIFLASH_ERR_COMPARE; - goto err; - } - - bootenv_destroy(&bootenv_flash); - bootenv_flash = NULL; - } - -err: - if (bootenv_pfi) - bootenv_destroy(&bootenv_pfi); - if (bootenv_res) - bootenv_destroy(&bootenv_res); - if (bootenv_flash) - bootenv_destroy(&bootenv_flash); - - return rc; -} - -static int compare_data(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size, - uint32_t bytes_left) -{ - unsigned int i; - size_t read_bytes, rc = 0; - char buf_pfi[COMPARE_BUFFER_SIZE]; - char *buf_flash[ids_size]; - - for (i = 0; i < ids_size; i++) { - buf_flash[i] = malloc(COMPARE_BUFFER_SIZE); - if (!buf_flash[i]) - return -PFIFLASH_ERR_COMPARE; - } - - while (bytes_left) { - if (bytes_left > COMPARE_BUFFER_SIZE) - read_bytes = COMPARE_BUFFER_SIZE; - else - read_bytes = bytes_left; - - rc = fread(buf_pfi, 1, read_bytes, fp_pfi); - if (rc != read_bytes) { - rc = -PFIFLASH_ERR_COMPARE; - goto err; - } - - for (i = 0; i < ids_size; i++) { - rc = fread(buf_flash[i], 1, read_bytes, fp_flash[i]); - if (rc != read_bytes) { - rc = -PFIFLASH_CMP_DIFF; - goto err; - } - - rc = memcmp(buf_pfi, buf_flash[i], read_bytes); - if (rc != 0) { - rc = -PFIFLASH_CMP_DIFF; - goto err; - } - } - - bytes_left -= read_bytes; - } - -err: - for (i = 0; i < ids_size; i++) - free(buf_flash[i]); - - return rc; -} - -static int compare_volumes(int devno, pfi_ubi_t u, FILE *fp_pfi, - pdd_func_t pdd_f, char *err_buf, size_t err_buf_size) -{ - int rc, is_bootenv = 0; - unsigned int i; - char path[PATH_MAX]; - libubi_t ulib = NULL; - FILE *fp_flash[u->ids_size]; - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - goto err; - } - - for (i = 0; i < u->ids_size; i++) { - if (u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_1 || - u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_2) - is_bootenv = 1; - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, u->ids[i]); - - fp_flash[i] = fopen(path, "r"); - if (fp_flash[i] == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - goto err; - } - } - - if (is_bootenv) - rc = compare_bootenv(fp_pfi, fp_flash, u->ids_size, - u->data_size, pdd_f, err_buf, err_buf_size); - else - rc = compare_data(fp_pfi, fp_flash, u->ids_size, u->data_size); - -err: - if (rc < 0) - EBUF(PFIFLASH_ERRSTR[-rc]); - - for (i = 0; i < u->ids_size; i++) - fclose(fp_flash[i]); - if (ulib) - libubi_close(ulib); - - return rc; -} - -static int -erase_mtd_region(FILE* file_p, int start, int length) -{ - int rc, fd; - erase_info_t erase; - mtd_info_t mtdinfo; - loff_t offset = start; - loff_t end = offset + length; - - fd = fileno(file_p); - if (fd < 0) - return -PFIFLASH_ERR_MTD_ERASE; - - rc = ioctl(fd, MEMGETINFO, &mtdinfo); - if (rc) - return -PFIFLASH_ERR_MTD_ERASE; - - /* check for bad blocks in case of NAND flash */ - if (mtdinfo.type == MTD_NANDFLASH) { - while (offset < end) { - rc = ioctl(fd, MEMGETBADBLOCK, &offset); - if (rc > 0) { - return -PFIFLASH_ERR_MTD_ERASE; - } - - offset += mtdinfo.erasesize; - } - } - - erase.start = start; - erase.length = length; - - rc = ioctl(fd, MEMERASE, &erase); - if (rc) { - return -PFIFLASH_ERR_MTD_ERASE; - } - - return rc; -} - -/** - * process_raw_volumes - writes the raw sections of the PFI data - * @pfi PFI data file pointer - * @pfi_raws list of PFI raw headers - * @rawdev device to use to write raw data - * - * Error handling: - * when early EOF in PFI data - * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err - * when file I/O error - * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err - * when CRC check fails - * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err - * when opening MTD device fails - * - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err - * when closing MTD device fails - * - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err - **/ -static int -process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, - char* err_buf, size_t err_buf_size) -{ - int rc; - char *pfi_data; - void *i; - uint32_t crc, crc32_table[256]; - size_t j, k; - FILE* mtd = NULL; - list_t ptr; - - if (is_empty(pfi_raws)) - return 0; - - if (rawdev == NULL) - return 0; - - rc = 0; - - pfi_data = NULL; - - log_msg("[ rawupdate dev=%s", rawdev); - - crc = UBI_CRC32_INIT; - init_crc32_table(crc32_table); - - /* most likely only one element in list, but just in case */ - foreach(i, ptr, pfi_raws) { - pfi_raw_t r = (pfi_raw_t)i; - - /* read in pfi data */ - if (pfi_data != NULL) - free(pfi_data); - pfi_data = malloc(r->data_size * sizeof(char)); - for (j = 0; j < r->data_size; j++) { - int c = fgetc(pfi); - if (c == EOF) { - rc = -PFIFLASH_ERR_EOF; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } else if (ferror(pfi)) { - rc = -PFIFLASH_ERR_FIO; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - pfi_data[j] = (char)c; - } - crc = clc_crc32(crc32_table, crc, pfi_data, r->data_size); - - /* check crc */ - if (crc != r->crc) { - rc = -PFIFLASH_ERR_CRC_CHECK; - EBUF(PFIFLASH_ERRSTR[-rc], r->crc, crc); - goto err; - } - - /* open device */ - mtd = fopen(rawdev, "r+"); - if (mtd == NULL) { - rc = -PFIFLASH_ERR_MTD_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc], rawdev); - goto err; - } - - for (j = 0; j < r->starts_size; j++) { - rc = erase_mtd_region(mtd, r->starts[j], r->data_size); - if (rc) { - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - fseek(mtd, r->starts[j], SEEK_SET); - for (k = 0; k < r->data_size; k++) { - int c = fputc((int)pfi_data[k], mtd); - if (c == EOF) { - fclose(mtd); - rc = -PFIFLASH_ERR_EOF; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - if ((char)c != pfi_data[k]) { - fclose(mtd); - rc = -1; - goto err; - } - } - } - rc = fclose(mtd); - mtd = NULL; - if (rc != 0) { - rc = -PFIFLASH_ERR_MTD_CLOSE; - EBUF(PFIFLASH_ERRSTR[-rc], rawdev); - goto err; - } - } - - err: - if (mtd != NULL) - fclose(mtd); - if (pfi_data != NULL) - free(pfi_data); - return rc; -} - - -/** - * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest - * @devno UBI device number - * @pfi_ubis list of UBI header data - * - * Error handling: - * when UBI id is out of bounds - * - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err - * when UBI volume can't be removed - * - passes rc, prepends err_buf with contextual aid - **/ -static int -erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, - char *err_buf, size_t err_buf_size) -{ - int rc; - uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; - size_t i; - list_t ptr; - pfi_ubi_t u; - - rc = 0; - - for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) - ubi_volumes[i] = 1; - - foreach(u, ptr, pfi_ubis) { - /* iterate over each vol_id */ - for(i = 0; i < u->ids_size; i++) { - if (u->ids[i] >= PFI_UBI_MAX_VOLUMES) { - rc = -PFIFLASH_ERR_UBI_VID_OOB; - EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]); - goto err; - } - /* remove from removal list */ - ubi_volumes[u->ids[i]] = 0; - } - } - - for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { - if (ubi_volumes[i]) { - rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("remove volume failed"); - goto err; - } - } - } - - err: - return rc; -} - - -/** - * process_ubi_volumes - delegate tasks regarding UBI volumes - * @pfi PFI data file pointer - * @seqnum sequence number - * @pfi_ubis list of UBI header data - * @bootenv_old storage for current system PDD - * @pdd_f function to handle PDD - * @ubi_update_process whether reading or writing - * - * Error handling: - * when and unknown ubi_update_process is given - * - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err - * otherwise - * - passes rc and err_buf - **/ -static int -process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, - bootenv_t bootenv_old, pdd_func_t pdd_f, - ubi_update_process_t ubi_update_process, - char *err_buf, size_t err_buf_size) -{ - int rc; - pfi_ubi_t u; - list_t ptr; - - rc = 0; - - foreach(u, ptr, pfi_ubis) { - int s = seqnum; - - if (s > ((int)u->ids_size - 1)) - s = 0; /* per default use the first */ - u->curr_seqnum = s; - - switch (ubi_update_process) { - case UBI_REMOVE: - /* TODO are all these "EXAMPLE" vars okay? */ - if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || - (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { - rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], bootenv_old, - err_buf, err_buf_size); - /* it's okay if there is no bootenv - * we're going to write one */ - if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) || - (rc == -PFIFLASH_ERR_BOOTENV_READ)) - rc = 0; - if (rc != 0) - goto err; - } - - rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], - err_buf, err_buf_size); - if (rc != 0) - goto err; - - break; - case UBI_WRITE: - rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("creating volume"); - goto err; - } - - if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || - (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { - rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], - bootenv_old, pdd_f, - pfi, - u->data_size, - u->crc, - err_buf, - err_buf_size); - if (rc != 0) - EBUF_PREPEND("bootenv volume"); - } else { - rc = write_normal_volume(EXAMPLE_UBI_DEVICE, - u->ids[s], - u->data_size, pfi, - u->crc, - err_buf, - err_buf_size); - if (rc != 0) - EBUF_PREPEND("normal volume"); - } - if (rc != 0) - goto err; - - break; - case UBI_COMPARE: - rc = compare_volumes(EXAMPLE_UBI_DEVICE, u, pfi, pdd_f, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("compare volume"); - goto err; - } - - break; - default: - rc = -PFIFLASH_ERR_UBI_UNKNOWN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - } - - err: - return rc; -} - - -/** - * mirror_ubi_volumes - mirror redundant pairs of volumes - * @devno UBI device number - * @pfi_ubis list of PFI header data - * - * Error handling: - * when UBI system couldn't be opened - * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err - **/ -static int -mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, - char *err_buf, size_t err_buf_size) -{ - int rc; - uint32_t j; - list_t ptr; - pfi_ubi_t i; - libubi_t ulib; - - rc = 0; - ulib = NULL; - - log_msg("[ mirror ..."); - - ulib = libubi_open(); - if (ulib == NULL) { - rc = -PFIFLASH_ERR_UBI_OPEN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - /** - * Execute all mirror operations on redundant groups. - * Create a volume within a redundant group if it does - * not exist already (this is a precondition of - * ubimirror). - */ - foreach(i, ptr, pfi_ubis) { - for (j = 0; j < i->ids_size; j++) { - /* skip self-match */ - if (i->ids[j] == i->ids[i->curr_seqnum]) - continue; - - rc = my_ubi_rmvol(devno, i->ids[j], - err_buf, err_buf_size); - if (rc != 0) - goto err; - - rc = my_ubi_mkvol(devno, j, i, - err_buf, err_buf_size); - if (rc != 0) - goto err; - } - } - - foreach(i, ptr, pfi_ubis) { - rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size, - err_buf, err_buf_size); - if (rc != 0) - goto err; - } - - - err: - if (ulib != NULL) - libubi_close(ulib); - - return rc; -} - - -/** - * pfiflash_with_options - exposed func to flash memory with a PFI file - * @pfi PFI data file pointer - * @complete flag to erase unmapped volumes - * @seqnum sequence number - * @compare flag to compare - * @pdd_handling method to handle pdd (keep, merge, overwrite...) - * - * Error handling: - * when bootenv can't be created - * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err - * when PFI headers can't be read, or - * when fail to skip raw sections, or - * when error occurs while processing raw volumes, or - * when fail to erase unmapped UBI vols, or - * when error occurs while processing UBI volumes, or - * when error occurs while mirroring UBI volumes - * - passes rc, prepends err_buf with contextual aid - **/ -int -pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare, - pdd_handling_t pdd_handling, const char* rawdev, - char *err_buf, size_t err_buf_size) -{ - int rc; - bootenv_t bootenv; - pdd_func_t pdd_f; - - if (pfi == NULL) - return -EINVAL; - - rc = 0; - pdd_f = NULL; - - /* If the user didnt specify a seqnum we start per default - * with the index 0 */ - int curr_seqnum = seqnum < 0 ? 0 : seqnum; - - list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ - list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ - - rc = bootenv_create(&bootenv); - if (rc != 0) { - rc = -PFIFLASH_ERR_BOOTENV_CREATE; - EBUF(PFIFLASH_ERRSTR[-rc], ""); - goto err; - } - - rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("reading PFI header"); - goto err; - } - - if (rawdev == NULL || compare) - rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size); - else - rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf, - err_buf_size); - if (rc != 0) { - EBUF_PREPEND("handling raw section"); - goto err; - } - - if (complete && !compare) { - rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("deleting unmapped UBI volumes"); - goto err; - } - } - - if (((int)pdd_handling >= 0) && - (pdd_handling < PDD_HANDLING_NUM)) - pdd_f = pdd_funcs[pdd_handling]; - else { - rc = -PFIFLASH_ERR_PDD_UNKNOWN; - EBUF(PFIFLASH_ERRSTR[-rc]); - goto err; - } - - if (!compare) { - rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, - pdd_f, UBI_REMOVE, err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("removing UBI volumes"); - goto err; - } - - rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, - pdd_f, UBI_WRITE, err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("writing UBI volumes"); - goto err; - } - - if (seqnum < 0) { /* mirror redundant pairs */ - rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, - err_buf, err_buf_size); - if (rc != 0) { - EBUF_PREPEND("mirroring UBI volumes"); - goto err; - } - } - } else { - /* only compare volumes, don't alter the content */ - rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, - pdd_f, UBI_COMPARE, err_buf, err_buf_size); - - if (rc == -PFIFLASH_CMP_DIFF) - /* update is necessary, return positive value */ - rc = 1; - - if (rc < 0) { - EBUF_PREPEND("comparing UBI volumes"); - goto err; - } - } - - err: - pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); - pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); - bootenv_destroy(&bootenv); - return rc; -} - - -/** - * pfiflash - passes to pfiflash_with_options - * @pfi PFI data file pointer - * @complete flag to erase unmapped volumes - * @seqnum sequence number - * @pdd_handling method to handle pdd (keep, merge, overwrite...) - **/ -int -pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, - char *err_buf, size_t err_buf_size) -{ - return pfiflash_with_options(pfi, complete, seqnum, 0, pdd_handling, - NULL, err_buf, err_buf_size); -} diff --git a/ubi-utils/sort-me-out/libubigen-old.c b/ubi-utils/sort-me-out/libubigen-old.c deleted file mode 100644 index 6aef291..0000000 --- a/ubi-utils/sort-me-out/libubigen-old.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * 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: Oliver Lohmann - * - * Add UBI headers to binary data. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <mtd/ubi-header.h> - -#include "config.h" -#include "ubigen.h" -#include "crc32.h" - -#define UBI_NAME_SIZE 256 -#define DEFAULT_VID_OFFSET ((DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -static uint32_t crc32_table[256]; - -struct ubi_info { - struct ubi_vid_hdr* v; /* Volume ID header */ - struct ubi_ec_hdr* ec; /* Erase count header */ - - FILE* fp_in; /* Input Stream */ - FILE* fp_out; /* Output stream */ - - size_t peb_size; /* Physical EB size in bytes */ - size_t leb_size; /* Size of a logical EB in a physical EB */ - size_t leb_total; /* Total input size in logical EB */ - size_t alignment; /* Block alignment */ - size_t data_pad; /* Size of padding in each physical EB */ - - size_t bytes_total; /* Total input size in bytes */ - size_t bytes_read; /* Nymber of read bytes (total) */ - - uint32_t blks_written; /* Number of written logical EB */ - - uint8_t* buf; /* Allocated buffer */ - uint8_t* ptr_ec_hdr; /* Pointer to EC hdr in buf */ - uint8_t* ptr_vid_hdr; /* Pointer to VID hdr in buf */ - uint8_t* ptr_data; /* Pointer to data region in buf */ -}; - - -static uint32_t -byte_to_blk(uint64_t byte, uint32_t peb_size) -{ - return (byte % peb_size) == 0 - ? (byte / peb_size) - : (byte / peb_size) + 1; -} - -static int -validate_ubi_info(ubi_info_t u) -{ - if ((u->v->vol_type != UBI_VID_DYNAMIC) && - (u->v->vol_type != UBI_VID_STATIC)) { - return EUBIGEN_INVALID_TYPE; - } - - if (__be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) { - return EUBIGEN_INVALID_HDR_OFFSET; - } - - return 0; -} - -static int -skip_blks(ubi_info_t u, uint32_t blks) -{ - uint32_t i; - size_t read = 0, to_read = 0; - - /* Step to a maximum of leb_total - 1 to keep the - restrictions. */ - for (i = 0; i < MIN(blks, u->leb_total-1); i++) { - /* Read in data */ - to_read = MIN(u->leb_size, - (u->bytes_total - u->bytes_read)); - read = fread(u->ptr_data, 1, to_read, u->fp_in); - if (read != to_read) { - return -EIO; - } - u->bytes_read += read; - u->blks_written++; - } - - return 0; -} - -static void -clear_buf(ubi_info_t u) -{ - memset(u->buf, 0xff, u->peb_size); -} - -static void -write_ec_hdr(ubi_info_t u) -{ - memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE); -} - -static int -fill_data_buffer_from_file(ubi_info_t u, size_t* read) -{ - size_t to_read = 0; - - if (u-> fp_in == NULL) - return -EIO; - - to_read = MIN(u->leb_size, (u->bytes_total - u->bytes_read)); - *read = fread(u->ptr_data, 1, to_read, u->fp_in); - if (*read != to_read) { - return -EIO; - } - return 0; -} - -static void -add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action) -{ - uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - u->ptr_data, data_size); - - u->v->data_size = __cpu_to_be32(data_size); - u->v->data_crc = __cpu_to_be32(crc); - - if (action & BROKEN_DATA_CRC) { - u->v->data_crc = - __cpu_to_be32(__be32_to_cpu(u->v->data_crc) + 1); - } - if (action & BROKEN_DATA_SIZE) { - u->v->data_size = - __cpu_to_be32(__be32_to_cpu(u->v->data_size) + 1); - } -} - -static void -write_vid_hdr(ubi_info_t u, ubigen_action_t action) -{ - uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - u->v, UBI_VID_HDR_SIZE_CRC); - /* Write VID header */ - u->v->hdr_crc = __cpu_to_be32(crc); - if (action & BROKEN_HDR_CRC) { - u->v->hdr_crc = __cpu_to_be32(__be32_to_cpu(u->v->hdr_crc) + 1); - } - memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE); -} - -static int -write_to_output_stream(ubi_info_t u) -{ - size_t written; - - written = fwrite(u->buf, 1, u->peb_size, u->fp_out); - if (written != u->peb_size) { - return -EIO; - } - return 0; -} - -int -ubigen_write_leb(ubi_info_t u, ubigen_action_t action) -{ - int rc = 0; - size_t read = 0; - - clear_buf(u); - write_ec_hdr(u); - - rc = fill_data_buffer_from_file(u, &read); - if (rc != 0) - return rc; - - if (u->v->vol_type == UBI_VID_STATIC) { - add_static_info(u, read, action); - } - - u->v->lnum = __cpu_to_be32(u->blks_written); - - if (action & MARK_AS_UPDATE) { - u->v->copy_flag = (u->v->copy_flag)++; - } - - write_vid_hdr(u, action); - rc = write_to_output_stream(u); - if (rc != 0) - return rc; - - /* Update current handle */ - u->bytes_read += read; - u->blks_written++; - return 0; -} - -int -ubigen_write_complete(ubi_info_t u) -{ - size_t i; - int rc = 0; - - for (i = 0; i < u->leb_total; i++) { - rc = ubigen_write_leb(u, NO_ERROR); - if (rc != 0) - return rc; - } - - return 0; -} - -int -ubigen_write_broken_update(ubi_info_t u, uint32_t blk) -{ - int rc = 0; - - rc = skip_blks(u, blk); - if (rc != 0) - return rc; - - rc = ubigen_write_leb(u, MARK_AS_UPDATE | BROKEN_DATA_CRC); - if (rc != 0) - return rc; - - - return 0; -} - -void -dump_info(ubi_info_t u ubi_unused) -{ -#ifdef DEBUG - int err = 0; - if (!u) { - fprintf(stderr, "<empty>"); - return; - } - if (!u->ec) { - fprintf(stderr, "<ec-empty>"); - err = 1; - } - if (!u->v) { - fprintf(stderr, "<v-empty>"); - err = 1; - } - if (err) return; - - fprintf(stderr, "ubi volume\n"); - fprintf(stderr, "version : %8d\n", u->v->version); - fprintf(stderr, "vol_id : %8d\n", __be32_to_cpu(u->v->vol_id)); - fprintf(stderr, "vol_type : %8s\n", - u->v->vol_type == UBI_VID_STATIC ? - "static" : "dynamic"); - fprintf(stderr, "used_ebs : %8d\n", - __be32_to_cpu(u->v->used_ebs)); - fprintf(stderr, "peb_size : 0x%08x\n", u->peb_size); - fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size); - fprintf(stderr, "data_pad : 0x%08x\n", - __be32_to_cpu(u->v->data_pad)); - fprintf(stderr, "leb_total : %8d\n", u->leb_total); - fprintf(stderr, "header offs : 0x%08x\n", - __be32_to_cpu(u->ec->vid_hdr_offset)); - fprintf(stderr, "bytes_total : %8d\n", u->bytes_total); - fprintf(stderr, " + in MiB : %8.2f M\n", - ((float)(u->bytes_total)) / 1024 / 1024); - fprintf(stderr, "-------------------------------\n\n"); -#else - return; -#endif -} - -int -ubigen_destroy(ubi_info_t *u) -{ - if (u == NULL) - return -EINVAL; - - ubi_info_t tmp = *u; - - if (tmp) { - if (tmp->v) - free(tmp->v); - if (tmp->ec) - free(tmp->ec); - if (tmp->buf) - free(tmp->buf); - free(tmp); - } - *u = NULL; - return 0; -} - -void -ubigen_init(void) -{ - init_crc32_table(crc32_table); -} - -int -ubigen_create(ubi_info_t* u, uint32_t vol_id, uint8_t vol_type, - uint32_t peb_size, uint64_t ec, uint32_t alignment, - uint8_t version, uint32_t vid_hdr_offset, uint8_t compat_flag, - size_t data_size, FILE* fp_in, FILE* fp_out) -{ - int rc = 0; - ubi_info_t res = NULL; - uint32_t crc; - uint32_t data_offset; - - if (alignment == 0) { - rc = EUBIGEN_INVALID_ALIGNMENT; - goto ubigen_create_err; - } - if ((fp_in == NULL) || (fp_out == NULL)) { - rc = -EINVAL; - goto ubigen_create_err; - } - - res = (ubi_info_t) calloc(1, sizeof(struct ubi_info)); - if (res == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - res->v = (struct ubi_vid_hdr*) calloc(1, sizeof(struct ubi_vid_hdr)); - if (res->v == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - res->ec = (struct ubi_ec_hdr*) calloc(1, sizeof(struct ubi_ec_hdr)); - if (res->ec == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - /* data which is needed in the general process */ - vid_hdr_offset = vid_hdr_offset ? vid_hdr_offset : DEFAULT_VID_OFFSET; - data_offset = vid_hdr_offset + UBI_VID_HDR_SIZE; - res->bytes_total = data_size; - res->peb_size = peb_size ? peb_size : DEFAULT_BLOCKSIZE; - res->data_pad = (res->peb_size - data_offset) % alignment; - res->leb_size = res->peb_size - data_offset - res->data_pad; - res->leb_total = byte_to_blk(data_size, res->leb_size); - res->alignment = alignment; - - if ((res->peb_size < (vid_hdr_offset + UBI_VID_HDR_SIZE))) { - rc = EUBIGEN_TOO_SMALL_EB; - goto ubigen_create_err; - } - res->fp_in = fp_in; - res->fp_out = fp_out; - - /* vid hdr data which doesn't change */ - res->v->magic = __cpu_to_be32(UBI_VID_HDR_MAGIC); - res->v->version = version ? version : UBI_VERSION; - res->v->vol_type = vol_type; - res->v->vol_id = __cpu_to_be32(vol_id); - res->v->compat = compat_flag; - res->v->data_pad = __cpu_to_be32(res->data_pad); - - /* static only: used_ebs */ - if (res->v->vol_type == UBI_VID_STATIC) { - res->v->used_ebs = __cpu_to_be32(byte_to_blk - (res->bytes_total, - res->leb_size)); - } - - /* ec hdr (fixed, doesn't change) */ - res->ec->magic = __cpu_to_be32(UBI_EC_HDR_MAGIC); - res->ec->version = version ? version : UBI_VERSION; - res->ec->ec = __cpu_to_be64(ec); - res->ec->vid_hdr_offset = __cpu_to_be32(vid_hdr_offset); - - res->ec->data_offset = __cpu_to_be32(data_offset); - - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec, - UBI_EC_HDR_SIZE_CRC); - res->ec->hdr_crc = __cpu_to_be32(crc); - - /* prepare a read buffer */ - res->buf = (uint8_t*) malloc (res->peb_size * sizeof(uint8_t)); - if (res->buf == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - /* point to distinct regions within the buffer */ - res->ptr_ec_hdr = res->buf; - res->ptr_vid_hdr = res->buf + __be32_to_cpu(res->ec->vid_hdr_offset); - res->ptr_data = res->buf + __be32_to_cpu(res->ec->vid_hdr_offset) - + UBI_VID_HDR_SIZE; - - rc = validate_ubi_info(res); - if (rc != 0) { - fprintf(stderr, "Volume validation failed: %d\n", rc); - goto ubigen_create_err; - } - - dump_info(res); - *u = res; - return rc; - -ubigen_create_err: - if (res) { - if (res->v) - free(res->v); - if (res->ec) - free(res->ec); - if (res->buf) - free(res->buf); - free(res); - } - *u = NULL; - return rc; -} - -int -ubigen_get_leb_size(ubi_info_t u, size_t* size) -{ - if (u == NULL) - return -EINVAL; - - *size = u->leb_size; - return 0; -} - - -int -ubigen_get_leb_total(ubi_info_t u, size_t* total) -{ - if (u == NULL) - return -EINVAL; - - *total = u->leb_total; - return 0; -} - -int -ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes, - const char* vol_name, struct ubi_vtbl_record *lvol_rec) -{ - uint32_t crc; - - if ((u == NULL) || (vol_name == NULL)) - return -EINVAL; - - memset(lvol_rec, 0x0, UBI_VTBL_RECORD_SIZE); - - lvol_rec->reserved_pebs = - __cpu_to_be32(byte_to_blk(reserved_bytes, u->leb_size)); - lvol_rec->alignment = __cpu_to_be32(u->alignment); - lvol_rec->data_pad = u->v->data_pad; - lvol_rec->vol_type = u->v->vol_type; - - lvol_rec->name_len = - __cpu_to_be16((uint16_t)strlen((const char*)vol_name)); - - memcpy(lvol_rec->name, vol_name, UBI_VOL_NAME_MAX + 1); - - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - lvol_rec, UBI_VTBL_RECORD_SIZE_CRC); - lvol_rec->crc = __cpu_to_be32(crc); - - return 0; -} diff --git a/ubi-utils/sort-me-out/libubimirror.c b/ubi-utils/sort-me-out/libubimirror.c deleted file mode 100644 index d06770e..0000000 --- a/ubi-utils/sort-me-out/libubimirror.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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. - */ - -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <memory.h> -#include <limits.h> -#include <fcntl.h> - -#include <libubi.h> -#include "ubimirror.h" - -#define COMPARE_BUF_SIZE (128 * 1024) - -#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" - -#define EBUF(fmt...) do { \ - snprintf(err_buf, err_buf_size, fmt); \ -} while (0) - -enum { - compare_error = -1, - seek_error = -2, - write_error = -3, - read_error = -4, - update_error = -5, - ubi_error = -6, - open_error = -7, - close_error = -8, - compare_equal = 0, - compare_different = 1 -}; - -/* - * Read len number of bytes from fd. - * Return 0 on EOF, -1 on error. - */ -static ssize_t fill_buffer(int fd, unsigned char *buf, ssize_t len) -{ - ssize_t got, have = 0; - - do { - got = read(fd, buf + have, len - have); - if (got == -1 && errno != EINTR) - return -1; - have += got; - } while (got > 0 && have < len); - return have; -} - -/* - * Write len number of bytes to fd. - * Return bytes written (>= 0), -1 on error. - */ -static ssize_t flush_buffer(int fd, unsigned char *buf, ssize_t len) -{ - ssize_t done, have = 0; - - do { - done = write(fd, buf + have, len - have); - if (done == -1 && errno != EINTR) - return -1; - have += done; - } while (done > 0 && have < len); - return have; -} - -/* - * Compare two files. Return 0, 1, or -1, depending on whether the - * files are equal, different, or an error occured. - * Return compare-different when target volume can not be read. Might be - * an interrupted volume update and then the target device returns -EIO but - * can be updated. - * - * fd_a is source - * fd_b is destination - */ -static int compare_files(int fd_a, int fd_b) -{ - unsigned char buf_a[COMPARE_BUF_SIZE], buf_b[COMPARE_BUF_SIZE]; - ssize_t len_a, len_b; - int rc; - - for (;;) { - len_a = fill_buffer(fd_a, buf_a, sizeof(buf_a)); - if (len_a == -1) { - rc = compare_error; - break; - } - len_b = fill_buffer(fd_b, buf_b, sizeof(buf_b)); - if (len_b == -1) { - rc = compare_different; - break; - } - if (len_a != len_b) { - rc = compare_different; - break; - } - if (len_a == 0) { /* Size on both files equal and EOF */ - rc = compare_equal; - break; - } - if (memcmp(buf_a, buf_b, len_a) != 0 ) { - rc = compare_different; - break; - } - } - /* Position both files at the beginning */ - if (lseek(fd_a, 0, SEEK_SET) == -1 || - lseek(fd_b, 0, SEEK_SET) == -1) - rc = seek_error; - return rc; -} - -int vol_get_used_bytes(int vol_fd, unsigned long long *bytes) -{ - off_t res; - - res = lseek(vol_fd, 0, SEEK_END); - if (res == (off_t)-1) - return -1; - *bytes = (unsigned long long) res; - res = lseek(vol_fd, 0, SEEK_SET); - return res == (off_t)-1 ? -1 : 0; -} - -static int copy_files(libubi_t ulib, int fd_in, int fd_out) -{ - unsigned char buf_a[COMPARE_BUF_SIZE]; - ssize_t len_a, len_b; - unsigned long long update_size, copied; - - if (vol_get_used_bytes(fd_in, &update_size) == -1 || - ubi_update_start(ulib, fd_out, update_size) == -1) - return update_error; - for (copied = 0; copied < update_size; copied += len_b ) { - len_a = fill_buffer(fd_in, buf_a, sizeof(buf_a)); - if (len_a == -1) - return read_error; - if (len_a == 0) /* Reach EOF */ - return 0; - len_b = flush_buffer(fd_out, buf_a, len_a); - if (len_b != len_a) - return write_error; - } - return 0; -} - -int ubimirror(uint32_t devno, int seqnum, uint32_t *ids, ssize_t ids_size, - char *err_buf, size_t err_buf_size) -{ - int rc = 0; - uint32_t src_id; - char path[PATH_MAX]; - libubi_t ulib; - int fd_in = -1, i = 0, fd_out = -1; - - if (ids_size == 0) - return 0; - else { - if ((seqnum < 0) || (seqnum > (ids_size - 1))) { - EBUF("volume id %d out of range", seqnum); - return EUBIMIRROR_NO_SRC; - } - src_id = ids[seqnum]; - } - - ulib = libubi_open(); - if (ulib == NULL) - return ubi_error; - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, src_id); - - fd_in = open(path, O_RDONLY); - if (fd_in == -1) { - EBUF("open error source volume %d", ids[i]); - rc = open_error; - goto err; - } - - for (i = 0; i < ids_size; i++) { - if (ids[i] == src_id) /* skip self-mirror */ - continue; - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, ids[i]); - - fd_out = open(path, O_RDWR); - if (fd_out < 0){ - EBUF("open error destination volume %d", ids[i]); - rc = open_error; - goto err; - } - rc = compare_files(fd_in, fd_out); - if (rc < 0) { - EBUF("compare error volume %d and %d", src_id, ids[i]); - goto err; - } else if (rc == compare_different) { - rc = copy_files(ulib, fd_in, fd_out); - if (rc != 0) { - EBUF("mirror error volume %d to %d", src_id, - ids[i]); - goto err; - } - } - if ((rc = close(fd_out)) == -1) { - EBUF("close error volume %d", ids[i]); - rc = close_error; - goto err; - } else - fd_out = -1; - } -err: - if (fd_out != -1) - close(fd_out); - if (fd_in != -1) - close(fd_in); - if (ulib != NULL) - libubi_close(ulib); - return rc; -} diff --git a/ubi-utils/sort-me-out/list.c b/ubi-utils/sort-me-out/list.c deleted file mode 100644 index 6eb716b..0000000 --- a/ubi-utils/sort-me-out/list.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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: Oliver Lohmann - */ - -#include <stdlib.h> -#include <assert.h> -#include <stdio.h> - -#include "list.h" - -list_t -mk_empty(void) -{ - return (list_t) NULL; -} - -int -is_empty(list_t l) -{ - return l == NULL; -} - -info_t -head(list_t l) -{ - assert(!is_empty(l)); - return l->info; -} - -list_t -tail(list_t l) -{ - assert(!is_empty(l)); - return l->next; -} - -list_t -remove_head(list_t l) -{ - list_t res; - assert(!is_empty(l)); - - res = l->next; - free(l); - return res; -} - -list_t -cons(info_t e, list_t l) -{ - list_t res = malloc(sizeof(*l)); - if (!res) - return NULL; - res->info = e; - res->next = l; - - return res; -} - -list_t -prepend_elem(info_t e, list_t l) -{ - return cons(e,l); -} - -list_t -append_elem(info_t e, list_t l) -{ - if (is_empty(l)) { - return cons(e,l); - } - l->next = append_elem(e, l->next); - - return l; -} - -list_t -insert_sorted(cmp_func_t cmp, info_t e, list_t l) -{ - if (is_empty(l)) - return cons(e, l); - - switch (cmp(e, l->info)) { - case -1: - case 0: - return l; - break; - case 1: - l->next = insert_sorted(cmp, e, l); - break; - default: - break; - } - - /* never reached */ - return NULL; -} - -list_t -remove_all(free_func_t free_func, list_t l) -{ - if (is_empty(l)) - return l; - list_t lnext = l->next; - - if (free_func && l->info) { - free_func(&(l->info)); - } - free(l); - - return remove_all(free_func, lnext); -} - - -info_t -is_in(cmp_func_t cmp, info_t e, list_t l) -{ - return - (is_empty(l)) - ? NULL - : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next); -} - - -void -apply(process_func_t process_func, list_t l) -{ - list_t ptr; - void *i; - foreach(i, ptr, l) { - process_func(i); - } -} diff --git a/ubi-utils/sort-me-out/list.h b/ubi-utils/sort-me-out/list.h deleted file mode 100644 index e8452a2..0000000 --- a/ubi-utils/sort-me-out/list.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __LIST_H__ -#define __LIST_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: Oliver Lohmann - */ - -#include <stdint.h> - -#define foreach(elem, ptr, list) \ - for (elem = list != NULL ? (typeof(elem)) head(list) \ - : NULL, ptr = list; \ - ptr != NULL; \ - ptr = tail(ptr), \ - elem = (typeof(elem)) ptr ? head(ptr) : NULL) - -typedef struct node* list_t; -typedef void* info_t; -typedef int (*free_func_t)(info_t*); -typedef int (*cmp_func_t)(info_t, info_t); -typedef void (*process_func_t)(info_t); - -struct node { - list_t next; - info_t info; -}; - -list_t mk_empty(void); -int is_empty(list_t l); -info_t is_in(cmp_func_t cmp, info_t e, list_t l); -info_t head(list_t l); -list_t tail(list_t l); -list_t remove_head(list_t l); -list_t cons(info_t e, list_t l); -list_t prepend_elem(info_t e, list_t); -list_t append_elem(info_t e, list_t); -list_t remove_all(free_func_t free_func, list_t l); -list_t insert_sorted(cmp_func_t cmp_func, info_t e, list_t l); -void apply(process_func_t process_func, list_t l); - -#endif /* __LIST_H__ */ diff --git a/ubi-utils/sort-me-out/mkbootenv.c b/ubi-utils/sort-me-out/mkbootenv.c deleted file mode 100644 index 952f651..0000000 --- a/ubi-utils/sort-me-out/mkbootenv.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * 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: Oliver Lohmann - * - * Create boot-parameter/pdd data from an ASCII-text input file. - * - * 1.2 Removed argp because we want to use uClibc. - * 1.3 Minor cleanup - */ - -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <getopt.h> -#include <unistd.h> -#include <errno.h> -#include <mtd/ubi-header.h> - -#include "config.h" -#include "bootenv.h" -#include "error.h" - -#define PROGRAM_VERSION "1.3" - -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "mkbootenv - processes bootenv text files and convertes " - "them into a binary format.\n"; - -static const char copyright [] __attribute__((unused)) = - "Copyright (c) International Business Machines Corp., 2006"; - -static const char *optionsstr = -" -c, --copyright Print copyright informatoin.\n" -" -o, --output=<fname> Write the output data to <output> instead of\n" -" stdout.\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" -V, --version Print program version\n"; - -static const char *usage = -"Usage: mkbootenv [-c?V] [-o <output>] [--copyright] [--output=<output>]\n" -" [--help] [--usage] [--version] [bootenv-txt-file]\n"; - -struct option long_options[] = { - { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, - { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -typedef struct myargs { - FILE* fp_in; - FILE* fp_out; - - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static int -parse_opt(int argc, char **argv, myargs *args) -{ - while (1) { - int key; - - key = getopt_long(argc, argv, "co:?V", long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'c': - fprintf(stderr, "%s\n", copyright); - exit(0); - break; - case 'o': - args->fp_out = fopen(optarg, "wb"); - if ((args->fp_out) == NULL) { - fprintf(stderr, "Cannot open file %s " - "for output\n", optarg); - exit(1); - } - break; - case '?': /* help */ - printf("%s", doc); - printf("%s", optionsstr); - printf("\nReport bugs to %s\n", - PACKAGE_BUGREPORT); - exit(0); - break; - case 'V': - printf("%s\n", PROGRAM_VERSION); - exit(0); - break; - default: - printf("%s", usage); - exit(-1); - } - } - - if (optind < argc) { - args->fp_in = fopen(argv[optind++], "rb"); - if ((args->fp_in) == NULL) { - fprintf(stderr, "Cannot open file %s for input\n", - argv[optind]); - exit(1); - } - } - - return 0; -} - -int -main(int argc, char **argv) { - int rc = 0; - bootenv_t env; - - myargs args = { - .fp_in = stdin, - .fp_out = stdout, - .arg1 = NULL, - .options = NULL, - }; - - parse_opt(argc, argv, &args); - - rc = bootenv_create(&env); - if (rc != 0) { - err_msg("Cannot create bootenv handle."); - goto err; - } - rc = bootenv_read_txt(args.fp_in, env); - if (rc != 0) { - err_msg("Cannot read bootenv from input file."); - goto err; - } - rc = bootenv_write(args.fp_out, env); - if (rc != 0) { - err_msg("Cannot write bootenv to output file."); - goto err; - } - - if (args.fp_in != stdin) { - fclose(args.fp_in); - } - if (args.fp_out != stdout) { - fclose(args.fp_out); - } - -err: - bootenv_destroy(&env); - return rc; -} diff --git a/ubi-utils/sort-me-out/nand2bin.c b/ubi-utils/sort-me-out/nand2bin.c deleted file mode 100644 index 8c95b27..0000000 --- a/ubi-utils/sort-me-out/nand2bin.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Frank Haverkamp - * - * An utility to decompose NAND images and strip OOB off. Not yet finished ... - * - * 1.2 Removed argp because we want to use uClibc. - * 1.3 Minor cleanup - * 1.4 Fixed OOB output file - * 1.5 Added verbose output and option to set blocksize. - * Added split block mode for more convenient analysis. - * 1.6 Fixed ECC error detection and correction. - * 1.7 Made NAND ECC layout configurable, the holes which were previously - * filled with 0x00 are untouched now and will be 0xff just like MTD - * behaves when writing the oob (haver) - */ - -#include <config.h> -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdint.h> -#include <getopt.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include "config.h" -#include "nandecc.h" -#include "ecclayouts.h" - -#define PROGRAM_VERSION "1.7" - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#define MAXPATH 1024 -#define MIN(x,y) ((x)<(y)?(x):(y)) - -struct args { - const char *oob_file; - const char *output_file; - size_t pagesize; - size_t oobsize; - int bad_marker_offs_in_oob; - size_t blocksize; - int split_blocks; - size_t in_len; /* size of input file */ - int correct_ecc; - struct nand_ecclayout *nand_oob; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -}; - -static struct args myargs = { - .output_file = "data.bin", - .oob_file = "oob.bin", - .pagesize = 2048, - .blocksize = 128 * 1024, - .nand_oob = &ibm_nand_oob_64, - .in_len = 0, - .split_blocks = 0, - .correct_ecc = 0, - .arg1 = NULL, - .options = NULL, -}; - -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "nand2bin - split data and OOB.\n"; - -static const char *optionsstr = -" -l, --ecc-placement=<MTD,IBM> OOB placement scheme (default is IBM).\n" -" -o, --output=<output> Data output file\n" -" -O, --oob=<oob> OOB output file\n" -" -p, --pagesize=<pagesize> NAND pagesize\n" -" -b, --blocksize=<blocksize> NAND blocksize\n" -" -s, --split-blocks generate binaries for each block\n" -" -e, --correct-ecc Correct data according to ECC info\n" -" -v, --verbose verbose output\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n"; - -static const char *usage = -"Usage: nand2bin [-?] [-o <output>] [-O <oob>] [-p <pagesize>]\n" -" [--output=<output>] [--oob=<oob>] [--pagesize=<pagesize>] [--help]\n" -" [--usage] input.mif\n"; - -static int verbose = 0; - -static struct option long_options[] = { - { .name = "ecc-layout", .has_arg = 1, .flag = NULL, .val = 'l' }, - { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, - { .name = "oob", .has_arg = 1, .flag = NULL, .val = 'O' }, - { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' }, - { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' }, - { .name = "split-blocks", .has_arg = 0, .flag = NULL, .val = 's' }, - { .name = "correct-ecc", .has_arg = 0, .flag = NULL, .val = 'e' }, - { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { NULL, 0, NULL, 0} -}; - -/* - * str_to_num - Convert string into number and cope with endings like - * k, K, kib, KiB for kilobyte - * m, M, mib, MiB for megabyte - */ -static uint32_t str_to_num(char *str) -{ - char *s = str; - ulong num = strtoul(s, &s, 0); - - if (*s != '\0') { - if (strcmp(s, "KiB") == 0) - num *= 1024; - else if (strcmp(s, "MiB") == 0) - num *= 1024*1024; - else { - fprintf(stderr, "WARNING: Wrong number format " - "\"%s\", check your paramters!\n", str); - } - } - return num; -} - -/* - * @brief Parse the arguments passed into the test case. - * - * @param argc The number of arguments - * @param argv The argument list - * @param args Pointer to program args structure - * - * @return error - * - */ -static int parse_opt(int argc, char **argv, struct args *args) -{ - unsigned int i, oob_idx = 0; - const char *ecc_layout = NULL; - - while (1) { - int key; - - key = getopt_long(argc, argv, "b:el:o:O:p:sv?", long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'b': /* --blocksize<blocksize> */ - args->blocksize = str_to_num(optarg); - break; - case 'e': /* --correct-ecc */ - args->correct_ecc = 1; - break; - case 'l': /* --ecc-layout=<...> */ - ecc_layout = optarg; - break; - case 'o': /* --output=<output.bin> */ - args->output_file = optarg; - break; - case 'O': /* --oob=<oob.bin> */ - args->oob_file = optarg; - break; - case 'p': /* --pagesize<pagesize> */ - args->pagesize = str_to_num(optarg); - break; - case 's': /* --split-blocks */ - args->split_blocks = 1; - break; - case 'v': /* --verbose */ - verbose++; - break; - case 'V': - printf("%s\n", PROGRAM_VERSION); - exit(0); - break; - case '?': /* help */ - printf("Usage: nand2bin [OPTION...] input.mif\n"); - printf("%s%s", doc, optionsstr); - printf("\nReport bugs to %s\n", - PACKAGE_BUGREPORT); - exit(0); - break; - default: - printf("%s", usage); - exit(-1); - } - } - - if (optind < argc) - args->arg1 = argv[optind++]; - - switch (args->pagesize) { - case 512: - args->oobsize = 16; - args->bad_marker_offs_in_oob = 5; - oob_idx = 0; - break; - case 2048: - args->oobsize = 64; - args->bad_marker_offs_in_oob = 0; - oob_idx = 1; - break; - default: - fprintf(stderr, "Unsupported page size: %d\n", args->pagesize); - return -EINVAL; - } - - /* Figure out correct oob layout if it differs from default */ - if (ecc_layout) { - for (i = 0; i < ARRAY_SIZE(oob_placement); i++) - if (strcmp(ecc_layout, oob_placement[i].name) == 0) - args->nand_oob = - oob_placement[i].nand_oob[oob_idx]; - } - return 0; -} - -/* - * We must only compare the relevant bytes in the OOB area. All other - * bytes can be ignored. The information we need to do this is in - * nand_oob. - */ -static int oob_cmp(struct nand_ecclayout *nand_oob, uint8_t *oob, - uint8_t *calc_oob) -{ - unsigned int i; - for (i = 0; i < nand_oob->eccbytes; i++) - if (oob[nand_oob->eccpos[i]] != calc_oob[nand_oob->eccpos[i]]) - return 1; - return 0; -} - -static inline void hexdump(FILE *fp, const uint8_t *buf, ssize_t size) -{ - int k; - - for (k = 0; k < size; k++) { - fprintf(fp, "%02x ", buf[k]); - if ((k & 15) == 15) - fprintf(fp, "\n"); - } -} - -static int process_page(struct args *args, uint8_t *buf, uint8_t *oobbuf) -{ - size_t i, j; - int eccpoi; - uint8_t ecc_code[3] = { 0, }; /* temp */ - - /* Calculate ECC */ - memset(oobbuf, 0xff, args->oobsize); - for (eccpoi = 0, i = 0; i < args->pagesize; i += 256, eccpoi += 3) { - nand_calculate_ecc(&buf[i], ecc_code); - for (j = 0; j < 3; j++) - oobbuf[args->nand_oob->eccpos[eccpoi + j]] = ecc_code[j]; - } - return 0; -} - -static int decompose_image(struct args *args, FILE *in_fp, - FILE *bin_fp, FILE *oob_fp) -{ - unsigned int i, eccpoi; - int read, rc, page = 0; - uint8_t *buf = malloc(args->pagesize); - uint8_t *oob = malloc(args->oobsize); - uint8_t *calc_oob = malloc(args->oobsize); - uint8_t *calc_buf = malloc(args->pagesize); - uint8_t *page_buf; - int pages_per_block = args->blocksize / args->pagesize; - int badpos = args->bad_marker_offs_in_oob; - uint8_t ecc_code[3] = { 0, }; /* temp */ - uint8_t calc_ecc_code[3] = { 0, }; /* temp */ - - if (!buf || !oob || !calc_oob || !calc_buf) - exit(EXIT_FAILURE); - - while (!feof(in_fp)) { - /* read page by page */ - read = fread(buf, 1, args->pagesize, in_fp); - if (ferror(in_fp)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - if (read != (ssize_t)args->pagesize) - break; - - read = fread(oob, 1, args->oobsize, in_fp); - if (ferror(in_fp)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - - page_buf = buf; /* default is unmodified data */ - - if ((page == 0 || page == 1) && (oob[badpos] != 0xff)) { - if (verbose) - printf("Block %d is bad\n", - page / pages_per_block); - goto write_data; - } - if (args->correct_ecc) - page_buf = calc_buf; - - process_page(args, buf, calc_oob); - memcpy(calc_buf, buf, args->pagesize); - - if (verbose && oob_cmp(args->nand_oob, oob, calc_oob) != 0) { - printf("\nECC compare mismatch found at block %d page %d!\n", - page / pages_per_block, page % pages_per_block); - - printf("Read out OOB Data:\n"); - hexdump(stdout, oob, args->oobsize); - - printf("Calculated OOB Data:\n"); - hexdump(stdout, calc_oob, args->oobsize); - } - - /* Do correction on subpage base */ - for (i = 0, eccpoi = 0; i < args->pagesize; i += 256, eccpoi += 3) { - int j; - - for (j = 0; j < 3; j++) { - ecc_code[j] = oob[args->nand_oob->eccpos[eccpoi + j]]; - calc_ecc_code[j] = - calc_oob[args->nand_oob->eccpos[eccpoi + j]]; - } - rc = nand_correct_data(calc_buf + i, ecc_code, - calc_ecc_code); - if (rc == -1) - fprintf(stdout, "Uncorrectable ECC error at " - "block %d page %d/%d\n", - page / pages_per_block, - page % pages_per_block, i / 256); - else if (rc > 0) - fprintf(stdout, "Correctable ECC error at " - "block %d page %d/%d\n", - page / pages_per_block, - page % pages_per_block, i / 256); - } - - write_data: - rc = fwrite(page_buf, 1, args->pagesize, bin_fp); - if (ferror(bin_fp)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - rc = fwrite(oob, 1, args->oobsize, oob_fp); - if (ferror(bin_fp)) { - fprintf(stderr, "I/O Error."); - exit(EXIT_FAILURE); - } - - page++; - } - free(calc_buf); - free(calc_oob); - free(oob); - free(buf); - return 0; -} - -static int split_blocks(struct args *args, FILE *in_fp) -{ - uint8_t *buf; - int pages_per_block = args->blocksize / args->pagesize; - int block_len = pages_per_block * (args->pagesize + args->oobsize); - int blocks = args->in_len / block_len; - char bname[256] = { 0, }; - int badpos = args->bad_marker_offs_in_oob; - int bad_blocks = 0, i, bad_block = 0; - ssize_t rc; - FILE *b; - - buf = malloc(block_len); - if (!buf) { - perror("Not enough memory"); - exit(EXIT_FAILURE); - } - - for (i = 0; i < blocks; i++) { - rc = fread(buf, 1, block_len, in_fp); - if (rc != block_len) { - fprintf(stderr, "cannot read enough data!\n"); - exit(EXIT_FAILURE); - } - - /* do block analysis */ - bad_block = 0; - if ((buf[args->pagesize + badpos] != 0xff) || - (buf[2 * args->pagesize + args->oobsize + badpos] != 0xff)) { - bad_blocks++; - bad_block = 1; - } - if ((verbose && bad_block) || (verbose > 1)) { - printf("-- (block %d oob of page 0 and 1)\n", i); - hexdump(stdout, buf + args->pagesize, args->oobsize); - printf("--\n"); - hexdump(stdout, buf + 2 * args->pagesize + - args->oobsize, args->oobsize); - } - - /* write complete block out */ - snprintf(bname, sizeof(bname) - 1, "%s.%d", args->arg1, i); - b = fopen(bname, "w+"); - if (!b) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - rc = fwrite(buf, 1, block_len, b); - if (rc != block_len) { - fprintf(stderr, "could not write all data!\n"); - exit(EXIT_FAILURE); - } - fclose(b); - } - - free(buf); - if (bad_blocks || verbose) - fprintf(stderr, "%d blocks, %d bad blocks\n", - blocks, bad_blocks); - return 0; -} - -int -main(int argc, char *argv[]) -{ - FILE *in, *bin = NULL, *oob = NULL; - struct stat file_info; - - parse_opt(argc, argv, &myargs); - - if (!myargs.arg1) { - fprintf(stderr, "Please specify input file!\n"); - exit(EXIT_FAILURE); - } - - if (lstat(myargs.arg1, &file_info) != 0) { - perror("Cannot fetch file size from input file.\n"); - exit(EXIT_FAILURE); - } - myargs.in_len = file_info.st_size; - - in = fopen(myargs.arg1, "r"); - if (!in) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - - if (myargs.split_blocks) { - split_blocks(&myargs, in); - goto out; - } - - bin = fopen(myargs.output_file, "w+"); - if (!bin) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - oob = fopen(myargs.oob_file, "w+"); - if (!oob) { - perror("Cannot open file"); - exit(EXIT_FAILURE); - } - decompose_image(&myargs, in, bin, oob); - - out: - if (in) fclose(in); - if (bin) fclose(bin); - if (oob) fclose(oob); - exit(EXIT_SUCCESS); -} diff --git a/ubi-utils/sort-me-out/nandcorr.c b/ubi-utils/sort-me-out/nandcorr.c deleted file mode 100644 index caa07e2..0000000 --- a/ubi-utils/sort-me-out/nandcorr.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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. - */ - -/* - * ECC algorithm for NAND FLASH. Detects and corrects 1 bit errors in - * a 256 bytes of data. - * - * Reimplement by Thomas Gleixner after staring long enough at the - * mess in drivers/mtd/nand/nandecc.c - * - */ - -#include "nandecc.h" - -static int countbits(uint32_t byte) -{ - int res = 0; - - for (;byte; byte >>= 1) - res += byte & 0x01; - return res; -} - -/** - * @dat: data which should be corrected - * @read_ecc: ecc information read from flash - * @calc_ecc: calculated ecc information from the data - * @return: number of corrected bytes - * or -1 when no correction is possible - */ -int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc, - const uint8_t *calc_ecc) -{ - uint8_t s0, s1, s2; - - /* - * Do error detection - * - * Be careful, the index magic is due to a pointer to a - * uint32_t. - */ - s0 = calc_ecc[0] ^ read_ecc[0]; - s1 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; - - if ((s0 | s1 | s2) == 0) - return 0; - - /* Check for a single bit error */ - if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && - ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && - ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { - - uint32_t byteoffs, bitnum; - - byteoffs = (s1 << 0) & 0x80; - byteoffs |= (s1 << 1) & 0x40; - byteoffs |= (s1 << 2) & 0x20; - byteoffs |= (s1 << 3) & 0x10; - - byteoffs |= (s0 >> 4) & 0x08; - byteoffs |= (s0 >> 3) & 0x04; - byteoffs |= (s0 >> 2) & 0x02; - byteoffs |= (s0 >> 1) & 0x01; - - bitnum = (s2 >> 5) & 0x04; - bitnum |= (s2 >> 4) & 0x02; - bitnum |= (s2 >> 3) & 0x01; - - dat[byteoffs] ^= (1 << bitnum); - - return 1; - } - - if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) - return 1; - - return -1; -} - diff --git a/ubi-utils/sort-me-out/nandecc.c b/ubi-utils/sort-me-out/nandecc.c deleted file mode 100644 index 71660ef..0000000 --- a/ubi-utils/sort-me-out/nandecc.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file contains an ECC algorithm from Toshiba that detects and - * corrects 1 bit errors in a 256 byte block of data. - * - * drivers/mtd/nand/nand_ecc.c - * - * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) - * Toshiba America Electronics Components, Inc. - * - * This file 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 or (at your option) any - * later version. - * - * This file 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 file; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * As a special exception, if other files instantiate templates or use - * macros or inline functions from these files, or you compile these - * files and link them with other works to produce a work based on these - * files, these files do not by themselves cause the resulting work to be - * covered by the GNU General Public License. However the source code for - * these files must still be made available in accordance with section (3) - * of the GNU General Public License. - * - * This exception does not invalidate any other reasons why a work based on - * this file might be covered by the GNU General Public License. - */ - -#include "nandecc.h" - -/* - * Pre-calculated 256-way 1 byte column parity - */ -static const uint8_t nand_ecc_precalc_table[] = { - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, - 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, - 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, - 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, - 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, - 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, - 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, - 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, - 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, - 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, - 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, - 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, - 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, - 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, - 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, - 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, - 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 -}; - -/** - * nand_trans_result - [GENERIC] create non-inverted ECC - * @reg2: line parity reg 2 - * @reg3: line parity reg 3 - * @ecc_code: ecc - * - * Creates non-inverted ECC code from line parity - */ -static void nand_trans_result(uint8_t reg2, uint8_t reg3, - uint8_t *ecc_code) -{ - uint8_t a, b, i, tmp1, tmp2; - - /* Initialize variables */ - a = b = 0x80; - tmp1 = tmp2 = 0; - - /* Calculate first ECC byte */ - for (i = 0; i < 4; i++) { - if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ - tmp1 |= b; - b >>= 1; - if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ - tmp1 |= b; - b >>= 1; - a >>= 1; - } - - /* Calculate second ECC byte */ - b = 0x80; - for (i = 0; i < 4; i++) { - if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ - tmp2 |= b; - b >>= 1; - if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ - tmp2 |= b; - b >>= 1; - a >>= 1; - } - - /* Store two of the ECC bytes */ - ecc_code[1] = tmp1; - ecc_code[0] = tmp2; -} - -/** - * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for - * 256 byte block - * - * @dat: raw data - * @ecc_code: buffer for ECC - */ -int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code) -{ - uint8_t idx, reg1, reg2, reg3; - int j; - - /* Initialize variables */ - reg1 = reg2 = reg3 = 0; - ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; - - /* Build up column parity */ - for(j = 0; j < 256; j++) { - - /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[dat[j]]; - reg1 ^= (idx & 0x3f); - - /* All bit XOR = 1 ? */ - if (idx & 0x40) { - reg3 ^= (uint8_t) j; - reg2 ^= ~((uint8_t) j); - } - } - - /* Create non-inverted ECC code from line parity */ - nand_trans_result(reg2, reg3, ecc_code); - - /* Calculate final ECC code */ - ecc_code[0] = ~ecc_code[0]; - ecc_code[1] = ~ecc_code[1]; - ecc_code[2] = ((~reg1) << 2) | 0x03; - return 0; -} diff --git a/ubi-utils/sort-me-out/nandecc.h b/ubi-utils/sort-me-out/nandecc.h deleted file mode 100644 index bcf1982..0000000 --- a/ubi-utils/sort-me-out/nandecc.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _NAND_ECC_H -#define _NAND_ECC_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. - * - * NAND ecc functions - */ - -#include <stdint.h> - -int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code); -int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc, - const uint8_t *calc_ecc); - -#endif diff --git a/ubi-utils/sort-me-out/pdd.txt b/ubi-utils/sort-me-out/pdd.txt deleted file mode 100644 index a3ad915..0000000 --- a/ubi-utils/sort-me-out/pdd.txt +++ /dev/null @@ -1,16 +0,0 @@ -pdd=flash_type,flash_size,flash_eraseblock_size,flash_page_size,card_serialnumber,card_type,ethaddr,eth1addr,eth0,eth1,total,card_hardwarelevel -pdd_preserve=ethaddr,eth1addr,card_serialnumber -# To be personalized -ethaddr=00:04:34:56:78:9A -eth1addr=00:04:34:56:78:9B -card_serialnumber=SN0 -# Static for this card type -total=102M -card_type=nand_driven_testcard -card_hardwarelevel=0 -eth0=bcm5222,eth0,0 -eth1=bcm5222,eth0,1 -flash_type=NAND -flash_size=0x08000000 -flash_eraseblock_size=0x00020000 -flash_page_size=0x00000800 diff --git a/ubi-utils/sort-me-out/pddcustomize.c b/ubi-utils/sort-me-out/pddcustomize.c deleted file mode 100644 index 515efd6..0000000 --- a/ubi-utils/sort-me-out/pddcustomize.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * 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: Oliver Lohmann - * - * PDD (platform description data) contains a set of system specific - * boot-parameters. Some of those parameters need to be handled - * special on updates, e.g. the MAC addresses. They must also be kept - * if the system is updated and one must be able to modify them when - * the system has booted the first time. This tool is intended to do - * PDD modification. - * - * 1.3 Removed argp because we want to use uClibc. - * 1.4 Minor cleanups - * 1.5 Migrated to new libubi - */ - -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <unistd.h> -#include <limits.h> -#include <errno.h> -#include <mtd/ubi-header.h> - -#include "config.h" -#include "bootenv.h" -#include "error.h" -#include "example_ubi.h" -#include "libubi.h" -#include "ubimirror.h" - -#define PROGRAM_VERSION "1.5" - -#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" - -typedef enum action_t { - ACT_NORMAL = 0, - ACT_LIST, - ACT_ARGP_ABORT, - ACT_ARGP_ERR, -} action_t; - -#define ABORT_ARGP do { \ - args->action = ACT_ARGP_ABORT; \ -} while (0) - -#define ERR_ARGP do { \ - args->action = ACT_ARGP_ERR; \ -} while (0) - -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "pddcustomize - customize bootenv and pdd values.\n"; - -static const char *optionsstr = -" -b, --both Mirror updated PDD to redundand copy.\n" -" -c, --copyright Print copyright information.\n" -" -i, --input=<input> Binary input file. For debug purposes.\n" -" -l, --list List card bootenv/pdd values.\n" -" -o, --output=<output> Binary output file. For debug purposes.\n" -" -s, --side=<seqnum> The side/seqnum to update.\n" -" -x, --host use x86 platform for debugging.\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" -V, --version Print program version\n"; - -static const char *usage = -"Usage: pddcustomize [-bclx?V] [-i <input>] [-o <output>] [-s <seqnum>]\n" -" [--both] [--copyright] [--input=<input>] [--list]\n" -" [--output=<output>] [--side=<seqnum>] [--host] [--help] [--usage]\n" -" [--version] [key=value] [...]\n"; - -struct option long_options[] = { - { .name = "both", .has_arg = 0, .flag = NULL, .val = 'b' }, - { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, - { .name = "input", .has_arg = 1, .flag = NULL, .val = 'i' }, - { .name = "list", .has_arg = 0, .flag = NULL, .val = 'l' }, - { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, - { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, - { .name = "host", .has_arg = 0, .flag = NULL, .val = 'x' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -static const char copyright [] __attribute__((unused)) = - "Copyright IBM Corp 2006"; - -typedef struct myargs { - action_t action; - const char* file_in; - const char* file_out; - int both; - int side; - int x86; /* X86 host, use files for testing */ - bootenv_t env_in; - - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static int -get_update_side(const char* str) -{ - uint32_t i = strtoul(str, NULL, 0); - - if ((i != 0) && (i != 1)) { - return -1; - } - - return i; -} - -static int -extract_pair(bootenv_t env, const char* str) -{ - int rc = 0; - char* key; - char* val; - - key = strdup(str); - if (key == NULL) - return -ENOMEM; - - val = strstr(key, "="); - if (val == NULL) { - err_msg("Wrong argument: %s\n" - "Expecting key=value pair.\n", str); - rc = -1; - goto err; - } - - *val = '\0'; /* split strings */ - val++; - rc = bootenv_set(env, key, val); - -err: - free(key); - return rc; -} - -static int -parse_opt(int argc, char **argv, myargs *args) -{ - int rc = 0; - - while (1) { - int key; - - key = getopt_long(argc, argv, "clbxs:i:o:?V", - long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'c': - err_msg("%s\n", copyright); - ABORT_ARGP; - break; - case 'l': - args->action = ACT_LIST; - break; - case 'b': - args->both = 1; - break; - case 'x': - args->x86 = 1; - break; - case 's': - args->side = get_update_side(optarg); - if (args->side < 0) { - err_msg("Unsupported seqnum: %d.\n" - "Supported seqnums are " - "'0' and '1'\n", - args->side, optarg); - ERR_ARGP; - } - break; - case 'i': - args->file_in = optarg; - break; - case 'o': - args->file_out = optarg; - break; - case '?': /* help */ - err_msg("Usage: pddcustomize [OPTION...] " - "[key=value] [...]"); - err_msg("%s", doc); - err_msg("%s", optionsstr); - err_msg("\nReport bugs to %s", - PACKAGE_BUGREPORT); - exit(0); - break; - case 'V': - err_msg("%s", PROGRAM_VERSION); - exit(0); - break; - default: - err_msg("%s", usage); - exit(-1); - } - } - - if (optind < argc) { - rc = extract_pair(args->env_in, argv[optind++]); - if (rc != 0) - ERR_ARGP; - } - - return 0; -} - -static int -list_bootenv(bootenv_t env) -{ - int rc = 0; - rc = bootenv_write_txt(stdout, env); - if (rc != 0) { - err_msg("Cannot list bootenv/pdd. rc: %d\n", rc); - goto err; - } -err: - return rc; -} - -static int -process_key_value(bootenv_t env_in, bootenv_t env) -{ - int rc = 0; - size_t size, i; - const char* tmp; - const char** key_vec = NULL; - - rc = bootenv_get_key_vector(env_in, &size, 0, &key_vec); - if (rc != 0) - goto err; - - for (i = 0; i < size; i++) { - rc = bootenv_get(env_in, key_vec[i], &tmp); - if (rc != 0) { - err_msg("Cannot read value to input key: %s. rc: %d\n", - key_vec[i], rc); - goto err; - } - rc = bootenv_set(env, key_vec[i], tmp); - if (rc != 0) { - err_msg("Cannot set value key: %s. rc: %d\n", - key_vec[i], rc); - goto err; - } - } - -err: - if (key_vec != NULL) - free(key_vec); - return rc; -} - -static int -read_bootenv(const char* file, bootenv_t env) -{ - int rc = 0; - FILE* fp_in = NULL; - - fp_in = fopen(file, "rb"); - if (fp_in == NULL) { - err_msg("Cannot open file: %s\n", file); - return -EIO; - } - - rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); - if (rc != 0) { - err_msg("Cannot read bootenv from file %s. rc: %d\n", - file, rc); - goto err; - } - -err: - fclose(fp_in); - return rc; -} - -/* - * Read bootenv from ubi volume - */ -static int -ubi_read_bootenv(uint32_t devno, uint32_t id, bootenv_t env) -{ - libubi_t ulib; - int rc = 0; - char path[PATH_MAX]; - FILE* fp_in = NULL; - - ulib = libubi_open(); - if (ulib == NULL) { - err_msg("Cannot allocate ubi structure\n"); - return -1; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - fp_in = fopen(path, "r"); - if (fp_in == NULL) { - err_msg("Cannot open volume:%d number:%d\n", devno, id); - goto err; - } - - rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); - if (rc != 0) { - err_msg("Cannot read volume:%d number:%d\n", devno, id); - goto err; - } - -err: - if (fp_in) - fclose(fp_in); - libubi_close(ulib); - return rc; -} - -static int -write_bootenv(const char* file, bootenv_t env) -{ - int rc = 0; - FILE* fp_out; - - fp_out = fopen(file, "wb"); - if (fp_out == NULL) { - err_msg("Cannot open file: %s\n", file); - return -EIO; - } - - rc = bootenv_write(fp_out, env); - if (rc != 0) { - err_msg("Cannot write bootenv to file %s. rc: %d\n", file, rc); - goto err; - } - -err: - fclose(fp_out); - return rc; -} - -/* - * Read bootenv from ubi volume - */ -static int -ubi_write_bootenv(uint32_t devno, uint32_t id, bootenv_t env) -{ - libubi_t ulib; - int rc = 0; - char path[PATH_MAX]; - FILE* fp_out = NULL; - size_t nbytes ; - - rc = bootenv_size(env, &nbytes); - if (rc) { - err_msg("Cannot determine size of bootenv structure\n"); - return rc; - } - ulib = libubi_open(); - if (ulib == NULL) { - err_msg("Cannot allocate ubi structure\n"); - return rc; - } - - snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); - - fp_out = fopen(path, "r+"); - if (fp_out == NULL) { - err_msg("Cannot fopen volume:%d number:%d\n", devno, id); - goto err; - } - - rc = bootenv_write(fp_out, env); - if (rc != 0) { - err_msg("Cannot write bootenv to volume %d number:%d\n", - devno, id); - goto err; - } - -err: - if( fp_out ) - fclose(fp_out); - libubi_close(ulib); - return rc; -} - -static int -do_mirror(int volno) -{ - char errbuf[1024]; - uint32_t ids[2]; - int rc; - int src_volno_idx = 0; - - ids[0] = EXAMPLE_BOOTENV_VOL_ID_1; - ids[1] = EXAMPLE_BOOTENV_VOL_ID_2; - - if (volno == EXAMPLE_BOOTENV_VOL_ID_2) - src_volno_idx = 1; - - rc = ubimirror(EXAMPLE_UBI_DEVICE, src_volno_idx, ids, 2, errbuf, - sizeof errbuf); - if( rc ) - err_msg(errbuf); - return rc; -} - -int -main(int argc, char **argv) { - int rc = 0; - bootenv_t env = NULL; - uint32_t boot_volno; - myargs args = { - .action = ACT_NORMAL, - .file_in = NULL, - .file_out = NULL, - .side = -1, - .x86 = 0, - .both = 0, - .env_in = NULL, - - .arg1 = NULL, - .options = NULL, - }; - - rc = bootenv_create(&env); - if (rc != 0) { - err_msg("Cannot create bootenv handle. rc: %d", rc); - goto err; - } - - rc = bootenv_create(&(args.env_in)); - if (rc != 0) { - err_msg("Cannot create bootenv handle. rc: %d", rc); - goto err; - } - - parse_opt(argc, argv, &args); - if (args.action == ACT_ARGP_ERR) { - rc = -1; - goto err; - } - if (args.action == ACT_ARGP_ABORT) { - rc = 0; - goto out; - } - - if ((args.side == 0) || (args.side == -1)) - boot_volno = EXAMPLE_BOOTENV_VOL_ID_1; - else - boot_volno = EXAMPLE_BOOTENV_VOL_ID_2; - - if( args.x86 ) - rc = read_bootenv(args.file_in, env); - else - rc = ubi_read_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); - if (rc != 0) { - goto err; - } - - if (args.action == ACT_LIST) { - rc = list_bootenv(env); - if (rc != 0) { - goto err; - } - goto out; - } - - rc = process_key_value(args.env_in, env); - if (rc != 0) { - goto err; - } - - if( args.x86 ) - rc = write_bootenv(args.file_in, env); - else - rc = ubi_write_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); - if (rc != 0) { - goto err; - } - if( args.both ) /* No side specified, update both */ - rc = do_mirror(boot_volno); - - out: - err: - bootenv_destroy(&env); - bootenv_destroy(&(args.env_in)); - return rc; -} diff --git a/ubi-utils/sort-me-out/peb.c b/ubi-utils/sort-me-out/peb.c deleted file mode 100644 index 160a463..0000000 --- a/ubi-utils/sort-me-out/peb.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -#include "peb.h" - -int -peb_cmp(peb_t eb_1, peb_t eb_2) -{ - assert(eb_1); - assert(eb_2); - - return eb_1->num == eb_2->num ? 0 - : eb_1->num > eb_2->num ? 1 : -1; -} - -int -peb_new(uint32_t eb_num, uint32_t peb_size, peb_t *peb) -{ - int rc = 0; - - peb_t res = (peb_t) malloc(sizeof(struct peb)); - if (!res) { - rc = -ENOMEM; - goto err; - } - - res->num = eb_num; - res->size = peb_size; - res->data = (uint8_t*) malloc(res->size * sizeof(uint8_t)); - if (!res->data) { - rc = -ENOMEM; - goto err; - } - memset(res->data, 0xff, res->size); - - *peb = res; - return 0; -err: - if (res) { - if (res->data) - free(res->data); - free(res); - } - *peb = NULL; - return rc; -} - -int -peb_fill(peb_t peb, uint8_t* buf, size_t buf_size) -{ - if (!peb) - return -EINVAL; - - if (buf_size > peb->size) - return -EINVAL; - - memcpy(peb->data, buf, buf_size); - return 0; -} - -int -peb_write(FILE* fp_out, peb_t peb) -{ - size_t written = 0; - - if (peb == NULL) - return -EINVAL; - - written = fwrite(peb->data, 1, peb->size, fp_out); - - if (written != peb->size) - return -EIO; - - return 0; -} - -int -peb_free(peb_t* peb) -{ - peb_t tmp = *peb; - if (tmp) { - if (tmp->data) - free(tmp->data); - free(tmp); - } - *peb = NULL; - - return 0; -} - -void peb_dump(FILE* fp_out, peb_t peb) -{ - fprintf(fp_out, "num: %08d\tsize: 0x%08x\n", peb->num, peb->size); -} diff --git a/ubi-utils/sort-me-out/peb.h b/ubi-utils/sort-me-out/peb.h deleted file mode 100644 index 246bce8..0000000 --- a/ubi-utils/sort-me-out/peb.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __RAW_BLOCK_H__ -#define __RAW_BLOCK_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: Oliver Lohmann - */ - -#include <stdint.h> -#include <stdio.h> - -typedef struct peb *peb_t; -struct peb { - uint32_t num; /* Physical eraseblock number - * in the RAW file. */ - uint32_t size; /* Data Size (equals physical - * erase block size) */ - uint8_t* data; /* Data buffer */ -}; - -int peb_new(uint32_t peb_num, uint32_t peb_size, peb_t* peb); -int peb_free(peb_t* peb); -int peb_cmp(peb_t peb_1, peb_t peb_2); -int peb_write(FILE* fp_out, peb_t peb); -void peb_dump(FILE* fp_out, peb_t peb); - -#endif /* __RAW_BLOCK_H__ */ diff --git a/ubi-utils/sort-me-out/pfi.c b/ubi-utils/sort-me-out/pfi.c deleted file mode 100644 index fa835e2..0000000 --- a/ubi-utils/sort-me-out/pfi.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * 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. - */ - -/* - * @file pfi.c - * - * @author Oliver Lohmann - * Andreas Arnez - * Joern Engel - * Frank Haverkamp - * - * @brief libpfi holds all code to create and process pfi files. - * - * <oliloh@de.ibm.com> Wed Feb 8 11:38:22 CET 2006: Initial creation. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <syslog.h> -#include <stdarg.h> -#include <errno.h> - -#include "pfi.h" - -#define PFI_MAGIC "PFI!\n" -#define PFI_DATA "DATA\n" /* The same size as PFI_MAGIC */ -#define PFI_MAGIC_LEN 5 - -static const char copyright [] __attribute__((unused)) = - "Copyright (c) International Business Machines Corp., 2006"; - -enum key_id { - /* version 1 */ - key_version, /* must be index position 0! */ - key_mode, - key_size, - key_crc, - key_label, - key_flags, - key_ubi_ids, - key_ubi_size, - key_ubi_type, - key_ubi_names, - key_ubi_alignment, - key_raw_starts, - key_raw_total_size, - num_keys, -}; - -struct pfi_header { - char defined[num_keys]; /* reserve all possible keys even if - version does not require this. */ - int mode_no; /* current mode no. -> can only increase */ - union { - char *str; - uint32_t num; - } value[num_keys]; -}; - - -#define PFI_MANDATORY 0x0001 -#define PFI_STRING 0x0002 -#define PFI_LISTVALUE 0x0004 /* comma seperated list of nums */ -#define PFI_MANDATORY_UBI 0x0008 -#define PFI_MANDATORY_RAW 0x0010 - -struct key_descriptor { - enum key_id id; - const char *name; - uint32_t flags; -}; - -static const struct key_descriptor key_desc_v1[] = { - { key_version, "version", PFI_MANDATORY }, - { key_mode, "mode", PFI_MANDATORY | PFI_STRING }, - { key_size, "size", PFI_MANDATORY }, - { key_crc, "crc", PFI_MANDATORY }, - { key_label, "label", PFI_MANDATORY | PFI_STRING }, - { key_flags, "flags", PFI_MANDATORY }, - { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI }, - { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI }, - { key_raw_starts, "raw_starts", PFI_MANDATORY_RAW | PFI_STRING }, - { key_raw_total_size, "raw_total_size", PFI_MANDATORY_RAW }, -}; - -static const struct key_descriptor *key_descriptors[] = { - NULL, - key_desc_v1, /* version 1 */ -}; - -static const int key_descriptors_max[] = { - 0, /* version 0 */ - sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */ -}; - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -static const char* modes[] = {"raw", "ubi"}; /* order isn't arbitrary! */ - -/* latest version contains all possible keys */ -static const struct key_descriptor *key_desc = key_desc_v1; - -#define PFI_IS_UBI(mode) \ - (((mode) != NULL) && (strcmp("ubi", (mode)) == 0)) - -#define PFI_IS_RAW(mode) \ - (((mode) != NULL) && (strcmp("raw", (mode)) == 0)) - -/** - * @return <0 On Error. - * >=0 Mode no. - */ -static int -get_mode_no(const char* mode) -{ - int i; - - for (i = 0; i < (int)ARRAY_SIZE(modes); i++) - if (strcmp(mode, modes[i]) == 0) - return i; - return -1; -} - -static int -find_key_by_name (const char *name) -{ - int i; - - for (i = 0; i < num_keys; i++) { - if (strcmp(name, key_desc[i].name) == 0) - return i; - } - return -1; -} - -static int -check_valid (pfi_header head) -{ - int i; - int max_keys; - uint32_t version; - const char *mode; - const struct key_descriptor *desc; - uint32_t to_check = PFI_MANDATORY; - - /* - * For the validity check the list of possible keys depends on - * the version of the PFI file used. - */ - version = head->value[key_version].num; - if (version > PFI_HDRVERSION) - return PFI_ENOHEADER; - - max_keys = key_descriptors_max[version]; - desc = key_descriptors[version]; - - if (!desc) - return PFI_ENOVERSION; - - mode = head->value[key_mode].str; - if (PFI_IS_UBI(mode)) { - to_check |= PFI_MANDATORY_UBI; - } - else if (PFI_IS_RAW(mode)) { - to_check |= PFI_MANDATORY_RAW; - } - else { /* neither UBI nor RAW == ERR */ - return PFI_EINSUFF; - } - - for (i = 0; i < max_keys; i++) { - if ((desc[i].flags & to_check) && !head->defined[i]) { - fprintf(stderr, "libpfi: %s missing\n", desc[i].name); - return PFI_EINSUFF; - } - } - - return 0; -} - -int pfi_header_init (pfi_header *head) -{ - int i; - pfi_header self = (pfi_header) malloc(sizeof(*self)); - - *head = self; - if (self == NULL) - return PFI_ENOMEM; - - /* initialize maximum number of possible keys */ - for (i = 0; i < num_keys; i++) { - memset(self, 0, sizeof(*self)); - self->defined[i] = 0; - } - - return 0; -} - -int pfi_header_destroy (pfi_header *head) -{ - int i; - pfi_header self = *head; - - for (i = 0; i < num_keys; i++) { - if (self->defined[i] && (key_desc[i].flags & PFI_STRING) && - self->value[i].str) { - free(self->value[i].str); - } - } - free(*head); - *head = NULL; - return 0; -} - -int pfi_header_setnumber (pfi_header head, - const char *key, uint32_t value) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) - return PFI_EBADTYPE; - - head->value[key_id].num = value; - head->defined[key_id] = 1; - return 0; -} - -int pfi_header_setvalue (pfi_header head, - const char *key, const char *value) -{ - int key_id = find_key_by_name(key); - - if (value == NULL) - return PFI_EINSUFF; - - if ((key_id < 0) || (key_id >= num_keys)) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) { - /* - * The value is a string. Copy to a newly allocated - * buffer. Delete the old value, if already set. - */ - size_t len = strlen(value) + 1; - char *old_str = NULL; - char *str; - - old_str = head->value[key_id].str; - if (old_str != NULL) - free(old_str); - - str = head->value[key_id].str = (char *) malloc(len); - if (str == NULL) - return PFI_ENOMEM; - - strcpy(str, value); - } else { - int len; - int ret; - /* FIXME: here we assume that the value is always - given in hex and starts with '0x'. */ - ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len); - if (ret < 1 || value[len] != '\0') - return PFI_EBADTYPE; - } - head->defined[key_id] = 1; - return 0; -} - -int pfi_header_getnumber (pfi_header head, - const char *key, uint32_t *value) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) - return PFI_EBADTYPE; - - if (!head->defined[key_id]) - return PFI_EUNDEF; - - *value = head->value[key_id].num; - return 0; -} - -int pfi_header_getstring (pfi_header head, - const char *key, char *value, size_t size) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (!(key_desc[key_id].flags & PFI_STRING)) - return PFI_EBADTYPE; - - if (!head->defined[key_id]) - return PFI_EUNDEF; - - strncpy(value, head->value[key_id].str, size-1); - value[size-1] = '\0'; - return 0; -} - -int pfi_header_write (FILE *out, pfi_header head) -{ - int i; - int ret; - - pfi_header_setnumber(head, "version", PFI_HDRVERSION); - - if ((ret = check_valid(head)) != 0) - return ret; - - /* OK. Now write the header. */ - - ret = fwrite(PFI_MAGIC, 1, PFI_MAGIC_LEN, out); - if (ret < PFI_MAGIC_LEN) - return ret; - - - for (i = 0; i < num_keys; i++) { - if (!head->defined[i]) - continue; - - ret = fprintf(out, "%s=", key_desc[i].name); - if (ret < 0) - return PFI_EFILE; - - if (key_desc[i].flags & PFI_STRING) { - ret = fprintf(out, "%s", head->value[i].str); - if (ret < 0) - return PFI_EFILE; - } else { - ret = fprintf(out, "0x%8x", head->value[i].num); - if (ret < 0) - return PFI_EFILE; - - } - ret = fprintf(out, "\n"); - if (ret < 0) - return PFI_EFILE; - } - ret = fprintf(out, "\n"); - if (ret < 0) - return PFI_EFILE; - - ret = fflush(out); - if (ret != 0) - return PFI_EFILE; - - return 0; -} - -int pfi_header_read (FILE *in, pfi_header head) -{ - char magic[PFI_MAGIC_LEN]; - char mode[PFI_KEYWORD_LEN]; - char buf[256]; - - if (PFI_MAGIC_LEN != fread(magic, 1, PFI_MAGIC_LEN, in)) - return PFI_EFILE; - if (memcmp(magic, PFI_MAGIC, PFI_MAGIC_LEN) != 0) { - if (memcmp(magic, PFI_DATA, PFI_MAGIC_LEN) == 0) { - return PFI_DATA_START; - } - return PFI_ENOHEADER; - } - - while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') { - char *value; - char *end; - value = strchr(buf, '='); - if (value == NULL) - return PFI_ENOHEADER; - - *value = '\0'; - value++; - end = strchr(value, '\n'); - if (end) - *end = '\0'; - - if (pfi_header_setvalue(head, buf, value)) - return PFI_ENOHEADER; - } - - if (check_valid(head) != 0) - return PFI_ENOHEADER; - - /* set current mode no. in head */ - pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN); - if (head->mode_no > get_mode_no(mode)) { - return PFI_EMODE; - } - head->mode_no = get_mode_no(mode); - return 0; -} - -int pfi_header_dump (FILE *out, pfi_header head __attribute__((__unused__))) -{ - fprintf(out, "Sorry not implemented yet. Write mail to " - "Andreas Arnez and complain!\n"); - return 0; -} - -int pfi_read (FILE *in, pfi_read_func func, void *priv_data) -{ - int rc; - pfi_header header; - - rc = pfi_header_init (&header); - if (0 != rc) - return rc; - if (!func) - return PFI_EINVAL; - - while ((0 == rc) && !feof(in)) { - /* - * Read header and check consistency of the fields. - */ - rc = pfi_header_read( in, header ); - if (0 != rc) - break; - if (func) { - rc = func(in, header, priv_data); - if (rc != 0) - break; - } - } - - pfi_header_destroy(&header); - return rc; -} diff --git a/ubi-utils/sort-me-out/pfi.h b/ubi-utils/sort-me-out/pfi.h deleted file mode 100644 index 8c5cc07..0000000 --- a/ubi-utils/sort-me-out/pfi.h +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef __pfi_h -#define __pfi_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. - */ - -/** - * @file pfi.h - * - * @author Oliver Lohmann <oliloh@de.ibm.com> - * Andreas Arnez <arnez@de.ibm.com> - * Joern Engel <engeljoe@de.ibm.com> - * Frank Haverkamp <haverkam@de.ibm.com> - * - * @brief libpfi will hold all code to create and process pfi - * images. Definitions made in this file are equaly usable for the - * development host and the target system. - * - * @note This header additionally holds the official definitions for - * the pfi headers. - */ - -#include <stdio.h> /* FILE */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Definitions. */ - -#define PFI_HDRVERSION 1 /* current header version */ - -#define PFI_ENOVERSION 1 /* unknown version */ -#define PFI_ENOHEADER 2 /* not a pfi header */ -#define PFI_EINSUFF 3 /* insufficient information */ -#define PFI_EUNDEF 4 /* key not defined */ -#define PFI_ENOMEM 5 /* out of memory */ -#define PFI_EBADTYPE 6 /* bad data type */ -#define PFI_EFILE 7 /* file I/O error: see errno */ -#define PFI_EFILEINVAL 8 /* file format not valid */ -#define PFI_EINVAL 9 /* invalid parameter */ -#define PFI_ERANGE 10 /* invalid range */ -#define PFI_EMODE 11 /* expecting other mode in this header */ -#define PFI_DATA_START 12 /* data section starts */ -#define PFI_EMAX 13 /* should be always larger as the largest - error code */ - -#define PFI_LABEL_LEN 64 /* This is the maximum length for a - PFI header label */ -#define PFI_KEYWORD_LEN 32 /* This is the maximum length for an - entry in the mode and type fields */ - -#define PFI_UBI_MAX_VOLUMES 128 -#define PFI_UBI_VOL_NAME_LEN 127 - -/** - * @brief The pfi header allows to set flags which influence the flashing - * behaviour. - */ -#define PFI_FLAG_PROTECTED 0x00000001 - - -/** - * @brief Handle to pfi header. Used in most of the functions associated - * with pfi file handling. - */ -typedef struct pfi_header *pfi_header; - - -/** - * @brief Initialize a pfi header object. - * - * @param head Pointer to handle. This function allocates memory - * for this data structure. - * @return 0 on success, otherwise: - * PFI_ENOMEM : no memory available for the handle. - */ -int pfi_header_init (pfi_header *head); - - -/** - * @brief Destroy a pfi header object. - * - * @param head handle. head is invalid after calling this function. - * @return 0 always. - */ -int pfi_header_destroy (pfi_header *head); - - -/** - * @brief Add a key/value pair to a pfi header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value string. Must be 0 terminated. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_ENOMEM : no memory available for the handle. - * PFI_EBADTYPE : value is not an hex string. This happens - * when the key stores an integer and the - * new value is not convertable e.g. not in - * 0xXXXXXXXX format. - */ -int pfi_header_setvalue (pfi_header head, - const char *key, const char *value); - - -/** - * @brief Add a key/value pair to a pfi header object. Provide the - * value as a number. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value value to set. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : value is not a string. This happens - * when the key stores a string. - */ -int pfi_header_setnumber (pfi_header head, - const char *key, uint32_t value); - - -/** - * @brief For a given key, return the numerical value stored in a - * pfi header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : stored value is not an integer but a string. - */ -int pfi_header_getnumber (pfi_header head, - const char *key, uint32_t *value); - - -static inline uint32_t -pfi_getnumber(pfi_header head, const char *key) -{ - uint32_t value; - pfi_header_getnumber(head, key, &value); - return value; -} - -/** - * @brief For a given key, return the string value stored in a pfi - * header object. - * - * @param head handle. - * @param key pointer to key string. Must be 0 terminated. - * @param value pointer to value string. Memory must be allocated by the user. - * @return 0 on success, otherwise: - * PFI_EUNDEF : key was not found. - * PFI_EBADTYPE : stored value is not a string but an integer. - */ -int pfi_header_getstring (pfi_header head, - const char *key, char *value, size_t size); - - -/** - * @brief Write a pfi header object into a given file. - * - * @param out output stream. - * @param head handle. - * @return 0 on success, error values otherwise: - * PFI_EINSUFF : not all mandatory fields are filled. - * PFI_ENOHEADER : wrong header version or magic number. - * -E* : see <asm/errno.h>. - */ -int pfi_header_write (FILE *out, pfi_header head); - - -/** - * @brief Read a pfi header object from a given file. - * - * @param in input stream. - * @param head handle. - * @return 0 on success, error values otherwise: - * PFI_ENOVERSION: unknown header version. - * PFI_EFILE : cannot read enough data. - * PFI_ENOHEADER : wrong header version or magic number. - * -E* : see <asm/errno.h>. - * - * If the header verification returned success the user can assume that - * all mandatory fields for a particular version are accessible. Checking - * the return code when calling the get-function for those keys is not - * required in those cases. For optional fields the checking must still be - * done. - */ -int pfi_header_read (FILE *in, pfi_header head); - - -/** - * @brief Display a pfi header in human-readable form. - * - * @param out output stream. - * @param head handle. - * @return always 0. - * - * @note Prints out that it is not implemented and whom you should - * contact if you need it urgently!. - */ -int pfi_header_dump (FILE *out, pfi_header head); - - -/* - * @brief Iterates over a stream of pfi files. The iterator function - * must advance the file pointer in FILE *in to the next pfi - * header. Function exists on feof(in). - * - * @param in input file descriptor, must be open and valid. - * @param func iterator function called when pfi header could be - * read and was validated. The function must return 0 on - * success. - * @return See pfi_header_init and pfi_header_read. - * PFI_EINVAL : func is not valid - * 0 ok. - */ -typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data); - -int pfi_read (FILE *in, pfi_read_func func, void *priv_data); - - -#ifdef __cplusplus -} -#endif - -#endif /* __pfi_h */ diff --git a/ubi-utils/sort-me-out/pfi2bin.c b/ubi-utils/sort-me-out/pfi2bin.c deleted file mode 100644 index 7f31938..0000000 --- a/ubi-utils/sort-me-out/pfi2bin.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - * 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: Oliver Lohmann - * - * Convert a PFI file (partial flash image) into a plain binary file. - * This tool can be used to prepare the data to be burned into flash - * chips in a manufacturing step where the flashes are written before - * being soldered onto the hardware. For NAND images another step is - * required to add the right OOB data to the binary image. - * - * 1.3 Removed argp because we want to use uClibc. - * 1.4 Minor cleanups - */ - -#include <stdlib.h> -#include <stdint.h> -#include <getopt.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <errno.h> - -#include <ubigen.h> -#include <mtd/ubi-header.h> - -#include "config.h" -#include "list.h" -#include "error.h" -#include "reader.h" -#include "peb.h" -#include "crc32.h" - -#define PROGRAM_VERSION "1.4" - -#define MAX_FNAME 255 -#define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */ -#define ERR_BUF_SIZE 1024 - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -static uint32_t crc32_table[256]; -static char err_buf[ERR_BUF_SIZE]; - -/* - * Data used to buffer raw blocks which have to be - * located at a specific point inside the generated RAW file - */ - -typedef enum action_t { - ACT_NOTHING = 0x00000000, - ACT_RAW = 0x00000001, -} action_t; - -static const char copyright [] __attribute__((unused)) = - "(c) Copyright IBM Corp 2006\n"; - -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "pfi2bin - a tool to convert PFI files into binary images.\n"; - -static const char *optionsstr = -" Common settings:\n" -" -c, --copyright\n" -" -v, --verbose Print more information.\n" -"\n" -" Input:\n" -" -j, --platform=pdd-file PDD information which contains the card settings.\n" -"\n" -" Output:\n" -" -o, --output=filename Outputfile, default: stdout.\n" -"\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" -V, --version Print program version\n"; - -static const char *usage = -"Usage: pfi2bin [-cv?V] [-j pdd-file] [-o filename] [--copyright]\n" -" [--verbose] [--platform=pdd-file] [--output=filename] [--help]\n" -" [--usage] [--version] pfifile\n"; - -struct option long_options[] = { - { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, - { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, - { .name = "platform", .has_arg = 1, .flag = NULL, .val = 'j' }, - { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -typedef struct io { - FILE* fp_pdd; /* a FilePointer to the PDD data */ - FILE* fp_pfi; /* a FilePointer to the PFI input stream */ - FILE* fp_out; /* a FilePointer to the output stream */ -} *io_t; - -typedef struct myargs { - /* common settings */ - action_t action; - int verbose; - const char *f_in_pfi; - const char *f_in_pdd; - const char *f_out; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static int -parse_opt(int argc, char **argv, myargs *args) -{ - while (1) { - int key; - - key = getopt_long(argc, argv, "cvj:o:?V", long_options, NULL); - if (key == -1) - break; - - switch (key) { - /* common settings */ - case 'v': /* --verbose=<level> */ - args->verbose = 1; - break; - - case 'c': /* --copyright */ - fprintf(stderr, "%s\n", copyright); - exit(0); - break; - - case 'j': /* --platform */ - args->f_in_pdd = optarg; - break; - - case 'o': /* --output */ - args->f_out = optarg; - break; - - case '?': /* help */ - printf("pfi2bin [OPTION...] pfifile\n"); - printf("%s", doc); - printf("%s", optionsstr); - printf("\nReport bugs to %s\n", - PACKAGE_BUGREPORT); - exit(0); - break; - - case 'V': - printf("%s\n", PROGRAM_VERSION); - exit(0); - break; - - default: - printf("%s", usage); - exit(-1); - } - } - - if (optind < argc) - args->f_in_pfi = argv[optind++]; - - return 0; -} - - -static size_t -byte_to_blk(size_t byte, size_t blk_size) -{ - return (byte % blk_size) == 0 - ? byte / blk_size - : byte / blk_size + 1; -} - - - - -/** - * @precondition IO: File stream points to first byte of RAW data. - * @postcondition IO: File stream points to first byte of next - * or EOF. - */ -static int -memorize_raw_eb(pfi_raw_t pfi_raw, pdd_data_t pdd, list_t *raw_pebs, - io_t io) -{ - int rc = 0; - uint32_t i; - - size_t read, to_read, eb_num; - size_t bytes_left; - list_t pebs = *raw_pebs; - peb_t peb = NULL; - - long old_file_pos = ftell(io->fp_pfi); - for (i = 0; i < pfi_raw->starts_size; i++) { - bytes_left = pfi_raw->data_size; - rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); - if (rc != 0) - goto err; - - eb_num = byte_to_blk(pfi_raw->starts[i], pdd->eb_size); - while (bytes_left) { - to_read = MIN(bytes_left, pdd->eb_size); - rc = peb_new(eb_num++, pdd->eb_size, &peb); - if (rc != 0) - goto err; - read = fread(peb->data, 1, to_read, io->fp_pfi); - if (read != to_read) { - rc = -EIO; - goto err; - } - pebs = append_elem(peb, pebs); - bytes_left -= read; - } - - } - *raw_pebs = pebs; - return 0; -err: - pebs = remove_all((free_func_t)&peb_free, pebs); - return rc; -} - -static int -convert_ubi_volume(pfi_ubi_t ubi, pdd_data_t pdd, list_t raw_pebs, - struct ubi_vtbl_record *vol_tab, - size_t *ebs_written, io_t io) -{ - int rc = 0; - uint32_t i, j; - peb_t raw_peb; - peb_t cmp_peb; - ubi_info_t u; - size_t leb_total = 0; - uint8_t vol_type; - - switch (ubi->type) { - case pfi_ubi_static: - vol_type = UBI_VID_STATIC; break; - case pfi_ubi_dynamic: - vol_type = UBI_VID_DYNAMIC; break; - default: - vol_type = UBI_VID_DYNAMIC; - } - - rc = peb_new(0, 0, &cmp_peb); - if (rc != 0) - goto err; - - long old_file_pos = ftell(io->fp_pfi); - for (i = 0; i < ubi->ids_size; i++) { - rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); - if (rc != 0) - goto err; - rc = ubigen_create(&u, ubi->ids[i], vol_type, - pdd->eb_size, DEFAULT_ERASE_COUNT, - ubi->alignment, UBI_VERSION, - pdd->vid_hdr_offset, 0, ubi->data_size, - io->fp_pfi, io->fp_out); - if (rc != 0) - goto err; - - rc = ubigen_get_leb_total(u, &leb_total); - if (rc != 0) - goto err; - - j = 0; - while(j < leb_total) { - cmp_peb->num = *ebs_written; - raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, - raw_pebs); - if (raw_peb) { - rc = peb_write(io->fp_out, raw_peb); - } - else { - rc = ubigen_write_leb(u, NO_ERROR); - j++; - } - if (rc != 0) - goto err; - (*ebs_written)++; - } - /* memorize volume table entry */ - rc = ubigen_set_lvol_rec(u, ubi->size, - ubi->names[i], - (void*) &vol_tab[ubi->ids[i]]); - if (rc != 0) - goto err; - ubigen_destroy(&u); - } - - peb_free(&cmp_peb); - return 0; - -err: - peb_free(&cmp_peb); - ubigen_destroy(&u); - return rc; -} - - -static FILE* -my_fmemopen (void *buf, size_t size, const char *opentype) -{ - FILE* f; - size_t ret; - - assert(strcmp(opentype, "r") == 0); - - f = tmpfile(); - ret = fwrite(buf, 1, size, f); - rewind(f); - - return f; -} - -/** - * @brief Builds a UBI volume table from a volume entry list. - * @return 0 On success. - * else Error. - */ -static int -write_ubi_volume_table(pdd_data_t pdd, list_t raw_pebs, - struct ubi_vtbl_record *vol_tab, size_t vol_tab_size, - size_t *ebs_written, io_t io) -{ - int rc = 0; - ubi_info_t u; - peb_t raw_peb; - peb_t cmp_peb; - size_t leb_size, leb_total, j = 0; - uint8_t *ptr = NULL; - FILE* fp_leb = NULL; - int vt_slots; - size_t vol_tab_size_limit; - - rc = peb_new(0, 0, &cmp_peb); - if (rc != 0) - goto err; - - /* @FIXME: Artem creates one volume with 2 LEBs. - * IMO 2 volumes would be more convenient. In order - * to get 2 reserved LEBs from ubigen, I have to - * introduce this stupid mechanism. Until no final - * decision of the VTAB structure is made... Good enough. - */ - rc = ubigen_create(&u, UBI_LAYOUT_VOL_ID, UBI_VID_DYNAMIC, - pdd->eb_size, DEFAULT_ERASE_COUNT, - 1, UBI_VERSION, - pdd->vid_hdr_offset, UBI_COMPAT_REJECT, - vol_tab_size, stdin, io->fp_out); - /* @FIXME stdin for fp_in is a hack */ - if (rc != 0) - goto err; - rc = ubigen_get_leb_size(u, &leb_size); - if (rc != 0) - goto err; - ubigen_destroy(&u); - - /* - * The number of supported volumes is restricted by the eraseblock size - * and by the UBI_MAX_VOLUMES constant. - */ - vt_slots = leb_size / UBI_VTBL_RECORD_SIZE; - if (vt_slots > UBI_MAX_VOLUMES) - vt_slots = UBI_MAX_VOLUMES; - vol_tab_size_limit = vt_slots * UBI_VTBL_RECORD_SIZE; - - ptr = (uint8_t*) malloc(leb_size * sizeof(uint8_t)); - if (ptr == NULL) - goto err; - - memset(ptr, 0xff, leb_size); - memcpy(ptr, vol_tab, vol_tab_size_limit); - fp_leb = my_fmemopen(ptr, leb_size, "r"); - - rc = ubigen_create(&u, UBI_LAYOUT_VOL_ID, UBI_VID_DYNAMIC, - pdd->eb_size, DEFAULT_ERASE_COUNT, - 1, UBI_VERSION, pdd->vid_hdr_offset, - UBI_COMPAT_REJECT, leb_size * UBI_LAYOUT_VOLUME_EBS, - fp_leb, io->fp_out); - if (rc != 0) - goto err; - rc = ubigen_get_leb_total(u, &leb_total); - if (rc != 0) - goto err; - - long old_file_pos = ftell(fp_leb); - while(j < leb_total) { - rc = fseek(fp_leb, old_file_pos, SEEK_SET); - if (rc != 0) - goto err; - - cmp_peb->num = *ebs_written; - raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, - raw_pebs); - if (raw_peb) { - rc = peb_write(io->fp_out, raw_peb); - } - else { - rc = ubigen_write_leb(u, NO_ERROR); - j++; - } - - if (rc != 0) - goto err; - (*ebs_written)++; - } - -err: - free(ptr); - peb_free(&cmp_peb); - ubigen_destroy(&u); - fclose(fp_leb); - return rc; -} - -static int -write_remaining_raw_ebs(pdd_data_t pdd, list_t raw_blocks, size_t *ebs_written, - FILE* fp_out) -{ - int rc = 0; - uint32_t j, delta; - list_t ptr; - peb_t empty_eb, peb; - - /* create an empty 0xff EB (for padding) */ - rc = peb_new(0, pdd->eb_size, &empty_eb); - - foreach(peb, ptr, raw_blocks) { - if (peb->num < *ebs_written) { - continue; /* omit blocks which - are already passed */ - } - - if (peb->num < *ebs_written) { - err_msg("eb_num: %d\n", peb->num); - err_msg("Bug: This should never happen. %d %s", - __LINE__, __FILE__); - goto err; - } - - delta = peb->num - *ebs_written; - if (((delta + *ebs_written) * pdd->eb_size) > pdd->flash_size) { - err_msg("RAW block outside of flash_size."); - goto err; - } - for (j = 0; j < delta; j++) { - rc = peb_write(fp_out, empty_eb); - if (rc != 0) - goto err; - (*ebs_written)++; - } - rc = peb_write(fp_out, peb); - if (rc != 0) - goto err; - (*ebs_written)++; - } - -err: - peb_free(&empty_eb); - return rc; -} - -static int -init_vol_tab(struct ubi_vtbl_record **vol_tab, size_t *vol_tab_size) -{ - uint32_t crc; - size_t i; - struct ubi_vtbl_record* res = NULL; - - *vol_tab_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; - - res = (struct ubi_vtbl_record*) calloc(1, *vol_tab_size); - if (vol_tab == NULL) { - return -ENOMEM; - } - - for (i = 0; i < UBI_MAX_VOLUMES; i++) { - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - &(res[i]), UBI_VTBL_RECORD_SIZE_CRC); - res[i].crc = __cpu_to_be32(crc); - } - - *vol_tab = res; - return 0; -} - -static int -create_raw(io_t io) -{ - int rc = 0; - size_t ebs_written = 0; /* eraseblocks written already... */ - size_t vol_tab_size; - list_t ptr; - - list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ - list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ - list_t raw_pebs = mk_empty(); /* list of raw eraseblocks */ - - struct ubi_vtbl_record *vol_tab = NULL; - pdd_data_t pdd = NULL; - - rc = init_vol_tab (&vol_tab, &vol_tab_size); - if (rc != 0) { - err_msg("Cannot initialize volume table."); - goto err; - } - - rc = read_pdd_data(io->fp_pdd, &pdd, - err_buf, ERR_BUF_SIZE); - if (rc != 0) { - err_msg("Cannot read necessary pdd_data: %s rc: %d", - err_buf, rc); - goto err; - } - - rc = read_pfi_headers(&pfi_raws, &pfi_ubis, io->fp_pfi, - err_buf, ERR_BUF_SIZE); - if (rc != 0) { - err_msg("Cannot read pfi header: %s rc: %d", - err_buf, rc); - goto err; - } - - pfi_raw_t pfi_raw; - foreach(pfi_raw, ptr, pfi_raws) { - rc = memorize_raw_eb(pfi_raw, pdd, &raw_pebs, - io); - if (rc != 0) { - err_msg("Cannot create raw_block in mem. rc: %d\n", - rc); - goto err; - } - } - - pfi_ubi_t pfi_ubi; - foreach(pfi_ubi, ptr, pfi_ubis) { - rc = convert_ubi_volume(pfi_ubi, pdd, raw_pebs, - vol_tab, &ebs_written, io); - if (rc != 0) { - err_msg("Cannot convert UBI volume. rc: %d\n", rc); - goto err; - } - } - - rc = write_ubi_volume_table(pdd, raw_pebs, vol_tab, vol_tab_size, - &ebs_written, io); - if (rc != 0) { - err_msg("Cannot write UBI volume table. rc: %d\n", rc); - goto err; - } - - rc = write_remaining_raw_ebs(pdd, raw_pebs, &ebs_written, io->fp_out); - if (rc != 0) - goto err; - - if (io->fp_out != stdout) - info_msg("Physical eraseblocks written: %8d\n", ebs_written); -err: - free(vol_tab); - pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); - pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); - raw_pebs = remove_all((free_func_t)&peb_free, raw_pebs); - free_pdd_data(&pdd); - return rc; -} - - -/* ------------------------------------------------------------------------- */ -static void -open_io_handle(myargs *args, io_t io) -{ - /* set PDD input */ - io->fp_pdd = fopen(args->f_in_pdd, "r"); - if (io->fp_pdd == NULL) { - err_sys("Cannot open: %s", args->f_in_pdd); - } - - /* set PFI input */ - io->fp_pfi = fopen(args->f_in_pfi, "r"); - if (io->fp_pfi == NULL) { - err_sys("Cannot open PFI input file: %s", args->f_in_pfi); - } - - /* set output prefix */ - if (strcmp(args->f_out,"") == 0) - io->fp_out = stdout; - else { - io->fp_out = fopen(args->f_out, "wb"); - if (io->fp_out == NULL) { - err_sys("Cannot open output file: %s", args->f_out); - } - } -} - -static void -close_io_handle(io_t io) -{ - if (fclose(io->fp_pdd) != 0) { - err_sys("Cannot close PDD file."); - } - if (fclose(io->fp_pfi) != 0) { - err_sys("Cannot close PFI file."); - } - if (io->fp_out != stdout) { - if (fclose(io->fp_out) != 0) { - err_sys("Cannot close output file."); - } - } - - io->fp_pdd = NULL; - io->fp_pfi = NULL; - io->fp_out = NULL; -} - -int -main(int argc, char *argv[]) -{ - int rc = 0; - - ubigen_init(); - init_crc32_table(crc32_table); - - struct io io = {NULL, NULL, NULL}; - myargs args = { - .action = ACT_RAW, - .verbose = 0, - - .f_in_pfi = "", - .f_in_pdd = "", - .f_out = "", - - /* arguments */ - .arg1 = NULL, - .options = NULL, - }; - - /* parse arguments */ - parse_opt(argc, argv, &args); - - if (strcmp(args.f_in_pfi, "") == 0) { - err_quit("No PFI input file specified!"); - } - - if (strcmp(args.f_in_pdd, "") == 0) { - err_quit("No PDD input file specified!"); - } - - open_io_handle(&args, &io); - - info_msg("[ Creating RAW..."); - rc = create_raw(&io); - if (rc != 0) { - err_msg("Creating RAW failed."); - goto err; - } - -err: - close_io_handle(&io); - if (rc != 0) { - remove(args.f_out); - } - - return rc; -} diff --git a/ubi-utils/sort-me-out/pfiflash.c b/ubi-utils/sort-me-out/pfiflash.c deleted file mode 100644 index 754fe33..0000000 --- a/ubi-utils/sort-me-out/pfiflash.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 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: Oliver Lohmann - * Frank Haverkamp - * - * Process a PFI (partial flash image) and write the data to the - * specified UBI volumes. This tool is intended to be used for system - * update using PFI files. - * - * 1.1 fixed output to stderr and stdout in logfile mode. - * 1.2 updated. - * 1.3 removed argp parsing to be able to use uClib. - * 1.4 Minor cleanups. - * 1.5 Forgot to delete raw block before updating it. - * 1.6 Migrated to new libubi. - */ - -#include <unistd.h> -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <unistd.h> -#include <errno.h> - -#include <pfiflash.h> -#undef DEBUG -#include "error.h" -#include "config.h" - -#define PROGRAM_VERSION "1.6" - -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "pfiflash - a tool for updating a controller with PFI files.\n"; - -static const char *optionsstr = -" Standard options:\n" -" -c, --copyright Print copyright information.\n" -" -l, --logfile=<file> Write a logfile to <file>.\n" -" -v, --verbose Be verbose during program execution.\n" -"\n" -" Process options:\n" -" -C, --complete Execute a complete system update. Updates both\n" -" sides.\n" -" -p, --pdd-update=<type> Specify the pdd-update algorithm. <type> is either\n" -" 'keep', 'merge' or 'overwrite'.\n" -" -r, --raw-flash=<dev> Flash the raw data. Use the specified mtd device.\n" -" -s, --side=<seqnum> Select the side which shall be updated.\n" -" -x, --compare Only compare on-flash and pfi data, print info if\n" -" an update is neccessary and return appropriate\n" -" error code.\n" -"\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" -V, --version Print program version\n"; - -static const char *usage = -"Usage: pfiflash [-cvC?V] [-l <file>] [-p <type>] [-r <dev>] [-s <seqnum>]\n" -" [--copyright] [--logfile=<file>] [--verbose] [--complete]\n" -" [--pdd-update=<type>] [--raw-flash=<dev>] [--side=<seqnum>]\n" -" [--compare] [--help] [--usage] [--version] [pfifile]\n"; - -static const char copyright [] __attribute__((unused)) = - "Copyright IBM Corp 2006"; - -struct option long_options[] = { - { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, - { .name = "logfile", .has_arg = 1, .flag = NULL, .val = 'l' }, - { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, - { .name = "complete", .has_arg = 0, .flag = NULL, .val = 'C' }, - { .name = "pdd-update", .has_arg = 1, .flag = NULL, .val = 'p' }, - { .name = "raw-flash", .has_arg = 1, .flag = NULL, .val = 'r' }, - { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, - { .name = "compare", .has_arg = 0, .flag = NULL, .val = 'x' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -typedef struct myargs { - int verbose; - const char *logfile; - const char *raw_dev; - - pdd_handling_t pdd_handling; - int seqnum; - int compare; - int complete; - - FILE* fp_in; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static pdd_handling_t -get_pdd_handling(const char* str) -{ - if (strcmp(str, "keep") == 0) { - return PDD_KEEP; - } - if (strcmp(str, "merge") == 0) { - return PDD_MERGE; - } - if (strcmp(str, "overwrite") == 0) { - return PDD_OVERWRITE; - } - - return -1; -} - -static int -get_update_seqnum(const char* str) -{ - uint32_t i = strtoul(str, NULL, 0); - - if ((i != 0) && (i != 1)) { - return -1; - } - - return i; -} - - -static int -parse_opt(int argc, char **argv, myargs *args) -{ - while (1) { - int key; - - key = getopt_long(argc, argv, "cl:vCp:r:s:x?V", - long_options, NULL); - if (key == -1) - break; - - switch (key) { - /* standard options */ - case 'c': - err_msg("%s\n", copyright); - exit(0); - break; - case 'v': - args->verbose = 1; - break; - case 'l': - args->logfile = optarg; - break; - /* process options */ - case 'C': - args->complete = 1; - break; - case 'p': - args->pdd_handling = get_pdd_handling(optarg); - if ((int)args->pdd_handling < 0) { - err_quit("Unknown PDD handling: %s.\n" - "Please use either " - "'keep', 'merge' or" - "'overwrite'.\n'"); - } - break; - case 's': - args->seqnum = get_update_seqnum(optarg); - if (args->seqnum < 0) { - err_quit("Unsupported side: %s.\n" - "Supported sides are '0' " - "and '1'\n", optarg); - } - break; - case 'x': - args->compare = 1; - break; - case 'r': - args->raw_dev = optarg; - break; - case '?': /* help */ - err_msg("Usage: pfiflash [OPTION...] [pfifile]"); - err_msg("%s", doc); - err_msg("%s", optionsstr); - err_msg("\nReport bugs to %s\n", - PACKAGE_BUGREPORT); - exit(0); - break; - case 'V': - err_msg("%s", PROGRAM_VERSION); - exit(0); - break; - default: - err_msg("%s", usage); - exit(-1); - - } - } - - if (optind < argc) { - args->fp_in = fopen(argv[optind++], "r"); - if ((args->fp_in) == NULL) { - err_sys("Cannot open PFI file %s for input", - argv[optind]); - } - } - - return 0; -} - -int main (int argc, char** argv) -{ - int rc = 0; - char err_buf[PFIFLASH_MAX_ERR_BUF_SIZE]; - memset(err_buf, '\0', PFIFLASH_MAX_ERR_BUF_SIZE); - - myargs args = { - .verbose = 0, - .seqnum = -1, - .compare = 0, - .complete = 0, - .logfile = NULL, /* "/tmp/pfiflash.log", */ - .pdd_handling = PDD_KEEP, - .fp_in = stdin, - .raw_dev = NULL, - }; - - parse_opt(argc, argv, &args); - error_initlog(args.logfile); - - if (!args.fp_in) { - rc = -1; - snprintf(err_buf, PFIFLASH_MAX_ERR_BUF_SIZE, - "No PFI input file specified!\n"); - goto err; - } - - rc = pfiflash_with_options(args.fp_in, args.complete, args.seqnum, - args.compare, args.pdd_handling, args.raw_dev, err_buf, - PFIFLASH_MAX_ERR_BUF_SIZE); - if (rc < 0) { - goto err_fp; - } - - err_fp: - if (args.fp_in != stdin) - fclose(args.fp_in); - err: - if (rc != 0) - err_msg("pfiflash: %s\nrc: %d\n", err_buf, rc); - return rc; -} diff --git a/ubi-utils/sort-me-out/pfiflash.h b/ubi-utils/sort-me-out/pfiflash.h deleted file mode 100644 index 039705d..0000000 --- a/ubi-utils/sort-me-out/pfiflash.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef __PFIFLASH_H__ -#define __PFIFLASH_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. - */ - -/** - * - * @file pfi.h - * - * @author Oliver Lohmann <oliloh@de.ibm.com> - * - * @brief The pfiflash library offers an interface for using the - * pfiflash * utility. - */ - -#include <stdio.h> /* FILE */ - -#define PFIFLASH_MAX_ERR_BUF_SIZE 1024 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum pdd_handling_t -{ - PDD_KEEP = 0, - PDD_MERGE, - PDD_OVERWRITE, - PDD_HANDLING_NUM, /* always the last item */ -} pdd_handling_t; /**< Possible PDD handle algorithms. */ - -/** - * @brief Flashes a PFI file to UBI Device 0. - * @param complete [0|1] Do a complete system update. - * @param seqnum Index in a redundant group. - * @param compare [0|1] Compare contents. - * @param pdd_handling The PDD handling algorithm. - * @param rawdev Device to use for raw flashing - * @param err_buf An error buffer. - * @param err_buf_size Size of the error buffer. - */ -int pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare, - pdd_handling_t pdd_handling, const char* rawdev, - char *err_buf, size_t err_buf_size); - -/** - * @brief Flashes a PFI file to UBI Device 0. - * @param complete [0|1] Do a complete system update. - * @param seqnum Index in a redundant group. - * @param pdd_handling The PDD handling algorithm. - * @param err_buf An error buffer. - * @param err_buf_size Size of the error buffer. - */ -int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, - char *err_buf, size_t err_buf_size); - -#ifdef __cplusplus -} -#endif - -#endif /* __PFIFLASH_H__ */ diff --git a/ubi-utils/sort-me-out/pfiflash_error.h b/ubi-utils/sort-me-out/pfiflash_error.h deleted file mode 100644 index 0f27f4a..0000000 --- a/ubi-utils/sort-me-out/pfiflash_error.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __PFIFLASH_ERROR_H__ -#define __PFIFLASH_ERROR_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 <dowsett@de.ibm.com> - * Contact: Andreas Arnez <arnez@de.ibm.com> - */ - -enum pfiflash_err { - PFIFLASH_ERR_EOF = 1, - PFIFLASH_ERR_FIO, - PFIFLASH_ERR_UBI_OPEN, - PFIFLASH_ERR_UBI_CLOSE, - PFIFLASH_ERR_UBI_MKVOL, - PFIFLASH_ERR_UBI_RMVOL, - PFIFLASH_ERR_UBI_VOL_UPDATE, - PFIFLASH_ERR_UBI_VOL_FOPEN, - PFIFLASH_ERR_UBI_UNKNOWN, - PFIFLASH_ERR_UBI_VID_OOB, - PFIFLASH_ERR_BOOTENV_CREATE, - PFIFLASH_ERR_BOOTENV_READ, - PFIFLASH_ERR_BOOTENV_SIZE, - PFIFLASH_ERR_BOOTENV_WRITE, - PFIFLASH_ERR_PDD_UNKNOWN, - PFIFLASH_ERR_MTD_OPEN, - PFIFLASH_ERR_MTD_CLOSE, - PFIFLASH_ERR_CRC_CHECK, - PFIFLASH_ERR_MTD_ERASE, - PFIFLASH_ERR_COMPARE, - PFIFLASH_CMP_DIFF -}; - -const char *const PFIFLASH_ERRSTR[] = { - "", - "unexpected EOF", - "file I/O error", - "couldn't open UBI", - "couldn't close UBI", - "couldn't make UBI volume %d", - "couldn't remove UBI volume %d", - "couldn't update UBI volume %d", - "couldn't open UBI volume %d", - "unknown UBI operation", - "PFI data contains out of bounds UBI id %d", - "couldn't create bootenv%s", - "couldn't read bootenv", - "couldn't resize bootenv", - "couldn't write bootenv on ubi%d_%d", - "unknown PDD handling algorithm", - "couldn't open MTD device %s", - "couldn't close MTD device %s", - "CRC check failed: given=0x%08x, calculated=0x%08x", - "couldn't erase raw mtd region", - "couldn't compare volumes", - "on-flash data differ from pfi data, update is neccessary" -}; - -#endif /* __PFIFLASH_ERROR_H__ */ diff --git a/ubi-utils/sort-me-out/reader.c b/ubi-utils/sort-me-out/reader.c deleted file mode 100644 index 0ea8c6d..0000000 --- a/ubi-utils/sort-me-out/reader.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * 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: Oliver Lohmann - * - * Read in PFI (partial flash image) data and store it into internal - * data structures for further processing. Take also care about - * special handling if the data contains PDD (platform description - * data/boot-parameters). - */ - -#include <string.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - -#include "bootenv.h" -#include "reader.h" - -#define __unused __attribute__((unused)) - -/* @FIXME hard coded offsets right now - get them from Artem? */ -#define NAND2048_DEFAULT_VID_HDR_OFF 1984 -#define NAND512_DEFAULT_VID_HDR_OFF 448 -#define NOR_DEFAULT_VID_HDR_OFF 64 - -#define EBUF_PFI(fmt...) \ - do { int i = snprintf(err_buf, err_buf_size, "%s\n", label); \ - snprintf(err_buf + i, err_buf_size - i, fmt); \ - } while (0) - -#define EBUF(fmt...) \ - do { snprintf(err_buf, err_buf_size, fmt); } while (0) - - -int -read_pdd_data(FILE* fp_pdd, pdd_data_t* pdd_data, - char* err_buf, size_t err_buf_size) -{ - int rc = 0; - bootenv_t pdd = NULL; - pdd_data_t res = NULL; - const char* value; - - res = (pdd_data_t) malloc(sizeof(struct pdd_data)); - if (!res) { - rc = -ENOMEM; - goto err; - } - rc = bootenv_create(&pdd); - if (rc != 0) { - goto err; - } - rc = bootenv_read_txt(fp_pdd, pdd); - if (rc != 0) { - goto err; - } - rc = bootenv_get(pdd, "flash_type", &value); - if (rc != 0) { - goto err; - } - - if (strcmp(value, "NAND") == 0) { - - rc = bootenv_get_num(pdd, "flash_page_size", - &(res->flash_page_size)); - if (rc != 0) { - EBUF("Cannot read 'flash_page_size' from pdd."); - goto err; - } - res->flash_type = NAND_FLASH; - - switch (res->flash_page_size) { - case 512: - res->vid_hdr_offset = NAND512_DEFAULT_VID_HDR_OFF; - break; - case 2048: - res->vid_hdr_offset = NAND2048_DEFAULT_VID_HDR_OFF; - break; - default: - EBUF("Unsupported 'flash_page_size' %d.", - res->flash_page_size); - goto err; - } - } - else if (strcmp(value, "NOR") == 0){ - res->flash_type = NOR_FLASH; - res->vid_hdr_offset = NOR_DEFAULT_VID_HDR_OFF; - } - else { - snprintf(err_buf, err_buf_size, - "Unkown flash type: %s", value); - goto err; - } - - rc = bootenv_get_num(pdd, "flash_eraseblock_size", - &(res->eb_size)); - if (rc != 0) { - EBUF("Cannot read 'flash_eraseblock_size' from pdd."); - goto err; - } - - rc = bootenv_get_num(pdd, "flash_size", - &(res->flash_size)); - if (rc != 0) { - EBUF("Cannot read 'flash_size' from pdd."); - goto err; - } - - goto out; - err: - if (res) { - free(res); - res = NULL; - } - out: - bootenv_destroy(&pdd); - *pdd_data = res; - return rc; -} - -int -read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw, - const char* label, char* err_buf, size_t err_buf_size) -{ - int rc = 0; - char tmp_str[PFI_KEYWORD_LEN]; - bootenv_list_t raw_start_list = NULL; - pfi_raw_t res; - size_t size; - - res = (pfi_raw_t) malloc(sizeof(struct pfi_raw)); - if (!res) - return -ENOMEM; - - rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); - if (rc != 0) { - EBUF_PFI("Cannot read 'size' from PFI."); - goto err; - } - - rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); - if (rc != 0) { - EBUF_PFI("Cannot read 'crc' from PFI."); - goto err; - } - - rc = pfi_header_getstring(pfi_hd, "raw_starts", - tmp_str, PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF_PFI("Cannot read 'raw_starts' from PFI."); - goto err; - } - - rc = bootenv_list_create(&raw_start_list); - if (rc != 0) { - goto err; - } - - rc = bootenv_list_import(raw_start_list, tmp_str); - if (rc != 0) { - EBUF_PFI("Cannot translate PFI value: %s", tmp_str); - goto err; - } - - rc = bootenv_list_to_num_vector(raw_start_list, - &size, &(res->starts)); - res->starts_size = size; - - if (rc != 0) { - EBUF_PFI("Cannot create numeric value array: %s", tmp_str); - goto err; - } - - goto out; - - err: - if (res) { - free(res); - res = NULL; - } - out: - bootenv_list_destroy(&raw_start_list); - *pfi_raw = res; - return rc; -} - -int -read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, - const char *label, char* err_buf, size_t err_buf_size) -{ - int rc = 0; - const char** tmp_names = NULL; - char tmp_str[PFI_KEYWORD_LEN]; - bootenv_list_t ubi_id_list = NULL; - bootenv_list_t ubi_name_list = NULL; - pfi_ubi_t res; - uint32_t i; - size_t size; - - res = (pfi_ubi_t) calloc(1, sizeof(struct pfi_ubi)); - if (!res) - return -ENOMEM; - - rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); - if (rc != 0) { - EBUF_PFI("Cannot read 'size' from PFI."); - goto err; - } - - rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); - if (rc != 0) { - EBUF_PFI("Cannot read 'crc' from PFI."); - goto err; - } - - rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_ids' from PFI."); - goto err; - } - - rc = bootenv_list_create(&ubi_id_list); - if (rc != 0) { - goto err; - } - rc = bootenv_list_create(&ubi_name_list); - if (rc != 0) { - goto err; - } - - rc = bootenv_list_import(ubi_id_list, tmp_str); - if (rc != 0) { - EBUF_PFI("Cannot translate PFI value: %s", tmp_str); - goto err; - } - - rc = bootenv_list_to_num_vector(ubi_id_list, &size, - &(res->ids)); - res->ids_size = size; - if (rc != 0) { - EBUF_PFI("Cannot create numeric value array: %s", tmp_str); - goto err; - } - - if (res->ids_size == 0) { - rc = -1; - EBUF_PFI("Sanity check failed: No ubi_ids specified."); - goto err; - } - - rc = pfi_header_getstring(pfi_hd, "ubi_type", - tmp_str, PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_type' from PFI."); - goto err; - } - if (strcmp(tmp_str, "static") == 0) - res->type = pfi_ubi_static; - else if (strcmp(tmp_str, "dynamic") == 0) - res->type = pfi_ubi_dynamic; - else { - EBUF_PFI("Unknown ubi_type in PFI."); - goto err; - } - - rc = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment)); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_alignment' from PFI."); - goto err; - } - - rc = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size)); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_size' from PFI."); - goto err; - } - - rc = pfi_header_getstring(pfi_hd, "ubi_names", - tmp_str, PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF_PFI("Cannot read 'ubi_names' from PFI."); - goto err; - } - - rc = bootenv_list_import(ubi_name_list, tmp_str); - if (rc != 0) { - EBUF_PFI("Cannot translate PFI value: %s", tmp_str); - goto err; - } - rc = bootenv_list_to_vector(ubi_name_list, &size, - &(tmp_names)); - res->names_size = size; - if (rc != 0) { - EBUF_PFI("Cannot create string array: %s", tmp_str); - goto err; - } - - if (res->names_size != res->ids_size) { - EBUF_PFI("Sanity check failed: ubi_ids list does not match " - "sizeof ubi_names list."); - rc = -1; - } - - /* copy tmp_names to own structure */ - res->names = (char**) calloc(1, res->names_size * sizeof (char*)); - if (res->names == NULL) - goto err; - - for (i = 0; i < res->names_size; i++) { - res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char)); - if (res->names[i] == NULL) - goto err; - strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1); - } - - goto out; - - err: - if (res) { - if (res->names) { - for (i = 0; i < res->names_size; i++) { - if (res->names[i]) { - free(res->names[i]); - } - } - free(res->names); - } - if (res->ids) { - free(res->ids); - } - free(res); - res = NULL; - } - - out: - bootenv_list_destroy(&ubi_id_list); - bootenv_list_destroy(&ubi_name_list); - if (tmp_names != NULL) - free(tmp_names); - *pfi_ubi = res; - return rc; -} - - -int -free_pdd_data(pdd_data_t* pdd_data) -{ - if (*pdd_data) { - free(*pdd_data); - } - *pdd_data = NULL; - - return 0; -} - -int -free_pfi_raw(pfi_raw_t* pfi_raw) -{ - pfi_raw_t tmp = *pfi_raw; - if (tmp) { - if (tmp->starts) - free(tmp->starts); - free(tmp); - } - *pfi_raw = NULL; - - return 0; -} - -int -free_pfi_ubi(pfi_ubi_t* pfi_ubi) -{ - size_t i; - pfi_ubi_t tmp = *pfi_ubi; - if (tmp) { - if (tmp->ids) - free(tmp->ids); - if (tmp->names) { - for (i = 0; i < tmp->names_size; i++) { - if (tmp->names[i]) { - free(tmp->names[i]); - } - } - free(tmp->names); - } - free(tmp); - } - *pfi_ubi = NULL; - - return 0; -} - - -int -read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi, - char* err_buf, size_t err_buf_size) -{ - int rc = 0; - char mode[PFI_KEYWORD_LEN]; - char label[PFI_LABEL_LEN]; - - *pfi_raws = mk_empty(); pfi_raw_t raw = NULL; - *pfi_ubis = mk_empty(); pfi_ubi_t ubi = NULL; - pfi_header pfi_header = NULL; - - /* read all headers from PFI and store them in lists */ - rc = pfi_header_init(&pfi_header); - if (rc != 0) { - EBUF("Cannot initialize pfi header."); - goto err; - } - while ((rc == 0) && !feof(fp_pfi)) { - rc = pfi_header_read(fp_pfi, pfi_header); - if (rc != 0) { - if (rc == PFI_DATA_START) { - rc = 0; - break; /* data section starts, - all headers read */ - } - else { - goto err; - } - } - rc = pfi_header_getstring(pfi_header, "label", label, - PFI_LABEL_LEN); - if (rc != 0) { - EBUF("Cannot read 'label' from PFI."); - goto err; - } - rc = pfi_header_getstring(pfi_header, "mode", mode, - PFI_KEYWORD_LEN); - if (rc != 0) { - EBUF("Cannot read 'mode' from PFI."); - goto err; - } - if (strcmp(mode, "ubi") == 0) { - rc = read_pfi_ubi(pfi_header, fp_pfi, &ubi, label, - err_buf, err_buf_size); - if (rc != 0) { - goto err; - } - *pfi_ubis = append_elem(ubi, *pfi_ubis); - } - else if (strcmp(mode, "raw") == 0) { - rc = read_pfi_raw(pfi_header, fp_pfi, &raw, label, - err_buf, err_buf_size); - if (rc != 0) { - goto err; - } - *pfi_raws = append_elem(raw, *pfi_raws); - } - else { - EBUF("Recvieved unknown mode from PFI: %s", mode); - goto err; - } - } - goto out; - - err: - *pfi_raws = remove_all((free_func_t)&free_pfi_raw, *pfi_raws); - *pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, *pfi_ubis); - out: - pfi_header_destroy(&pfi_header); - return rc; - -} diff --git a/ubi-utils/sort-me-out/reader.h b/ubi-utils/sort-me-out/reader.h deleted file mode 100644 index 715e464..0000000 --- a/ubi-utils/sort-me-out/reader.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef __READER_H__ -#define __READER_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: Oliver Lohmann - * - * Read Platform Description Data (PDD). - */ - -#include <stdint.h> -#include <stdio.h> - -#include "pfi.h" -#include "bootenv.h" -#include "list.h" - -typedef enum flash_type_t { - NAND_FLASH = 0, - NOR_FLASH, -} flash_type_t; - -typedef struct pdd_data *pdd_data_t; -typedef struct pfi_raw *pfi_raw_t; -typedef struct pfi_ubi *pfi_ubi_t; - -struct pdd_data { - uint32_t flash_size; - uint32_t flash_page_size; - uint32_t eb_size; - uint32_t vid_hdr_offset; - flash_type_t flash_type; -}; - -struct pfi_raw { - uint32_t data_size; - uint32_t *starts; - uint32_t starts_size; - uint32_t crc; -}; - -struct pfi_ubi { - uint32_t data_size; - uint32_t alignment; - uint32_t *ids; - uint32_t ids_size; - char **names; - uint32_t names_size; - uint32_t size; - enum { pfi_ubi_dynamic, pfi_ubi_static } type; - int curr_seqnum; /* specifies the seqnum taken in an update, - default: 0 (used by pfiflash, ubimirror) */ - uint32_t crc; -}; - -int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data, - char *err_buf, size_t err_buf_size); -int read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi, pfi_raw_t *pfi_raw, - const char *label, char *err_buf, size_t err_buf_size); -int read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi, pfi_ubi_t *pfi_ubi, - const char *label, char *err_buf, size_t err_buf_size); - -/** - * @brief Reads all pfi headers into list structures, separated by - * RAW and UBI sections. - */ -int read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi, - char* err_buf, size_t err_buf_size); -int free_pdd_data(pdd_data_t *pdd_data); -int free_pfi_raw(pfi_raw_t *raw_pfi); -int free_pfi_ubi(pfi_ubi_t *pfi_ubi); - -#endif /* __READER_H__ */ diff --git a/ubi-utils/sort-me-out/run_all.sh b/ubi-utils/sort-me-out/run_all.sh deleted file mode 100755 index 040bcbd..0000000 --- a/ubi-utils/sort-me-out/run_all.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/sh - -exit_success () -{ - echo "UBI Utils Test Scripts - SUCCESS!" - exit 0 -} - -exit_failure () -{ - echo $1 - echo "UBI Utils Test Scripts - FAILED!" - exit 1 -} - -echo UBI Utils Test Scripts - -devno=$1 -logfile=temp-test-log.txt - -if test -z "$devno"; -then - echo "Usage is $0 <mtd device number>" - exit 1 -fi - -cwd=`pwd` || exit_failure "pwd failed" - -log="${cwd}/${logfile}" - -PATH=$PATH:$cwd:.. - -cat /dev/null > $log || exit_failure "Failed to create $log" - -echo "Setting up for jffs2_test.sh" | tee -a $log - -avail=`cat /sys/class/ubi/ubi${devno}/avail_eraseblocks` -size=`cat /sys/class/ubi/ubi${devno}/eraseblock_size` - -bytes=`expr $avail \* $size` - -ubimkvol -d$devno -s$bytes -n0 -Njtstvol || exit_failure "ubimkvol failed" - -mkdir -p /mnt/test_file_system || exit_failure "mkdir failed" - -mtd=`cat /proc/mtd | grep jtstvol | cut -d: -f1` - -if test -z "$mtd"; -then - exit_failure "mtd device not found" -fi - -mount -t jffs2 $mtd /mnt/test_file_system || exit_failure "mount failed" - -cd /mnt/test_file_system || exit_failure "cd failed" - -echo Running jffs2_test.sh | tee -a $log - -jffs2_test.sh >> $log 2>&1 || exit_failure "jffs2_test.sh failed" - -rm -f * - -cd $cwd || exit_failure "cd failed" - -umount /mnt/test_file_system || exit_failure "umount failed" - -ubirmvol -d$devno -n0 || exit_failure "ubirmvol failed" - -major=`cat /sys/class/ubi/ubi${devno}/dev | cut -d: -f1` - -for minor in `seq 0 32`; do - if test ! -e /dev/ubi${devno}_$minor ; - then - mknod /dev/ubi${devno}_$minor c $major $(($minor + 1)) - fi -done - -rm -f testdata.bin readdata.bin - -echo Running ubi_jffs2_test.sh | tee -a $log - -ubi_jffs2_test.sh >> $log 2>&1 || exit_failure "ubi_jffs2_test.sh failed" - -echo Running ubi_test.sh | tee -a $log - -ubi_test.sh >> $log 2>&1 || exit_failure "ubi_test.sh failed" - -for minor in `seq 0 32`; do - if test -e /sys/class/ubi/ubi${devno}/$minor; - then - ubirmvol -d$devno -n$minor || exit_failure "ubirmvol failed" - fi -done - -echo Running ubi_tools_test.sh | tee -a $log - -ubi_tools_test.sh >> $log 2>&1 || exit_failure "ubi_tools_test failed" - -rm -f $log - -exit_success diff --git a/ubi-utils/sort-me-out/test.cfg b/ubi-utils/sort-me-out/test.cfg deleted file mode 100644 index 0b5ec48..0000000 --- a/ubi-utils/sort-me-out/test.cfg +++ /dev/null @@ -1,23 +0,0 @@ -[targets] -test_complete=spl,kernel,rootfs - -[spl] -image=test_u-boot.bin -ubi_ids=10,11 -ubi_size=1MiB -ubi_type=static -ubi_names=test_spl_0,test_spl_1 - -[kernel] -image=test_vmlinux.bin -ubi_ids=12,13 -ubi_size=2MiB -ubi_type=static -ubi_names=test_kernel_0,test_kernel_1 - -[rootfs] -image=test_rootfs.bin -ubi_ids=14,15 -ubi_size=2MiB -ubi_type=dynamic -ubi_names=test_rootfs_0,test_rootfs_1 diff --git a/ubi-utils/sort-me-out/ubi_test.sh b/ubi-utils/sort-me-out/ubi_test.sh deleted file mode 100755 index 73e4b19..0000000 --- a/ubi-utils/sort-me-out/ubi_test.sh +++ /dev/null @@ -1,328 +0,0 @@ -#!/bin/sh -# -# UBI Volume creation/deletion/write/read test script -# -# Written in shell language to reduce dependencies to more sophisticated -# interpreters, which may not be available on some stupid platforms. -# -# Author: Frank Haverkamp <haver@vnet.ibm.com> -# -# 1.0 Initial version -# 1.1 Use ubiupdatevol instead of ubiwritevol -# - -VERSION="1.1" - -export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/ - -UBIMKVOL=ubimkvol -UBIRMVOL=ubirmvol -UBIUPDATEVOL=ubiupdatevol - -# 128 KiB 131072 -# 256 KiB 262144 -# 512 KiB 524288 - -SIZE_512K=524288 -SIZE_1M=1310720 - -SELF=$0 -MINVOL=10 -MAXVOL=12 - -# -# To have a standardized output I define the following function to be -# used when a test was ok or when it failed. -# -failed () -{ - echo "FAILED" -} - -passed () -{ - echo "PASSED" -} - -# -# Print sucess message. Consider to exit with zero as return code. -# -exit_success () -{ - echo "SUCCESS" - exit 0 -} - -# -# Print failure message. Consider to exit with non zero return code. -# -exit_failure () -{ - echo "FAILED" - exit 1 -} - -############################################################################### -# -# START -# -############################################################################### - -fix_sysfs_issue () -{ - echo -n "*** Fixing the sysfs issue with the /dev nodes ... " - - minor=0 - major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` - - rm -rf /dev/ubi0 - mknod /dev/ubi0 c $major 0 - - for minor in `seq 0 $MAXVOL`; do - ### echo " mknod /dev/ubi0_$minor c $major $(($minor + 1))" - rm -rf /dev/ubi0_$minor - mknod /dev/ubi0_$minor c $major $(($minor + 1)) - done - passed -} - -# delete_volume - Delete a volume. If it does not exist, do not try -# to delete it. -# @id: volume id -# -delete_volume () -{ - volume=$1 - - ### FIXME broken sysfs!!!! - if [ -e /sys/class/ubi/$volume -o -e /sys/class/ubi/ubi0/$volume -o -e /sys/class/ubi/ubi0_$volume ]; then - - echo -n "*** Truncate volume if it exists ... " - $UBIUPDATEVOL -d0 -n$volume -t - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - - echo -n "*** Delete volume if it exists ... " - $UBIRMVOL -d0 -n$volume - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - fi -} - -mkvol_rmvol_test () -{ - type=$1 - -### Test if volume delete on non-existing volumes fails nicely - - for i in `seq $MINVOL $MAXVOL`; do - echo "*** Delete if exist or not $i ... " - - delete_volume $i - passed - done - -### Now deleting volumes must fail - - for i in `seq $MINVOL $MAXVOL`; do - echo "*** Trying to delete non existing UBI Volume $i ... " - - $UBIRMVOL -d0 -n$i - if [ $? -eq "0" ] ; then - exit_failure - fi - passed - done - -### Test if volume creation works ok - - for i in `seq $MINVOL $MAXVOL`; do - echo "*** Creating UBI Volume $i ... " - echo " $UBIMKVOL -d0 -n$i -t$type -NNEW$i -s $SIZE_512K" - - $UBIMKVOL -d0 -n$i -t$type -N"NEW$i" -s $SIZE_512K - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - done - -### Now deleting volumes must be ok - - for i in `seq $MINVOL $MAXVOL`; do - echo "*** Trying to delete UBI Volume $i ... " - - $UBIRMVOL -d0 -n$i - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - done - -### Now allocate too large volume - - echo -n "*** Try to create too large volume" - $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s 800000000 - if [ $? -eq "0" ] ; then - exit_failure - fi - passed -} - -# writevol_test - Tests volume creation and writing data to it. -# -# @size: Size of random data to write -# @type: Volume type static or dynamic -# -writevol_test () -{ - size=$1 - type=$2 - - echo "*** Write volume test with size $size" - -### Make sure that volume exist, delete existing volume, create new - - delete_volume $MINVOL - - echo -n "*** Try to create volume ... " - $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s $SIZE_1M - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - -### Try to create same volume again - echo -n "*** Try to create some volume again, this must fail ... " - $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s $SIZE_1M - if [ $? -eq "0" ] ; then - exit_failure - fi - passed - -### Now create test data, write it, read it, compare it - echo -n "*** Create test data ... " - dd if=/dev/urandom of=testdata.bin bs=$size count=1 - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - - echo "*** Now writing data to volume ... " - # sleep 5 - ls -l testdata.bin - echo " $UBIUPDATEVOL -d0 -n$MINVOL testdata.bin" - $UBIUPDATEVOL -d0 -n$MINVOL testdata.bin - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - - if [ $type = "static" ] ; then - echo "*** Download data with cat ... " - cat /dev/ubi0_$MINVOL > readdata.bin - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - else - echo "*** Download data with dd bs=1 ... " - dd if=/dev/ubi0_$MINVOL of=readdata.bin bs=$size count=1 - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - - # Size 1 does not work with this test ... - # - #echo "*** Download data with dd bs=$size ... " - #dd if=/dev/ubi0_$MINVOL of=readdata2.bin bs=$size count=1 - #if [ $? -ne "0" ] ; then - # exit_failure - #fi - #passed - - #echo -n "*** Comparing data (1) ... " - #cmp readdata.bin readdata2.bin - #if [ $? -ne "0" ] ; then - # exit_failure - #fi - #passed - fi - - echo -n "*** Comparing data ... " - cmp readdata.bin testdata.bin - if [ $? -ne "0" ] ; then - exit_failure - fi - passed -} - -echo "***********************************************************************" -echo "* UBI Testing starts now ... *" -echo "* Good luck! *" -echo "***********************************************************************" - -# Set to zero if not running on example hardware -grep ubi /proc/devices > /dev/null -if [ $? -ne "0" ]; then - echo "No UBI found in /proc/devices! I am broken!" - exit_failure -fi - -# Set to zero if not running on example hardware -grep 1142 /proc/cpuinfo > /dev/null -if [ $? -eq "0" ]; then - echo "Running on example hardware" - mount -o remount,rw / / - sleep 1 - fix_sysfs_issue -else - echo "Running on Artems hardware" -fi - -echo "***********************************************************************" -echo "* mkvol/rmvol testing for static volumes ... *" -echo "***********************************************************************" - -mkvol_rmvol_test static - -echo "***********************************************************************" -echo "* mkvol/rmvol testing for dynamic volumes ... *" -echo "***********************************************************************" - -mkvol_rmvol_test dynamic - -echo "***********************************************************************" -echo "* write to static volumes ... *" -echo "***********************************************************************" - -# 10 Erase blocks = (128 KiB - 64 * 2) * 10 -# = 1309440 bytes -# 128 KiB 131072 -# 256 KiB 262144 -# 512 KiB 524288 - -for size in 262144 131073 131072 2048 1 4096 12800 31313 ; do - writevol_test $size static -done - -echo "***********************************************************************" -echo "* write to dynamic volumes ... *" -echo "***********************************************************************" -echo "VERSION: $VERSION" - -for size in 131073 131072 2048 1 4096 12800 31313 262144 ; do - writevol_test $size dynamic -done - -echo "***********************************************************************" -echo "* Congratulations, no errors found! *" -echo "* Have fun with your cool UBI system! *" -echo "***********************************************************************" - -exit_success diff --git a/ubi-utils/sort-me-out/ubi_tools_test.sh b/ubi-utils/sort-me-out/ubi_tools_test.sh deleted file mode 100755 index 7f121f1..0000000 --- a/ubi-utils/sort-me-out/ubi_tools_test.sh +++ /dev/null @@ -1,252 +0,0 @@ -#!/bin/sh -# -# UBI Volume creation/deletion/write/read test script. -# Uses our flash update tools and the associated toolchain for flash -# image creation. -# -# Written in shell language to reduce dependencies to more sophisticated -# interpreters, which may not be available on some stupid platforms. -# -# Author: Frank Haverkamp <haver@vnet.ibm.com> -# -# 1.0 Initial version -# - -VERSION="1.0" - -export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/ - -UBIMKVOL=ubimkvol -UBIRMVOL=ubirmvol -UBIWRITEVOL=ubiupdatevol -PFIFLASH=pfiflash -CMP=cmp - -MAXVOL=32 - -test_pfi=test_complete.pfi -real_pfi=example_complete.pfi - -# 128 KiB 131072 -# 256 KiB 262144 -# 512 KiB 524288 - -# -# To have a standardized output I define the following function to be -# used when a test was ok or when it failed. -# -failed () -{ - echo "FAILED" -} - -passed () -{ - echo "PASSED" -} - -# -# Print sucess message. Consider to exit with zero as return code. -# -exit_success () -{ - echo "SUCCESS" - exit 0 -} - -# -# Print failure message. Consider to exit with non zero return code. -# -exit_failure () -{ - echo "FAILED" - exit 1 -} - -############################################################################### -# -# START -# -############################################################################### - -fix_sysfs_issue () -{ - echo -n "*** Fixing the sysfs issue with the /dev nodes ... " - - minor=0 - major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` - - rm -rf /dev/ubi0 - mknod /dev/ubi0 c $major 0 - - for minor in `seq 0 $MAXVOL`; do - ### echo " mknod /dev/ubi0_$minor c $major $(($minor + 1))" - rm -rf /dev/ubi0_$minor - mknod /dev/ubi0_$minor c $major $(($minor + 1)) - done - passed -} - -# delete_volume - Delete a volume. If it does not exist, do not try -# to delete it. -# @id: volume id -# -delete_volume () -{ - volume=$1 - - ### FIXME broken sysfs!!!! - if [ -e /sys/class/ubi/$volume -o -e /sys/class/ubi/ubi0/$volume -o -e /sys/class/ubi/ubi0_$volume ]; then - - echo -n "*** Truncate volume if it exists ... " - $UBIWRITEVOL -d0 -n$volume -t - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - - echo -n "*** Delete volume if it exists ... " - $UBIRMVOL -d0 -n$volume - if [ $? -ne "0" ] ; then - exit_failure - fi - passed - fi -} - -echo "***********************************************************************" -echo "* UBI Tools Testing starts now ... *" -echo "* Good luck! *" -echo "***********************************************************************" - -# Set to zero if not running on example hardware -grep ubi /proc/devices > /dev/null -if [ $? -ne "0" ]; then - echo "No UBI found in /proc/devices! I am broken!" - exit_failure -fi - -# Set to zero if not running on example hardware -grep 1142 /proc/cpuinfo > /dev/null -if [ $? -eq "0" ]; then - echo "Running on example hardware" - mount -o remount,rw / / - sleep 1 - fix_sysfs_issue -else - echo "Running on other hardware" -fi - -### Test basic stuff -pfiflash_basic () -{ - echo "Calling pfiflash with test-data ... " - echo " $PFIFLASH $test_pfi" - $PFIFLASH $test_pfi - if [ $? -ne "0" ]; then - echo "Uhhh something went wrong!" - exit_failure - fi - passed - - echo "Testing if data is correct 10 and 11 ... " - $CMP /dev/ubi0_10 /dev/ubi0_11 - if [ $? -ne "0" ]; then - echo "Mirrored volumes not equal!" - exit_failure - fi - passed - - echo "Comparing against original data ... " - $CMP /dev/ubi0_10 test_u-boot.bin - if [ $? -ne "0" ]; then - echo "Compared volume not equal!" - exit_failure - fi - passed - - echo "Testing if data is correct 12 and 13 ... " - $CMP /dev/ubi0_12 /dev/ubi0_13 - if [ $? -ne "0" ]; then - echo "Mirrored volumes not equal!" - exit_failure - fi - passed - - echo "Comparing against original data ... " - $CMP /dev/ubi0_12 test_vmlinux.bin - if [ $? -ne "0" ]; then - echo "Compared volume not equal!" - exit_failure - fi - passed - - echo "Testing if data is correct 14 and 15 ... " - $CMP /dev/ubi0_14 /dev/ubi0_15 - if [ $? -ne "0" ]; then - echo "Mirrored volumes not equal!" - exit_failure - fi - passed -} - -### Test each and everything -pfiflash_advanced () -{ - if [ -e example_complete.pfi ]; then - echo "Calling pfiflash with real data ... " - $PFIFLASH -p overwrite --complete example_complete.pfi - if [ $? -ne "0" ]; then - echo "Uhhh something went wrong!" - exit_failure - fi - passed - - echo "Testing if data is correct 2 and 3 ... " - $CMP /dev/ubi0_2 /dev/ubi0_3 - if [ $? -ne "0" ]; then - echo "Mirrored volumes not equal!" - exit_failure - fi - passed - - echo "Comparing against original data ... " - $CMP /dev/ubi0_2 u-boot.bin - if [ $? -ne "0" ]; then - echo "Compared volume not equal!" - exit_failure - fi - passed - - echo "Testing if data is correct 6 and 7 ... " - $CMP /dev/ubi0_6 /dev/ubi0_7 - if [ $? -ne "0" ]; then - echo "Mirrored volumes not equal!" - exit_failure - fi - passed - - echo "Comparing against original data ... " - $CMP /dev/ubi0_6 vmlinux.bin - if [ $? -ne "0" ]; then - echo "Compared volume not equal!" - exit_failure - fi - passed - fi -} - -echo "***********************************************************************" -echo "* Testing pfiflash ... *" -echo "***********************************************************************" -echo "VERSION: $VERSION" - -pfiflash_basic -pfiflash_advanced - -echo "***********************************************************************" -echo "* Congratulations, no errors found! *" -echo "* Have fun with your cool UBI system! *" -echo "***********************************************************************" - -exit_success diff --git a/ubi-utils/sort-me-out/ubicrc32.pl b/ubi-utils/sort-me-out/ubicrc32.pl deleted file mode 100644 index 92711cb..0000000 --- a/ubi-utils/sort-me-out/ubicrc32.pl +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/perl -w - -# Subroutine crc32(): Calculates the CRC on a given string. - -{ - my @table = (); - - # @brief Calculate CRC32 for a given string. - sub crc32 - { - unless (@table) { - # Initialize the CRC table - my $poly = 0xEDB88320; - @table = (); - - for my $i (0..255) { - my $c = $i; - - for my $j (0..7) { - $c = ($c & 1) ? (($c >> 1) ^ $poly) : ($c >> 1); - } - $table[$i] = $c; - } - } - my $s = shift; # string to calculate the CRC for - my $crc = shift; # CRC start value - - defined($crc) - or $crc = 0xffffffff; # Default CRC start value - - for (my $i = 0; $i < length($s); $i++) { - $crc = $table[($crc ^ ord(substr($s, $i, 1))) & 0xff] - ^ ($crc >> 8); - } - return $crc; - } -} - -sub crc32_on_file -{ - my $file = shift; - - my $crc32 = crc32(''); - my $buf = ''; - my $ret = 0; - - while ($ret = read($file, $buf, 8192)) { - $crc32 = crc32($buf, $crc32); - } - defined($ret) - or return undef; - printf("0x%x\n", $crc32); -} - - -# Main routine: Calculate the CRCs on the given files and print the -# results. - -{ - if (@ARGV) { - while (my $path = shift) { - my $file; - open $file, "<", $path - or die "Error opening '$path'.\n"; - - &crc32_on_file($file) - or die "Error reading from '$path'.\n"; - close $file; - } - } else { - &crc32_on_file(\*STDIN) - or die "Error reading from stdin.\n"; - } -} diff --git a/ubi-utils/sort-me-out/ubigen.c b/ubi-utils/sort-me-out/ubigen.c deleted file mode 100644 index 35fad27..0000000 --- a/ubi-utils/sort-me-out/ubigen.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * 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. - */ - -/* - * An utility to generate UBI images. - * - * Authors: Oliver Lohmann - * Artem Bityutskiy - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <getopt.h> -#include <unistd.h> -#include <sys/stat.h> -#include <mtd/ubi-header.h> - -#include "ubigen.h" -#include "common.h" - -#define PROGRAM_VERSION "1.4" -#define PROGRAM_NAME "ubigen" - -struct args { - FILE *fp_in; - FILE *fp_out; - int peb_size; - int id; - int min_io_size; - int type; - int sub_page_size; - int alignment; - int vid_hdr_offs; - int ec; - int ubi_ver; -}; - -struct args args = { - .fp_in = NULL, - .fp_out = NULL, - .peb_size = -1, - .id = -1, - .min_io_size = -1, - .type = UBI_VID_DYNAMIC, - .sub_page_size = -1, - .alignment = 1, - .vid_hdr_offs = 0, - .ec = 0, - .ubi_ver = 0, -}; - -static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -" - a tool for adding UBI headers to a binary image.\n" -"Note, the images generated by this program are not ready to be used\n" -"because they do not contain the volume table. If not sure about one\n" -"of the parameters, do not specify and let the utility to use default\n" -"values."; - -static const char *optionsstr = -"-i, --infile=<filename> the input file\n" -"-o, --outfile=<filename> the output file (default is stdout)\n" -"-b, --peb-size=<bytes> size of the physical eraseblock of the flash this\n" -" UBI image is created for in bytes, kilobytes (KiB),\n" -" or megabytes (MiB) (mandatory parameter)\n" -"-I, --vol-id=<num> volume ID (mandatory parameter)\n" -"-m, --min-io-size=<bytes> minimum input/output unit size of the flash in bytes\n" -" kilobytes (KiB), or megabytes (MiB) (mandatory\n" -" parameter); e.g. this is NAND page size in case of\n" -" NAND flash\n" -"-t, --type=<static|dynamic> volume type: dynamic or static (default is dynamic)\n" -"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI headers, e.g.\n" -" sub-page size in case of NAND flash (equivalent to\n" -" the minimum input/output unit size by default)\n" -"-a, --alignment=<bytes> volume alignment in bytes, kilobytes (KiB), or\n" -" megabytes (MiB) (default is 1)\n" -"-O, --vid-hdr-offset=<num> offset if the VID header from start of the physical\n" -" eraseblock (default is the second minimum I/O unit\n" -" or sub-page, if it was specified)\n" -"-e, --erase-counter=<num> the erase counter value to put to EC headers\n" -" (default is 0)\n" -"-x, --ubi-ver=<num> UBI version number to put to EC headers\n" -" (default is 1)\n" -"-h, --help print help message\n" -"-V, --version print program version"; - -static const char *usage = -"Usage: " PROGRAM_NAME " -i <input file> -o <output file> -b <PEB size>\n" -" -I <volume ID> -m <min I/O unit size> [-s <sub-page size>]\n" -" [-a <alignment>] [-O <volume ID header offset>]\n" -" [-e <erase counter value>] [-x <UBI version>] [-h] [-V]"; - -struct option long_options[] = { - { .name = "infile", .has_arg = 1, .flag = NULL, .val = 'i' }, - { .name = "outfile", .has_arg = 1, .flag = NULL, .val = 'o' }, - { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'b' }, - { .name = "vol-id", .has_arg = 1, .flag = NULL, .val = 'I' }, - { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' }, - { .name = "type", .has_arg = 1, .flag = NULL, .val = 't' }, - { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, - { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'a' }, - { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, - { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, - { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -static int parse_opt(int argc, char * const argv[]) -{ - while (1) { - int key; - char *endp; - - key = getopt_long(argc, argv, "i:o:b:I:m:t:s:a:O:e:x:hV", - long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'o': - args.fp_out = fopen(optarg, "wb"); - if (!args.fp_out) { - errmsg("cannot open file \"%s\"", optarg); - return -1; - } - break; - - case 'i': - args.fp_in = fopen(optarg, "rb"); - if (!args.fp_in) { - errmsg("cannot open file \"%s\"", optarg); - return -1; - } - break; - - case 'b': - args.peb_size = strtoull(optarg, &endp, 0); - if (endp == optarg || args.peb_size <= 0) { - errmsg("bad physical eraseblock size: \"%s\"", optarg); - return -1; - } - if (*endp != '\0') { - int mult = ubiutils_get_multiplier(endp); - - if (mult == -1) { - errmsg("bad size specifier: \"%s\" - " - "should be 'KiB', 'MiB' or 'GiB'", endp); - return -1; - } - args.peb_size *= mult; - } - break; - - case 'm': - args.min_io_size = strtoull(optarg, &endp, 0); - if (endp == optarg || args.min_io_size <= 0) { - errmsg("bad min. I/O unit size: \"%s\"", optarg); - return -1; - } - if (*endp != '\0') { - int mult = ubiutils_get_multiplier(endp); - - if (mult == -1) { - errmsg("bad size specifier: \"%s\" - " - "should be 'KiB', 'MiB' or 'GiB'", endp); - return -1; - } - args.min_io_size *= mult; - } - break; - - case 'e': - args.ec = strtoul(optarg, &endp, 0); - if (endp == optarg || args.ec < 0) { - errmsg("bad erase counter value: \"%s\"", optarg); - return -1; - } - break; - - case 'I': - args.id = strtoul(optarg, &endp, 0); - if (endp == optarg || args.id < 0) { - errmsg("bad volume ID: \"%s\"", optarg); - return -1; - } - break; - - case 't': - if (!strcmp(optarg, "dynamic")) - args.type = UBI_VID_DYNAMIC; - else if (!strcmp(optarg, "static")) - args.type = UBI_VID_STATIC; - else { - errmsg("bad volume type: \"%s\"", optarg); - return -1; - } - break; - - case 'x': - args.ubi_ver = strtoul(optarg, &endp, 0); - if (endp == optarg || args.ubi_ver < 0) { - errmsg("bad UBI version: \"%s\"", optarg); - return -1; - } - break; - - case 'O': - args.vid_hdr_offs = strtoul(optarg, &endp, 0); - if (endp == optarg || args.vid_hdr_offs < 0) { - errmsg("bad VID header offset: \"%s\"", optarg); - return -1; - } - break; - - case 'h': - fprintf(stderr, "%s\n\n", doc); - fprintf(stderr, "%s\n\n", usage); - fprintf(stderr, "%s\n", optionsstr); - exit(EXIT_SUCCESS); - - case 'V': - fprintf(stderr, "%s\n", PROGRAM_VERSION); - exit(EXIT_SUCCESS); - - case ':': - errmsg("parameter is missing"); - return -1; - - default: - fprintf(stderr, "Use -h for help\n"); - return -1; - } - } - - if (!args.fp_in) { - errmsg("input file was not specified (use -h for help)"); - return -1; - } - - if (!args.fp_out) - args.fp_out = stdout; - - if (args.id < 0) { - errmsg("wolume ID was not specified (use -h for help)"); - return -1; - } - - if (args.peb_size < 0) { - errmsg("physical eraseblock size was not specified " - "(use -h for help)"); - return -1; - } - - if (args.min_io_size < 0) { - errmsg("min. I/O unit size was not specified " - "(use -h for help)"); - return -1; - } - - if (args.sub_page_size < 0) - args.sub_page_size = args.min_io_size; - - return 0; -} - - -int main(int argc, char * const argv[]) -{ - int err; - ubi_info_t u; - struct stat file_info; - off_t input_len = 0; /* only used in static volumes */ - - ubigen_init(); - - err = parse_opt(argc, argv); - if (err) - return -1; - - if (fstat(fileno(args.fp_in), &file_info) != 0) { - fprintf(stderr, "Cannot fetch file size " - "from input file.\n"); - } - input_len = file_info.st_size; - - err = ubigen_create(&u, (uint32_t)args.id, args.type, - args.peb_size, args.ec, args.alignment, - args.ubi_ver, args.vid_hdr_offs, 0 ,input_len, - args.fp_in, args.fp_out); - - if (err) { - fprintf(stderr, "Cannot create UBI info handler err: %d\n", err); - return -1; - } - - err = ubigen_write_complete(u); - if (err != 0) { - fprintf(stderr, "Error converting input data.\n"); - return -1; - } - - err = ubigen_destroy(&u); - return err; -} diff --git a/ubi-utils/sort-me-out/ubimirror.c b/ubi-utils/sort-me-out/ubimirror.c deleted file mode 100644 index 2cc4596..0000000 --- a/ubi-utils/sort-me-out/ubimirror.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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: Oliver Lohmann - * - * 1.2 Removed argp because we want to use uClibc. - * 1.3 Minor cleanups - * 1.4 Migrated to new libubi - */ - -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <unistd.h> -#include <errno.h> -#include <mtd/ubi-header.h> - -#include "config.h" -#include "error.h" -#include "example_ubi.h" -#include "ubimirror.h" - -#define PROGRAM_VERSION "1.4" - -typedef enum action_t { - ACT_NORMAL = 0, - ACT_ARGP_ABORT, - ACT_ARGP_ERR, -} action_t; - -#define ABORT_ARGP do { \ - args->action = ACT_ARGP_ABORT; \ -} while (0) - -#define ERR_ARGP do { \ - args->action = ACT_ARGP_ERR; \ -} while (0) - -#define VOL_ARGS_MAX 2 - -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "ubimirror - mirrors ubi volumes.\n"; - -static const char *optionsstr = -" -c, --copyright Print copyright information.\n" -" -s, --side=<seqnum> Use the side <seqnum> as source.\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" -V, --version Print program version\n"; - -static const char *usage = -"Usage: ubimirror [-c?V] [-s <seqnum>] [--copyright] [--side=<seqnum>]\n" -" [--help] [--usage] [--version] <source> <destination>\n"; - -static const char copyright [] __attribute__((unused)) = - "(C) IBM Coorporation 2007"; - -struct option long_options[] = { - { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, - { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -typedef struct myargs { - action_t action; - int side; - int vol_no; /* index of current volume */ - /* @FIXME replace by bootenv_list, makes live easier */ - /* @FIXME remove the constraint of two entries in the array */ - const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst - volumes */ - char *arg1; - char **options; /* [STRING...] */ -} myargs; - -static int -get_update_side(const char* str) -{ - uint32_t i = strtoul(str, NULL, 0); - - if ((i != 0) && (i != 1)) { - return -1; - } - return i; -} - - -static int -parse_opt(int argc, char **argv, myargs *args) -{ - while (1) { - int key; - - key = getopt_long(argc, argv, "cs:?V", long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'c': - err_msg("%s", copyright); - ABORT_ARGP; - break; - case 's': - args->side = get_update_side(optarg); - if (args->side < 0) { - err_msg("Unsupported seqnum: %s.\n" - "Supported seqnums are '0' " - "and '1'\n", optarg); - ERR_ARGP; - } - break; - case '?': /* help */ - err_msg("Usage: ubimirror [OPTION...] " - "<source> <destination>\n"); - err_msg("%s", doc); - err_msg("%s", optionsstr); - err_msg("\nReport bugs to %s\n", - PACKAGE_BUGREPORT); - exit(0); - break; - case 'V': - err_msg("%s", PROGRAM_VERSION); - exit(0); - break; - default: - err_msg("%s", usage); - exit(-1); - } - } - - while (optind < argc) { - /* only two entries allowed */ - if (args->vol_no >= VOL_ARGS_MAX) { - err_msg("%s", usage); - ERR_ARGP; - } - args->vol[(args->vol_no)++] = argv[optind++]; - } - - return 0; -} - - -int -main(int argc, char **argv) { - int rc = 0; - unsigned int ids[VOL_ARGS_MAX]; - char err_buf[1024]; - - myargs args = { - .action = ACT_NORMAL, - .side = -1, - .vol_no = 0, - .vol = {"", ""}, - .options = NULL, - }; - - parse_opt(argc, argv, &args); - if (args.action == ACT_ARGP_ERR) { - rc = 127; - goto err; - } - if (args.action == ACT_ARGP_ABORT) { - rc = 126; - goto out; - } - if (args.vol_no < VOL_ARGS_MAX) { - fprintf(stderr, "missing volume number for %s\n", - args.vol_no == 0 ? "source and target" : "target"); - rc = 125; - goto out; - } - for( rc = 0; rc < args.vol_no; ++rc){ - char *endp; - ids[rc] = strtoul(args.vol[rc], &endp, 0); - if( *endp != '\0' ){ - fprintf(stderr, "invalid volume number %s\n", - args.vol[rc]); - rc = 125; - goto out; - } - } - rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no, - err_buf, sizeof(err_buf)); - if( rc ){ - err_buf[sizeof err_buf - 1] = '\0'; - fprintf(stderr, err_buf); - if( rc < 0 ) - rc = -rc; - } - out: - err: - return rc; -} diff --git a/ubi-utils/sort-me-out/ubimirror.h b/ubi-utils/sort-me-out/ubimirror.h deleted file mode 100644 index d7ae2ad..0000000 --- a/ubi-utils/sort-me-out/ubimirror.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __UBIMIRROR_H__ -#define __UBIMIRROR_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: Oliver Lohmann - * - * An utility to mirror UBI volumes. - */ - -#include <stdint.h> - -/** - * @def EUBIMIRROR_SRC_EQ_DST - * @brief Given source volume is also in the set of destination volumes. - */ -#define EUBIMIRROR_SRC_EQ_DST 20 - -/** - * @def EUBIMIRROR_NO_SRC - * @brief The given source volume does not exist. - */ -#define EUBIMIRROR_NO_SRC 21 - -/** - * @def EUBIMIRROR_NO_DST - * @brief One of the given destination volumes does not exist. - */ -#define EUBIMIRROR_NO_DST 22 - -/** - * @brief Mirrors UBI devices from a source device (specified by seqnum) - * to n target devices. - * @param devno Device number used by the UBI operations. - * @param seqnum An index into ids (defines the src_id). - * @param ids An array of ids. - * @param ids_size The number of entries in the ids array. - * @param err_buf A buffer to store verbose error messages. - * @param err_buf_size The size of the error buffer. - * - * @note A seqnum of value < 0 defaults to a seqnum of 0. - * @note A seqnum exceeding the range of ids_size defaults to 0. - * @note An empty ids list results in a empty stmt. - * @pre The UBI volume which shall be used as source volume exists. - * @pre The UBI volumes which are defined as destination volumes exist. - * @post The content of the UBI volume which was defined as source volume - * equals the content of the volumes which were defined as destination. - */ -int ubimirror(uint32_t devno, int seqnum, uint32_t* ids, ssize_t ids_size, - char *err_buf, size_t err_buf_size); - -#endif /* __UBIMIRROR_H__ */ diff --git a/ubi-utils/sort-me-out/unubi_test.sh b/ubi-utils/sort-me-out/unubi_test.sh deleted file mode 100644 index 40dc2e2..0000000 --- a/ubi-utils/sort-me-out/unubi_test.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/sh -# -# Use raw NAND data, extract UBI image and apply tool to it. -# Test basic functionality. -# -# 2007 Frank Haverkamp <haver@vnet.ibm.com> -# - -version=1.1 - -image=data.mif -oob=oob.bin -data=data.bin -pagesize=2048 -volmax=31 -datadir=unubi_data - -# 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 ${unubi_args} -r${v} -d${datadir}/volumes ${data} - echo -n "." -done -echo "ok" -ls -l ${datadir}/volumes -echo - -echo "------------------------------------------------------------------------" -echo "Extracting graphics ..." -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 "------------------------------------------------------------------------" -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 "------------------------------------------------------------------------" -cat ${datadir}/vol_info_table0 -echo - -echo "------------------------------------------------------------------------" -echo "Table 1" -echo "------------------------------------------------------------------------" -cat ${datadir}/vol_info_table1 -echo diff --git a/ubi-utils/src/bootenv.c b/ubi-utils/src/bootenv.c deleted file mode 100644 index 5a4205f..0000000 --- a/ubi-utils/src/bootenv.c +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * 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: Oliver Lohmann - */ - -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <netinet/in.h> -#include <sys/stat.h> -#include <bootenv.h> - -#include "hashmap.h" -#include "error.h" - -#include <mtd/ubi-header.h> -#include "crc32.h" - -#define ubi_unused __attribute__((unused)) - -#define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */ - -/* Structures */ -struct bootenv { - hashmap_t map; ///< Pointer to hashmap which holds data structure. -}; - -struct bootenv_list { - hashmap_t head; ///< Pointer to list which holds the data structure. -}; - -/** - * @brief Remove the '\n' from a given line. - * @param line Input/Output line. - * @param size Size of the line. - * @param fp File Pointer. - * @return 0 - * @return or error - */ -static int -remove_lf(char *line, size_t size, FILE* fp) -{ - size_t i; - - for (i = 0; i < size; i++) { - if (line[i] == '\n') { - line[i] = '\0'; - return 0; - } - } - - if (!feof(fp)) { - return BOOTENV_EINVAL; - } - - return 0; -} - -/** - * @brief Determine if a line contains only WS. - * @param line The line to process. - * @param size Size of input line. - * @return 1 Yes, only WS. - * @return 0 No, contains data. - */ -static int -is_ws(const char *line, size_t size) -{ - size_t i = 0; - - while (i < size) { - switch (line[i]) { - case '\n': - return 1; - case '#': - return 1; - case ' ': - i++; - continue; - case '\t': - i++; - continue; - default: /* any other char -> no cmnt */ - return 0; - } - } - - return 0; -} - - -/* ------------------------------------------------------------------------- */ - -/** - * @brief Build a list from a comma seperated value string. - * @param list Pointer to hashmap structure which shall store - * the list. - * @param value Comma seperated value string. - * @return 0 - * @return or error. - */ -static int -build_list_definition(hashmap_t list, const char *value) -{ - int rc = 0; - char *str = NULL; - char *ptr = NULL; - size_t len, i, j; - - /* str: val1,val2 , val4,...,valN */ - len = strlen(value); - str = (char*) malloc((len+1) * sizeof(char)); - - /* 1. reformat string: remove spaces */ - for (i = 0, j = 0; i < len; i++) { - if (value[i] == ' ') - continue; - - str[j] = value[i]; - j++; - } - str[j] = '\0'; - - /* str: val1,val2,val4,...,valN\0*/ - /* 2. replace ',' seperator with '\0' */ - len = strlen(str); - for (i = 0; i < len; i++) { - if (str[i] == ',') { - str[i] = '\0'; - } - } - - /* str: val1\0val2\0val4\0...\0valN\0*/ - /* 3. insert definitions into a hash map, using it like a list */ - i = j = 0; - ptr = str; - while (((i = strlen(ptr)) > 0) && (j < len)) { - rc = hashmap_add(list, ptr, ""); - if (rc != 0) { - free(str); - return rc; - } - j += i+1; - if (j < len) - ptr += i+1; - } - - free(str); - return rc; -} - -/** - * @brief Extract a key value pair and add it to a hashmap - * @param str Input string which contains a key value pair. - * @param env The updated handle which contains the new pair. - * @return 0 - * @return or error - * @note The input string format is: "key=value" - */ -static int -extract_pair(const char *str, bootenv_t env) -{ - int rc = 0; - char *key = NULL; - char *val = NULL; - - key = strdup(str); - if (key == NULL) - return -ENOMEM; - - val = strstr(key, "="); - if (val == NULL) { - rc = BOOTENV_EBADENTRY; - goto err; - } - - *val = '\0'; /* split strings */ - val++; - - rc = bootenv_set(env, key, val); - - err: - free(key); - return rc; -} - -int -bootenv_destroy(bootenv_t* env) -{ - int rc = 0; - - if (env == NULL || *env == NULL) - return -EINVAL; - - bootenv_t tmp = *env; - - rc = hashmap_free(tmp->map); - if (rc != 0) - return rc; - - free(tmp); - return rc; -} - -int -bootenv_create(bootenv_t* env) -{ - bootenv_t res; - res = (bootenv_t) calloc(1, sizeof(struct bootenv)); - - if (res == NULL) - return -ENOMEM; - - res->map = hashmap_new(); - - if (res->map == NULL) { - free(res); - return -ENOMEM; - } - - *env = res; - - return 0; -} - - -/** - * @brief Read a formatted buffer and scan it for valid bootenv - * key/value pairs. Add those pairs into a hashmap. - * @param env Hashmap which shall be used to hold the data. - * @param buf Formatted buffer. - * @param size Size of the buffer. - * @return 0 - * @return or error - */ -static int -rd_buffer(bootenv_t env, const char *buf, size_t size) -{ - const char *curr = buf; /* ptr to current key/value pair */ - uint32_t i, j; /* current length, chars processed */ - - if (buf[size - 1] != '\0') /* must end in '\0' */ - return BOOTENV_EFMT; - - for (j = 0; j < size; j += i, curr += i) { - /* strlen returns the size of the string upto - but not including the null terminator; - adding 1 to account for '\0' */ - i = strlen(curr) + 1; - - if (i == 1) - return 0; /* no string found */ - - if (extract_pair(curr, env) != 0) - return BOOTENV_EINVAL; - } - - return 0; -} - - -int -bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc) -{ - int rc; - char *buf = NULL; - size_t i = 0; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - /* allocate temp buffer */ - buf = (char*) calloc(1, size * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - /* FIXME Andreas, please review this I removed size-1 and - * replaced it by just size, I saw the kernel image starting - * with a 0x0060.... and not with the 0x60.... what it should - * be. Is this a tools problem or is it a problem here where - * fp is moved not to the right place due to the former size-1 - * here. - */ - while((i < size) && (!feof(fp))) { - int c = fgetc(fp); - if (c == EOF) { - /* FIXME isn't this dangerous, to update - the boot envs with incomplete data? */ - buf[i++] = '\0'; - break; /* we have enough */ - } - if (ferror(fp)) { - rc = -EIO; - goto err; - } - - buf[i++] = (char)c; - } - - /* calculate crc to return */ - if (ret_crc != NULL) { - *ret_crc = crc32(UBI_CRC32_INIT, buf, size); - } - - /* transfer to hashmap */ - rc = rd_buffer(env, buf, size); - -err: - free(buf); - return rc; -} - - -/** - * If we have a single file containing the boot-parameter size should - * be specified either as the size of the file or as BOOTENV_MAXSIZE. - * If the bootparameter are in the middle of a file we need the exact - * length of the data. - */ -int -bootenv_read(FILE* fp, bootenv_t env, size_t size) -{ - return bootenv_read_crc(fp, env, size, NULL); -} - - -int -bootenv_read_txt(FILE* fp, bootenv_t env) -{ - int rc = 0; - char *buf = NULL; - char *line = NULL; - char *lstart = NULL; - char *curr = NULL; - size_t len; - size_t size; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - size = BOOTENV_MAXSIZE; - - /* allocate temp buffers */ - buf = (char*) calloc(1, size * sizeof(char)); - lstart = line = (char*) calloc(1, size * sizeof(char)); - if ((buf == NULL) || (line == NULL)) { - rc = -ENOMEM; - goto err; - } - - curr = buf; - while ((line = fgets(line, size, fp)) != NULL) { - if (is_ws(line, size)) { - continue; - } - rc = remove_lf(line, BOOTENV_MAXSIZE, fp); - if (rc != 0) { - goto err; - } - - /* copy new line to binary buffer */ - len = strlen(line); - if (len > size) { - rc = -EFBIG; - goto err; - } - size -= len; /* track remaining space */ - - memcpy(curr, line, len); - curr += len + 1; /* for \0 seperator */ - } - - rc = rd_buffer(env, buf, BOOTENV_MAXSIZE); -err: - if (buf != NULL) - free(buf); - if (lstart != NULL) - free(lstart); - return rc; -} - -static int -fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max ubi_unused, - size_t *written) -{ - int rc = 0; - size_t keys_size, i; - size_t wr = 0; - const char **keys = NULL; - const char *val = NULL; - - rc = bootenv_get_key_vector(env, &keys_size, 1, &keys); - if (rc != 0) - goto err; - - for (i = 0; i < keys_size; i++) { - if (wr > BOOTENV_MAXSIZE) { - rc = -ENOSPC; - goto err; - } - - rc = bootenv_get(env, keys[i], &val); - if (rc != 0) - goto err; - - wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr, - "%s=%s", keys[i], val); - wr++; /* for \0 */ - } - - *written = wr; - -err: - if (keys != NULL) - free(keys); - - return rc; -} - -int -bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc) -{ - int rc = 0; - size_t size = 0; - char *buf = NULL; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - - rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size); - if (rc != 0) - goto err; - - /* calculate crc to return */ - if (ret_crc != NULL) { - *ret_crc = crc32(UBI_CRC32_INIT, buf, size); - } - - if (fwrite(buf, size, 1, fp) != 1) { - rc = -EIO; - goto err; - } - -err: - if (buf != NULL) - free(buf); - return rc; -} - -int -bootenv_write(FILE* fp, bootenv_t env) -{ - return bootenv_write_crc(fp, env, NULL); -} - -int -bootenv_compare(bootenv_t first, bootenv_t second) -{ - int rc; - size_t written_first, written_second; - char *buf_first, *buf_second; - - if (first == NULL || second == NULL) - return -EINVAL; - - buf_first = malloc(BOOTENV_MAXSIZE); - if (!buf_first) - return -ENOMEM; - buf_second = malloc(BOOTENV_MAXSIZE); - if (!buf_second) { - rc = -ENOMEM; - goto err; - } - - rc = fill_output_buffer(first, buf_first, BOOTENV_MAXSIZE, - &written_first); - if (rc < 0) - goto err; - rc = fill_output_buffer(second, buf_second, BOOTENV_MAXSIZE, - &written_second); - if (rc < 0) - goto err; - - if (written_first != written_second) { - rc = 1; - goto err; - } - - rc = memcmp(buf_first, buf_second, written_first); - if (rc != 0) { - rc = 2; - goto err; - } - -err: - if (buf_first) - free(buf_first); - if (buf_second) - free(buf_second); - - return rc; -} - -int -bootenv_size(bootenv_t env, size_t *size) -{ - int rc = 0; - char *buf = NULL; - - if (env == NULL) - return -EINVAL; - - buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); - if (buf == NULL) - return -ENOMEM; - - rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, size); - if (rc != 0) - goto err; - -err: - if (buf != NULL) - free(buf); - return rc; -} - -int -bootenv_write_txt(FILE* fp, bootenv_t env) -{ - int rc = 0; - size_t size, wr, i; - const char **keys = NULL; - const char *key = NULL; - const char *val = NULL; - - if ((fp == NULL) || (env == NULL)) - return -EINVAL; - - rc = bootenv_get_key_vector(env, &size, 1, &keys); - if (rc != 0) - goto err; - - for (i = 0; i < size; i++) { - key = keys[i]; - rc = bootenv_get(env, key, &val); - if (rc != 0) - goto err; - - wr = fprintf(fp, "%s=%s\n", key, val); - if (wr != strlen(key) + strlen(val) + 2) { - rc = -EIO; - goto err; - } - } - -err: - if (keys != NULL) - free(keys); - return rc; -} - -int -bootenv_valid(bootenv_t env ubi_unused) -{ - /* @FIXME No sanity check implemented. */ - return 0; -} - -int -bootenv_copy_bootenv(bootenv_t in, bootenv_t *out) -{ - int rc = 0; - const char *tmp = NULL; - const char **keys = NULL; - size_t vec_size, i; - - if ((in == NULL) || (out == NULL)) - return -EINVAL; - - /* purge output var for sure... */ - rc = bootenv_destroy(out); - if (rc != 0) - return rc; - - /* create the new map */ - rc = bootenv_create(out); - if (rc != 0) - goto err; - - /* get the key list from the input map */ - rc = bootenv_get_key_vector(in, &vec_size, 0, &keys); - if (rc != 0) - goto err; - - if (vec_size != hashmap_size(in->map)) { - rc = BOOTENV_ECOPY; - goto err; - } - - /* make a deep copy of the hashmap */ - for (i = 0; i < vec_size; i++) { - rc = bootenv_get(in, keys[i], &tmp); - if (rc != 0) - goto err; - - rc = bootenv_set(*out, keys[i], tmp); - if (rc != 0) - goto err; - } - -err: - if (keys != NULL) - free(keys); - - return rc; -} - -/* ------------------------------------------------------------------------- */ - - -int -bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, - int *warnings, char *err_buf ubi_unused, - size_t err_buf_size ubi_unused) -{ - bootenv_list_t l_old = NULL; - bootenv_list_t l_new = NULL; - const char *pdd_old = NULL; - const char *pdd_new = NULL; - const char *tmp = NULL; - const char **vec_old = NULL; - const char **vec_new = NULL; - const char **pdd_up_vec = NULL; - size_t vec_old_size, vec_new_size, pdd_up_vec_size, i; - int rc = 0; - - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - /* get the pdd strings, e.g.: - * pdd_old=a,b,c - * pdd_new=a,c,d,e */ - rc = bootenv_get(env_old, "pdd", &pdd_old); - if (rc != 0) - goto err; - rc = bootenv_get(env_new, "pdd", &pdd_new); - if (rc != 0) - goto err; - - /* put it into a list and then convert it to an vector */ - rc = bootenv_list_create(&l_old); - if (rc != 0) - goto err; - rc = bootenv_list_create(&l_new); - if (rc != 0) - goto err; - - rc = bootenv_list_import(l_old, pdd_old); - if (rc != 0) - goto err; - - rc = bootenv_list_import(l_new, pdd_new); - if (rc != 0) - goto err; - - rc = bootenv_list_to_vector(l_old, &vec_old_size, &vec_old); - if (rc != 0) - goto err; - - rc = bootenv_list_to_vector(l_new, &vec_new_size, &vec_new); - if (rc != 0) - goto err; - - rc = bootenv_copy_bootenv(env_new, env_res); - if (rc != 0) - goto err; - - /* calculate the update vector between the old and new pdd */ - pdd_up_vec = hashmap_get_update_key_vector(vec_old, vec_old_size, - vec_new, vec_new_size, &pdd_up_vec_size); - - if (pdd_up_vec == NULL) { - rc = -ENOMEM; - goto err; - } - - if (pdd_up_vec_size != 0) { - /* need to warn the user about the unset of - * some pdd/bootenv values */ - *warnings = BOOTENV_WPDD_STRING_DIFFERS; - - /* remove all entries in the new bootenv load */ - for (i = 0; i < pdd_up_vec_size; i++) { - bootenv_unset(*env_res, pdd_up_vec[i]); - } - } - - /* generate the keep array and copy old pdd values to new bootenv */ - for (i = 0; i < vec_old_size; i++) { - rc = bootenv_get(env_old, vec_old[i], &tmp); - if (rc != 0) { - rc = BOOTENV_EPDDINVAL; - goto err; - } - rc = bootenv_set(*env_res, vec_old[i], tmp); - if (rc != 0) { - goto err; - } - } - /* put the old pdd string into the result map */ - rc = bootenv_set(*env_res, "pdd", pdd_old); - if (rc != 0) { - goto err; - } - - -err: - if (vec_old != NULL) - free(vec_old); - if (vec_new != NULL) - free(vec_new); - if (pdd_up_vec != NULL) - free(pdd_up_vec); - - bootenv_list_destroy(&l_old); - bootenv_list_destroy(&l_new); - return rc; -} - - -int -bootenv_pdd_overwrite(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings ubi_unused, - char *err_buf ubi_unused, size_t err_buf_size ubi_unused) -{ - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - return bootenv_copy_bootenv(env_new, env_res); -} - -int -bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, - int *warnings ubi_unused, char *err_buf, size_t err_buf_size) -{ - if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) - return -EINVAL; - - snprintf(err_buf, err_buf_size, "The PDD merge operation is not " - "implemented. Contact: <oliloh@de.ibm.com>"); - - return BOOTENV_ENOTIMPL; -} - -/* ------------------------------------------------------------------------- */ - -int -bootenv_get(bootenv_t env, const char *key, const char **value) -{ - if (env == NULL) - return -EINVAL; - - *value = hashmap_lookup(env->map, key); - if (*value == NULL) - return BOOTENV_ENOTFOUND; - - return 0; -} - -int -bootenv_get_num(bootenv_t env, const char *key, uint32_t *value) -{ - char *endptr = NULL; - const char *str; - - if (env == NULL) - return 0; - - str = hashmap_lookup(env->map, key); - if (!str) - return -EINVAL; - - *value = strtoul(str, &endptr, 0); - - if (*endptr == '\0') { - return 0; - } - - return -EINVAL; -} - -int -bootenv_set(bootenv_t env, const char *key, const char *value) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_add(env->map, key, value); -} - -int -bootenv_unset(bootenv_t env, const char *key) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_remove(env->map, key); -} - -int -bootenv_get_key_vector(bootenv_t env, size_t* size, int sort, - const char ***vector) -{ - if ((env == NULL) || (size == NULL)) - return -EINVAL; - - *vector = hashmap_get_key_vector(env->map, size, sort); - - if (*vector == NULL) - return -EINVAL; - - return 0; -} - -int -bootenv_dump(bootenv_t env) -{ - if (env == NULL) - return -EINVAL; - - return hashmap_dump(env->map); -} - -int -bootenv_list_create(bootenv_list_t *list) -{ - bootenv_list_t res; - res = (bootenv_list_t) calloc(1, sizeof(struct bootenv_list)); - - if (res == NULL) - return -ENOMEM; - - res->head = hashmap_new(); - - if (res->head == NULL) { - free(res); - return -ENOMEM; - } - - *list = res; - return 0; -} - -int -bootenv_list_destroy(bootenv_list_t *list) -{ - int rc = 0; - - if (list == NULL) - return -EINVAL; - - bootenv_list_t tmp = *list; - if (tmp == 0) - return 0; - - rc = hashmap_free(tmp->head); - if (rc != 0) - return rc; - - free(tmp); - *list = NULL; - return 0; -} - -int -bootenv_list_import(bootenv_list_t list, const char *str) -{ - if (list == NULL) - return -EINVAL; - - return build_list_definition(list->head, str); -} - -int -bootenv_list_export(bootenv_list_t list, char **string) -{ - size_t size, i, j, bufsize, tmp, rc = 0; - const char **items; - - if (list == NULL) - return -EINVAL; - - bufsize = BOOTENV_MAXLINE; - char *res = (char*) malloc(bufsize * sizeof(char)); - if (res == NULL) - return -ENOMEM; - - rc = bootenv_list_to_vector(list, &size, &items); - if (rc != 0) { - goto err; - } - - j = 0; - for (i = 0; i < size; i++) { - tmp = strlen(items[i]); - if (j >= bufsize) { - bufsize += BOOTENV_MAXLINE; - res = (char*) realloc(res, bufsize * sizeof(char)); - if (res == NULL) { - rc = -ENOMEM; - goto err; - } - } - memcpy(res + j, items[i], tmp); - j += tmp; - if (i < (size - 1)) { - res[j] = ','; - j++; - } - } - j++; - res[j] = '\0'; - free(items); - *string = res; - return 0; -err: - free(items); - return rc; -} - -int -bootenv_list_add(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_add(list->head, item, ""); -} - -int -bootenv_list_remove(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_remove(list->head, item); -} - -int -bootenv_list_is_in(bootenv_list_t list, const char *item) -{ - if ((list == NULL) || (item == NULL)) - return -EINVAL; - - return hashmap_lookup(list->head, item) != NULL ? 1 : 0; -} - -int -bootenv_list_to_vector(bootenv_list_t list, size_t *size, const char ***vector) -{ - if ((list == NULL) || (size == NULL)) - return -EINVAL; - - *vector = hashmap_get_key_vector(list->head, size, 1); - if (*vector == NULL) - return -ENOMEM; - - return 0; -} - -int -bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, - uint32_t **vector) -{ - int rc = 0; - size_t i; - uint32_t* res = NULL; - char *endptr = NULL; - const char **a = NULL; - - rc = bootenv_list_to_vector(list, size, &a); - if (rc != 0) - goto err; - - res = (uint32_t*) malloc (*size * sizeof(uint32_t)); - if (!res) - goto err; - - for (i = 0; i < *size; i++) { - res[i] = strtoul(a[i], &endptr, 0); - if (*endptr != '\0') - goto err; - } - - if (a) - free(a); - *vector = res; - return 0; - -err: - if (a) - free(a); - if (res) - free(res); - return rc; -} diff --git a/ubi-utils/src/bootenv.h b/ubi-utils/src/bootenv.h deleted file mode 100644 index 8fecdbf..0000000 --- a/ubi-utils/src/bootenv.h +++ /dev/null @@ -1,434 +0,0 @@ -#ifndef __BOOTENV_H__ -#define __BOOTENV_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. - */ - -#include <stdio.h> /* FILE */ -#include <stdint.h> -#include <pfiflash.h> - -/* DOXYGEN DOCUMENTATION */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @file bootenv.h - * @author oliloh@de.ibm.com - * @version 1.3 - * - * 1.3 Some renaming - */ - -/** - * @mainpage Usage - * - * @section intro Introduction - * This library provides all functionality to handle with the so-called - * platform description data (PDD) and the bootparameters defined in - * U-Boot. It is able to apply the defined PDD operations in PDD update - * scenarios. For more information about the PDD and bootparameter - * environment "bootenv" confer the PDD documentation. - * - * @section ret Return codes - * This library defines some return codes which will be delivered classified - * as warnings or errors. See the "Defines" section for details and numeric - * values. - * - * @section benv Bootenv format description - * There are two different input formats: - * - text files - * - binary files - * - * @subsection txt Text Files - * Text files have to be specified like: - * @verbatim key1=value1,value2,value7\n key2=value55,value1\n key4=value1\n@endverbatim - * - * @subsection bin Binary files - * Binary files have to be specified like: - * @verbatim<CRC32-bit>key1=value1,value2,value7\0key2=value55,value1\0... @endverbatim - * You can confer the U-Boot documentation for more details. - * - * @section benvlists Bootenv lists format description. - * Values referenced in the preceeding subsection can be - * defined like lists: - * @verbatim value1,value2,value3 @endverbatim - * There are some situation where a conversion of a comma - * seperated list can be useful, e.g. to get a list - * of defined PDD entries. - */ - -#define BOOTENV_MAXSIZE (1024 * 100) /* max 100kiB space for bootenv */ - -/** - * @def BOOTENV_ECRC - * @brief Given binary file is to large. - * @def BOOTENV_EFMT - * @brief Given bootenv section has an invalid format - * @def BOOTENV_EBADENTRY - * @brief Bad entry in the bootenv section. - * @def BOOTENV_EINVAL - * @brief Invalid bootenv defintion. - * @def BOOTENV_ENOPDD - * @brief Given bootenv sectoin has no PDD defintion string (pdd=...). - * @def BOOTENV_EPDDINVAL - * @brief Given bootenv section has an invalid PDD defintion. - * @def BOOTENV_ENOTIMPL - * @brief Functionality not implemented. - * @def BOOTENV_ECOPY - * @brief Bootenv memory copy error - * @def BOOTENV_ENOTFOUND - * @brief Given key has has no value. - * @def BOOTENV_EMAX - * @brief Highest error value. - */ -#define BOOTENV_ETOOBIG 1 -#define BOOTENV_EFMT 2 -#define BOOTENV_EBADENTRY 3 -#define BOOTENV_EINVAL 4 -#define BOOTENV_ENOPDD 5 -#define BOOTENV_EPDDINVAL 6 -#define BOOTENV_ENOTIMPL 7 -#define BOOTENV_ECOPY 8 -#define BOOTENV_ENOTFOUND 9 -#define BOOTENV_EMAX 10 - -/** - * @def BOOTENV_W - * @brief A warning which is handled internally as an error - * but can be recovered by manual effort. - * @def BOOTENV_WPDD_STRING_DIFFERS - * @brief The PDD strings of old and new PDD differ and - * can cause update problems, because new PDD values - * are removed from the bootenv section completely. - */ -#define BOOTENV_W 20 -#define BOOTENV_WPDD_STRING_DIFFERS 21 -#define BOOTENV_WMAX 22 /* highest warning value */ - - -typedef struct bootenv *bootenv_t; - /**< A bootenv library handle. */ - -typedef struct bootenv_list *bootenv_list_t; - /**< A handle for a value list. */ - -typedef int(*pdd_func_t)(bootenv_t, bootenv_t, bootenv_t*, - int*, char*, size_t); - - -/** - * @brief Get a new handle. - * @return 0 - * @return or error - * */ -int bootenv_create(bootenv_t *env); - -/** - * @brief Cleanup structure. - * @param env Bootenv structure which shall be destroyed. - * @return 0 - * @return or error - */ -int bootenv_destroy(bootenv_t *env); - -/** - * @brief Copy a bootenv handle. - * @param in The input bootenv. - * @param out The copied output bootenv. Discards old data. - * @return 0 - * @return or error - */ -int bootenv_copy_bootenv(bootenv_t in, bootenv_t *out); - -/** - * @brief Looks for a value inside the bootenv data. - * @param env Handle to a bootenv structure. - * @param key The key. - * @return NULL key not found - * @return !NULL ptr to value - */ -int bootenv_get(bootenv_t env, const char *key, const char **value); - - -/** - * @brief Looks for a value inside the bootenv data and converts it to num. - * @param env Handle to a bootenv structure. - * @param key The key. - * @param value A pointer to the resulting numerical value - * @return NULL key not found - * @return !NULL ptr to value - */ -int bootenv_get_num(bootenv_t env, const char *key, uint32_t *value); - -/** - * @brief Set a bootenv value by key. - * @param env Handle to a bootenv structure. - * @param key Key. - * @param value Value to set. - * @return 0 - * @return or error - */ -int bootenv_set(bootenv_t env, const char *key, const char *value); - -/** - * @brief Remove the given key (and its value) from a bootenv structure. - * @param env Handle to a bootenv structure. - * @param key Key. - * @return 0 - * @return or error - */ -int bootenv_unset(bootenv_t env, const char *key); - - -/** - * @brief Get a vector of all keys which are currently set - * within a bootenv handle. - * @param env Handle to a bootenv structure. - * @param size The size of the allocated array structure. - * @param sort Flag, if set the vector is sorted ascending. - * @return NULL on error. - * @return !NULL a pointer to the first element the allocated vector. - * @warning Free the allocate memory yourself! - */ -int bootenv_get_key_vector(bootenv_t env, size_t *size, int sort, - const char ***vector); - -/** - * @brief Calculate the size in bytes which are necessary to write the - * current bootenv section in a *binary file. - * @param env bootenv handle. - * @param size The size in bytes of the bootenv handle. - * @return 0 - * @return or ERROR. - */ -int bootenv_size(bootenv_t env, size_t *size); - -/** - * @brief Read a binary bootenv file. - * @param fp File pointer to input stream. - * @param env bootenv handle. - * @param size maximum data size. - * @return 0 - * @return or ERROR. - */ -int bootenv_read(FILE* fp, bootenv_t env, size_t size); - -/** - * @param ret_crc return value of crc of read data - */ -int bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t *ret_crc); - -/** - * @brief Read bootenv data from an text/ascii file. - * @param fp File pointer to ascii PDD file. - * @param env bootenv handle - * @return 0 - * @return or ERROR. - */ -int bootenv_read_txt(FILE* fp, bootenv_t env); - -/** - * @brief Write a bootenv structure to the given location (binary). - * @param fp Filepointer to binary file. - * @param env Bootenv structure which shall be written. - * @return 0 - * @return or error - */ -int bootenv_write(FILE* fp, bootenv_t env); - -/** - * @param ret_crc return value of crc of read data - */ -int bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc); - -/** - * @brief Write a bootenv structure to the given location (text). - * @param fp Filepointer to text file. - * @param env Bootenv structure which shall be written. - * @return 0 - * @return or error - */ -int bootenv_write_txt(FILE* fp, bootenv_t env); - -/** - * @brief Compare bootenvs using memcmp(). - * @param first First bootenv. - * @param second Second bootenv. - * @return 0 if bootenvs are equal - * @return < 0 if error - * @return > 0 if unequal - */ -int bootenv_compare(bootenv_t first, bootenv_t second); - -/** - * @brief Prototype for a PDD handling funtion - */ - -/** - * @brief The PDD keep operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of PDD keep. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - - -/** - * @brief The PDD merge operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of merge-pdd. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, - bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - -/** - * @brief The PDD overwrite operation. - * @param env_old The old bootenv structure. - * @param env_new The new bootenv structure. - * @param env_res The result of overwrite-pdd. - * @param warnings A flag which marks any warnings. - * @return 0 - * @return or error - * @note For a complete documentation about the algorithm confer the - * PDD documentation. - */ -int bootenv_pdd_overwrite(bootenv_t env_new, - bootenv_t env_old, bootenv_t *env_res, int *warnings, - char *err_buf, size_t err_buf_size); - -/** - * @brief Dump a bootenv structure to stdout. (Debug) - * @param env Handle to a bootenv structure. - * @return 0 - * @return or error - */ -int bootenv_dump(bootenv_t env); - -/** - * @brief Validate a bootenv structure. - * @param env Handle to a bootenv structure. - * @return 0 - * @return or error - */ -int bootenv_valid(bootenv_t env); - -/** - * @brief Create a new bootenv list structure. - * @return NULL on error - * @return or a new list handle. - * @note This structure is used to store values in a list. - * A useful addition when handling PDD strings. - */ -int bootenv_list_create(bootenv_list_t *list); - -/** - * @brief Destroy a bootenv list structure - * @param list Handle to a bootenv list structure. - * @return 0 - * @return or error - */ -int bootenv_list_destroy(bootenv_list_t *list); - -/** - * @brief Import a list from a comma seperated string - * @param list Handle to a bootenv list structure. - * @param str Comma seperated string list. - * @return 0 - * @return or error - */ -int bootenv_list_import(bootenv_list_t list, const char *str); - -/** - * @brief Export a list to a string of comma seperated values. - * @param list Handle to a bootenv list structure. - * @return NULL one error - * @return or pointer to a newly allocated string. - * @warning Free the allocated memory by yourself! - */ -int bootenv_list_export(bootenv_list_t list, char **string); - -/** - * @brief Add an item to the list. - * @param list A handle of a list structure. - * @param item An item. - * @return 0 - * @return or error - */ -int bootenv_list_add(bootenv_list_t list, const char *item); - -/** - * @brief Remove an item from the list. - * @param list A handle of a list structure. - * @param item An item. - * @return 0 - * @return or error - */ -int bootenv_list_remove(bootenv_list_t list, const char *item); - -/** - * @brief Check if a given item is in a given list. - * @param list A handle of a list structure. - * @param item An item. - * @return 1 Item is in list. - * @return 0 Item is not in list. - */ -int bootenv_list_is_in(bootenv_list_t list, const char *item); - - -/** - * @brief Convert a list into a vector of all values inside the list. - * @param list Handle to a bootenv structure. - * @param size The size of the allocated vector structure. - * @return 0 - * @return or error - * @warning Free the allocate memory yourself! - */ -int bootenv_list_to_vector(bootenv_list_t list, size_t *size, - const char ***vector); - -/** - * @brief Convert a list into a vector of all values inside the list. - * @param list Handle to a bootenv structure. - * @param size The size of the allocated vector structure. - * @return 0 - * @return or error - * @warning Free the allocate memory yourself! - */ -int bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, - uint32_t **vector); - -#ifdef __cplusplus -} -#endif -#endif /*__BOOTENV_H__ */ diff --git a/ubi-utils/src/common.c b/ubi-utils/src/common.c index f8110c3..56244df 100644 --- a/ubi-utils/src/common.c +++ b/ubi-utils/src/common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) Artem Bityutskiy, 2007 + * Copyright (C) 2007, 2008 Nokia Corporation * * 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 @@ -19,11 +19,13 @@ /* * This file contains various common stuff used by UBI utilities. * - * Author: Artem Bityutskiy + * Authors: Artem Bityutskiy + * Adrian Hunter */ #include <stdio.h> #include <string.h> +#include <ctype.h> /** * ubiutils_bytes_multiplier - convert size specifier to an integer @@ -87,3 +89,56 @@ void ubiutils_print_bytes(long long bytes, int bracket) if (bracket) printf(")"); } + +/** + * ubiutils_print_text - print text and fold it. + * @stream: file stream to print to + * @text: text to print + * @width: maximum allowed text width + * + * Print text and fold it so that each line would not have more then @width + * characters. + */ +void ubiutils_print_text(FILE *stream, const char *text, int width) +{ + int pos, bpos = 0; + const char *p; + char line[1024]; + + if (width > 1023) { + fprintf(stream, "%s\n", text); + return; + } + p = text; + pos = 0; + while (p[pos]) { + while (!isspace(p[pos])) { + line[pos] = p[pos]; + if (!p[pos]) + break; + ++pos; + if (pos == width) { + line[pos] = '\0'; + fprintf(stream, "%s\n", line); + p += pos; + pos = 0; + } + } + while (pos < width) { + line[pos] = p[pos]; + if (!p[pos]) { + bpos = pos; + break; + } + if (isspace(p[pos])) + bpos = pos; + ++pos; + } + line[bpos] = '\0'; + fprintf(stream, "%s\n", line); + p += bpos; + pos = 0; + while (p[pos] && isspace(p[pos])) + ++p; + } +} diff --git a/ubi-utils/src/common.h b/ubi-utils/src/common.h index 89094ab..3ee93ff 100644 --- a/ubi-utils/src/common.h +++ b/ubi-utils/src/common.h @@ -19,6 +19,8 @@ #ifndef __UBI_UTILS_COMMON_H__ #define __UBI_UTILS_COMMON_H__ +#include <stdio.h> + #ifdef __cplusplus extern "C" { #endif @@ -26,18 +28,30 @@ extern "C" { #define MIN(a ,b) ((a) < (b) ? (a) : (b)) #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +/* Verbose messages */ +#define verbose(verbose, fmt, ...) do { \ + if (verbose) \ + printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \ +} while(0) + +/* Normal messages */ +#define normsg(fmt, ...) do { \ + printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \ +} while(0) + /* Error messages */ #define errmsg(fmt, ...) do { \ - fprintf(stderr, PROGRAM_NAME " error: " fmt "\n", ##__VA_ARGS__); \ + fprintf(stderr, PROGRAM_NAME " error: " fmt "\n", ##__VA_ARGS__); \ } while(0) /* Warnings */ #define warnmsg(fmt, ...) do { \ - fprintf(stderr, PROGRAM_NAME " warning: " fmt "\n", ##__VA_ARGS__); \ + fprintf(stderr, PROGRAM_NAME " warning: " fmt "\n", ##__VA_ARGS__); \ } while(0) int ubiutils_get_multiplier(const char *str); void ubiutils_print_bytes(long long bytes, int bracket); +void ubiutils_print_text(FILE *stream, const char *txt, int len); #ifdef __cplusplus } diff --git a/ubi-utils/src/config.h b/ubi-utils/src/config.h deleted file mode 100644 index 55e60f3..0000000 --- a/ubi-utils/src/config.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __CONFIG_H__ -#define __CONFIG_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: Frank Haverkamp - */ - -#define PACKAGE_BUGREPORT \ - "haver@vnet.ibm.com, dedekind@linutronix.de, or tglx@linutronix.de" - -#define ubi_unused __attribute__((unused)) - -#endif diff --git a/ubi-utils/src/dictionary.c b/ubi-utils/src/dictionary.c new file mode 100644 index 0000000..b7c9ebf --- /dev/null +++ b/ubi-utils/src/dictionary.c @@ -0,0 +1,405 @@ +/*-------------------------------------------------------------------------*/ +/** + @file dictionary.c + @author N. Devillard + @date Sep 2007 + @version $Revision: 1.27 $ + @brief Implements a dictionary for string variables. + + This module implements a simple dictionary object, i.e. a list + of string/string associations. This object is useful to store e.g. + informations retrieved from a configuration file (ini files). +*/ +/*--------------------------------------------------------------------------*/ + +/* + $Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $ + $Revision: 1.27 $ +*/ +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ +#include "dictionary.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/** Maximum value size for integers and doubles. */ +#define MAXVALSZ 1024 + +/** Minimal allocated number of entries in a dictionary */ +#define DICTMINSZ 128 + +/** Invalid key token */ +#define DICT_INVALID_KEY ((char*)-1) + +/*--------------------------------------------------------------------------- + Private functions + ---------------------------------------------------------------------------*/ + +/* Doubles the allocated size associated to a pointer */ +/* 'size' is the current allocated size. */ +static void * mem_double(void * ptr, int size) +{ + void * newptr ; + + newptr = calloc(2*size, 1); + if (newptr==NULL) { + return NULL ; + } + memcpy(newptr, ptr, size); + free(ptr); + return newptr ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Duplicate a string + @param s String to duplicate + @return Pointer to a newly allocated string, to be freed with free() + + This is a replacement for strdup(). This implementation is provided + for systems that do not have it. + */ +/*--------------------------------------------------------------------------*/ +static char * xstrdup(char * s) +{ + char * t ; + if (!s) + return NULL ; + t = malloc(strlen(s)+1) ; + if (t) { + strcpy(t,s); + } + return t ; +} + +/*--------------------------------------------------------------------------- + Function codes + ---------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +/** + @brief Compute the hash key for a string. + @param key Character string to use for key. + @return 1 unsigned int on at least 32 bits. + + This hash function has been taken from an Article in Dr Dobbs Journal. + This is normally a collision-free function, distributing keys evenly. + The key is stored anyway in the struct so that collision can be avoided + by comparing the key itself in last resort. + */ +/*--------------------------------------------------------------------------*/ +unsigned dictionary_hash(char * key) +{ + int len ; + unsigned hash ; + int i ; + + len = strlen(key); + for (hash=0, i=0 ; i<len ; i++) { + hash += (unsigned)key[i] ; + hash += (hash<<10); + hash ^= (hash>>6) ; + } + hash += (hash <<3); + hash ^= (hash >>11); + hash += (hash <<15); + return hash ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Create a new dictionary object. + @param size Optional initial size of the dictionary. + @return 1 newly allocated dictionary objet. + + This function allocates a new dictionary object of given size and returns + it. If you do not know in advance (roughly) the number of entries in the + dictionary, give size=0. + */ +/*--------------------------------------------------------------------------*/ +dictionary * dictionary_new(int size) +{ + dictionary * d ; + + /* If no size was specified, allocate space for DICTMINSZ */ + if (size<DICTMINSZ) size=DICTMINSZ ; + + if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) { + return NULL; + } + d->size = size ; + d->val = (char **)calloc(size, sizeof(char*)); + d->key = (char **)calloc(size, sizeof(char*)); + d->hash = (unsigned int *)calloc(size, sizeof(unsigned)); + return d ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a dictionary object + @param d dictionary object to deallocate. + @return void + + Deallocate a dictionary object and all memory associated to it. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_del(dictionary * d) +{ + int i ; + + if (d==NULL) return ; + for (i=0 ; i<d->size ; i++) { + if (d->key[i]!=NULL) + free(d->key[i]); + if (d->val[i]!=NULL) + free(d->val[i]); + } + free(d->val); + free(d->key); + free(d->hash); + free(d); + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get a value from a dictionary. + @param d dictionary object to search. + @param key Key to look for in the dictionary. + @param def Default value to return if key not found. + @return 1 pointer to internally allocated character string. + + This function locates a key in a dictionary and returns a pointer to its + value, or the passed 'def' pointer if no such key can be found in + dictionary. The returned character pointer points to data internal to the + dictionary object, you should not try to free it or modify it. + */ +/*--------------------------------------------------------------------------*/ +char * dictionary_get(dictionary * d, char * key, char * def) +{ + unsigned hash ; + int i ; + + hash = dictionary_hash(key); + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + /* Compare hash */ + if (hash==d->hash[i]) { + /* Compare string, to avoid hash collisions */ + if (!strcmp(key, d->key[i])) { + return d->val[i] ; + } + } + } + return def ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Set a value in a dictionary. + @param d dictionary object to modify. + @param key Key to modify or add. + @param val Value to add. + @return int 0 if Ok, anything else otherwise + + If the given key is found in the dictionary, the associated value is + replaced by the provided one. If the key cannot be found in the + dictionary, it is added to it. + + It is Ok to provide a NULL value for val, but NULL values for the dictionary + or the key are considered as errors: the function will return immediately + in such a case. + + Notice that if you dictionary_set a variable to NULL, a call to + dictionary_get will return a NULL value: the variable will be found, and + its value (NULL) is returned. In other words, setting the variable + content to NULL is equivalent to deleting the variable from the + dictionary. It is not possible (in this implementation) to have a key in + the dictionary without value. + + This function returns non-zero in case of failure. + */ +/*--------------------------------------------------------------------------*/ +int dictionary_set(dictionary * d, char * key, char * val) +{ + int i ; + unsigned hash ; + + if (d==NULL || key==NULL) return -1 ; + + /* Compute hash for this key */ + hash = dictionary_hash(key) ; + /* Find if value is already in dictionary */ + if (d->n>0) { + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + if (hash==d->hash[i]) { /* Same hash value */ + if (!strcmp(key, d->key[i])) { /* Same key */ + /* Found a value: modify and return */ + if (d->val[i]!=NULL) + free(d->val[i]); + d->val[i] = val ? xstrdup(val) : NULL ; + /* Value has been modified: return */ + return 0 ; + } + } + } + } + /* Add a new value */ + /* See if dictionary needs to grow */ + if (d->n==d->size) { + + /* Reached maximum size: reallocate dictionary */ + d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ; + d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ; + d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ; + if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { + /* Cannot grow dictionary */ + return -1 ; + } + /* Double size */ + d->size *= 2 ; + } + + /* Insert key in the first empty slot */ + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) { + /* Add key here */ + break ; + } + } + /* Copy key */ + d->key[i] = xstrdup(key); + d->val[i] = val ? xstrdup(val) : NULL ; + d->hash[i] = hash; + d->n ++ ; + return 0 ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a key in a dictionary + @param d dictionary object to modify. + @param key Key to remove. + @return void + + This function deletes a key in a dictionary. Nothing is done if the + key cannot be found. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_unset(dictionary * d, char * key) +{ + unsigned hash ; + int i ; + + if (key == NULL) { + return; + } + + hash = dictionary_hash(key); + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + /* Compare hash */ + if (hash==d->hash[i]) { + /* Compare string, to avoid hash collisions */ + if (!strcmp(key, d->key[i])) { + /* Found key */ + break ; + } + } + } + if (i>=d->size) + /* Key not found */ + return ; + + free(d->key[i]); + d->key[i] = NULL ; + if (d->val[i]!=NULL) { + free(d->val[i]); + d->val[i] = NULL ; + } + d->hash[i] = 0 ; + d->n -- ; + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump + @param f Opened file pointer. + @return void + + Dumps a dictionary onto an opened file pointer. Key pairs are printed out + as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as + output file pointers. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_dump(dictionary * d, FILE * out) +{ + int i ; + + if (d==NULL || out==NULL) return ; + if (d->n<1) { + fprintf(out, "empty dictionary\n"); + return ; + } + for (i=0 ; i<d->size ; i++) { + if (d->key[i]) { + fprintf(out, "%20s\t[%s]\n", + d->key[i], + d->val[i] ? d->val[i] : "UNDEF"); + } + } + return ; +} + + +/* Test code */ +#ifdef TESTDIC +#define NVALS 20000 +int main(int argc, char *argv[]) +{ + dictionary * d ; + char * val ; + int i ; + char cval[90] ; + + /* Allocate dictionary */ + printf("allocating...\n"); + d = dictionary_new(0); + + /* Set values in dictionary */ + printf("setting %d values...\n", NVALS); + for (i=0 ; i<NVALS ; i++) { + sprintf(cval, "%04d", i); + dictionary_set(d, cval, "salut"); + } + printf("getting %d values...\n", NVALS); + for (i=0 ; i<NVALS ; i++) { + sprintf(cval, "%04d", i); + val = dictionary_get(d, cval, DICT_INVALID_KEY); + if (val==DICT_INVALID_KEY) { + printf("cannot get value for key [%s]\n", cval); + } + } + printf("unsetting %d values...\n", NVALS); + for (i=0 ; i<NVALS ; i++) { + sprintf(cval, "%04d", i); + dictionary_unset(d, cval); + } + if (d->n != 0) { + printf("error deleting values\n"); + } + printf("deallocating...\n"); + dictionary_del(d); + return 0 ; +} +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/ubi-utils/src/dictionary.h b/ubi-utils/src/dictionary.h new file mode 100644 index 0000000..c7d1790 --- /dev/null +++ b/ubi-utils/src/dictionary.h @@ -0,0 +1,174 @@ + +/*-------------------------------------------------------------------------*/ +/** + @file dictionary.h + @author N. Devillard + @date Sep 2007 + @version $Revision: 1.12 $ + @brief Implements a dictionary for string variables. + + This module implements a simple dictionary object, i.e. a list + of string/string associations. This object is useful to store e.g. + informations retrieved from a configuration file (ini files). +*/ +/*--------------------------------------------------------------------------*/ + +/* + $Id: dictionary.h,v 1.12 2007-11-23 21:37:00 ndevilla Exp $ + $Author: ndevilla $ + $Date: 2007-11-23 21:37:00 $ + $Revision: 1.12 $ +*/ + +#ifndef _DICTIONARY_H_ +#define _DICTIONARY_H_ + +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/*--------------------------------------------------------------------------- + New types + ---------------------------------------------------------------------------*/ + + +/*-------------------------------------------------------------------------*/ +/** + @brief Dictionary object + + This object contains a list of string/string associations. Each + association is identified by a unique string key. Looking up values + in the dictionary is speeded up by the use of a (hopefully collision-free) + hash function. + */ +/*-------------------------------------------------------------------------*/ +typedef struct _dictionary_ { + int n ; /** Number of entries in dictionary */ + int size ; /** Storage size */ + char ** val ; /** List of string values */ + char ** key ; /** List of string keys */ + unsigned * hash ; /** List of hash values for keys */ +} dictionary ; + + +/*--------------------------------------------------------------------------- + Function prototypes + ---------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------*/ +/** + @brief Compute the hash key for a string. + @param key Character string to use for key. + @return 1 unsigned int on at least 32 bits. + + This hash function has been taken from an Article in Dr Dobbs Journal. + This is normally a collision-free function, distributing keys evenly. + The key is stored anyway in the struct so that collision can be avoided + by comparing the key itself in last resort. + */ +/*--------------------------------------------------------------------------*/ +unsigned dictionary_hash(char * key); + +/*-------------------------------------------------------------------------*/ +/** + @brief Create a new dictionary object. + @param size Optional initial size of the dictionary. + @return 1 newly allocated dictionary objet. + + This function allocates a new dictionary object of given size and returns + it. If you do not know in advance (roughly) the number of entries in the + dictionary, give size=0. + */ +/*--------------------------------------------------------------------------*/ +dictionary * dictionary_new(int size); + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a dictionary object + @param d dictionary object to deallocate. + @return void + + Deallocate a dictionary object and all memory associated to it. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_del(dictionary * vd); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get a value from a dictionary. + @param d dictionary object to search. + @param key Key to look for in the dictionary. + @param def Default value to return if key not found. + @return 1 pointer to internally allocated character string. + + This function locates a key in a dictionary and returns a pointer to its + value, or the passed 'def' pointer if no such key can be found in + dictionary. The returned character pointer points to data internal to the + dictionary object, you should not try to free it or modify it. + */ +/*--------------------------------------------------------------------------*/ +char * dictionary_get(dictionary * d, char * key, char * def); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Set a value in a dictionary. + @param d dictionary object to modify. + @param key Key to modify or add. + @param val Value to add. + @return int 0 if Ok, anything else otherwise + + If the given key is found in the dictionary, the associated value is + replaced by the provided one. If the key cannot be found in the + dictionary, it is added to it. + + It is Ok to provide a NULL value for val, but NULL values for the dictionary + or the key are considered as errors: the function will return immediately + in such a case. + + Notice that if you dictionary_set a variable to NULL, a call to + dictionary_get will return a NULL value: the variable will be found, and + its value (NULL) is returned. In other words, setting the variable + content to NULL is equivalent to deleting the variable from the + dictionary. It is not possible (in this implementation) to have a key in + the dictionary without value. + + This function returns non-zero in case of failure. + */ +/*--------------------------------------------------------------------------*/ +int dictionary_set(dictionary * vd, char * key, char * val); + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a key in a dictionary + @param d dictionary object to modify. + @param key Key to remove. + @return void + + This function deletes a key in a dictionary. Nothing is done if the + key cannot be found. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_unset(dictionary * d, char * key); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump + @param f Opened file pointer. + @return void + + Dumps a dictionary onto an opened file pointer. Key pairs are printed out + as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as + output file pointers. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_dump(dictionary * d, FILE * out); + +#endif diff --git a/ubi-utils/src/eb_chain.c b/ubi-utils/src/eb_chain.c deleted file mode 100644 index a018ae6..0000000 --- a/ubi-utils/src/eb_chain.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Author: Drake Dowsett, dowsett@de.ibm.com - * Contact: Andreas Arnez, arnez@de.ibm.com - */ - -/* see eb_chain.h */ - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include "unubi_analyze.h" -#include "crc32.h" - -#define COPY(dst, src) \ - do { \ - dst = malloc(sizeof(*dst)); \ - if (dst == NULL) \ - return -ENOMEM; \ - memcpy(dst, src, sizeof(*dst)); \ - } while (0) - - -/** - * inserts an eb_info into the chain starting at head, then searching - * linearly for the correct position; - * new should contain valid vid and ec headers and the data_crc should - * already have been checked before insertion, otherwise the chain - * could be have un an undesired manner; - * returns -ENOMEM if alloc fails, otherwise SHOULD always return 0, - * if not, the code reached the last line and returned -EAGAIN, - * meaning there is a bug or a case not being handled here; - **/ -int -eb_chain_insert(struct eb_info **head, struct eb_info *new) -{ - uint32_t vol, num, ver; - uint32_t new_vol, new_num, new_ver; - struct eb_info *prev, *cur, *hist, *ins; - struct eb_info **prev_ptr; - - if ((head == NULL) || (new == NULL)) - return 0; - - if (*head == NULL) { - COPY(*head, new); - (*head)->next = NULL; - return 0; - } - - new_vol = __be32_to_cpu(new->vid.vol_id); - new_num = __be32_to_cpu(new->vid.lnum); - new_ver = __be32_to_cpu(new->vid.leb_ver); - - /** TRAVERSE HORIZONTALY **/ - - cur = *head; - prev = NULL; - - /* traverse until vol_id/lnum align */ - vol = __be32_to_cpu(cur->vid.vol_id); - num = __be32_to_cpu(cur->vid.lnum); - while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) { - /* insert new at end of chain */ - if (cur->next == NULL) { - COPY(ins, new); - ins->next = NULL; - cur->next = ins; - return 0; - } - - prev = cur; - cur = cur->next; - vol = __be32_to_cpu(cur->vid.vol_id); - num = __be32_to_cpu(cur->vid.lnum); - } - - if (prev == NULL) - prev_ptr = head; - else - prev_ptr = &(prev->next); - - /* insert new into the middle of chain */ - if ((new_vol != vol) || (new_num != num)) { - COPY(ins, new); - ins->next = cur; - *prev_ptr = ins; - return 0; - } - - /** TRAVERSE VERTICALY **/ - - hist = cur; - prev = NULL; - - /* traverse until versions align */ - ver = __be32_to_cpu(cur->vid.leb_ver); - while (new_ver < ver) { - /* insert new at bottom of history */ - if (hist->older == NULL) { - COPY(ins, new); - ins->next = NULL; - ins->older = NULL; - hist->older = ins; - return 0; - } - - prev = hist; - hist = hist->older; - ver = __be32_to_cpu(hist->vid.leb_ver); - } - - if (prev == NULL) { - /* replace active version */ - COPY(ins, new); - ins->next = hist->next; - *prev_ptr = ins; - - /* place cur in vertical histroy */ - ins->older = hist; - hist->next = NULL; - return 0; - } - - /* insert between versions, beneath active version */ - COPY(ins, new); - ins->next = NULL; - ins->older = prev->older; - prev->older = ins; - return 0; -} - - -/** - * sets the pointer at pos to the position of the first entry in the chain - * with of vol_id and, if given, with the same lnum as *lnum; - * if there is no entry in the chain, then *pos is NULL on return; - * always returns 0; - **/ -int -eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum, - struct eb_info **pos) -{ - uint32_t vol, num; - struct eb_info *cur; - - if ((head == NULL) || (*head == NULL) || (pos == NULL)) - return 0; - - *pos = NULL; - - cur = *head; - while (cur != NULL) { - vol = __be32_to_cpu(cur->vid.vol_id); - num = __be32_to_cpu(cur->vid.lnum); - - if ((vol_id == vol) && ((lnum == NULL) || (*lnum == num))) { - *pos = cur; - return 0; - } - - cur = cur->next; - } - - return 0; -} - - -/** - * prints to stream, the vol_id, lnum and leb_ver for each entry in the - * chain, starting at head; - * this is intended for debuging purposes; - * always returns 0; - * - * FIXME I do not like the double list traversion ... - **/ -int -eb_chain_print(FILE* stream, struct eb_info *head) -{ - struct eb_info *cur; - - if (stream == NULL) - stream = stdout; - - if (head == NULL) { - fprintf(stream, "EMPTY\n"); - return 0; - } - /* 012345678012345678012345678012301230123 0123 01234567 0123457 01234567*/ - fprintf(stream, "VOL_ID LNUM LEB_VER EC VID DAT PBLK PADDR DSIZE EC\n"); - cur = head; - while (cur != NULL) { - struct eb_info *hist; - - fprintf(stream, "%08x %-8u %08x %-4s%-4s", - __be32_to_cpu(cur->vid.vol_id), - __be32_to_cpu(cur->vid.lnum), - __be32_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, " %-4d %08x %-8u %-8llu\n", cur->phys_block, - cur->phys_addr, __be32_to_cpu(cur->vid.data_size), - __be64_to_cpu(cur->ec.ec)); - - hist = cur->older; - while (hist != NULL) { - fprintf(stream, "%08x %-8u %08x %-4s%-4s", - __be32_to_cpu(hist->vid.vol_id), - __be32_to_cpu(hist->vid.lnum), - __be32_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, " %-4d %08x %-8u %-8llu (*)\n", - hist->phys_block, hist->phys_addr, - __be32_to_cpu(hist->vid.data_size), - __be64_to_cpu(hist->ec.ec)); - - hist = hist->older; - } - cur = cur->next; - } - - return 0; -} - - -/** - * frees the memory of the entire chain, starting at head; - * head will be NULL on return; - * always returns 0; - **/ -int -eb_chain_destroy(struct eb_info **head) -{ - if (head == NULL) - return 0; - - while (*head != NULL) { - struct eb_info *cur; - struct eb_info *hist; - - cur = *head; - *head = (*head)->next; - - hist = cur->older; - while (hist != NULL) { - struct eb_info *temp; - - temp = hist; - hist = hist->older; - free(temp); - } - free(cur); - } - return 0; -} - diff --git a/ubi-utils/src/example_ubi.h b/ubi-utils/src/example_ubi.h deleted file mode 100644 index 23c7b54..0000000 --- a/ubi-utils/src/example_ubi.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __EXAMPLE_UBI_H__ -#define __EXAMPLE_UBI_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. - */ - -/** - * Defaults for our cards. - */ -#define EXAMPLE_UBI_DEVICE 0 -#define EXAMPLE_BOOTENV_VOL_ID_1 4 -#define EXAMPLE_BOOTENV_VOL_ID_2 5 - -#endif /* __EXAMPLE_UBI_H__ */ diff --git a/ubi-utils/src/hashmap.c b/ubi-utils/src/hashmap.c deleted file mode 100644 index 3511d56..0000000 --- a/ubi-utils/src/hashmap.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * 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: Oliver Lohmann - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include "error.h" -#include "hashmap.h" -#define DEFAULT_BUCKETS 4096 - -#if 0 -#define INFO_MSG(fmt...) do { \ - info_msg(fmt); \ -} while (0) -#else -#define INFO_MSG(fmt...) -#endif - -struct hashentry { - char* key; /* key '0' term. str */ - char* value; /* payload '0' term. str */ - - hashentry_t next; -}; - -struct hashmap { - size_t entries; /* current #entries */ - size_t maxsize; /* no. of hash buckets */ - hashentry_t* data; /* array of buckets */ -}; - -static int -is_empty(hashentry_t l) -{ - return l == NULL ? 1 : 0; -} - -hashmap_t -hashmap_new(void) -{ - hashmap_t res; - res = (hashmap_t) calloc(1, sizeof(struct hashmap)); - - if (res == NULL) - return NULL; - - res->maxsize = DEFAULT_BUCKETS; - res->entries = 0; - - res->data = (hashentry_t*) - calloc(1, res->maxsize * sizeof(struct hashentry)); - - if (res->data == NULL) - return NULL; - - return res; -} - -static hashentry_t -new_entry(const char* key, const char* value) -{ - hashentry_t res; - - res = (hashentry_t) calloc(1, sizeof(struct hashentry)); - - if (res == NULL) - return NULL; - - /* allocate key and value and copy them */ - res->key = strdup(key); - if (res->key == NULL) { - free(res); - return NULL; - } - - res->value = strdup(value); - if (res->value == NULL) { - free(res->key); - free(res); - return NULL; - } - - res->next = NULL; - - return res; -} - -static hashentry_t -free_entry(hashentry_t e) -{ - if (!is_empty(e)) { - if(e->key != NULL) { - free(e->key); - } - if(e->value != NULL) - free(e->value); - free(e); - } - - return NULL; -} - -static hashentry_t -remove_entry(hashentry_t l, const char* key, size_t* entries) -{ - hashentry_t lnext; - if (is_empty(l)) - return NULL; - - if(strcmp(l->key,key) == 0) { - lnext = l->next; - l = free_entry(l); - (*entries)--; - return lnext; - } - - l->next = remove_entry(l->next, key, entries); - - return l; -} - -static hashentry_t -insert_entry(hashentry_t l, hashentry_t e, size_t* entries) -{ - if (is_empty(l)) { - (*entries)++; - return e; - } - - /* check for update */ - if (strcmp(l->key, e->key) == 0) { - e->next = l->next; - l = free_entry(l); - return e; - } - - l->next = insert_entry(l->next, e, entries); - return l; -} - -static hashentry_t -remove_all(hashentry_t l, size_t* entries) -{ - hashentry_t lnext; - if (is_empty(l)) - return NULL; - - lnext = l->next; - free_entry(l); - (*entries)--; - - return remove_all(lnext, entries); -} - -static const char* -value_lookup(hashentry_t l, const char* key) -{ - if (is_empty(l)) - return NULL; - - if (strcmp(l->key, key) == 0) - return l->value; - - return value_lookup(l->next, key); -} - -static void -print_all(hashentry_t l) -{ - if (is_empty(l)) { - printf("\n"); - return; - } - - printf("%s=%s", l->key, l->value); - if (!is_empty(l->next)) { - printf(","); - } - - print_all(l->next); -} - -static void -keys_to_array(hashentry_t l, const char** a, size_t* i) -{ - if (is_empty(l)) - return; - - a[*i] = l->key; - (*i)++; - - keys_to_array(l->next, a, i); -} - -uint32_t -hash_str(const char* str, uint32_t mapsize) -{ - uint32_t hash = 0; - uint32_t x = 0; - uint32_t i = 0; - size_t len = strlen(str); - - for(i = 0; i < len; str++, i++) { - hash = (hash << 4) + (*str); - if((x = hash & 0xF0000000L) != 0) { - hash ^= (x >> 24); - hash &= ~x; - } - } - - return (hash & 0x7FFFFFFF) % mapsize; -} - - -int -hashmap_is_empty(hashmap_t map) -{ - if (map == NULL) - return -EINVAL; - - return map->entries > 0 ? 1 : 0; -} - -const char* -hashmap_lookup(hashmap_t map, const char* key) -{ - uint32_t i; - - if ((map == NULL) || (key == NULL)) - return NULL; - - i = hash_str(key, map->maxsize); - - return value_lookup(map->data[i], key); -} - -int -hashmap_add(hashmap_t map, const char* key, const char* value) -{ - uint32_t i; - hashentry_t entry; - - if ((map == NULL) || (key == NULL) || (value == NULL)) - return -EINVAL; - - i = hash_str(key, map->maxsize); - entry = new_entry(key, value); - if (entry == NULL) - return -ENOMEM; - - map->data[i] = insert_entry(map->data[i], - entry, &map->entries); - - INFO_MSG("HASH_ADD: chain[%d] key:%s val:%s",i, key, value); - return 0; -} - -int -hashmap_remove(hashmap_t map, const char* key) -{ - uint32_t i; - - if ((map == NULL) || (key == NULL)) - return -EINVAL; - - i = hash_str(key, map->maxsize); - map->data[i] = remove_entry(map->data[i], key, &map->entries); - - return 0; -} - -size_t -hashmap_size(hashmap_t map) -{ - if (map != NULL) - return map->entries; - else - return 0; -} - -int -hashmap_free(hashmap_t map) -{ - size_t i; - - if (map == NULL) - return -EINVAL; - - /* "children" first */ - for(i = 0; i < map->maxsize; i++) { - map->data[i] = remove_all(map->data[i], &map->entries); - } - free(map->data); - free(map); - - return 0; -} - -int -hashmap_dump(hashmap_t map) -{ - size_t i; - if (map == NULL) - return -EINVAL; - - for(i = 0; i < map->maxsize; i++) { - if (map->data[i] != NULL) { - printf("[%zd]: ", i); - print_all(map->data[i]); - } - } - - return 0; -} - -static const char** -sort_key_vector(const char** a, size_t size) -{ - /* uses bubblesort */ - size_t i, j; - const char* tmp; - - if (size <= 0) - return a; - - for (i = size - 1; i > 0; i--) { - for (j = 0; j < i; j++) { - if (strcmp(a[j], a[j+1]) > 0) { - tmp = a[j]; - a[j] = a[j+1]; - a[j+1] = tmp; - } - } - } - return a; -} - -const char** -hashmap_get_key_vector(hashmap_t map, size_t* size, int sort) -{ - const char** res; - size_t i, j; - *size = map->entries; - - res = (const char**) malloc(*size * sizeof(char*)); - if (res == NULL) - return NULL; - - j = 0; - for(i=0; i < map->maxsize; i++) { - keys_to_array(map->data[i], res, &j); - } - - if (sort) - res = sort_key_vector(res, *size); - - return res; -} - -int -hashmap_key_is_in_vector(const char** vec, size_t size, const char* key) -{ - size_t i; - for (i = 0; i < size; i++) { - if (strcmp(vec[i], key) == 0) /* found */ - return 1; - } - - return 0; -} - -const char** -hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, - const char** vec2, size_t vec2_size, size_t* res_size) -{ - const char** res; - size_t i, j; - - *res_size = vec2_size; - - res = (const char**) malloc(*res_size * sizeof(char*)); - if (res == NULL) - return NULL; - - /* get all keys from vec2 which are not set in vec1 */ - j = 0; - for (i = 0; i < vec2_size; i++) { - if (!hashmap_key_is_in_vector(vec1, vec1_size, vec2[i])) - res[j++] = vec2[i]; - } - - *res_size = j; - return res; -} diff --git a/ubi-utils/src/hashmap.h b/ubi-utils/src/hashmap.h deleted file mode 100644 index 1b13e95..0000000 --- a/ubi-utils/src/hashmap.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __HASHMAP_H__ -#define __HASHMAP_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: Oliver Lohmann - */ - -#include <stdlib.h> -#include <stdint.h> - -typedef struct hashentry *hashentry_t; -typedef struct hashmap *hashmap_t; - -hashmap_t hashmap_new(void); -int hashmap_free(hashmap_t map); - -int hashmap_add(hashmap_t map, const char* key, const char* value); -int hashmap_update(hashmap_t map, const char* key, const char* value); -int hashmap_remove(hashmap_t map, const char* key); -const char* hashmap_lookup(hashmap_t map, const char* key); - -const char** hashmap_get_key_vector(hashmap_t map, size_t* size, int sort); -int hashmap_key_is_in_vector(const char** vec, size_t size, const char* key); -const char** hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, - const char** vec2, size_t vec2_size, size_t* res_size); - -int hashmap_dump(hashmap_t map); - -int hashmap_is_empty(hashmap_t map); -size_t hashmap_size(hashmap_t map); - -uint32_t hash_str(const char* str, uint32_t mapsize); - -#endif /* __HASHMAP_H__ */ diff --git a/ubi-utils/src/libiniparser.c b/ubi-utils/src/libiniparser.c new file mode 100644 index 0000000..3bea51e --- /dev/null +++ b/ubi-utils/src/libiniparser.c @@ -0,0 +1,646 @@ + +/*-------------------------------------------------------------------------*/ +/** + @file iniparser.c + @author N. Devillard + @date Sep 2007 + @version 3.0 + @brief Parser for ini files. +*/ +/*--------------------------------------------------------------------------*/ +/* + $Id: iniparser.c,v 2.18 2008-01-03 18:35:39 ndevilla Exp $ + $Revision: 2.18 $ + $Date: 2008-01-03 18:35:39 $ +*/ +/*---------------------------- Includes ------------------------------------*/ +#include <ctype.h> +#include <libiniparser.h> + +/*---------------------------- Defines -------------------------------------*/ +#define ASCIILINESZ (1024) +#define INI_INVALID_KEY ((char*)-1) + +/*--------------------------------------------------------------------------- + Private to this module + ---------------------------------------------------------------------------*/ +/** + * This enum stores the status for each parsed line (internal use only). + */ +typedef enum _line_status_ { + LINE_UNPROCESSED, + LINE_ERROR, + LINE_EMPTY, + LINE_COMMENT, + LINE_SECTION, + LINE_VALUE +} line_status ; + +/*-------------------------------------------------------------------------*/ +/** + @brief Convert a string to lowercase. + @param s String to convert. + @return ptr to statically allocated string. + + This function returns a pointer to a statically allocated string + containing a lowercased version of the input string. Do not free + or modify the returned string! Since the returned string is statically + allocated, it will be modified at each function call (not re-entrant). + */ +/*--------------------------------------------------------------------------*/ +static char * strlwc(const char * s) +{ + static char l[ASCIILINESZ+1]; + int i ; + + if (s==NULL) return NULL ; + memset(l, 0, ASCIILINESZ+1); + i=0 ; + while (s[i] && i<ASCIILINESZ) { + l[i] = (char)tolower((int)s[i]); + i++ ; + } + l[ASCIILINESZ]=(char)0; + return l ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Remove blanks at the beginning and the end of a string. + @param s String to parse. + @return ptr to statically allocated string. + + This function returns a pointer to a statically allocated string, + which is identical to the input string, except that all blank + characters at the end and the beg. of the string have been removed. + Do not free or modify the returned string! Since the returned string + is statically allocated, it will be modified at each function call + (not re-entrant). + */ +/*--------------------------------------------------------------------------*/ +static char * strstrip(char * s) +{ + static char l[ASCIILINESZ+1]; + char * last ; + + if (s==NULL) return NULL ; + + while (isspace((int)*s) && *s) s++; + memset(l, 0, ASCIILINESZ+1); + strcpy(l, s); + last = l + strlen(l); + while (last > l) { + if (!isspace((int)*(last-1))) + break ; + last -- ; + } + *last = (char)0; + return (char*)l ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get number of sections in a dictionary + @param d Dictionary to examine + @return int Number of sections found in dictionary + + This function returns the number of sections found in a dictionary. + The test to recognize sections is done on the string stored in the + dictionary: a section name is given as "section" whereas a key is + stored as "section:key", thus the test looks for entries that do not + contain a colon. + + This clearly fails in the case a section name contains a colon, but + this should simply be avoided. + + This function returns -1 in case of error. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getnsec(dictionary * d) +{ + int i ; + int nsec ; + + if (d==NULL) return -1 ; + nsec=0 ; + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + if (strchr(d->key[i], ':')==NULL) { + nsec ++ ; + } + } + return nsec ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get name for section n in a dictionary. + @param d Dictionary to examine + @param n Section number (from 0 to nsec-1). + @return Pointer to char string + + This function locates the n-th section in a dictionary and returns + its name as a pointer to a string statically allocated inside the + dictionary. Do not free or modify the returned string! + + This function returns NULL in case of error. + */ +/*--------------------------------------------------------------------------*/ +char * iniparser_getsecname(dictionary * d, int n) +{ + int i ; + int foundsec ; + + if (d==NULL || n<0) return NULL ; + foundsec=0 ; + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + if (strchr(d->key[i], ':')==NULL) { + foundsec++ ; + if (foundsec>n) + break ; + } + } + if (foundsec<=n) { + return NULL ; + } + return d->key[i] ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump. + @param f Opened file pointer to dump to. + @return void + + This function prints out the contents of a dictionary, one element by + line, onto the provided file pointer. It is OK to specify @c stderr + or @c stdout as output files. This function is meant for debugging + purposes mostly. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_dump(dictionary * d, FILE * f) +{ + int i ; + + if (d==NULL || f==NULL) return ; + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + if (d->val[i]!=NULL) { + fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); + } else { + fprintf(f, "[%s]=UNDEF\n", d->key[i]); + } + } + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary to a loadable ini file + @param d Dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given dictionary into a loadable ini file. + It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_dump_ini(dictionary * d, FILE * f) +{ + int i, j ; + char keym[ASCIILINESZ+1]; + int nsec ; + char * secname ; + int seclen ; + + if (d==NULL || f==NULL) return ; + + nsec = iniparser_getnsec(d); + if (nsec<1) { + /* No section in file: dump all keys as they are */ + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + fprintf(f, "%s = %s\n", d->key[i], d->val[i]); + } + return ; + } + for (i=0 ; i<nsec ; i++) { + secname = iniparser_getsecname(d, i) ; + seclen = (int)strlen(secname); + fprintf(f, "\n[%s]\n", secname); + sprintf(keym, "%s:", secname); + for (j=0 ; j<d->size ; j++) { + if (d->key[j]==NULL) + continue ; + if (!strncmp(d->key[j], keym, seclen+1)) { + fprintf(f, + "%-30s = %s\n", + d->key[j]+seclen+1, + d->val[j] ? d->val[j] : ""); + } + } + } + fprintf(f, "\n"); + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key + @param d Dictionary to search + @param key Key string to look for + @param def Default value to return if key not found. + @return pointer to statically allocated character string + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the pointer passed as 'def' is returned. + The returned char pointer is pointing to a string allocated in + the dictionary, do not free or modify it. + */ +/*--------------------------------------------------------------------------*/ +char * iniparser_getstring(dictionary * d, const char * key, char * def) +{ + char * lc_key ; + char * sval ; + + if (d==NULL || key==NULL) + return def ; + + lc_key = strlwc(key); + sval = dictionary_get(d, lc_key, def); + return sval ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + "42" -> 42 + "042" -> 34 (octal -> decimal) + "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + + Credits: Thanks to A. Becker for suggesting strtol() + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getint(dictionary * d, const char * key, int notfound) +{ + char * str ; + + str = iniparser_getstring(d, key, INI_INVALID_KEY); + if (str==INI_INVALID_KEY) return notfound ; + return (int)strtol(str, NULL, 0); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a double + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return double + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + */ +/*--------------------------------------------------------------------------*/ +double iniparser_getdouble(dictionary * d, char * key, double notfound) +{ + char * str ; + + str = iniparser_getstring(d, key, INI_INVALID_KEY); + if (str==INI_INVALID_KEY) return notfound ; + return atof(str); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a boolean + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + A true boolean is found if one of the following is matched: + + - A string starting with 'y' + - A string starting with 'Y' + - A string starting with 't' + - A string starting with 'T' + - A string starting with '1' + + A false boolean is found if one of the following is matched: + + - A string starting with 'n' + - A string starting with 'N' + - A string starting with 'f' + - A string starting with 'F' + - A string starting with '0' + + The notfound value returned if no boolean is identified, does not + necessarily have to be 0 or 1. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getboolean(dictionary * d, const char * key, int notfound) +{ + char * c ; + int ret ; + + c = iniparser_getstring(d, key, INI_INVALID_KEY); + if (c==INI_INVALID_KEY) return notfound ; + if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { + ret = 1 ; + } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { + ret = 0 ; + } else { + ret = notfound ; + } + return ret; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Finds out if a given entry exists in a dictionary + @param ini Dictionary to search + @param entry Name of the entry to look for + @return integer 1 if entry exists, 0 otherwise + + Finds out if a given entry exists in the dictionary. Since sections + are stored as keys with NULL associated values, this is the only way + of querying for the presence of sections in a dictionary. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_find_entry( + dictionary * ini, + char * entry +) +{ + int found=0 ; + if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { + found = 1 ; + } + return found ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Set an entry in a dictionary. + @param ini Dictionary to modify. + @param entry Entry to modify (entry name) + @param val New value to associate to the entry. + @return int 0 if Ok, -1 otherwise. + + If the given entry can be found in the dictionary, it is modified to + contain the provided value. If it cannot be found, -1 is returned. + It is Ok to set val to NULL. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_set(dictionary * ini, char * entry, char * val) +{ + return dictionary_set(ini, strlwc(entry), val) ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete an entry in a dictionary + @param ini Dictionary to modify + @param entry Entry to delete (entry name) + @return void + + If the given entry can be found, it is deleted from the dictionary. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_unset(dictionary * ini, char * entry) +{ + dictionary_unset(ini, strlwc(entry)); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Load a single line from an INI file + @param input_line Input line, may be concatenated multi-line input + @param section Output space to store section + @param key Output space to store key + @param value Output space to store value + @return line_status value + */ +/*--------------------------------------------------------------------------*/ +static line_status iniparser_line( + char * input_line, + char * section, + char * key, + char * value) +{ + line_status sta ; + char line[ASCIILINESZ+1]; + int len ; + + strcpy(line, strstrip(input_line)); + len = (int)strlen(line); + + sta = LINE_UNPROCESSED ; + if (len<1) { + /* Empty line */ + sta = LINE_EMPTY ; + } else if (line[0]=='#') { + /* Comment line */ + sta = LINE_COMMENT ; + } else if (line[0]=='[' && line[len-1]==']') { + /* Section name */ + sscanf(line, "[%[^]]", section); + strcpy(section, strstrip(section)); + strcpy(section, strlwc(section)); + sta = LINE_SECTION ; + } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 + || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 + || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { + /* Usual key=value, with or without comments */ + strcpy(key, strstrip(key)); + strcpy(key, strlwc(key)); + strcpy(value, strstrip(value)); + /* + * sscanf cannot handle '' or "" as empty values + * this is done here + */ + if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { + value[0]=0 ; + } + sta = LINE_VALUE ; + } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 + || sscanf(line, "%[^=] %[=]", key, value) == 2) { + /* + * Special cases: + * key= + * key=; + * key=# + */ + strcpy(key, strstrip(key)); + strcpy(key, strlwc(key)); + value[0]=0 ; + sta = LINE_VALUE ; + } else { + /* Generate syntax error */ + sta = LINE_ERROR ; + } + return sta ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Parse an ini file and return an allocated dictionary object + @param ininame Name of the ini file to read. + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the name of the file to be read. It returns a dictionary object that + should not be accessed directly, but through accessor functions + instead. + + The returned dictionary must be freed using iniparser_freedict(). + */ +/*--------------------------------------------------------------------------*/ +dictionary * iniparser_load(const char * ininame) +{ + FILE * in ; + + char line [ASCIILINESZ+1] ; + char section [ASCIILINESZ+1] ; + char key [ASCIILINESZ+1] ; + char tmp [ASCIILINESZ+1] ; + char val [ASCIILINESZ+1] ; + + int last=0 ; + int len ; + int lineno=0 ; + int errs=0; + + dictionary * dict ; + + if ((in=fopen(ininame, "r"))==NULL) { + fprintf(stderr, "iniparser: cannot open %s\n", ininame); + return NULL ; + } + + dict = dictionary_new(0) ; + if (!dict) { + fclose(in); + return NULL ; + } + + memset(line, 0, ASCIILINESZ); + memset(section, 0, ASCIILINESZ); + memset(key, 0, ASCIILINESZ); + memset(val, 0, ASCIILINESZ); + last=0 ; + + while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { + lineno++ ; + len = (int)strlen(line)-1; + /* Safety check against buffer overflows */ + if (line[len]!='\n') { + fprintf(stderr, + "iniparser: input line too long in %s (%d)\n", + ininame, + lineno); + dictionary_del(dict); + fclose(in); + return NULL ; + } + /* Get rid of \n and spaces at end of line */ + while ((len>=0) && + ((line[len]=='\n') || (isspace(line[len])))) { + line[len]=0 ; + len-- ; + } + /* Detect multi-line */ + if (line[len]=='\\') { + /* Multi-line value */ + last=len ; + continue ; + } else { + last=0 ; + } + switch (iniparser_line(line, section, key, val)) { + case LINE_EMPTY: + case LINE_COMMENT: + break ; + + case LINE_SECTION: + errs = dictionary_set(dict, section, NULL); + break ; + + case LINE_VALUE: + sprintf(tmp, "%s:%s", section, key); + errs = dictionary_set(dict, tmp, val) ; + break ; + + case LINE_ERROR: + fprintf(stderr, "iniparser: syntax error in %s (%d):\n", + ininame, + lineno); + fprintf(stderr, "-> %s\n", line); + errs++ ; + break; + + default: + break ; + } + memset(line, 0, ASCIILINESZ); + last=0; + if (errs<0) { + fprintf(stderr, "iniparser: memory allocation failure\n"); + break ; + } + } + if (errs) { + dictionary_del(dict); + dict = NULL ; + } + fclose(in); + return dict ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Free all memory associated to an ini dictionary + @param d Dictionary to free + @return void + + Free all memory associated to an ini dictionary. + It is mandatory to call this function before the dictionary object + gets out of the current context. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_freedict(dictionary * d) +{ + dictionary_del(d); +} + +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/ubi-utils/src/libpfi.c b/ubi-utils/src/libpfi.c deleted file mode 100644 index 6de24ea..0000000 --- a/ubi-utils/src/libpfi.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -/* - * A library to work with pfi files. - * - * Authors Oliver Lohmann - * Andreas Arnez - * Joern Engel - * Frank Haverkamp - * Artem Bityutskiy - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> - -#include <mtd/ubi-header.h> -#include <libpfi.h> -#include "common.h" -#include "bootenv.h" - -#define PROGRAM_NAME "libpfi" - -#define PFI_MAGIC "PFI!\n" -#define PFI_MAGIC_LEN (sizeof(PFI_MAGIC) - 1) -#define PFI_DATA "DATA\n" - - - - - - - - - - - - - - - - -#define PFI_MANDATORY 0x0001 -#define PFI_STRING 0x0002 -#define PFI_LISTVALUE 0x0004 -#define PFI_MANDATORY_UBI 0x0008 - -enum key_id { - /* version 1 */ - key_version, /* must be index position 0! */ - key_mode, - key_size, - key_crc, - key_label, - key_flags, - key_ubi_ids, - key_ubi_size, - key_ubi_type, - key_ubi_names, - key_ubi_alignment, - num_keys, -}; - -struct pfi_header { - uint8_t defined[num_keys]; /* reserve all possible keys even if - version does not require this. */ - int mode_no; /* current mode no. -> can only increase */ - union { - char *str; - uint32_t num; - } value[num_keys]; -}; - -struct key_descriptor { - enum key_id id; - const char *name; - uint32_t flags; -}; - -static const struct key_descriptor key_desc_v1[] = { - { key_version, "version", PFI_MANDATORY }, - { key_mode, "mode", PFI_MANDATORY | PFI_STRING }, - { key_size, "size", PFI_MANDATORY }, - { key_crc, "crc", PFI_MANDATORY }, - { key_label, "label", PFI_MANDATORY | PFI_STRING }, - { key_flags, "flags", PFI_MANDATORY }, - { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI }, - { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING }, - { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI }, -}; - -static const struct key_descriptor *key_descriptors[] = { - NULL, - key_desc_v1, /* version 1 */ -}; - -static const int key_descriptors_max[] = { - 0, /* version 0 */ - sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */ -}; - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -static const char* modes[] = {"ubi"}; - -/* latest version contains all possible keys */ -static const struct key_descriptor *key_desc = key_desc_v1; - -#define PFI_IS_UBI(mode) \ - (((mode) != NULL) && (strcmp("ubi", (mode)) == 0)) - -static int get_mode_no(const char *mode) -{ - int i; - - for (i = 0; i < (int)ARRAY_SIZE(modes); i++) - if (strcmp(mode, modes[i]) == 0) - return i; - return -1; -} - -static int -find_key_by_name (const char *name) -{ - int i; - - for (i = 0; i < num_keys; i++) { - if (strcmp(name, key_desc[i].name) == 0) - return i; - } - return -1; -} - -static int -check_valid (struct pfi_header *head) -{ - int i; - int max_keys; - uint32_t version; - const char *mode; - const struct key_descriptor *desc; - uint32_t to_check = PFI_MANDATORY; - - /* - * For the validity check the list of possible keys depends on - * the version of the PFI file used. - */ - version = head->value[key_version].num; - if (version > PFI_HDRVERSION) - return PFI_ENOHEADER; - - max_keys = key_descriptors_max[version]; - desc = key_descriptors[version]; - - if (!desc) - return PFI_ENOVERSION; - - mode = head->value[key_mode].str; - if (PFI_IS_UBI(mode)) { - to_check |= PFI_MANDATORY_UBI; - } - else { /* neither UBI nor RAW == ERR */ - return PFI_EINSUFF; - } - - for (i = 0; i < max_keys; i++) { - if ((desc[i].flags & to_check) && !head->defined[i]) { - fprintf(stderr, "libpfi: %s missing\n", desc[i].name); - return PFI_EINSUFF; - } - } - - return 0; -} - -int pfi_header_init (struct pfi_header **head) -{ - int i; - struct pfi_header *self = malloc(sizeof(*self)); - - *head = self; - if (self == NULL) - return PFI_ENOMEM; - - /* initialize maximum number of possible keys */ - for (i = 0; i < num_keys; i++) { - memset(self, 0, sizeof(*self)); - self->defined[i] = 0; - } - - return 0; -} - -int pfi_header_destroy (struct pfi_header **head) -{ - int i; - struct pfi_header *self = *head; - - for (i = 0; i < num_keys; i++) { - if (self->defined[i] && (key_desc[i].flags & PFI_STRING) && - self->value[i].str) { - free(self->value[i].str); - } - } - free(*head); - *head = NULL; - return 0; -} - -int pfi_header_setnumber (struct pfi_header *head, - const char *key, uint32_t value) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) - return PFI_EBADTYPE; - - head->value[key_id].num = value; - head->defined[key_id] = 1; - return 0; -} - -int pfi_header_setvalue (struct pfi_header *head, - const char *key, const char *value) -{ - int key_id = find_key_by_name(key); - - if (value == NULL) - return PFI_EINSUFF; - - if ((key_id < 0) || (key_id >= num_keys)) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) { - /* - * The value is a string. Copy to a newly allocated - * buffer. Delete the old value, if already set. - */ - size_t len = strlen(value) + 1; - char *old_str = NULL; - char *str; - - old_str = head->value[key_id].str; - if (old_str != NULL) - free(old_str); - - str = head->value[key_id].str = (char *) malloc(len); - if (str == NULL) - return PFI_ENOMEM; - - strcpy(str, value); - } else { - int len; - int ret; - /* FIXME: here we assume that the value is always - given in hex and starts with '0x'. */ - ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len); - if (ret < 1 || value[len] != '\0') - return PFI_EBADTYPE; - } - head->defined[key_id] = 1; - return 0; -} - -int pfi_header_getnumber (struct pfi_header *head, - const char *key, uint32_t *value) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (key_desc[key_id].flags & PFI_STRING) - return PFI_EBADTYPE; - - if (!head->defined[key_id]) - return PFI_EUNDEF; - - *value = head->value[key_id].num; - return 0; -} - -int pfi_header_getstring (struct pfi_header *head, - const char *key, char *value, size_t size) -{ - int key_id = find_key_by_name(key); - - if (key_id < 0) - return PFI_EUNDEF; - - if (!(key_desc[key_id].flags & PFI_STRING)) - return PFI_EBADTYPE; - - if (!head->defined[key_id]) - return PFI_EUNDEF; - - strncpy(value, head->value[key_id].str, size-1); - value[size-1] = '\0'; - return 0; -} - -int pfi_header_read(FILE *in, struct pfi_header *head) -{ - char mode[PFI_KEYWORD_LEN]; - char buf[256]; - - if (fread(buf, 1, PFI_MAGIC_LEN, in) != PFI_MAGIC_LEN) { - errmsg("cannot read %d bytes", PFI_MAGIC_LEN); - perror("fread"); - return -1; - } - - if (memcmp(buf, PFI_MAGIC, PFI_MAGIC_LEN) != 0) { - if (memcmp(buf, PFI_DATA, PFI_MAGIC_LEN) == 0) - return 1; - - errmsg("PFI magic \"%s\" not found", PFI_MAGIC); - return -1; - } - - while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') { - char *value; - char *end; - value = strchr(buf, '='); - if (value == NULL) - return PFI_ENOHEADER; - - *value = '\0'; - value++; - end = strchr(value, '\n'); - if (end) - *end = '\0'; - - if (pfi_header_setvalue(head, buf, value)) - return PFI_ENOHEADER; - } - - if (check_valid(head) != 0) - return PFI_ENOHEADER; - - /* set current mode no. in head */ - pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN); - if (head->mode_no > get_mode_no(mode)) { - return PFI_EMODE; - } - head->mode_no = get_mode_no(mode); - return 0; -} -int -read_pfi_ubi(struct pfi_header *pfi_hd, struct pfi_ubi **pfi_ubi, - const char *label) -{ - int err = 0; - const char** tmp_names = NULL; - char tmp_str[PFI_KEYWORD_LEN]; - bootenv_list_t ubi_id_list = NULL; - bootenv_list_t ubi_name_list = NULL; - struct pfi_ubi *res; - uint32_t i; - size_t size; - - res = (struct pfi_ubi *) calloc(1, sizeof(struct pfi_ubi)); - if (!res) - return -ENOMEM; - - err = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); - if (err != 0) { - errmsg("cannot read 'size' from PFI."); - goto err; - } - - err = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); - if (err != 0) { - errmsg("cannot read 'crc' from PFI."); - goto err; - } - - err = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN); - if (err != 0) { - errmsg("cannot read 'ubi_ids' from PFI."); - goto err; - } - - err = bootenv_list_create(&ubi_id_list); - if (err != 0) { - goto err; - } - err = bootenv_list_create(&ubi_name_list); - if (err != 0) { - goto err; - } - - err = bootenv_list_import(ubi_id_list, tmp_str); - if (err != 0) { - errmsg("cannot translate PFI value: %s", tmp_str); - goto err; - } - - err = bootenv_list_to_num_vector(ubi_id_list, &size, - &(res->ids)); - res->ids_size = size; - if (err != 0) { - errmsg("cannot create numeric value array: %s", tmp_str); - goto err; - } - - if (res->ids_size == 0) { - err = -1; - errmsg("sanity check failed: No ubi_ids specified."); - goto err; - } - - err = pfi_header_getstring(pfi_hd, "ubi_type", - tmp_str, PFI_KEYWORD_LEN); - if (err != 0) { - errmsg("cannot read 'ubi_type' from PFI."); - goto err; - } - if (strcmp(tmp_str, "static") == 0) - res->vol_type = UBI_VID_STATIC; - else if (strcmp(tmp_str, "dynamic") == 0) - res->vol_type = UBI_VID_DYNAMIC; - else { - errmsg("unknown ubi_type in PFI."); - goto err; - } - - err = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment)); - if (err != 0) { - errmsg("cannot read 'ubi_alignment' from PFI."); - goto err; - } - - err = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size)); - if (err != 0) { - errmsg("cannot read 'ubi_size' from PFI."); - goto err; - } - - err = pfi_header_getstring(pfi_hd, "ubi_names", - tmp_str, PFI_KEYWORD_LEN); - if (err != 0) { - errmsg("cannot read 'ubi_names' from PFI."); - goto err; - } - - err = bootenv_list_import(ubi_name_list, tmp_str); - if (err != 0) { - errmsg("cannot translate PFI value: %s", tmp_str); - goto err; - } - err = bootenv_list_to_vector(ubi_name_list, &size, - &(tmp_names)); - res->names_size = size; - if (err != 0) { - errmsg("cannot create string array: %s", tmp_str); - goto err; - } - - if (res->names_size != res->ids_size) { - errmsg("sanity check failed: ubi_ids list does not match " - "sizeof ubi_names list."); - err = -1; - } - - /* copy tmp_names to own structure */ - res->names = calloc(1, res->names_size * sizeof (char*)); - if (res->names == NULL) - goto err; - - for (i = 0; i < res->names_size; i++) { - res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char)); - if (res->names[i] == NULL) - goto err; - strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1); - } - - goto out; - - err: - if (res) { - if (res->names) { - for (i = 0; i < res->names_size; i++) { - if (res->names[i]) { - free(res->names[i]); - } - } - free(res->names); - } - if (res->ids) { - free(res->ids); - } - free(res); - res = NULL; - } - - out: - bootenv_list_destroy(&ubi_id_list); - bootenv_list_destroy(&ubi_name_list); - if (tmp_names != NULL) - free(tmp_names); - *pfi_ubi = res; - return err; -} - -int -free_pfi_ubi(struct pfi_ubi **pfi_ubi) -{ - size_t i; - struct pfi_ubi *tmp = *pfi_ubi; - if (tmp) { - if (tmp->ids) - free(tmp->ids); - if (tmp->names) { - for (i = 0; i < tmp->names_size; i++) { - if (tmp->names[i]) { - free(tmp->names[i]); - } - } - free(tmp->names); - } - free(tmp); - } - *pfi_ubi = NULL; - - return 0; -} - -int read_pfi_headers(struct list_entry **ubi_list, FILE *fp_pfi) -{ - int err = 0; - long long data_offs = 0; - long fpos; - char mode[PFI_KEYWORD_LEN]; - char label[PFI_LABEL_LEN]; - struct list_entry *tmp; - - *ubi_list = list_empty(); struct pfi_ubi *ubi = NULL; - struct pfi_header *pfi_header = NULL; - - /* read all headers from PFI and store them in lists */ - err = pfi_header_init(&pfi_header); - if (err != 0) { - errmsg("cannot initialize pfi header."); - goto err; - } - while ((err == 0) && !feof(fp_pfi)) { - err = pfi_header_read(fp_pfi, pfi_header); - if (err != 0) { - if (err == 1) { - err = 0; - break; /* data section starts, - all headers read */ - } - else { - goto err; - } - } - err = pfi_header_getstring(pfi_header, "label", label, - PFI_LABEL_LEN); - if (err != 0) { - errmsg("cannot read 'label' from PFI."); - goto err; - } - err = pfi_header_getstring(pfi_header, "mode", mode, - PFI_KEYWORD_LEN); - if (err != 0) { - errmsg("cannot read 'mode' from PFI."); - goto err; - } - if (strcmp(mode, "ubi") == 0) { - err = read_pfi_ubi(pfi_header, &ubi, label); - if (err != 0) { - goto err; - } - *ubi_list = append_elem(ubi, *ubi_list); - } - else { - errmsg("recvieved unknown mode from PFI: %s", mode); - goto err; - } - ubi->data_offs = data_offs; - data_offs += ubi->data_size; - } - - fpos = ftell(fp_pfi); - if (fpos == -1) { - errmsg("ftell returned error"); - perror("ftell"); - goto err; - } - - list_for_each(ubi, tmp, *ubi_list) - ubi->data_offs += fpos; - - goto out; - - err: - *ubi_list = remove_all((free_func_t)&free_pfi_ubi, *ubi_list); - out: - pfi_header_destroy(&pfi_header); - return err; - -} diff --git a/ubi-utils/src/libubigen.c b/ubi-utils/src/libubigen.c index c3a0f9c..9cbd1b7 100644 --- a/ubi-utils/src/libubigen.c +++ b/ubi-utils/src/libubigen.c @@ -38,35 +38,6 @@ #define PROGRAM_NAME "libubigen" /** - * ubigen_create_empty_vtbl - creates empty volume table. - * @size: physical eraseblock size on input, size of the volume table on output - * - * This function creates an empty volume table and returns a pointer to it in - * case of success and %NULL in case of failure. The volume table size is - * returned in @size which has to contain PEB size on input. - */ -struct ubi_vtbl_record *ubigen_create_empty_vtbl(int *size) -{ - struct ubi_vtbl_record *vtbl; - int i; - - if (*size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE) - *size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; - - vtbl = calloc(1, *size); - if (!vtbl) - return NULL; - - for (i = 0; i < UBI_MAX_VOLUMES; i++) { - uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i], - UBI_VTBL_RECORD_SIZE_CRC); - vtbl[i].crc = __cpu_to_be32(crc); - } - - return vtbl; -} - -/** * ubigen_info_init - initialize libubigen. * @ui: libubigen information * @peb_size: flash physical eraseblock size @@ -93,28 +64,67 @@ void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size, ui->leb_size = peb_size - ui->data_offs; ui->ubi_ver = ubi_ver; ui->ec = ec; + + ui->vtbl_size = ui->leb_size; + if (ui->vtbl_size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE) + ui->vtbl_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; + ui->max_volumes = ui->vtbl_size / UBI_VTBL_RECORD_SIZE; +} + +/** + * ubigen_create_empty_vtbl - creates empty volume table. + * + * This function creates an empty volume table and returns a pointer to it in + * case of success and %NULL in case of failure. The returned object has to be + * freed with 'free()' call. + */ +struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui) +{ + struct ubi_vtbl_record *vtbl; + int i; + + vtbl = calloc(1, ui->vtbl_size); + if (!vtbl) { + errmsg("cannot allocate %d bytes of memory", ui->vtbl_size); + return NULL; + } + + for (i = 0; i < UBI_MAX_VOLUMES; i++) { + uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i], + UBI_VTBL_RECORD_SIZE_CRC); + vtbl[i].crc = __cpu_to_be32(crc); + } + + return vtbl; } /** * ubigen_add_volume - add a volume to the volume table. - * @vol_id: volume ID - * @bytes: volume size in bytes - * @alignment: volume alignment - * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) - * @name: volume name * @ui: libubigen information + * @vi: volume information * @vtbl: volume table to add to * * This function adds volume described by input parameters to the volume table * @vtbl. */ -void ubigen_add_volume(const struct ubigen_info *ui, +int ubigen_add_volume(const struct ubigen_info *ui, const struct ubigen_vol_info *vi, struct ubi_vtbl_record *vtbl) { struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id]; uint32_t tmp; + if (vi->id >= ui->max_volumes) { + errmsg("too high volume id %d, max. volumes is %d", + vi->id, ui->max_volumes); + return -1; + } + if (vi->alignment >= ui->leb_size) { + errmsg("too large alignment %d, max is %d (LEB size)", + vi->alignment, ui->leb_size); + return -1; + } + memset(vtbl_rec, '\0', sizeof(struct ubi_vtbl_record)); tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size; vtbl_rec->reserved_pebs = __cpu_to_be32(tmp); @@ -129,6 +139,7 @@ void ubigen_add_volume(const struct ubigen_info *ui, tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC); vtbl_rec->crc = __cpu_to_be32(tmp); + return 0; } /** @@ -213,6 +224,17 @@ int ubigen_write_volume(const struct ubigen_info *ui, int len = vi->usable_leb_size, rd, lnum = 0; char inbuf[ui->leb_size], outbuf[ui->peb_size]; + if (vi->id >= ui->max_volumes) { + errmsg("too high volume id %d, max. volumes is %d", + vi->id, ui->max_volumes); + return -1; + } + if (vi->alignment >= ui->leb_size) { + errmsg("too large alignment %d, max is %d (LEB size)", + vi->alignment, ui->leb_size); + return -1; + } + memset(outbuf, 0xFF, ui->data_offs); init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf); diff --git a/ubi-utils/src/list.c b/ubi-utils/src/list.c deleted file mode 100644 index a701158..0000000 --- a/ubi-utils/src/list.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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: Oliver Lohmann - */ - -#include <stdlib.h> -#include <assert.h> -#include <stdio.h> - -#include "list.h" - -int -is_empty(struct list_entry *l) -{ - return l == NULL; -} - -info_t -head(struct list_entry *l) -{ - assert(!is_empty(l)); - return l->info; -} - -struct list_entry * -tail(struct list_entry *l) -{ - assert(!is_empty(l)); - return l->next; -} - -struct list_entry * -remove_head(struct list_entry *l) -{ - struct list_entry *res; - assert(!is_empty(l)); - - res = l->next; - free(l); - return res; -} - -struct list_entry * -cons(info_t e, struct list_entry *l) -{ - struct list_entry *res = malloc(sizeof(*l)); - if (!res) - return NULL; - res->info = e; - res->next = l; - - return res; -} - -struct list_entry * -prepend_elem(info_t e, struct list_entry *l) -{ - return cons(e,l); -} - -struct list_entry * -append_elem(info_t e, struct list_entry *l) -{ - if (is_empty(l)) { - return cons(e,l); - } - l->next = append_elem(e, l->next); - - return l; -} - -struct list_entry * -insert_sorted(cmp_func_t cmp, info_t e, struct list_entry *l) -{ - if (is_empty(l)) - return cons(e, l); - - switch (cmp(e, l->info)) { - case -1: - case 0: - return l; - break; - case 1: - l->next = insert_sorted(cmp, e, l); - break; - default: - break; - } - - /* never reached */ - return NULL; -} - -struct list_entry * -remove_all(free_func_t free_func, struct list_entry *l) -{ - if (is_empty(l)) - return l; - struct list_entry *lnext = l->next; - - if (free_func && l->info) { - free_func(&(l->info)); - } - free(l); - - return remove_all(free_func, lnext); -} - - -info_t -is_in(cmp_func_t cmp, info_t e, struct list_entry *l) -{ - return - (is_empty(l)) - ? NULL - : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next); -} - - -void -apply(process_func_t process_func, struct list_entry *l) -{ - struct list_entry *ptr; - void *i; - list_for_each(i, ptr, l) { - process_func(i); - } -} diff --git a/ubi-utils/src/list.h b/ubi-utils/src/list.h deleted file mode 100644 index 58bfe7e..0000000 --- a/ubi-utils/src/list.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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: Oliver Lohmann - */ - -#ifndef __UBIUTILS_LIST_H__ -#define __UBIUTILS_LIST_H__ - -#include <stdint.h> - -#define list_for_each(elem, ptr, list) \ - for ((elem) = (list) != NULL ? (typeof(elem)) head(list) \ - : NULL, (ptr) = (list); \ - ptr != NULL; \ - ptr = tail(ptr), \ - elem = (typeof(elem)) (ptr) ? head(ptr) : NULL) - -static inline struct list_entry *list_empty(void) -{ - return NULL; -} - -typedef void* info_t; -typedef int (*free_func_t)(info_t*); -typedef int (*cmp_func_t)(info_t, info_t); -typedef void (*process_func_t)(info_t); - -struct list_entry { - struct list_entry *next; - info_t info; -}; - -struct list_entry *list_empty(void); -int is_empty(struct list_entry *l); -info_t is_in(cmp_func_t cmp, info_t e, struct list_entry *l); -info_t head(struct list_entry *l); -struct list_entry *tail(struct list_entry *l); -struct list_entry *remove_head(struct list_entry *l); -struct list_entry *cons(info_t e, struct list_entry *l); -struct list_entry *prepend_elem(info_t e, struct list_entry *); -struct list_entry *append_elem(info_t e, struct list_entry *); -struct list_entry *remove_all(free_func_t free_func, struct list_entry *l); -struct list_entry *insert_sorted(cmp_func_t cmp_func, info_t e, struct list_entry *l); -void apply(process_func_t process_func, struct list_entry *l); - -#endif /* !__UBIUTILS_LIST_H__ */ diff --git a/ubi-utils/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c deleted file mode 100644 index 4289fca..0000000 --- a/ubi-utils/src/pfi2bin.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * Copyright (C) 2008 Nokia Corporation - * - * 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. - */ - -/* - * - * Convert a PFI file (partial flash image) into a plain binary file. - * This tool can be used to prepare the data to be burned into flash - * chips in a manufacturing step where the flashes are written before - * being soldered onto the hardware. For NAND images one more step may be - * needed to add the right OOB data to the binary image. - * - * Authors: Oliver Lohmann - * Artem Bityutskiy - */ - -#include <stdlib.h> -#include <getopt.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> - -#include <mtd/ubi-header.h> -#include <libubigen.h> -#include <libpfi.h> -#include "common.h" -#include "list.h" - -#define PROGRAM_VERSION "1.5" -#define PROGRAM_NAME "pfi2bin" - -static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -" - a tool to convert PFI files into raw flash images. Note, if not\n" -"sure about some of the parameters, do not specify them and let the utility to\n" -"use default values."; - -static const char *optionsstr = -"-o, --output=<file name> output file name (default is stdout)\n" -"-p, --peb-size=<bytes> size of the physical eraseblock of the flash this\n" -" UBI image is created for in bytes, kilobytes (KiB),\n" -" or megabytes (MiB) (mandatory parameter)\n" -"-m, --min-io-size=<bytes> minimum input/output unit size of the flash in bytes\n" -"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI headers, e.g.\n" -" sub-page size in case of NAND flash (equivalent to\n" -" the minimum input/output unit size by default)\n" -"-O, --vid-hdr-offset=<num> offset if the VID header from start of the physical\n" -" eraseblock (default is the second minimum I/O unit\n" -" or sub-page, if it was specified)\n" -"-e, --erase-counter=<num> the erase counter value to put to EC headers\n" -" (default is 0)\n" -"-x, --ubi-ver=<num> UBI version number to put to EC headers\n" -" (default is 1)\n" -"-h, --help print help message\n" -"-V, --version print program version"; - -static const char *usage = -"Usage: " PROGRAM_NAME "[-o filename] [-h] [-V] [--output=<filename>] [--help] [--version] pfifile\n" -"Example:" PROGRAM_NAME "-o fs.raw fs.pfi"; - -struct option long_options[] = { - { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, - { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'p' }, - { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' }, - { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, - { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, - { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, - { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, - { NULL, 0, NULL, 0} -}; - -struct args { - const char *f_in; - const char *f_out; - FILE *fp_in; - FILE *fp_out; - int peb_size; - int min_io_size; - int subpage_size; - int vid_hdr_offs; - int ec; - int ubi_ver; -}; - -static struct args args = { - .f_out = NULL, - .peb_size = -1, - .min_io_size = -1, - .subpage_size = -1, - .vid_hdr_offs = 0, - .ec = 0, - .ubi_ver = 1, -}; - -static int parse_opt(int argc, char * const argv[]) -{ - while (1) { - int key; - char *endp; - - key = getopt_long(argc, argv, "o:p:m:s:O:e:x:hV", long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'o': - args.fp_out = fopen(optarg, "wb"); - if (!args.fp_out) { - errmsg("cannot open file \"%s\"", optarg); - return -1; - } - args.f_out = optarg; - break; - - case 'p': - args.peb_size = strtoull(optarg, &endp, 0); - if (endp == optarg || args.peb_size <= 0) { - errmsg("bad physical eraseblock size: \"%s\"", optarg); - return -1; - } - if (*endp != '\0') { - int mult = ubiutils_get_multiplier(endp); - - if (mult == -1) { - errmsg("bad size specifier: \"%s\" - " - "should be 'KiB', 'MiB' or 'GiB'", endp); - return -1; - } - args.peb_size *= mult; - } - break; - - case 'm': - args.min_io_size = strtoull(optarg, &endp, 0); - if (endp == optarg || args.min_io_size <= 0) { - errmsg("bad min. I/O unit size: \"%s\"", optarg); - return -1; - } - if (*endp != '\0') { - int mult = ubiutils_get_multiplier(endp); - - if (mult == -1) { - errmsg("bad size specifier: \"%s\" - " - "should be 'KiB', 'MiB' or 'GiB'", endp); - return -1; - } - args.min_io_size *= mult; - } - break; - - case 's': - args.subpage_size = strtoull(optarg, &endp, 0); - if (endp == optarg || args.subpage_size <= 0) { - errmsg("bad sub-page size: \"%s\"", optarg); - return -1; - } - if (*endp != '\0') { - int mult = ubiutils_get_multiplier(endp); - - if (mult == -1) { - errmsg("bad size specifier: \"%s\" - " - "should be 'KiB', 'MiB' or 'GiB'", endp); - return -1; - } - args.subpage_size *= mult; - } - break; - - case 'O': - args.vid_hdr_offs = strtoul(optarg, &endp, 0); - if (endp == optarg || args.vid_hdr_offs < 0) { - errmsg("bad VID header offset: \"%s\"", optarg); - return -1; - } - break; - - case 'e': - args.ec = strtoul(optarg, &endp, 0); - if (endp == optarg || args.ec < 0) { - errmsg("bad erase counter value: \"%s\"", optarg); - return -1; - } - break; - - case 'x': - args.ubi_ver = strtoul(optarg, &endp, 0); - if (endp == optarg || args.ubi_ver < 0) { - errmsg("bad UBI version: \"%s\"", optarg); - return -1; - } - break; - - case 'h': - fprintf(stderr, "%s\n\n", doc); - fprintf(stderr, "%s\n\n", usage); - fprintf(stderr, "%s\n", optionsstr); - exit(EXIT_SUCCESS); - - case 'V': - fprintf(stderr, "%s\n", PROGRAM_VERSION); - exit(EXIT_SUCCESS); - - default: - fprintf(stderr, "Use -h for help\n"); - return -1; - } - } - - if (optind == argc) { - errmsg("input PFI file was not specified (use -h for help)"); - return -1; - } - - if (optind != argc - 1) { - errmsg("more then one input PFI file was specified (use -h for help)"); - return -1; - } - - if (args.peb_size < 0) { - errmsg("physical eraseblock size was not specified (use -h for help)"); - return -1; - } - - if (args.min_io_size < 0) { - errmsg("min. I/O unit size was not specified (use -h for help)"); - return -1; - } - - if (args.subpage_size < 0) - args.subpage_size = args.min_io_size; - - args.f_in = argv[optind++]; - args.fp_in = fopen(args.f_in, "rb"); - if (!args.fp_in) { - errmsg("cannot open file \"%s\"", args.f_in); - return -1; - } - - if (!args.f_out) { - args.f_out = "stdout"; - args.fp_out = stdout; - } - - return 0; -} - -/** - * pfi2vol_info - convert PFI UBI volume information to libubigen. - * @pfi: PFI UBI volume information - * @n: PFI volume index to convert - * @vi: libubigen volume information - */ -static void pfi2vol_info(const struct pfi_ubi *pfi, int n, - struct ubigen_vol_info *vi, - const struct ubigen_info *ui) -{ - vi->id = pfi->ids[n]; - vi->bytes = pfi->size; - vi->alignment = pfi->alignment; - vi->data_pad = ui->leb_size % vi->alignment; - vi->usable_leb_size = ui->leb_size - vi->data_pad; - vi->type = pfi->vol_type; - vi->name = pfi->names[n]; - vi->name_len = strlen(vi->name); - if (vi->name_len > UBI_VOL_NAME_MAX) { - errmsg("too long name, cut to %d symbols: \"%s\"", - UBI_VOL_NAME_MAX, vi->name); - vi->name_len = UBI_VOL_NAME_MAX; - } - - vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size; - vi->compat = 0; -} - -static int create_flash_image(void) -{ - int i, err, vtbl_size = args.peb_size; - struct ubigen_info ui; - struct list_entry *ubi_list = list_empty(), *ptr; - struct ubi_vtbl_record *vtbl; - struct pfi_ubi *pfi; - - vtbl = ubigen_create_empty_vtbl(&vtbl_size); - if (!vtbl) { - errmsg("cannot initialize volume table"); - return -1; - } - - ubigen_info_init(&ui, args.peb_size, args.min_io_size, - args.subpage_size, args.vid_hdr_offs, args.ubi_ver, - args.ec); - - err = read_pfi_headers(&ubi_list, args.fp_in); - if (err != 0) { - errmsg("cannot read PFI headers, error %d", err); - goto error; - } - - /* Add all volumes to the volume table */ - list_for_each(pfi, ptr, ubi_list) - for (i = 0; i < pfi->ids_size; i++) { - struct ubigen_vol_info vi; - - pfi2vol_info(pfi, i, &vi, &ui); - ubigen_add_volume(&ui, &vi, vtbl); - } - - err = ubigen_write_layout_vol(&ui, vtbl, args.fp_out); - if (err) { - errmsg("cannot create layout volume"); - goto error; - } - - /* Write all volumes */ - list_for_each(pfi, ptr, ubi_list) - for (i = 0; i < pfi->ids_size; i++) { - struct ubigen_vol_info vi; - - pfi2vol_info(pfi, i, &vi, &ui); - err = fseek(args.fp_in, pfi->data_offs, SEEK_SET); - if (err == -1) { - errmsg("cannot seek input file"); - perror("fseek"); - goto error; - } - - err = ubigen_write_volume(&ui, &vi, pfi->data_size, - args.fp_in, args.fp_out); - if (err) { - errmsg("cannot write volume %d", vi.id); - goto error; - } - } - - if (args.fp_out != stdout) { - i = ftell(args.fp_out); - if (i == -1) { - errmsg("cannot seek output file"); - perror("ftell"); - goto error; - } - - printf("physical eraseblocks written: %d (", i / ui.peb_size); - ubiutils_print_bytes(i, 0); - printf(")\n"); - } - -error: - free(vtbl); - ubi_list = remove_all((free_func_t)&free_pfi_ubi, ubi_list); - return err; -} - -int main(int argc, char * const argv[]) -{ - int err; - - err = parse_opt(argc, argv); - if (err) - return -1; - - err = create_flash_image(); - if (err) - remove(args.f_out); - - return err; -} diff --git a/ubi-utils/src/pfiflash.h b/ubi-utils/src/pfiflash.h deleted file mode 100644 index 039705d..0000000 --- a/ubi-utils/src/pfiflash.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef __PFIFLASH_H__ -#define __PFIFLASH_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. - */ - -/** - * - * @file pfi.h - * - * @author Oliver Lohmann <oliloh@de.ibm.com> - * - * @brief The pfiflash library offers an interface for using the - * pfiflash * utility. - */ - -#include <stdio.h> /* FILE */ - -#define PFIFLASH_MAX_ERR_BUF_SIZE 1024 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum pdd_handling_t -{ - PDD_KEEP = 0, - PDD_MERGE, - PDD_OVERWRITE, - PDD_HANDLING_NUM, /* always the last item */ -} pdd_handling_t; /**< Possible PDD handle algorithms. */ - -/** - * @brief Flashes a PFI file to UBI Device 0. - * @param complete [0|1] Do a complete system update. - * @param seqnum Index in a redundant group. - * @param compare [0|1] Compare contents. - * @param pdd_handling The PDD handling algorithm. - * @param rawdev Device to use for raw flashing - * @param err_buf An error buffer. - * @param err_buf_size Size of the error buffer. - */ -int pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare, - pdd_handling_t pdd_handling, const char* rawdev, - char *err_buf, size_t err_buf_size); - -/** - * @brief Flashes a PFI file to UBI Device 0. - * @param complete [0|1] Do a complete system update. - * @param seqnum Index in a redundant group. - * @param pdd_handling The PDD handling algorithm. - * @param err_buf An error buffer. - * @param err_buf_size Size of the error buffer. - */ -int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, - char *err_buf, size_t err_buf_size); - -#ifdef __cplusplus -} -#endif - -#endif /* __PFIFLASH_H__ */ diff --git a/ubi-utils/src/ubinize.c b/ubi-utils/src/ubinize.c new file mode 100644 index 0000000..28991f9 --- /dev/null +++ b/ubi-utils/src/ubinize.c @@ -0,0 +1,615 @@ +/* + * Copyright (C) 2008 Nokia Corporation + * 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. + */ + +/* + * Generate UBI images. + * + * Authors: Artem Bityutskiy + * Oliver Lohmann + */ + +#include <stdlib.h> +#include <getopt.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/stat.h> + +#include <mtd/ubi-header.h> +#include <libubigen.h> +#include <libiniparser.h> +#include "common.h" + +#define PROGRAM_VERSION "1.5" +#define PROGRAM_NAME "ubinize" + +static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION +" - a tool to generate UBI images. An UBI image may contain one or more UBI " +"volumes which have to be defined in the input configuration ini-file. The " +"ini file defines all the UBI volumes - their characteristics and the and the " +"contents, but it does not define the characteristics of the flash the UBI " +"image is generated for. Instead, the flash characteristics are defined via " +"the comman-line options. " +"Note, if not sure about some of the command-line parameters, do not specify " +"them and let the utility to use default values."; + +static const char *optionsstr = +"-o, --output=<file name> output file name (default is stdout)\n" +"-p, --peb-size=<bytes> size of the physical eraseblock of the flash\n" +" this UBI image is created for in bytes,\n" +" kilobytes (KiB), or megabytes (MiB)\n" +" (mandatory parameter)\n" +"-m, --min-io-size=<bytes> minimum input/output unit size of the flash\n" +" in bytes\n" +"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI\n" +" headers, e.g. sub-page size in case of NAND\n" +" flash (equivalent to the minimum input/output\n" +" unit size by default)\n" +"-O, --vid-hdr-offset=<num> offset if the VID header from start of the\n" +" physical eraseblock (default is the second\n" +" minimum I/O unit or sub-page, if it was\n" +" specified)\n" +"-e, --erase-counter=<num> the erase counter value to put to EC headers\n" +" (default is 0)\n" +"-x, --ubi-ver=<num> UBI version number to put to EC headers\n" +" (default is 1)\n" +"-v --verbose be verbose\n" +"-h, --help print help message\n" +"-V, --version print program version"; + +static const char *usage = +"Usage: " PROGRAM_NAME " [-o filename] [-h] [-V] [--output=<filename>] [--help]\n" +"\t\t[--version] inifile\n" +"Example: " PROGRAM_NAME "-o fs.raw cfg.ini"; + +struct option long_options[] = { + { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, + { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'p' }, + { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' }, + { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, + { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, + { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, + { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, + { .name = "verbose", .has_arg = 1, .flag = NULL, .val = 'v' }, + { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, + { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, + { NULL, 0, NULL, 0} +}; + +struct args { + const char *f_in; + const char *f_out; + FILE *fp_out; + int peb_size; + int min_io_size; + int subpage_size; + int vid_hdr_offs; + int ec; + int ubi_ver; + int verbose; + dictionary *dict; +}; + +static struct args args = { + .f_out = NULL, + .peb_size = -1, + .min_io_size = -1, + .subpage_size = -1, + .vid_hdr_offs = 0, + .ec = 0, + .ubi_ver = 1, + .verbose = 0, +}; + +static int parse_opt(int argc, char * const argv[]) +{ + while (1) { + int key; + char *endp; + + key = getopt_long(argc, argv, "o:p:m:s:O:e:x:vhV", long_options, NULL); + if (key == -1) + break; + + switch (key) { + case 'o': + args.fp_out = fopen(optarg, "wb"); + if (!args.fp_out) { + errmsg("cannot open file \"%s\"", optarg); + return -1; + } + args.f_out = optarg; + break; + + case 'p': + args.peb_size = strtoull(optarg, &endp, 0); + if (endp == optarg || args.peb_size <= 0) { + errmsg("bad physical eraseblock size: \"%s\"", optarg); + return -1; + } + if (*endp != '\0') { + int mult = ubiutils_get_multiplier(endp); + + if (mult == -1) { + errmsg("bad size specifier: \"%s\" - " + "should be 'KiB', 'MiB' or 'GiB'", endp); + return -1; + } + args.peb_size *= mult; + } + break; + + case 'm': + args.min_io_size = strtoull(optarg, &endp, 0); + if (endp == optarg || args.min_io_size <= 0) { + errmsg("bad min. I/O unit size: \"%s\"", optarg); + return -1; + } + if (*endp != '\0') { + int mult = ubiutils_get_multiplier(endp); + + if (mult == -1) { + errmsg("bad size specifier: \"%s\" - " + "should be 'KiB', 'MiB' or 'GiB'", endp); + return -1; + } + args.min_io_size *= mult; + } + break; + + case 's': + args.subpage_size = strtoull(optarg, &endp, 0); + if (endp == optarg || args.subpage_size <= 0) { + errmsg("bad sub-page size: \"%s\"", optarg); + return -1; + } + if (*endp != '\0') { + int mult = ubiutils_get_multiplier(endp); + + if (mult == -1) { + errmsg("bad size specifier: \"%s\" - " + "should be 'KiB', 'MiB' or 'GiB'", endp); + return -1; + } + args.subpage_size *= mult; + } + break; + + case 'O': + args.vid_hdr_offs = strtoul(optarg, &endp, 0); + if (endp == optarg || args.vid_hdr_offs < 0) { + errmsg("bad VID header offset: \"%s\"", optarg); + return -1; + } + break; + + case 'e': + args.ec = strtoul(optarg, &endp, 0); + if (endp == optarg || args.ec < 0) { + errmsg("bad erase counter value: \"%s\"", optarg); + return -1; + } + break; + + case 'x': + args.ubi_ver = strtoul(optarg, &endp, 0); + if (endp == optarg || args.ubi_ver < 0) { + errmsg("bad UBI version: \"%s\"", optarg); + return -1; + } + break; + + case 'v': + args.verbose = 1; + break; + + case 'h': + ubiutils_print_text(stderr, doc, 80); + fprintf(stderr, "\n\n%s\n\n", usage); + fprintf(stderr, "%s\n", optionsstr); + exit(EXIT_SUCCESS); + + case 'V': + fprintf(stderr, "%s\n", PROGRAM_VERSION); + exit(EXIT_SUCCESS); + + default: + fprintf(stderr, "Use -h for help\n"); + return -1; + } + } + + if (optind == argc) { + errmsg("input PFI file was not specified (use -h for help)"); + return -1; + } + + if (optind != argc - 1) { + errmsg("more then one input PFI file was specified (use -h for help)"); + return -1; + } + + args.f_in = argv[optind]; + + if (args.peb_size < 0) { + errmsg("physical eraseblock size was not specified (use -h for help)"); + return -1; + } + + if (args.min_io_size < 0) { + errmsg("min. I/O unit size was not specified (use -h for help)"); + return -1; + } + + if (args.subpage_size < 0) + args.subpage_size = args.min_io_size; + + if (!args.f_out) { + args.f_out = "stdout"; + args.fp_out = stdout; + } + + return 0; +} + +int read_section(const char *sname, struct ubigen_vol_info *vi, + const char **img) +{ + char buf[256]; + const char *p; + + *img = NULL; + + if (strlen(sname) > 128) { + errmsg("too long section name \"%s\"", sname); + return -1; + } + + /* Make sure mode is UBI, otherwise ignore this section */ + sprintf(buf, "%s:mode", sname); + p = iniparser_getstring(args.dict, buf, NULL); + if (!p) { + errmsg("\"mode\" key not found in section \"%s\"", sname); + errmsg("the \"mode\" key is mandatory and has to be " + "\"mode=ubi\" if the section describes an UBI volume"); + return -1; + } + + /* If mode is not UBI, skip this section */ + if (strcmp(p, "ubi")) { + verbose(args.verbose, "skip non-ubi section \"%s\"", sname); + return 1; + } + + verbose(args.verbose, "mode=ubi, keep parsing"); + + /* Fetch the name of the volume image file */ + sprintf(buf, "%s:image", sname); + p = iniparser_getstring(args.dict, buf, NULL); + if (p) + *img = p; + + /* Fetch volume id */ + sprintf(buf, "%s:vol_id", sname); + vi->id = iniparser_getint(args.dict, buf, -1); + if (vi->id == -1) { + errmsg("\"vol_id\" key not found in section \"%s\"", sname); + return -1; + } + + if (vi->id < 0) { + errmsg("negative volume ID %d", vi->id); + return -1; + } + + if (vi->id >= UBI_MAX_VOLUMES) { + errmsg("too highe volume ID %d, max. is %d", + vi->id, UBI_MAX_VOLUMES); + return -1; + } + + verbose(args.verbose, "volume ID: %d", vi->id); + + /* Fetch volume size */ + sprintf(buf, "%s:vol_size", sname); + p = iniparser_getstring(args.dict, buf, NULL); + if (p) { + char *endp; + + vi->bytes = strtoull((char *)p, &endp, 0); + if (endp == p || vi->bytes <= 0) { + errmsg("bad \"vol_size\" key: \"%s\"", p); + return -1; + } + + if (*endp != '\0') { + int mult = ubiutils_get_multiplier(endp); + + if (mult == -1) { + errmsg("bad size specifier: \"%s\" - " + "should be 'KiB', 'MiB' or 'GiB'", endp); + return -1; + } + vi->bytes *= mult; + } + + verbose(args.verbose, "volume size: %lld bytes", vi->bytes); + } else { + struct stat st; + + if (!*img) { + errmsg("neither image file (\"image=\") nor volume size" + " (\"vol_size=\") specified"); + return -1; + } + + if (stat(*img, &st)) { + errmsg("cannot stat \"%s\"", *img); + perror("stat"); + return -1; + } + + vi->bytes = st.st_size; + + if (vi->bytes == 0) { + errmsg("file \"%s\" referred from section \"%s\" is empty", + *img, sname); + return -1; + } + + printf(PROGRAM_NAME ": volume size was not specified in" + "section \"%s\", assume ", sname); + ubiutils_print_bytes(vi->bytes, 1); + printf("\n"); + } + + /* Fetch volume type */ + sprintf(buf, "%s:vol_type", sname); + p = iniparser_getstring(args.dict, buf, NULL); + if (!p) { + normsg(": volume type was not specified in " + "section \"%s\", assume \"dynamic\"\n", sname); + vi->type = UBI_VID_DYNAMIC; + } else { + if (!strcmp(p, "static")) + vi->type = UBI_VID_STATIC; + else if (!strcmp(p, "dynamic")) + vi->type = UBI_VID_DYNAMIC; + else { + errmsg("invalid volume type \"%s\"", p); + return -1; + } + } + + verbose(args.verbose, "volume type: %s", + vi->type == UBI_VID_DYNAMIC ? "dynamic" : "static"); + + /* Fetch volume name */ + sprintf(buf, "%s:vol_name", sname); + p = iniparser_getstring(args.dict, buf, NULL); + if (!p) { + errmsg("\"vol_name\" key not found in section \"%s\"", sname); + return -1; + } + + vi->name = p; + vi->name_len = strlen(p); + if (vi->name_len > UBI_VOL_NAME_MAX) { + errmsg("too long volume name in section \"%s\", max. is " + "%d characters", vi->name, UBI_VOL_NAME_MAX); + return -1; + } + + verbose(args.verbose, "volume name: %s", p); + + /* Fetch volume alignment */ + sprintf(buf, "%s:vol_alignment", sname); + vi->alignment = iniparser_getint(args.dict, buf, -1); + if (vi->alignment == -1) { + normsg("volume alignment was not specified in section " + "\"%s\", assume 1", sname); + vi->alignment = 1; + } else if (vi->id < 0) { + errmsg("negative volume alignement %d", vi->alignment); + return -1; + } + + verbose(args.verbose, "volume alignment: %d", vi->alignment); + + return 0; +} + +static void init_vol_info(const struct ubigen_info *ui, + struct ubigen_vol_info *vi) +{ + vi->data_pad = ui->leb_size % vi->alignment; + vi->usable_leb_size = ui->leb_size - vi->data_pad; + vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size; + vi->compat = 0; +} + +int main(int argc, char * const argv[]) +{ + int err = -1, sects, i, volumes; + struct ubigen_info ui; + struct ubi_vtbl_record *vtbl; + + err = parse_opt(argc, argv); + if (err) + return -1; + + ubigen_info_init(&ui, args.peb_size, args.min_io_size, + args.subpage_size, args.vid_hdr_offs, + args.ubi_ver, args.ec); + + verbose(args.verbose, "LEB size: %d", ui.leb_size); + verbose(args.verbose, "PEB size: %d", ui.peb_size); + verbose(args.verbose, "min_io_size: %d", ui.min_io_size); + verbose(args.verbose, "VID offset: %d", ui.vid_hdr_offs); + + vtbl = ubigen_create_empty_vtbl(&ui); + if (!vtbl) + goto out; + + args.dict = iniparser_load(args.f_in); + if (!args.dict) { + errmsg("cannot load the input ini file \"%s\"", args.f_in); + goto out_vtbl; + } + + verbose(args.verbose, "loaded the ini-file \"%s\"", args.f_in); + + /* Each section describes one volume */ + sects = iniparser_getnsec(args.dict); + if (sects == -1) { + errmsg("ini-file parsing error (iniparser_getnsec)"); + goto out_dict; + } + + verbose(args.verbose, "count of sections: %d", sects); + if (sects == 0) { + errmsg("no sections found the ini-file \"%s\"", args.f_in); + goto out_dict; + } + + /* + * Skip 2 PEBs at the beginning of the file for the volume table which + * will be written later. + */ + if (fseek(args.fp_out, ui.peb_size * 2, SEEK_SET) == -1) { + errmsg("cannot seek file \"%s\"", args.f_out); + goto out_dict; + } + + for (i = 0; i < sects; i++) { + const char *sname = iniparser_getsecname(args.dict, i); + struct ubigen_vol_info vi; + const char *img = NULL; + struct stat st; + FILE *f; + + if (!sname) { + errmsg("ini-file parsing error (iniparser_getsecname)"); + goto out_dict; + } + + if (args.verbose) + printf("\n"); + verbose(args.verbose, "parsing section \"%s\"", sname); + + err = read_section(sname, &vi, &img); + if (err == -1) + goto out_dict; + if (!err) + volumes += 1; + init_vol_info(&ui, &vi); + + verbose(args.verbose, "adding volume %d", vi.id); + + err = ubigen_add_volume(&ui, &vi, vtbl); + if (err) { + errmsg("cannot add volume for section \"%s\"", sname); + goto out_dict; + } + + if (!img) + continue; + + if (stat(img, &st)) { + errmsg("cannot stat \"%s\"", img); + perror("stat"); + goto out_dict; + } + + f = fopen(img, "r"); + if (!f) { + errmsg("cannot open \"%s\"", img); + perror("fopen"); + goto out_dict; + } + + verbose(args.verbose, "writing volume %d", vi.id); + verbose(args.verbose, "image file: %s", img); + + err = ubigen_write_volume(&ui, &vi, st.st_size, f, args.fp_out); + fclose(f); + if (err) { + errmsg("cannot write volume for section \"%s\"", sname); + goto out_dict; + } + + if (args.verbose) + printf("\n"); + } + + verbose(args.verbose, "writing layout volume"); + + err = ubigen_write_layout_vol(&ui, vtbl, args.fp_out); + if (err) { + errmsg("cannot write layout volume"); + goto out_dict; + } + + verbose(args.verbose, "done"); + + iniparser_freedict(args.dict); + free(vtbl); + fclose(args.fp_out); + return 0; + +out_dict: + iniparser_freedict(args.dict); +out_vtbl: + free(vtbl); +out: + fclose(args.fp_out); + remove(args.f_out); + return err; +} + +#if 0 +/** + * pfi2vol_info - convert PFI UBI volume information to libubigen. + * @pfi: PFI UBI volume information + * @n: PFI volume index to convert + * @vi: libubigen volume information + */ +static void pfi2vol_info(const struct pfi_ubi *pfi, int n, + struct ubigen_vol_info *vi, + const struct ubigen_info *ui) +{ + vi->id = pfi->ids[n]; + vi->bytes = pfi->size; + vi->alignment = pfi->alignment; + vi->data_pad = ui->leb_size % vi->alignment; + vi->usable_leb_size = ui->leb_size - vi->data_pad; + vi->type = pfi->vol_type; + vi->name = pfi->names[n]; + vi->name_len = strlen(vi->name); + if (vi->name_len > UBI_VOL_NAME_MAX) { + errmsg("too long name, cut to %d symbols: \"%s\"", + UBI_VOL_NAME_MAX, vi->name); + vi->name_len = UBI_VOL_NAME_MAX; + } + + vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size; + vi->compat = 0; +} +#endif diff --git a/ubi-utils/src/unubi.c b/ubi-utils/src/unubi.c deleted file mode 100644 index 1d4b35b..0000000 --- a/ubi-utils/src/unubi.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Authors: Drake Dowsett, dowsett@de.ibm.com - * 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 - */ - -/* - * unubi reads an image file containing blocks of UBI headers and data - * (such as produced from nand2bin) and rebuilds the volumes within. The - * default operation (when no flags are given) is to rebuild all valid - * volumes found in the image. unubi can also read straight from the - * onboard MTD device (ex. /dev/mtdblock/NAND). - */ - -/* TODO: consideration for dynamic vs. static volumes */ - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdint.h> -#include <getopt.h> -#include <stdarg.h> -#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 "unubi_analyze.h" - -#define EXEC "unubi" -#define CONTACT "haver@vnet.ibm.com" -#define VERSION "1.5" - -static char doc[] = "\nVersion: " VERSION "\n"; -static int debug = 0; - -static const char *optionsstr = -"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 and create gnuplot graphs\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 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" -" eraseblocks)\n" -" -v, --vol-split Generate individual eraseblock images (valid\n" -" eraseblocks only)\n" -" -V, --vol-split! Raw split by eraseblock (valid eraseblocks only)\n" -"\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" --version Print program version\n" -"\n"; - -static const char *usage = -"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) - -#define SPLIT_DATA 1 -#define SPLIT_RAW 2 - -#define DIR_FMT "unubi_%s" -#define KIB 1024 -#define MIB (KIB * KIB) -#define MAXPATH KIB - -/* filenames */ -#define FN_INVAL "%s/eb%04u%s" /* invalid eraseblock */ -#define FN_NSURE "%s/eb%04u_%03u_%03u_%03x%s" /* unsure eraseblock */ -#define FN_VALID "%s/eb%04u_%03u_%03u_%03x%s" /* valid eraseblock */ -#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04u" /* split volume */ -#define FN_VOLWH "%s/volume%03u" /* whole volume */ -#define FN_VITBL "%s/vol_info_table%u" /* vol info table */ - -/* 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 - * vol_split flag, when non-zero output vol###_#### - * note: SPLIT_DATA vs. SPLIT_RAW - * odir_path string, directory to place volumes in - * img_path string, file to read as ubi image - * vols int array of size UBI_MAX_VOLUMES, where a 1 can be - * written for each --rebuild flag in the index specified - * then the array can be counted and collapsed using - * count_set() and collapse() - */ -struct args { - int analyze; - int itable; - uint32_t *vols; - - 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; - char *img_path; - - char **options; -}; - -struct option long_options[] = { - { .name = "rebuild", .has_arg = 1, .flag = NULL, .val = 'r' }, - { .name = "dir", .has_arg = 1, .flag = NULL, .val = 'd' }, - { .name = "analyze", .has_arg = 0, .flag = NULL, .val = 'a' }, - { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' }, - { .name = "eb-split", .has_arg = 0, .flag = NULL, .val = 'e' }, - { .name = "vol-split", .has_arg = 0, .flag = NULL, .val = 'v' }, - { .name = "vol-split!", .has_arg = 0, .flag = NULL, .val = 'e' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'J' }, - { NULL, 0, NULL, 0} -}; - -/** - * parses out a numerical value from a string of numbers followed by: - * k, K, kib, KiB for kibibyte - * m, M, mib, MiB for mebibyte - **/ -static uint32_t -str_to_num(char *str) -{ - char *s; - ulong num; - - s = str; - num = strtoul(s, &s, 0); - - if (*s != '\0') { - if ((strcmp(s, "KiB") == 0) || (strcmp(s, "K") == 0) || - (strcmp(s, "kib") == 0) || (strcmp(s, "k") == 0)) - num *= KIB; - else if ((strcmp(s, "MiB") == 0) || (strcmp(s, "M") == 0) || - (strcmp(s, "mib") == 0) || (strcmp(s, "m") == 0)) - num *= MIB; - else - ERR_MSG("couldn't parse '%s', assuming %lu\n", - s, num); - } - return num; -} - -static int -parse_opt(int argc, char **argv, struct args *args) -{ - uint32_t i; - - while (1) { - int key; - - key = getopt_long(argc, argv, "ab:s:d:Deir:vV?J", - long_options, NULL); - if (key == -1) - break; - - switch (key) { - case 'a': /* --analyze */ - args->analyze = 1; - break; - case 'b': /* --block-size=<block-size> */ - args->bsize = str_to_num(optarg); - break; - case 's': /* --header-size=<header-size> */ - args->hsize = str_to_num(optarg); - break; - case 'd': /* --dir=<output-dir> */ - args->odir_path = optarg; - break; - case 'D': /* --debug */ - /* I wanted to use -v but that was already - used ... */ - debug = 1; - break; - case 'e': /* --eb-split */ - args->eb_split = SPLIT_RAW; - break; - case 'i': /* --info-table */ - args->itable = 1; - break; - case 'r': /* --rebuild=<volume-id> */ - 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': /* --vol-split */ - if (args->vol_split != SPLIT_RAW) - args->vol_split = SPLIT_DATA; - break; - case 'V': /* --vol-split! */ - 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); - } - } - - /* 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; -} - - -/** - * counts the number of indicies which are flagged in full_array; - * full_array is an array of flags (1/0); - **/ -static size_t -count_set(uint32_t *full_array, size_t full_len) -{ - size_t count, i; - - if (full_array == NULL) - return 0; - - for (i = 0, count = 0; i < full_len; i++) - if (full_array[i] != 0) - count++; - - return count; -} - - -/** - * generates coll_array from full_array; - * full_array is an array of flags (1/0); - * coll_array is an array of the indicies in full_array which are flagged (1); - **/ -static size_t -collapse(uint32_t *full_array, size_t full_len, - uint32_t *coll_array, size_t coll_len) -{ - size_t i, j; - - if ((full_array == NULL) || (coll_array == NULL)) - return 0; - - for (i = 0, j = 0; (i < full_len) && (j < coll_len); i++) - if (full_array[i] != 0) { - coll_array[j] = i; - j++; - } - - return j; -} - -/** - * data_crc: save the FILE* position, calculate the crc over a span, - * reset the position - * returns non-zero when EOF encountered - **/ -static int -data_crc(FILE* fpin, size_t length, uint32_t *ret_crc) -{ - int rc; - size_t i; - char buf[length]; - uint32_t crc; - fpos_t start; - - rc = fgetpos(fpin, &start); - if (rc < 0) - return -1; - - for (i = 0; i < length; i++) { - int c = fgetc(fpin); - if (c == EOF) { - ERR_MSG("unexpected EOF\n"); - return -1; - } - buf[i] = (char)c; - } - - rc = fsetpos(fpin, &start); - if (rc < 0) - return -1; - - crc = crc32(UBI_CRC32_INIT, buf, length); - *ret_crc = crc; - return 0; -} - - -/** - * reads data of size len from fpin and writes it to path - **/ -static int -extract_data(FILE* fpin, size_t len, const char *path) -{ - int rc; - size_t i; - FILE* fpout; - - rc = 0; - fpout = NULL; - - fpout = fopen(path, "wb"); - if (fpout == NULL) { - ERR_MSG("couldn't open file for writing: %s\n", path); - rc = -1; - goto err; - } - - for (i = 0; i < len; i++) { - int c = fgetc(fpin); - if (c == EOF) { - ERR_MSG("unexpected EOF while writing: %s\n", path); - rc = -2; - goto err; - } - c = fputc(c, fpout); - if (c == EOF) { - ERR_MSG("couldn't write: %s\n", path); - rc = -3; - goto err; - } - } - - err: - if (fpout != NULL) - fclose(fpout); - return rc; -} - - -/** - * 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, struct eb_info *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_vtbl_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, __be32_to_cpu(cur->ec.data_offset), SEEK_CUR); - - /* prepare output file */ - if (__be32_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 - __be32_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 = crc32(UBI_CRC32_INIT, &rec, UBI_VTBL_RECORD_SIZE_CRC); - if (crc != __be32_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[__be16_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, - __be32_to_cpu(rec.reserved_pebs), - __be32_to_cpu(rec.alignment), - type, - __be32_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, 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; - struct eb_info *cur; - - rc = 0; - - if ((fpin == NULL) || (head == NULL) || (*head == NULL)) - return 0; - - /* when vol_id is null, then do all */ - if (vol_id == NULL) { - cur = *head; - vol = __be32_to_cpu(cur->vid.vol_id); - } else { - vol = *vol_id; - eb_chain_position(head, vol, NULL, &cur); - if (cur == NULL) { - if (debug) - ERR_MSG("no valid volume %d was found\n", vol); - return -1; - } - } - - num = 0; - snprintf(filename, MAXPATH, FN_VOLWH, path, vol); - fpout = fopen(filename, "wb"); - if (fpout == NULL) { - ERR_MSG("couldn't open file for writing: %s\n", filename); - return -1; - } - - while (cur != NULL) { - size_t i; - - if (__be32_to_cpu(cur->vid.vol_id) != vol) { - /* close out file */ - fclose(fpout); - - /* only stay around if that was the only volume */ - if (vol_id != NULL) - goto out; - - /* begin with next */ - vol = __be32_to_cpu(cur->vid.vol_id); - num = 0; - snprintf(filename, MAXPATH, FN_VOLWH, path, vol); - fpout = fopen(filename, "wb"); - if (fpout == NULL) { - ERR_MSG("couldn't open file for writing: %s\n", - filename); - return -1; - } - } - - while (num < __be32_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, __be32_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 = __be32_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", - filename); - rc = -2; - goto out; - } - c = fputc(c, fpout); - if (c == EOF) { - ERR_MSG("couldn't write: %s\n", filename); - rc = -3; - goto out; - } - } - - cur = cur->next; - num++; - } - - out: - if (vol_id == NULL) - fclose(fpout); - return rc; -} - - -/** - * traverses FILE* trying to load complete, valid and accurate header data - * into the eb chain; - **/ -static int -unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) -{ - char filename[MAXPATH + 1]; - char reason[MAXPATH + 1]; - int rc; - size_t i, count, itable_num; - /* relations: - * cur ~ head - * next ~ first */ - struct eb_info *head, *cur, *first, *next; - struct eb_info **next_ptr; - - rc = 0; - count = 0; - itable_num = 0; - head = NULL; - first = NULL; - next = NULL; - cur = malloc(sizeof(*cur)); - if (cur == NULL) { - ERR_MSG("out of memory\n"); - rc = -ENOMEM; - goto err; - } - memset(cur, 0, sizeof(*cur)); - - fgetpos(fpin, &(cur->eb_top)); - while (1) { - const char *raw_path; - uint32_t crc; - - cur->phys_addr = ftell(fpin); - cur->phys_block = cur->phys_addr / a->bsize; - 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); - - /* in case of an incomplete ec header */ - raw_path = FN_INVAL; - - /* read erasecounter header */ - rc = fread(&cur->ec, 1, sizeof(cur->ec), fpin); - if (rc == 0) - goto out; /* EOF */ - if (rc != sizeof(cur->ec)) { - ERR_MSG("reading ec-hdr failed\n"); - rc = -1; - goto err; - } - - /* check erasecounter header magic */ - if (__be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) { - snprintf(reason, MAXPATH, ".invalid.ec_magic"); - goto invalid; - } - - /* check erasecounter header crc */ - crc = crc32(UBI_CRC32_INIT, &(cur->ec), UBI_EC_HDR_SIZE_CRC); - if (__be32_to_cpu(cur->ec.hdr_crc) != crc) { - snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc"); - goto invalid; - } - - /* read volume id header */ - rc = fsetpos(fpin, &(cur->eb_top)); - if (rc != 0) - goto err; - fseek(fpin, __be32_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->vid)) { - ERR_MSG("reading vid-hdr failed\n"); - rc = -1; - goto err; - } - - /* if the magic number is 0xFFFFFFFF, then it's very likely - * that the volume is empty */ - if (__be32_to_cpu(cur->vid.magic) == 0xffffffff) { - snprintf(reason, MAXPATH, ".empty"); - goto invalid; - } - - /* vol_id should be in bounds */ - if ((__be32_to_cpu(cur->vid.vol_id) >= UBI_MAX_VOLUMES) && - (__be32_to_cpu(cur->vid.vol_id) < - UBI_INTERNAL_VOL_START)) { - snprintf(reason, MAXPATH, ".invalid"); - goto invalid; - } else - raw_path = FN_NSURE; - - /* check volume id header magic */ - if (__be32_to_cpu(cur->vid.magic) != UBI_VID_HDR_MAGIC) { - snprintf(reason, MAXPATH, ".invalid.vid_magic"); - goto invalid; - } - cur->ec_crc_ok = 1; - - /* check volume id header crc */ - crc = crc32(UBI_CRC32_INIT, &(cur->vid), UBI_VID_HDR_SIZE_CRC); - if (__be32_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) { - rc = data_crc(fpin, __be32_to_cpu(cur->vid.data_size), - &crc); - if (rc < 0) - goto err; - if (__be32_to_cpu(cur->vid.data_crc) != crc) { - snprintf(reason, MAXPATH, ".invalid.data_crc"); - goto invalid; - } - cur->data_crc_ok = 1; - } - - /* enlist this vol, it's valid */ - raw_path = FN_VALID; - cur->linear = count; - rc = eb_chain_insert(&head, cur); - if (rc < 0) { - if (rc == -ENOMEM) { - ERR_MSG("out of memory\n"); - goto err; - } - ERR_MSG("unknown and unexpected error, please contact " - CONTACT "\n"); - goto err; - } - - /* extract info-table */ - if (a->itable && - (__be32_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; - - rc = fsetpos(fpin, &(cur->eb_top)); - 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 */ - if (cur->vid.vol_type == UBI_VID_DYNAMIC) { - /* FIXME Formular is not - always right ... */ - size = a->bsize - a->hsize; - } else - size = __be32_to_cpu(cur->vid.data_size); - - fseek(fpin, - __be32_to_cpu(cur->ec.data_offset), - SEEK_CUR); - } - else if (a->vol_split == SPLIT_RAW) - /* write entire eraseblock */ - size = a->bsize; - - snprintf(filename, MAXPATH, FN_VOLSP, - a->odir_path, - __be32_to_cpu(cur->vid.vol_id), - __be32_to_cpu(cur->vid.lnum), - __be32_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)); - if (rc != 0) - goto err; - - if (strcmp(raw_path, FN_INVAL) == 0) - snprintf(filename, MAXPATH, raw_path, - a->odir_path, count, reason); - else - snprintf(filename, MAXPATH, raw_path, - a->odir_path, - count, - __be32_to_cpu(cur->vid.vol_id), - __be32_to_cpu(cur->vid.lnum), - __be32_to_cpu(cur->vid.leb_ver), - reason); - - rc = extract_data(fpin, a->bsize, filename); - if (rc < 0) - goto err; - } - - /* append to simple linked list */ - if (first == NULL) - next_ptr = &first; - else - next_ptr = &next->next; - - *next_ptr = malloc(sizeof(**next_ptr)); - if (*next_ptr == NULL) { - ERR_MSG("out of memory\n"); - rc = -ENOMEM; - goto err; - } - memset(*next_ptr, 0, sizeof(**next_ptr)); - - next = *next_ptr; - memcpy(next, cur, sizeof(*next)); - next->next = NULL; - - count++; - rc = fsetpos(fpin, &(cur->eb_top)); - if (rc != 0) - goto err; - fseek(fpin, a->bsize, SEEK_CUR); - memset(cur, 0, sizeof(*cur)); - - fgetpos(fpin, &(cur->eb_top)); - } - - out: - for (i = 0; i < vc; i++) { - 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) && (!a->itable)) { - rc = rebuild_volume(fpin, NULL, &head, a->odir_path, a->bsize, - a->hsize); - if (rc < 0) - goto err; - } - - err: - free(cur); - - 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); - - return rc; -} - - -/** - * handles command line arguments, then calls unubi_volumes - **/ -int -main(int argc, char *argv[]) -{ - int rc, free_a_odir; - size_t vols_len; - uint32_t *vols; - FILE* fpin; - struct args a; - - rc = 0; - free_a_odir = 0; - vols_len = 0; - vols = NULL; - fpin = NULL; - - /* 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"); - rc = ENOMEM; - goto err; - } - memset(a.vols, 0, sizeof(*a.vols) * UBI_MAX_VOLUMES); - - /* parse args and check for validity */ - parse_opt(argc, argv, &a); - if (a.img_path == NULL) { - ERR_MSG("no image file specified\n"); - rc = EINVAL; - goto err; - } - else if (a.odir_path == NULL) { - char *ptr; - int len; - - ptr = strrchr(a.img_path, '/'); - if (ptr == NULL) - ptr = a.img_path; - else - ptr++; - - len = strlen(DIR_FMT) + strlen(ptr); - free_a_odir = 1; - a.odir_path = malloc(sizeof(*a.odir_path) * len); - if (a.odir_path == NULL) { - ERR_MSG("out of memory\n"); - rc = ENOMEM; - goto err; - } - snprintf(a.odir_path, len, DIR_FMT, ptr); - } - - fpin = fopen(a.img_path, "rb"); - if (fpin == NULL) { - ERR_MSG("couldn't open file for reading: " - "%s\n", a.img_path); - rc = EINVAL; - goto err; - } - - rc = mkdir(a.odir_path, 0777); - if ((rc < 0) && (errno != EEXIST)) { - ERR_MSG("couldn't create ouput directory: " - "%s\n", a.odir_path); - rc = -rc; - goto err; - } - - /* fill in vols array */ - vols_len = count_set(a.vols, UBI_MAX_VOLUMES); - if (vols_len > 0) { - vols = malloc(sizeof(*vols) * vols_len); - if (vols == NULL) { - ERR_MSG("out of memory\n"); - rc = ENOMEM; - goto err; - } - collapse(a.vols, UBI_MAX_VOLUMES, vols, vols_len); - } - - /* unubi volumes */ - rc = unubi_volumes(fpin, vols, vols_len, &a); - if (rc < 0) { - /* ERR_MSG("error encountered while working on image file: " - "%s\n", a.img_path); */ - rc = -rc; - goto err; - } - - err: - free(a.vols); - if (free_a_odir != 0) - free(a.odir_path); - if (fpin != NULL) - fclose(fpin); - if (vols_len > 0) - free(vols); - return rc; -} diff --git a/ubi-utils/src/unubi_analyze.c b/ubi-utils/src/unubi_analyze.c deleted file mode 100644 index 3f3a480..0000000 --- a/ubi-utils/src/unubi_analyze.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Authors: Drake Dowsett, dowsett@de.ibm.com - * Contact: Andreas Arnez, arnez@de.ibm.com - * - * unubi uses the following functions to generate analysis output based on - * the header information in a raw-UBI image - */ - -/* - * TODO: use OOB data to check for eraseblock validity in NAND images - */ - -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "unubi_analyze.h" -#include "crc32.h" - -#define EC_X_INT 50 - -/** - * intcmp - function needed by qsort to order integers - **/ -int intcmp(const void *a, const void *b) -{ - int A = *(int *)a; - int B = *(int *)b; - return A - B; -} - -int longcmp(const void *a, const void *b) -{ - long long A = *(long long *)a; - long long B = *(long long *)b; - return A - B; -} - - -/** - * unubi_analyze_group_index - finds the normalized index in an array - * item: look for this item in the array - * array: array to search through - * size: length of the array - * array should be sorted for this algorithm to perform properly; - * if the item is not found returns -1, otherwise return value is the - * index in the array (note this contricts the array size to 2^32-1); - **/ -int -norm_index(uint32_t item, uint32_t *array, size_t length) -{ - size_t i, index; - - for (index = 0, i = 0; i < length; i++) { - if ((i != 0) && (array[i] != array[i - 1])) - index++; - - if (item == array[i]) - return index; - } - - return -1; -} - - -/** - * unubi_analyze_ec_hdr - generate data table and plot script - * first: head of simple linked list - * path: folder to write into - * generates a data file containing the eraseblock index in the image - * and the erase counter found in its ec header; - * if the crc check fails, the line is commented out in the data file; - * also generates a simple gnuplot sript for quickly viewing one - * display of the data file; - **/ -int -unubi_analyze_ec_hdr(struct eb_info *first, const char *path) -{ - char filename[PATH_MAX + 1]; - size_t count, eraseblocks; - uint32_t crc; - uint64_t *erase_counts; - FILE* fpdata; - FILE* fpplot; - struct eb_info *cur; - - if (first == NULL) - return -1; - - /* prepare output files */ - 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, PATH_MAX + 1); - snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_PLOT); - fpplot = fopen(filename, "w"); - if (fpplot == NULL) { - fclose(fpdata); - return -1; - } - - /* make executable */ - chmod(filename, 0755); - - /* first run: count elements */ - count = 0; - cur = first; - while (cur != NULL) { - cur = cur->next; - count++; - } - eraseblocks = count; - - erase_counts = malloc(eraseblocks * sizeof(*erase_counts)); - if (!erase_counts) { - perror("out of memory"); - exit(EXIT_FAILURE); - } - - memset(erase_counts, 0, eraseblocks * sizeof(*erase_counts)); - - /* second run: populate array to sort */ - count = 0; - cur = first; - while (cur != NULL) { - erase_counts[count] = __be64_to_cpu(cur->ec.ec); - cur = cur->next; - count++; - } - qsort(erase_counts, eraseblocks, sizeof(*erase_counts), - (void *)longcmp); - - /* third run: generate data file */ - count = 0; - cur = first; - fprintf(fpdata, "# eraseblock_no actual_erase_count " - "sorted_erase_count\n"); - while (cur != NULL) { - crc = crc32(UBI_CRC32_INIT, &cur->ec, UBI_EC_HDR_SIZE_CRC); - - if ((__be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) || - (crc != __be32_to_cpu(cur->ec.hdr_crc))) - fprintf(fpdata, "# "); - - fprintf(fpdata, "%u %llu %llu", count, - __be64_to_cpu(cur->ec.ec), - erase_counts[count]); - - if (__be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) - fprintf(fpdata, " ## bad magic: %08x", - __be32_to_cpu(cur->ec.magic)); - - if (crc != __be32_to_cpu(cur->ec.hdr_crc)) - fprintf(fpdata, " ## CRC mismatch: given=%08x, " - "calc=%08x", __be32_to_cpu(cur->ec.hdr_crc), - crc); - - fprintf(fpdata, "\n"); - - cur = cur->next; - count++; - } - fclose(fpdata); - - fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); - fprintf(fpplot, "set xlabel \"eraseblock\"\n"); - - /* fourth run: generate plot file xtics */ - count = 0; - cur = first; - fprintf(fpplot, "set xtics ("); - while (cur != NULL) { - if ((count % EC_X_INT) == 0) { - if (count > 0) - fprintf(fpplot, ", "); - fprintf(fpplot, "%d", count); - } - - cur = cur->next; - count++; - } - fprintf(fpplot, ")\n"); - - fprintf(fpplot, "set ylabel \"erase count\"\n"); - fprintf(fpplot, "set xrange [-1:%u]\n", eraseblocks + 1); - fprintf(fpplot, "# set yrange [-1:%llu]\n", - erase_counts[eraseblocks - 1] + 1); - fprintf(fpplot, "plot \"%s\" u 1:2 t \"unsorted: %s\" with boxes\n", - FN_EH_DATA, FN_EH_DATA); - fprintf(fpplot, "# replot \"%s\" u 1:3 t \"sorted: %s\" with lines\n", - FN_EH_DATA, FN_EH_DATA); - fprintf(fpplot, "pause -1 \"press ENTER\"\n"); - - fclose(fpplot); - - return 0; -} - - -/** - * unubi_analyze_vid_hdr - generate data table and plot script - * head: head of complex linked list (eb_chain) - * path: folder to write into - * generates a data file containing the volume id, logical number, leb version, - * and data size from the vid header; - * all eraseblocks listed in the eb_chain are valid (checked in unubi); - * also generates a simple gnuplot sript for quickly viewing one - * display of the data file; - **/ -int -unubi_analyze_vid_hdr(struct eb_info **head, const char *path) -{ - char filename[PATH_MAX + 1]; - int rc, y1, y2; - size_t count, step, breadth; - uint32_t *leb_versions, *data_sizes; - FILE* fpdata; - FILE* fpplot; - struct eb_info *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, 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, PATH_MAX + 1); - snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_PLOT); - fpplot = fopen(filename, "w"); - if (fpplot == NULL) { - rc = -1; - goto exit; - } - - /* make executable */ - chmod(filename, 0755); - - /* first run: count elements */ - count = 0; - cur = *head; - while (cur != NULL) { - cur = cur->next; - count++; - } - breadth = count; - - leb_versions = malloc(breadth * sizeof(uint32_t)); - if (leb_versions == NULL) { - rc = -1; - goto exit; - } - memset(leb_versions, 0, breadth * sizeof(uint32_t)); - - 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] = __be32_to_cpu(cur->vid.leb_ver); - data_sizes[count] = __be32_to_cpu(cur->vid.data_size); - cur = cur->next; - count++; - } - qsort(leb_versions, breadth, sizeof(*leb_versions), (void *)intcmp); - qsort(data_sizes, breadth, sizeof(*data_sizes), (void *)intcmp); - - /* third run: generate data file */ - count = 0; - cur = *head; - fprintf(fpdata, "# x_axis vol_id lnum y1_axis leb_ver " - "y2_axis data_size\n"); - while (cur != NULL) { - y1 = norm_index(__be32_to_cpu(cur->vid.leb_ver), leb_versions, - breadth); - y2 = norm_index(__be32_to_cpu(cur->vid.data_size), data_sizes, - breadth); - - if ((y1 == -1) || (y2 == -1)) { - rc = -1; - goto exit; - } - - fprintf(fpdata, "%u %u %u %u %u %u %u\n", - count, - __be32_to_cpu(cur->vid.vol_id), - __be32_to_cpu(cur->vid.lnum), - y1, - __be32_to_cpu(cur->vid.leb_ver), - y2, - __be32_to_cpu(cur->vid.data_size)); - cur = cur->next; - count++; - } - - fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); - fprintf(fpplot, "set xlabel \"volume\"\n"); - - /* fourth run: generate plot file xtics */ - count = 0; - step = 0; - cur = *head; - fprintf(fpplot, "set xtics ("); - while (cur != NULL) { - if (count > 0) - fprintf(fpplot, ", "); - if (step != __be32_to_cpu(cur->vid.vol_id)) { - step = __be32_to_cpu(cur->vid.vol_id); - fprintf(fpplot, "\"%d\" %d 0", step, count); - } - else - fprintf(fpplot, "\"%d\" %d 1", - __be32_to_cpu(cur->vid.lnum), count); - cur = cur->next; - count++; - } - fprintf(fpplot, ")\n"); - fprintf(fpplot, "set nox2tics\n"); - - /* fifth run: generate plot file ytics */ - count = 0; - cur = *head; - fprintf(fpplot, "set ylabel \"leb version\"\n"); - fprintf(fpplot, "set ytics ("); - while (cur->next != NULL) { - y1 = norm_index(__be32_to_cpu(cur->vid.leb_ver), leb_versions, - breadth); - - if (y1 == -1) { - rc = -1; - goto exit; - } - - if (count > 0) - fprintf(fpplot, ", "); - - fprintf(fpplot, "\"%u\" %u", __be32_to_cpu(cur->vid.leb_ver), - y1); - - cur = cur->next; - count++; - } - fprintf(fpplot, ")\n"); - - /* sixth run: generate plot file y2tics */ - count = 0; - cur = *head; - fprintf(fpplot, "set y2label \"data size\"\n"); - fprintf(fpplot, "set y2tics ("); - while (cur != NULL) { - y2 = norm_index(__be32_to_cpu(cur->vid.data_size), - data_sizes, breadth); - - if (y2 == -1) { - rc = -1; - goto exit; - } - - if (count > 0) - fprintf(fpplot, ", "); - - fprintf(fpplot, "\"%u\" %u", __be32_to_cpu(cur->vid.data_size), - y2); - - cur = cur->next; - count++; - } - fprintf(fpplot, ")\n"); - - y1 = norm_index(leb_versions[breadth - 1], leb_versions, breadth); - y2 = norm_index(data_sizes[breadth - 1], data_sizes, breadth); - fprintf(fpplot, "set xrange [-1:%u]\n", count + 1); - fprintf(fpplot, "set yrange [-1:%u]\n", y1 + 1); - fprintf(fpplot, "set y2range [-1:%u]\n", y2 + 1); - fprintf(fpplot, "plot \"%s\" u 1:4 t \"leb version: %s\" " - "axes x1y1 with lp\n", FN_VH_DATA, FN_VH_DATA); - fprintf(fpplot, "replot \"%s\" u 1:6 t \"data size: %s\" " - "axes x1y2 with lp\n", FN_VH_DATA, FN_VH_DATA); - fprintf(fpplot, "pause -1 \"press ENTER\"\n"); - - 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; -} - - -/** - * unubi_analyze - run all analyses - * head: eb_chain head - * first: simple linked list of eraseblock headers (use .next) - * path: directory (without trailing slash) to output to - * returns 0 upon successful completion, or -1 otherwise - **/ -int -unubi_analyze(struct eb_info **head, struct eb_info *first, const char *path) -{ - int ec_rc, vid_rc; - - if (path == NULL) - return -1; - - 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; -} diff --git a/ubi-utils/src/unubi_analyze.h b/ubi-utils/src/unubi_analyze.h deleted file mode 100644 index 8588219..0000000 --- a/ubi-utils/src/unubi_analyze.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 - * 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. - */ - -#ifndef __UNUBI_ANALYZE_H__ -#define __UNUBI_ANALYZE_H__ - -/* - * 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 <stdio.h> -#include <stdint.h> -#include <mtd/ubi-header.h> - -#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; - int phys_block; - - 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); - -#endif /* __UNUBI_ANALYZE_H__ */ |