]> www.infradead.org Git - mtd-utils.git/commitdiff
Revert ubi-tools changes
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Tue, 19 Feb 2008 12:54:17 +0000 (14:54 +0200)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Tue, 19 Feb 2008 14:41:16 +0000 (16:41 +0200)
Restore ubi tools to their "original" state, which means to
the state they were before I stareted cleaning them up.

Instead, create a "new-utils" subdirectory and move my work
there.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
121 files changed:
tests/fs-tests/stress/stress00.sh
tests/ubi-tests/Makefile
ubi-utils/Makefile
ubi-utils/README [new file with mode: 0644]
ubi-utils/UBI.TXT [moved from ubi-utils/old-tools/README with 71% similarity]
ubi-utils/doc/unubi.roff [new file with mode: 0644]
ubi-utils/inc/libubi.h [new file with mode: 0644]
ubi-utils/lib/Makefile.am [new file with mode: 0644]
ubi-utils/new-utils/LICENSE.libiniparser [moved from ubi-utils/LICENSE.libiniparser with 100% similarity]
ubi-utils/new-utils/Makefile [new file with mode: 0644]
ubi-utils/new-utils/README [new file with mode: 0644]
ubi-utils/new-utils/include/libiniparser.h [moved from ubi-utils/include/libiniparser.h with 100% similarity]
ubi-utils/new-utils/include/libubi.h [moved from ubi-utils/include/libubi.h with 100% similarity]
ubi-utils/new-utils/include/libubigen.h [moved from ubi-utils/include/libubigen.h with 100% similarity]
ubi-utils/new-utils/src/common.c [moved from ubi-utils/src/common.c with 100% similarity]
ubi-utils/new-utils/src/common.h [moved from ubi-utils/src/common.h with 100% similarity]
ubi-utils/new-utils/src/crc32.c [new file with mode: 0644]
ubi-utils/new-utils/src/crc32.h [new file with mode: 0644]
ubi-utils/new-utils/src/dictionary.c [moved from ubi-utils/src/dictionary.c with 100% similarity]
ubi-utils/new-utils/src/dictionary.h [moved from ubi-utils/src/dictionary.h with 100% similarity]
ubi-utils/new-utils/src/libiniparser.c [moved from ubi-utils/src/libiniparser.c with 100% similarity]
ubi-utils/new-utils/src/libubi.c [moved from ubi-utils/old-tools/src/libubi.c with 91% similarity]
ubi-utils/new-utils/src/libubi_int.h [moved from ubi-utils/old-tools/src/libubi_int.h with 89% similarity]
ubi-utils/new-utils/src/libubigen.c [new file with mode: 0644]
ubi-utils/new-utils/src/ubi-attach.c [moved from ubi-utils/src/ubiattach.c with 99% similarity]
ubi-utils/new-utils/src/ubi-crc32.c [new file with mode: 0644]
ubi-utils/new-utils/src/ubi-detach.c [moved from ubi-utils/src/ubidetach.c with 99% similarity]
ubi-utils/new-utils/src/ubi-info.c [moved from ubi-utils/src/ubinfo.c with 99% similarity]
ubi-utils/new-utils/src/ubi-mkvol.c [new file with mode: 0644]
ubi-utils/new-utils/src/ubi-nize.c [moved from ubi-utils/src/ubinize.c with 99% similarity]
ubi-utils/new-utils/src/ubi-rmvol.c [new file with mode: 0644]
ubi-utils/new-utils/src/ubi-update.c [moved from ubi-utils/src/ubiupdate.c with 98% similarity]
ubi-utils/old-tools/Makefile [deleted file]
ubi-utils/old-tools/inc/libubi.h [deleted file]
ubi-utils/old-tools/src/common.c [deleted file]
ubi-utils/old-tools/src/common.h [deleted file]
ubi-utils/old-tools/src/crc32.c [deleted file]
ubi-utils/old-tools/src/crc32.h [deleted file]
ubi-utils/old-tools/src/ecclayouts.h [deleted file]
ubi-utils/old-tools/src/libubigen.c [deleted file]
ubi-utils/old-tools/src/ubiupdate.c [deleted file]
ubi-utils/perl/f128_nand_sample.cfg [moved from ubi-utils/old-tools/scripts/f128_nand_sample.cfg with 92% similarity]
ubi-utils/perl/f64_nor_sample.cfg [moved from ubi-utils/old-tools/scripts/f64_nor_sample.cfg with 91% similarity]
ubi-utils/perl/mkpfi [moved from ubi-utils/old-tools/scripts/mkpfi with 100% similarity, mode: 0755]
ubi-utils/perl/ubicrc32.pl [moved from ubi-utils/old-tools/scripts/ubicrc32.pl with 99% similarity, mode: 0755]
ubi-utils/scripts/Makefile [moved from ubi-utils/old-tools/scripts/Makefile with 70% similarity]
ubi-utils/scripts/README [moved from ubi-utils/old-tools/scripts/README with 78% similarity]
ubi-utils/scripts/TODO [new file with mode: 0644]
ubi-utils/scripts/bin2nand2bin_test.sh [moved from ubi-utils/old-tools/scripts/bin2nand2bin_test.sh with 80% similarity]
ubi-utils/scripts/inject_biterror.pl [moved from ubi-utils/old-tools/scripts/inject_biterror.pl with 100% similarity]
ubi-utils/scripts/jffs2_test.sh [moved from ubi-utils/old-tools/scripts/jffs2_test.sh with 100% similarity]
ubi-utils/scripts/mkdevs.pl [moved from ubi-utils/old-tools/scripts/mkdevs.pl with 100% similarity]
ubi-utils/scripts/pdd.txt [moved from ubi-utils/old-tools/scripts/pdd.txt with 100% similarity]
ubi-utils/scripts/run_all.sh [moved from ubi-utils/old-tools/scripts/run_all.sh with 100% similarity]
ubi-utils/scripts/test.cfg [moved from ubi-utils/old-tools/scripts/test.cfg with 100% similarity]
ubi-utils/scripts/ubi_jffs2_test.sh [moved from tests/ubi-tests/ubi_jffs2_test.sh with 89% similarity]
ubi-utils/scripts/ubi_test.sh [moved from ubi-utils/old-tools/scripts/ubi_test.sh with 100% similarity]
ubi-utils/scripts/ubi_tools_test.sh [moved from ubi-utils/old-tools/scripts/ubi_tools_test.sh with 100% similarity]
ubi-utils/scripts/unubi_test.sh [moved from ubi-utils/old-tools/scripts/unubi_test.sh with 100% similarity]
ubi-utils/src/bin2nand.c [moved from ubi-utils/old-tools/src/bin2nand.c with 68% similarity]
ubi-utils/src/bootenv.c [moved from ubi-utils/old-tools/src/bootenv.c with 100% similarity]
ubi-utils/src/bootenv.h [moved from ubi-utils/old-tools/src/bootenv.h with 100% similarity]
ubi-utils/src/config.h [moved from ubi-utils/old-tools/src/config.h with 100% similarity]
ubi-utils/src/crc32.c
ubi-utils/src/crc32.h
ubi-utils/src/eb_chain.c [moved from ubi-utils/old-tools/src/eb_chain.c with 100% similarity]
ubi-utils/src/error.c [moved from ubi-utils/old-tools/src/error.c with 100% similarity]
ubi-utils/src/error.h [moved from ubi-utils/old-tools/src/error.h with 100% similarity]
ubi-utils/src/example_ubi.h [moved from ubi-utils/old-tools/src/example_ubi.h with 100% similarity]
ubi-utils/src/hashmap.c [moved from ubi-utils/old-tools/src/hashmap.c with 100% similarity]
ubi-utils/src/hashmap.h [moved from ubi-utils/old-tools/src/hashmap.h with 100% similarity]
ubi-utils/src/libpfiflash.c [moved from ubi-utils/old-tools/src/libpfiflash.c with 100% similarity]
ubi-utils/src/libubi.c
ubi-utils/src/libubi_int.h
ubi-utils/src/libubigen.c
ubi-utils/src/libubimirror.c [moved from ubi-utils/old-tools/src/libubimirror.c with 100% similarity]
ubi-utils/src/list.c [moved from ubi-utils/old-tools/src/list.c with 100% similarity]
ubi-utils/src/list.h [moved from ubi-utils/old-tools/src/list.h with 100% similarity]
ubi-utils/src/mkbootenv.c [moved from ubi-utils/old-tools/src/mkbootenv.c with 100% similarity]
ubi-utils/src/nand2bin.c [moved from ubi-utils/old-tools/src/nand2bin.c with 74% similarity]
ubi-utils/src/nandcorr.c [moved from ubi-utils/old-tools/src/nandcorr.c with 100% similarity]
ubi-utils/src/nandecc.c [moved from ubi-utils/old-tools/src/nandecc.c with 100% similarity]
ubi-utils/src/nandecc.h [moved from ubi-utils/old-tools/src/nandecc.h with 100% similarity]
ubi-utils/src/pddcustomize.c [moved from ubi-utils/old-tools/src/pddcustomize.c with 100% similarity]
ubi-utils/src/peb.c [moved from ubi-utils/old-tools/src/peb.c with 96% similarity]
ubi-utils/src/peb.h [moved from ubi-utils/old-tools/src/peb.h with 100% similarity]
ubi-utils/src/pfi.c [moved from ubi-utils/old-tools/src/pfi.c with 100% similarity]
ubi-utils/src/pfi.h [moved from ubi-utils/old-tools/src/pfi.h with 100% similarity]
ubi-utils/src/pfi2bin.c [moved from ubi-utils/old-tools/src/pfi2bin.c with 99% similarity]
ubi-utils/src/pfiflash.c [moved from ubi-utils/old-tools/src/pfiflash.c with 100% similarity]
ubi-utils/src/pfiflash.h [moved from ubi-utils/old-tools/src/pfiflash.h with 100% similarity]
ubi-utils/src/pfiflash_error.h [moved from ubi-utils/old-tools/src/pfiflash_error.h with 100% similarity]
ubi-utils/src/reader.c [moved from ubi-utils/old-tools/src/reader.c with 100% similarity]
ubi-utils/src/reader.h [moved from ubi-utils/old-tools/src/reader.h with 100% similarity]
ubi-utils/src/ubicrc32.c
ubi-utils/src/ubigen.c [moved from ubi-utils/old-tools/src/ubigen.c with 100% similarity]
ubi-utils/src/ubigen.h [moved from ubi-utils/old-tools/src/ubigen.h with 99% similarity]
ubi-utils/src/ubimirror.c [moved from ubi-utils/old-tools/src/ubimirror.c with 100% similarity]
ubi-utils/src/ubimirror.h [moved from ubi-utils/old-tools/src/ubimirror.h with 100% similarity]
ubi-utils/src/ubimkvol.c
ubi-utils/src/ubirmvol.c
ubi-utils/src/ubiupdatevol.c [moved from tests/ubi-tests/helpers/ubiupdatevol.c with 98% similarity]
ubi-utils/src/unubi.c [moved from ubi-utils/old-tools/src/unubi.c with 100% similarity]
ubi-utils/src/unubi_analyze.c [moved from ubi-utils/old-tools/src/unubi_analyze.c with 100% similarity]
ubi-utils/src/unubi_analyze.h [moved from ubi-utils/old-tools/src/unubi_analyze.h with 100% similarity]
ubi-utils/testcases.txt [new file with mode: 0644]
ubi-utils/tests/Makefile [new file with mode: 0644]
ubi-utils/tests/README.udev [new file with mode: 0644]
ubi-utils/tests/common.c [new file with mode: 0644]
ubi-utils/tests/common.h [new file with mode: 0644]
ubi-utils/tests/integ.c [new file with mode: 0644]
ubi-utils/tests/io_basic.c [new file with mode: 0644]
ubi-utils/tests/io_paral.c [new file with mode: 0644]
ubi-utils/tests/io_read.c [new file with mode: 0644]
ubi-utils/tests/io_update.c [new file with mode: 0644]
ubi-utils/tests/mkvol_bad.c [new file with mode: 0644]
ubi-utils/tests/mkvol_basic.c [new file with mode: 0644]
ubi-utils/tests/mkvol_paral.c [new file with mode: 0644]
ubi-utils/tests/rsvol.c [new file with mode: 0644]
ubi-utils/tests/runtests.pl [new file with mode: 0755]
ubi-utils/tests/runtests.sh [new file with mode: 0755]

index be95d7c13a90afddb59c99c4a59270e994b45426..60f8c0dbf3fb77acc1448ed55c564feaf33ee034 100755 (executable)
@@ -43,8 +43,7 @@ FSIZE=$(( $FREESPACE/15 ));
 "$FWRITE00 -z $FSIZE -n0 -p 100 -s -o" \
 "$RNDWR -z $FSIZE -n0 -p 10 -e" \
 "$RNDWR -z $FSIZE -n0 -p 100 -e" \
-"$PDFLUSH -z 1073741824 -n0" \
-"$GCHUP -n0"
+"$PDFLUSH -z 1073741824 -n0"
 
 STATUS=$?
 
index 0566ebc5fdc4b66098d77a982ab430e93f1b662e..b02dca4024a3352efee0f3eefc8ab5d60cd4bb09 100644 (file)
@@ -1,8 +1,8 @@
-LIBUBI_PATH=../../ubi-utils/
-LIBUBI_SRC_PATH=../../ubi-utils/src
-LIBUBI_HEADER_PATH=../../ubi-utils/include
+LIBUBI_PATH=../../ubi-utils/new-utils/
+LIBUBI_SRC_PATH=../../ubi-utils/new-utils/src/
+LIBUBI_HEADER_PATH=../../ubi-utils/new-utils/include
 UBI_HEADERS_PATH=../../include/
-UBIUTILS_PATH=../../ubi-utils/
+UBIUTILS_PATH=../../ubi-utils/new-utils/
 
 CC := $(CROSS)gcc
 
index 8d4412daaf49c4f7d882626bcfc97288cc055dc5..7c573e0d682b622da22be0c69e0014d9153f444f 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for ubi-utils
 #
 
-OPTFLAGS := -O2 -Wall
+OPTFLAGS := -O2 -g -Wall
 KERNELHDR := ../include
 DESTDIR := /usr/local
 SBINDIR=/usr/sbin
@@ -10,53 +10,82 @@ MANDIR=/usr/man
 INCLUDEDIR=/usr/include
 
 CC := $(CROSS)gcc
-CFLAGS := -Iinclude -Isrc -I$(KERNELHDR) $(OPTFLAGS) -Werror -Wall
+CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror \
+       -Wwrite-strings -W -std=gnu99 -DPACKAGE_VERSION=\"1.0\"
 
-LIBS = libubi libubigen libiniparser
-UTILS = ubiupdate ubimkvol ubirmvol ubicrc32 ubinfo ubiattach ubidetach ubinize
+PERLPROGS = mkpfi ubicrc32.pl
+TARGETS = ubiupdatevol ubimkvol ubirmvol pfiflash pddcustomize ubimirror \
+       bin2nand nand2bin ubigen mkbootenv unubi pfi2bin ubicrc32
 
-vpath %.c src
+vpath   %.c ./src
 
-all: $(UTILS)
+%: %.o
+       $(CC) $(LDFLAGS) -g -o $@ $^
 
-# The below cancels existing implicite rule to make programs from .c files,
-# in order to force make using our rule defined below
-%: %.c
-
-# The below is the rule to get an .o file from a .c file
 %.o: %.c
-       $(CC) $(CFLAGS) $< -c -o $@
+       $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,.$(shell basename $<).dep
 
-# 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 $@
+all: $(TARGETS)
+       make -C new-utils
 
-ubicrc32: ubicrc32.o crc32.o
-       $(CC) $(CFLAGS) -o $@ $^
+IGNORE=${wildcard .*.c.dep}
+-include ${IGNORE}
 
-ubinize: ubinize.o common.o crc32.o libiniparser libubigen
-       $(CC) $(CFLAGS) $(filter %.o, $^) -L. -liniparser -lubigen -o $@
+clean:
+       rm -rf *.o $(TARGETS) .*.c.dep
+       make -C new-utils clean
 
-libubi: libubi.o
-       $(AR) crv $@.a $^
-       ranlib $@.a
+ubiupdatevol: ubiupdatevol.o error.o libubi.o
+       $(CC) $(LDFLAGS) -o $@ $^
 
-libubigen: libubigen.o
-       $(AR) crv $@.a $^
-       ranlib $@.a
+ubimkvol: ubimkvol.o error.o libubi.o
+       $(CC) $(LDFLAGS) -o $@ $^
 
-libiniparser: libiniparser.o dictionary.o
-       $(AR) crv $@.a $^
-       ranlib $@.a
+ubirmvol: ubirmvol.o error.o libubi.o
+       $(CC) $(LDFLAGS) -o $@ $^
 
-clean:
-       rm -rf *.o $(addsuffix .a, $(LIBS)) $(UTILS) .*.c.dep
+pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \
+               libubi.o crc32.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \
+               bootenv.o hashmap.o pfi.o libubi.o crc32.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \
+               libubi.o crc32.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+nand2bin: nand2bin.o nandecc.o nandcorr.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+bin2nand: bin2nand.o error.o nandecc.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+ubigen: ubigen.o libubigen.o crc32.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+unubi: unubi.o crc32.o unubi_analyze.o eb_chain.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+pfi2bin: pfi2bin.o peb.o error.o list.o crc32.o libubigen.o bootenv.o \
+               hashmap.o reader.o pfi.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+ubicrc32: ubicrc32.o crc32.o
+       $(CC) $(LDFLAGS) -o $@ $^
 
-install: ${UTILS}
+install: ${TARGETS}
        mkdir -p ${DESTDIR}/${SBINDIR}
-       install -m0755 ${UTILS} ${DESTDIR}/${SBINDIR}/
+       install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
+       (cd perl && install ${PERLPROGS} ${DESTDIR}/${SBINDIR}/)
+       make -C new-utils install
 
 uninstall:
-       for file in ${UTILS}; do \
+       for file in ${TARGETS} ${PERLPROGS}; do \
                $(RM) ${DESTDIR}/${SBINDIR}/$$file; \
        done
+       make -C new-utils uninstall
diff --git a/ubi-utils/README b/ubi-utils/README
new file mode 100644 (file)
index 0000000..d976a76
--- /dev/null
@@ -0,0 +1,236 @@
+README
+======
+
+The programs and libraries in this directory provide a tool-chain to
+generate binary data for embedded systems which can be flashed either
+by a hardware flash programmer, e.g. JTAG debugger, or on the target
+system directly using pfiflash, or ubimkvol, ubirmvol, ubiwritevol.
+
+The latter is the case when there is already Linux running which has
+build in UBI support.
+
+Authors: Oliver Lohmann
+         Frank Haverkamp
+        Andreas Arnez
+
+mkpfi           - tool for flash content generation in PFI
+                  format
+pfi2bin         - conversion tool to transfer a PFI file into a
+                  binary image
+pfiflash        - tool to update the embedded systems flash using
+                  pfi files created by mkpfi
+libbootenv      - library for boot-parameter processing
+libpfi          - library for partial flash image (PFI) creation
+                  and handling
+ubigen          - tool to create binary UBI images e.g. for a
+                  jtag flashing tool
+nandimg         - tool to add OOB data to binary images intended
+                  for NAND flash systems
+ubilib          - UBI library
+
+!!! NOTICE !!!
+If you execute ./configure in the top_level directory the helper Makefile
+gets overwritten. Thats actually no problem, but be aware of that.
+
+1. Build Process
+
+1.1 Build, install and forget
+    o Build all and everything
+      $make all (takes a while, builds ppc and x86 binaries/libs)
+    o Installation:
+      $make install
+    o Uninstallation:
+      $make uninstall
+
+    o x86 only would be:
+      $make x86 && make install_x86
+    
+1.2 Usage for a developer
+
+    1.2.1 The build process in detail
+
+    o If you've checked out the sources from the CVS repository you'll find a
+      directory setup like this:
+
+       flashutils/
+       -rw-r--r--  1 olli olli 1.3K Mar 14 11:53 Makefile
+       -rw-r--r--  1 olli olli 1.9K Mar 14 10:50 Makefile.am
+       -rwxr-xr-x  1 olli olli  265 Mar  9 00:47 bootstrap
+       -rw-r--r--  1 olli olli 1.1K Mar  9 16:55 configure.ac
+       drwxr-xr-x  2 olli olli 4.0K Mar  9 00:28 doc
+       drwxr-xr-x  2 olli olli 4.0K Mar 14 11:56 inc
+       drwxr-xr-x  2 olli olli 4.0K Mar 14 11:56 lib
+       drwxr-xr-x 17 olli olli 4.0K Mar 13 16:50 src
+
+    o To generate the initial build templates you have to  call the bootstrap
+      script:
+      $ ./bootstrap
+    o Create a directory for the target platform 
+      $ mkdir build_x86
+    o Descend into the directory and call the top-level configure script
+      with the desired options.
+      $ cd build_x86
+      $ ../configure --prefix=/usr/local [...]
+    o Now you'll find a directory structure like this:
+      
+       flashutils/build_x86/
+       -rw-r--r-- 1 olli olli  47K Mar 14 13:33 Makefile
+       -rw-r--r-- 1 olli olli  33K Mar 14 13:33 config.log
+       -rwxr-xr-x 1 olli olli  38K Mar 14 13:33 config.status
+       drwxr-xr-x 2 olli olli 4.0K Mar 14 13:33 inc
+       drwxr-xr-x 3 olli olli 4.0K Mar 14 13:33 lib
+       -rwxr-xr-x 1 olli olli 202K Mar 14 13:33 libtool
+
+    o The config.guess script can be used to update the Makefiles in the
+      target directory after a change of the top-level template files 
+      (i.e. the Makefile.in files).
+      $ ./config.guess
+    o To compile everything for this platform just invoke make in
+      flashutils/build_x86:
+      $ make
+      or from toplevel:
+      $ make -C ./build_x86
+    o The build process creates a new directory "bin":
+       flashutils/build_x86/
+       [...]
+       drwxr-xr-x 3 olli olli 4.0K Mar 14 13:41 bin
+       [...]
+
+      This directory contains all binary files which will be installed
+      by make install, e.g.:
+
+       flashutils/build_x86/bin/
+       -rwxr-xr-x 1 olli olli 7.2K Mar 14 13:41 bin2nand
+       -rwxr-xr-x 1 olli olli  15K Mar 14 13:41 mkbootenv
+       -rwxr-xr-x 1 olli olli  16K Mar 14 13:41 pddcustomize
+       -rwxr-xr-x 1 olli olli  36K Mar 14 13:41 pfi2bin
+       -rwxr-xr-x 1 olli olli 6.8K Mar 14 13:41 pfiflash
+       -rwxr-xr-x 1 olli olli 5.0K Mar 14 13:41 ubicrc32
+       -rwxr-xr-x 1 olli olli  13K Mar 14 13:41 ubigen
+       -rwxr-xr-x 1 olli olli 6.3K Mar 14 13:41 ubimirror
+
+
+    1.2.2 Modifying and Adding Sources
+
+    o There is a dedicated directory which contains all source code
+      of the flashutils package, e.g.:
+
+       flashutils/src/
+       drwxr-xr-x 2 olli olli 4.0K Mar 13 11:42 libbootenv
+       drwxr-xr-x 2 olli olli 4.0K Mar 13 11:42 liberror
+       drwxr-xr-x 2 olli olli 4.0K Mar 13 16:48 mkpfi
+       drwxr-xr-x 2 olli olli 4.0K Mar 13 16:12 pddcustomize
+
+      
+      
+      The prefix "lib" is used to mark directories as part of a convenience
+      library. Binaries have no special prefix.
+
+    o How to add sources?
+      
+      Just create a new directory at flashutils/src/, e.g.:
+
+      For a binary:
+      $ mkdir rider
+      $ cd rider
+      $ vi rider.c
+      /* do sth with that file... */
+
+      For a convenience library (as well as for "normal libs")
+      $ mkdir libworld
+      $ cd libworld
+      $ vi world.c
+      /* do sth with that file... */
+
+    o How to register sources in the build process (for binaries)?
+
+      You have to register your sources at the top-level automake Makefile:
+
+      In directory flashutils/
+      $ vi Makefile.am
+
+      Binaries have to be registered at "bin_PROGRAMS", e.g.:
+       bin_PROGRAMS    = bin/pddcustomize \
+                         bin/rider
+
+      Add the rule how the binary is assembled, e.g.:
+       bin_pddcustomize_SOURCES = \
+               $(top_srcdir)/src/pddcustomize/pddcustomize.c 
+       bin_pddcustomize_LDADD   = \
+               $(top_builddir)/lib/libbootenv.la \
+               $(top_builddir)/lib/liberror.la 
+
+       bin_rider_SOURCES = \
+               $(top_srcdir)/src/rider/rider.c
+
+      This example reflects a simple build process for "rider". "rider"
+      is built without any other dependencies or convenience libraries.
+      The example for pddcustomize is a bit more complicated.
+      "_LDADD" adds some convenience libraris into the link process of 
+      "pddcustomize". Imagine, that your "rider" has common code 
+      with "dragon_bin" which is held in a library called "libworld".
+      The build rules would like like the following:
+
+       bin_rider_SOURCES = \
+               $(top_srcdir)/src/rider/rider.c
+       bin_rider_LDADD   = \
+               $(top_builddir)/lib/libworld.la 
+
+       bin_dragon_SOURCES = \
+               $(top_srcdir)/src/dragon_bin/dragon_bin.c
+       bin_dragon_LDADD   = \
+               $(top_builddir)/lib/libworld.la 
+
+      Don't forget to add "dragon" to "bin_PROGRAMS"!
+      Don't forget to set the build rule for the "libworld" itself!
+      This is documented in the next section.
+       
+
+    o How to register sources in the build process (for libraries)?
+
+      Until now we didn't care about the build process of "libworld".
+      Libraries are handled special in this build process because
+      they are handled as "modules", i.e. they are able to be built
+      without building the binaries in the same step. Additionally,
+      it is possible to assemble complex libraries out of simple ones.
+      That especially makes sense if you want to export (install) a 
+      library on a system which uses some common code and makes
+      some adoptions for usability and presents a comfortable interface to
+      the user (see libpfiflash in the sources for an example).
+
+    o Registering "libworld" as convenience library.
+
+      Instead of editing the "Makefile.am" in "flashtools/", we have to 
+      edit now the "Makefile.am" in "flashtools/lib/":
+
+       noinst_LTLIBRARIES      = libworld.la 
+
+       libworld_la_SOURCES     = $(top_srcdir)/src/libworld/world.c
+
+    o Registering "libworld" as library which gets installed.
+      
+       lib_LTLIBRARIES         = libworld.la 
+       libworld_la_SOURCES     = $(top_srcdir)/src/libworld/world.c
+       libworld_la_LDFLAGS     = -no-undefined -version-info 0:0:0
+
+    o Header files
+      
+      All header files are stored at "flashutils/inc", regardless
+      if convenience library or not. 
+
+      If you want to export headers you have to specify this in the Makefile.am
+      located at "flashutils/inc", e.g. (this should not be done 
+      for convenience libraries):
+
+         nobase_include_HEADERS = world.h
+
+
+Appendix
+
+A.1. FAQ
+
+   Q How to call configure to setup a cross-platform build?
+   A $ ./configure --build=i686-pc-linux-gnu --host=ppc-linux \
+       --prefix=/opt/.../ppcnf/crossroot/ \
+       --exec-prefix=/opt/..../ppcnf/crossroot/usr
similarity index 71%
rename from ubi-utils/old-tools/README
rename to ubi-utils/UBI.TXT
index 39ed0e961af6969a88840b9c8c4a6071686e9977..9a1c3c78c771436ae94fc996e7a2705b23acbefe 100644 (file)
@@ -1,50 +1,3 @@
-This directory contains old UBI tools which I cannot maintain
-because they are too messy and vague for me and the original authors
-do not seem to have much time for them. Some of the utilities are
-just not of general interest because they are oriented to specific
-tasks of the guys from IBM.
-
-But the "unubi" utility must be very useful but it fails when I
-try to feed an image to it, so it should be looked at and fixed,
-then moved to the main "main" place.
-
-Artem Bityutskiy
-
-README
-======
-
-The programs and libraries in this directory provide a tool-chain to
-generate binary data for embedded systems which can be flashed either
-by a hardware flash programmer, e.g. JTAG debugger, or on the target
-system directly using pfiflash, or ubimkvol, ubirmvol, ubiupdatevol.
-
-The latter is the case when there is already Linux running which has
-build in UBI support.
-
-Authors: Oliver Lohmann
-         Frank Haverkamp
-        Andreas Arnez
-        Artem Bityutskiy
-
-mkpfi           - tool for flash content generation in PFI
-                  format
-pfi2bin         - conversion tool to transfer a PFI file into a
-                  binary image
-pfiflash        - tool to update the embedded systems flash using
-                  pfi files created by mkpfi
-libbootenv      - library for boot-parameter processing
-libpfi          - library for partial flash image (PFI) creation
-                  and handling
-ubigen          - tool to create binary UBI images e.g. for a
-                  jtag flashing tool
-nandimg         - tool to add OOB data to binary images intended
-                  for NAND flash systems
-ubilib          - UBI library
-
-
-The following text is from original UBI announcement
-====================================================
-
 UBI - Unsorted Block Images
 
 UBI (Latin: "where?") manages multiple logical volumes on a single
@@ -57,7 +10,7 @@ In a sense, UBI may be compared to the Logical Volume Manager
 numbers, UBI maps logical eraseblocks to physical eraseblocks.
 
 More information may be found in the UBI design documentation:
-ubidesign.pdf. Which can be found here:
+ubidesign.pdf. Which can be found here: 
 http://www.linux-mtd.infradead.org/doc/ubi.html
 
 Partitioning/Re-partitioning
@@ -131,7 +84,7 @@ UBI volumes vs. static partitions
 Where can it be found?
 
   Documentation, kernel code and applications can be found in the MTD
-  gits.
+  gits. 
 
 What are the applications for?
 
diff --git a/ubi-utils/doc/unubi.roff b/ubi-utils/doc/unubi.roff
new file mode 100644 (file)
index 0000000..6cebc46
--- /dev/null
@@ -0,0 +1,123 @@
+.TH UNUBI 1 "NOVEMBER 2006" FSP "FSP Flashutils"
+.SH NAME
+unubi \- extract volumes/eraseblocks from a raw\-UBI image
+.SH SYNOPSIS
+\fBunubi [\-aevEV] [\-d \fIout\-dir\fB] [\-r \fIvolume\-id\fB]
+[\-b \fIblock\-size\fB] \fIimage\-file
+.SH DESCRIPTION
+.PP
+\fBunubi\fR reads an image file containing blocks of UBI headers and data
+(such as produced from \fBnand2bin\fR) and rebuilds the volumes within.
+The default operation (when no flags are given) is to rebuild all valid
+volumes found in the image. \fBunubi\fR can also read straight from the
+onboard MTD device (ex. /dev/mtdblock/NAND).
+.SH OPTIONS
+.IP "\-a, \-\-analyze"
+When flagged, analysis files are generated within the output directory. These
+may include tables and or graphs detailing statistics gathered from the
+eraseblock data. Files are prefixed `analysis_'.
+
+See \fBANALYSIS\fR.
+.IP "\-b, \-\-blocksize \fIblock\-size\fR"
+Specify in bytes the \fIimage\-file\fR eraseblock size. Sizes may be
+postfixed with `KiB' or `MiB' to indicate mebibytes or kibibytes
+respectively. Default is 128KiB.
+.IP "\-d, \-\-dir \fIoutput\-dir\fR"
+Specify the output directory. If no directory is specified, the default
+is `unubi_\fIimage\-file\fR' within the curent working directory. If the
+attempt to create the output directory fails,
+.B unubi
+will try to create it in /tmp before aborting.
+.IP "\-e, \-\-eb\-split"
+When flagged, images are created for each eraseblock in \fIimage\-file\fR
+regardless of its validity. Each image is the complete eraseblock, including
+headers and any space to the end of the eraseblock after where the data may
+end.
+
+Invalid images are named `ebEEEE', where EEEE is the physical index of the
+eraseblock in the image. Valid images are named `ebEEEE_VVV_NNN_RRR' where
+VVV is the known volume ID, NNN is the logical number and RRR is the version
+of the eraseblock data. Note that the version number is in hexadecimal.
+
+Invalid images may also contain this postfix, if the data in the header
+could be valid (ie. the header contains a resonable volume ID, but the
+header and/or data CRCs are not valid). If this is the case, images are named
+`ebEEEE_VVV_NNN_RRR.reason', so as to distinguish known values from
+non\-definite ones.
+
+See \fBREASON SUFFIXES\fR.
+.IP "\-r, \-\-rebuild \fIvolume\-id\fR"
+Specify a volume to rebuild. Can be used successively to specify
+several volumes to be rebuilt.
+
+Images are named `volumeVVV' where VVV is the volume ID. For each missing
+eraseblock, an error message will be printed.
+.IP "\-v, \-\-vol\-split"
+When flagged, images are created for each valid eraseblock in
+\fIimage\-file\fR. Since a vaild eraseblock will have a defined data start and
+data length, only this range will make up the image.
+
+Images are named `volVVV_NNN_RRR_EEEE', where, for the data in the eraseblock,
+VVV is the volume ID, NNN is the logical number, RRR is the version and EEEE
+is the phyisical index of the eraseblock in the image.
+.IP "\-V, \-\-vol\-split!"
+Same as above, only all images are the complete eraseblock (including headers,
+and raw data, even past the point where the data is supposed to end).
+Overrides \-v when both \-v and \-V are flagged.
+.SH ANALYSIS
+The following files will be generated during the analysis:
+.IP "analysis_ec_hdr.data"
+A space delimited table with these two columns for each eraseblock: the
+eraseblock's index or physical position in the image, and the eraseblock's
+erase count. The third column contains the erase count data sorted.
+.IP "analysis_vid_hdr.data"
+A space delimited table with these four colums for each eraseblock: the
+volume ID, the volume logical number, the leb version, and the data size.
+In addition there are a normalized column representing the volume ID and
+volume logical number, a normalized column representing the leb version, and
+a normalized column representing the data_size. These normalized columns are
+used to better draw the the gnuplot image.
+.IP "analysis_ec_hdr.plot"
+A gnuplot script for quickly viewing a sample output from the respective .data
+file.
+.IP "analysis_vid_hdr.plot"
+A gnuplot script for quickly viewing a sample output from the respective .data
+file.
+.SH REASONS SUFFIXES
+When \-\-eb\-split produces possibly invalid, though usable, eraseblocks, the
+known reason suffixes are:
+.IP ".ec_magic"
+The erase counter header did not contain a valid magic field.
+.IP ".ec_hdr_crc"
+The erase counter header did not contain a vaild header CRC field.
+.IP ".vid_magic"
+The volume ID header did not contain a valid magic field.
+.IP ".vid_hdr_crc"
+The volume ID header did not contain a valid header CRC field.
+.IP ".data_crc"
+The volume ID header did not contain a valid data CRC field.
+.SH EXAMPLES
+To extract and rebuild all valid volumes from demo.img (note the output
+directory will be /home/user/unubi_demo.img):
+.sp 1
+.RS
+.B /home/user# unubi demo.img
+.sp 1
+.RE
+To analyze demo.img as well as extract and rebuild volume 7:
+.sp 1
+.RS
+.B /home/user# unubi \-a \-r 7 demo.img
+.sp 1
+.RE
+To split demo.img into raw images for each eraseblock into the folder
+/var/eraseblocks:
+.sp 1
+.RS
+.B /home/user# unubi \-e \-d /var/eraseblocks demo.img
+.SH AUTHORS
+Frank Haverkamp <haver@vnet.ibm.com>
+.sp 0
+Drake Dowsett <dowsett@de.ibm.com>
+.SH CONTACT
+Andreas Arnez <arnez@de.ibm.com>
diff --git a/ubi-utils/inc/libubi.h b/ubi-utils/inc/libubi.h
new file mode 100644 (file)
index 0000000..d39c1b9
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#ifndef __LIBUBI_H__
+#define __LIBUBI_H__
+
+#include <stdint.h>
+#include <mtd/ubi-user.h>
+#include <ctype.h>
+#include <mtd/ubi-header.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* UBI version libubi is made for */
+#define LIBUBI_UBI_VERSION 1
+
+/* UBI library descriptor */
+typedef void * libubi_t;
+
+/**
+ * struct ubi_mkvol_request - volume creation request.
+ * */
+struct ubi_mkvol_request
+{
+       int vol_id;
+       int alignment;
+       long long bytes;
+       int vol_type;
+       const char *name;
+};
+
+/**
+ * struct ubi_info - general UBI information.
+ *
+ * @dev_count        count of UBI devices in system
+ * @lowest_dev_num   lowest UBI device number
+ * @highest_dev_num  highest UBI device number
+ * @version          UBI version
+ */
+struct ubi_info
+{
+       int dev_count;
+       int lowest_dev_num;
+       int highest_dev_num;
+       int version;
+};
+
+/**
+ * struct ubi_dev_info - UBI device information.
+ *
+ * @vol_count        count of volumes on this UBI device
+ * @lowest_vol_num   lowest volume number
+ * @highest_vol_num  highest volume number
+ * @total_ebs        total number of eraseblocks on this UBI device
+ * @avail_ebs        how many eraseblocks are not used and available for new
+ *                   volumes
+ * @total_bytes      @total_ebs * @eb_size
+ * @avail_bytes      @avail_ebs * @eb_size
+ * @bad_count        count of bad eraseblocks
+ * @eb_size          size of UBI eraseblock
+ * @max_ec           current highest erase counter value
+ * @bad_rsvd         how many physical eraseblocks of the underlying flash
+ *                   device are reserved for bad eraseblocks handling
+ * @max_vol_count    maximum count of volumes on this UBI device
+ * @min_io_size      minimum input/output size of the UBI device
+ */
+struct ubi_dev_info
+{
+       int dev_num;
+       int vol_count;
+       int lowest_vol_num;
+       int highest_vol_num;
+       int total_ebs;
+       int avail_ebs;
+       long long total_bytes;
+       long long avail_bytes;
+       int bad_count;
+       int eb_size;
+       long long max_ec;
+       int bad_rsvd;
+       int max_vol_count;
+       int min_io_size;
+};
+
+/**
+ * struct ubi_vol_info - UBI volume information.
+ *
+ * @dev_num      UBI device number the volume resides on
+ * @vol_id       ID of this volume
+ * @type         volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @alignment    alignemnt of this volume
+ * @data_bytes   how many data bytes are stored on this volume (equivalent to
+ *               @rsvd_bytes for dynamic volumes)
+ * @rsvd_bytes   how many bytes are reserved for this volume
+ * @rsvd_ebs     how many eraseblocks are reserved for this volume
+ * @eb_size      logical eraseblock size of this volume (may be less then
+ *               device's logical eraseblock size due to alignment)
+ * @corrupted    the volume is corrupted if this flag is not zero
+ * @name         volume name (null-terminated)
+ */
+struct ubi_vol_info
+{
+       int dev_num;
+       int vol_id;
+       int type;
+       int alignment;
+       long long data_bytes;
+       long long rsvd_bytes;
+       int rsvd_ebs;
+       int eb_size;
+       int corrupted;
+       char name[UBI_VOL_NAME_MAX + 1];
+};
+
+/**
+ * libubi_open - open UBI library.
+ *
+ * This function initializes and opens the UBI library and returns UBI library
+ * descriptor in case of success and %NULL in case of failure.
+ */
+libubi_t libubi_open(void);
+
+/**
+ * libubi_close - close UBI library
+ *
+ * @desc UBI library descriptor
+ */
+void libubi_close(libubi_t desc);
+
+/**
+ * ubi_get_info - get general UBI information.
+ *
+ * @info  pointer to the &struct ubi_info object to fill
+ * @desc  UBI library descriptor
+ *
+ * This function fills the passed @info object with general UBI information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_info(libubi_t desc, struct ubi_info *info);
+
+/**
+ * ubi_mkvol - create an UBI volume.
+ *
+ * @desc  UBI library descriptor
+ * @node  name of the UBI character device to create a volume at
+ * @req   UBI volume creation request (defined at <mtd/ubi-user.h>)
+ *
+ * This function creates a UBI volume as described at @req and returns %0 in
+ * case of success and %-1 in case of failure. The assigned volume ID is
+ * returned in @req->vol_id.
+ */
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req);
+
+/**
+ * ubi_rmvol - remove a UBI volume.
+ *
+ * @desc    UBI library descriptor
+ * @node    name of the UBI character device to remove a volume from
+ * @vol_id  ID of the volume to remove
+ *
+ * This function removes volume @vol_id from UBI device @node and returns %0 in
+ * case of success and %-1 in case of failure.
+ */
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id);
+
+/**
+ * ubi_rsvol - re-size UBI volume.
+ *
+ * @desc   UBI library descriptor
+ * @node   name of the UBI character device owning the volume which should be
+ *         re-sized
+ * @vol_id volume ID to re-size
+ * @bytes  new volume size in bytes
+ *
+ * This function returns %0 in case of success and %-1 in case of error.
+ */
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes);
+
+/**
+ * ubi_get_dev_info - get UBI device information.
+ *
+ * @desc  UBI library descriptor
+ * @node  name of the UBI character device to fetch information about
+ * @info  pointer to the &struct ubi_dev_info object to fill
+ *
+ * This function fills the passed @info object with UBI device information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_dev_info(libubi_t desc, const char *node,
+                    struct ubi_dev_info *info);
+
+/**
+ * ubi_get_dev_info1 - get UBI device information.
+ *
+ * @desc     UBI library descriptor
+ * @dev_num  UBI device number to fetch information about
+ * @info     pointer to the &struct ubi_dev_info object to fill
+ *
+ * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI
+ * device number, not UBI character device.
+ */
+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info);
+
+/**
+ * ubi_get_vol_info - get UBI volume information.
+ *
+ * @desc     UBI library descriptor
+ * @node     name of the UBI volume character device to fetch information about
+ * @info     pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function fills the passed @info object with UBI volume information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_vol_info(libubi_t desc, const char *node,
+                    struct ubi_vol_info *info);
+
+/**
+ * ubi_get_vol_info1 - get UBI volume information.
+ *
+ * @desc     UBI library descriptor
+ * @dev_num  UBI device number
+ * @vol_id   ID of the UBI volume to fetch information about
+ * @info     pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI
+ * volume number, not UBI volume character device.
+ */
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+                     struct ubi_vol_info *info);
+
+/**
+ * ubi_update_start - start UBI volume update.
+ *
+ * @desc   UBI library descriptor
+ * @fd     volume character devie file descriptor
+ * @bytes  how many bytes will be written to the volume
+ *
+ * This function initiates UBI volume update and returns %0 in case of success
+ * and %-1 in case of error.
+ */
+int ubi_update_start(libubi_t desc, int fd, long long bytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_H__ */
diff --git a/ubi-utils/lib/Makefile.am b/ubi-utils/lib/Makefile.am
new file mode 100644 (file)
index 0000000..1b0dc01
--- /dev/null
@@ -0,0 +1,58 @@
+AUTOMAKE_OPTIONS = foreign
+INCLUDES=-I$(top_srcdir)/inc -I$(top_srcdir)/../../kernel/include
+
+# -----------------------------------------------------------------------------
+# all export libs which shall be generated
+lib_LTLIBRARIES                = libubi.la \
+                         libpfiflash.la
+
+# -----------------------------------------------------------------------------
+# all convinence libs which shall be generated
+noinst_LTLIBRARIES     = libcrc32.la \
+                         libubigen.la \
+                         liberror.la \
+                         liblist.la \
+                         libbootenv.la \
+                         libpfi.la \
+                         libpeb.la \
+                         libreader.la \
+                         libubimirror.la
+
+# -----------------------------------------------------------------------------
+# exported libs
+libpfiflash_la_SOURCES = $(top_srcdir)/src/libpfiflash/pfiflash.c
+libpfiflash_la_LDFLAGS  = -no-undefined -version-info 1:0:0
+libpfiflash_la_LIBADD  = libreader.la \
+                         libubimirror.la \
+                         libubi.la
+
+libubi_la_SOURCES      = $(top_srcdir)/src/libubi/libubi.c \
+                         $(top_srcdir)/src/libubi/libubi_sysfs.c
+libubi_la_LDFLAGS      = -no-undefined -version-info 1:0:0
+
+# -----------------------------------------------------------------------------
+# complex convinence libs, beware for double includes.
+libreader_la_SOURCES    = $(top_srcdir)/src/libreader/reader.c 
+libreader_la_LIBADD    = libpfi.la \
+                         liblist.la  \
+                         libpeb.la \
+                         libbootenv.la
+
+libubigen_la_SOURCES   = $(top_srcdir)/src/libubigen/ubigen.c
+libubigen_la_LIBADD    = libcrc32.la
+
+libbootenv_la_SOURCES  = $(top_srcdir)/src/libbootenv/bootenv.c \
+                         $(top_srcdir)/src/libbootenv/hashmap.c 
+libbootenv_la_LIBADD   = libcrc32.la
+
+libubimirror_la_SOURCES        = $(top_srcdir)/src/libubimirror/ubimirror.c 
+libubimirror_la_LIBADD  = libubi.la
+
+
+# -----------------------------------------------------------------------------
+# simple convinence libs
+libcrc32_la_SOURCES    = $(top_srcdir)/src/libcrc32/crc32.c
+liberror_la_SOURCES    = $(top_srcdir)/src/liberror/error.c
+liblist_la_SOURCES     = $(top_srcdir)/src/liblist/list.c
+libpeb_la_SOURCES      = $(top_srcdir)/src/libpeb/peb.c
+libpfi_la_SOURCES      = $(top_srcdir)/src/libpfi/pfi.c 
diff --git a/ubi-utils/new-utils/Makefile b/ubi-utils/new-utils/Makefile
new file mode 100644 (file)
index 0000000..fe60ffe
--- /dev/null
@@ -0,0 +1,63 @@
+#
+# Makefile for ubi-utils
+#
+
+OPTFLAGS := -O2 -Wall
+KERNELHDR := ../../include
+DESTDIR := /usr/local
+SBINDIR=/usr/sbin
+MANDIR=/usr/man
+INCLUDEDIR=/usr/include
+
+CC := $(CROSS)gcc
+CFLAGS := -Iinclude -Isrc -I$(KERNELHDR) $(OPTFLAGS) -Werror -Wall
+
+LIBS = libubi libubigen libiniparser
+UTILS = ubi-update ubi-mkvol ubi-rmvol ubi-crc32 ubi-info ubi-attach \
+        ubi-detach ubi-nize
+
+vpath %.c src
+
+all: $(UTILS)
+
+# The below cancels existing implicite rule to make programs from .c files,
+# in order to force make using our rule defined below
+%: %.c
+
+# The below is the rule to get an .o file from a .c file
+%.o: %.c
+       $(CC) $(CFLAGS) $< -c -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 $@
+
+ubi-crc32: ubi-crc32.o crc32.o
+       $(CC) $(CFLAGS) -o $@ $^
+
+ubi-nize: ubi-nize.o common.o crc32.o libiniparser libubigen
+       $(CC) $(CFLAGS) $(filter %.o, $^) -L. -liniparser -lubigen -o $@
+
+libubi: libubi.o
+       $(AR) crv $@.a $^
+       ranlib $@.a
+
+libubigen: libubigen.o
+       $(AR) crv $@.a $^
+       ranlib $@.a
+
+libiniparser: libiniparser.o dictionary.o
+       $(AR) crv $@.a $^
+       ranlib $@.a
+
+clean:
+       rm -rf *.o $(addsuffix .a, $(LIBS)) $(UTILS) .*.c.dep
+
+install: ${UTILS}
+       mkdir -p ${DESTDIR}/${SBINDIR}
+       install -m0755 ${UTILS} ${DESTDIR}/${SBINDIR}/
+
+uninstall:
+       for file in ${UTILS}; do \
+               $(RM) ${DESTDIR}/${SBINDIR}/$$file; \
+       done
diff --git a/ubi-utils/new-utils/README b/ubi-utils/new-utils/README
new file mode 100644 (file)
index 0000000..7113b69
--- /dev/null
@@ -0,0 +1,56 @@
+This directory contains a new UBI toolchain which is intended to replace
+the old one. All the utilities start with "ubi-" to distinguish them from
+the old utilities. All support "-h" option which prints sufficient usage
+information. See the MTD web-site for more information.
+
+Motivation for new tool-chain.
+
+I was doing very active UBI development and had to add new features like
+dynamic UBI devices and auto-resize feature. Because of the mess in the
+the old tools I basically could not figure out how to upgrade them. In
+my humble oppinion, they are unmaintainable. The original authors did not
+show enthusiasm when I mailed them and asked to clean-up the tool-chain
+[1]. Thus, I re-implemented them, but I did borrow things from the old
+tool-chain and preserved copyrights and author names.
+
+I really did try to clean-up the old tool chain, but gave up (see git
+history for confirmation). So,
+
+1. I found the source codes very difficult to navigate and read, especially
+   those related to pdd, pfi, and bootenv. Try to do this yourself - they
+   are a puzzle.
+2. I foud the concept of PFI needlesly complecated - PFI file is nothing
+   else but the initial configuration .ini file + the contents of the
+   UBI volumes packed into one file, but with some changes of the .ini file's
+   format. The PFI file format is not very nice and it is difficult to parse,
+   especially because the PFI headers do not tell you data star and end for
+   each data chunk, and you have to do additional parsing.
+
+   So basically, you have .ini file + images, then you transfer this to pfi,
+   which does not add any other information. For .ini you have libraries
+   which may parse them, for pfi - not. Then you have to parse this pfi
+   which adds unneeded and complex code. This all needs lists, hashmaps,
+   and so on - for no reason.
+3. I found the command line options of the utilities to be inconsistent.
+   This is OK when you script your single task and do not touch it anymore.
+   But when you have to use the utilities while developing and testing,
+   It is difficult to remember their inconsistent options.
+4. I found it wrong to add development options to user utilities like
+   "broken update". End users should not see them.
+5. I did not find any consistent style and convention inside which
+   irritated me.
+6. I found it weird to introduce needless "logging infrastructure" instead
+   of just re-directing stdout and stderr to another file.
+7. I found the tool to be rather IBM-setup oriented. For example, the VID
+   header position was hard-coded. Some utilities were just weird, like
+   mkbootenv, which changed some ethernet addresses mentioned in a
+   configuration file.
+8. Finally, it was very difficult to realize what is pfi and pdd, what for,
+   why I need this transiant pfi file when I just want to create an UBI
+   image. There was zero documentation.
+
+And so on.
+
+Feb 19, 2008, Artem Bityutskiy.
+
+[1]. http://lists.infradead.org/pipermail/linux-mtd/2007-December/020134.html
diff --git a/ubi-utils/new-utils/src/crc32.c b/ubi-utils/new-utils/src/crc32.c
new file mode 100644 (file)
index 0000000..6b1e50c
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+ *  code or tables extracted from it, as desired without restriction.
+ *
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to hight-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera
+ *      tions for all combinations of data and CRC register values
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc
+ *      logic; the shift must be unsigned (bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions
+ *      polynomial $edb88320
+ */
+
+#include <stdint.h>
+
+const uint32_t crc32_table[256] = {
+       0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+       0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+       0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+       0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+       0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+       0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+       0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+       0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+       0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+       0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+       0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+       0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+       0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+       0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+       0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+       0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+       0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+       0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+       0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+       0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+       0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+       0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+       0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+       0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+       0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+       0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+       0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+       0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+       0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+       0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+       0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+       0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+       0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+       0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+       0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+       0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+       0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+       0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+       0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+       0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+       0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+       0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+       0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+       0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+       0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+       0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+       0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+       0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+       0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+       0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+       0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+       0x2d02ef8dL
+};
diff --git a/ubi-utils/new-utils/src/crc32.h b/ubi-utils/new-utils/src/crc32.h
new file mode 100644 (file)
index 0000000..ee3145b
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <stdint.h>
+
+extern const uint32_t crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+       static inline uint32_t
+crc32(uint32_t val, const void *ss, int len)
+{
+       const unsigned char *s = ss;
+       while (--len >= 0)
+               val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+       return val;
+}
+
+#endif
similarity index 91%
rename from ubi-utils/old-tools/src/libubi.c
rename to ubi-utils/new-utils/src/libubi.c
index be06f70a8c45131e5bfcf6984434fc39bfb33067..b53f18c0db92d3c41cd82d9f35cdc8cc4ffe4eb7 100644 (file)
@@ -27,7 +27,6 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <dirent.h>
-#include <errno.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <limits.h>
@@ -50,8 +49,7 @@ static char *mkpath(const char *path, const char *name)
 
        n = malloc(len1 + len2 + 2);
        if (!n) {
-               errmsg("cannot allocate %d bytes", len1 + len2 + 2);
-               perror("malloc");
+               sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2);
                return NULL;
        }
 
@@ -83,8 +81,7 @@ static int read_positive_ll(const char *file, long long *value)
 
        rd = read(fd, buf, 50);
        if (rd == -1) {
-               errmsg("cannot read \"%s\"", file);
-               perror("read");
+               sys_errmsg("cannot read \"%s\"", file);
                goto out_error;
        }
        if (rd == 50) {
@@ -106,11 +103,8 @@ static int read_positive_ll(const char *file, long long *value)
                goto out_error;
        }
 
-       if (close(fd)) {
-               errmsg("close failed on \"%s\"", file);
-               perror("close");
-               return -1;
-       }
+       if (close(fd))
+               return sys_errmsg("close failed on \"%s\"", file);
 
        return 0;
 
@@ -166,16 +160,14 @@ static int read_data(const char *file, void *buf, int buf_len)
 
        rd = read(fd, buf, buf_len);
        if (rd == -1) {
-               errmsg("cannot read \"%s\"", file);
-               perror("read");
+               sys_errmsg("cannot read \"%s\"", file);
                goto out_error;
        }
 
        /* Make sure all data is read */
        tmp1 = read(fd, &tmp, 1);
        if (tmp1 == 1) {
-               errmsg("cannot read \"%s\"", file);
-               perror("read");
+               sys_errmsg("cannot read \"%s\"", file);
                goto out_error;
        }
        if (tmp1) {
@@ -186,8 +178,7 @@ static int read_data(const char *file, void *buf, int buf_len)
        }
 
        if (close(fd)) {
-               errmsg("close failed on \"%s\"", file);
-               perror("close");
+               sys_errmsg("close failed on \"%s\"", file);
                return -1;
        }
 
@@ -217,16 +208,14 @@ static int read_major(const char *file, int *major, int *minor)
 
        ret = sscanf(buf, "%d:%d\n", major, minor);
        if (ret != 2) {
-               errmsg("\"%s\" does not have major:minor format", file);
                errno = EINVAL;
-               return -1;
+               return errmsg("\"%s\" does not have major:minor format", file);
        }
 
        if (*major < 0 || *minor < 0) {
-               errmsg("bad major:minor %d:%d in \"%s\"",
-                      *major, *minor, file);
                errno = EINVAL;
-               return -1;
+               return errmsg("bad major:minor %d:%d in \"%s\"",
+                             *major, *minor, file);
        }
 
        return 0;
@@ -319,31 +308,6 @@ static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
        return read_data(file, buf, buf_len);
 }
 
-/**
- * dent_is_dir - check if a file is a directory.
- * @dir: the base directory path of the file
- * @name: file name
- *
- * This function returns %1 if file @name in directory @dir is a directoru, and
- * %0 if not.
- */
-static int dent_is_dir(const char *dir, const char *name)
-{
-       int ret;
-       struct stat st;
-       char full_path[strlen(dir) + strlen(name) + 2];
-
-       sprintf(full_path, "%s/%s", dir, name);
-       ret = lstat(full_path, &st);
-       if (ret) {
-               errmsg("lstat failed on \"%s\"", full_path);
-               perror("lstat");
-               return -1;
-       }
-
-       return !!S_ISDIR(st.st_mode);
-}
-
 /**
  * dev_get_major - get major and minor numbers of an UBI device.
  * @lib: libubi descriptor
@@ -402,18 +366,16 @@ static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num,
                return -1;
 
        if (!S_ISCHR(st.st_mode)) {
-               errmsg("\"%s\" is not a character device", node);
                errno = EINVAL;
-               return -1;
+               return errmsg("\"%s\" is not a character device", node);
        }
 
        major = major(st.st_rdev);
        minor = minor(st.st_rdev);
 
        if (minor == 0) {
-               errmsg("\"%s\" is not a volume character device", node);
                errno = EINVAL;
-               return -1;
+               return errmsg("\"%s\" is not a volume character device", node);
        }
 
        if (ubi_get_info((libubi_t *)lib, &info))
@@ -470,18 +432,16 @@ static int dev_node2num(struct libubi *lib, const char *node, int *dev_num)
                return -1;
 
        if (!S_ISCHR(stat.st_mode)) {
-               errmsg("\"%s\" is not a character device", node);
                errno = EINVAL;
-               return -1;
+               return errmsg("\"%s\" is not a character device", node);
        }
 
        major = major(stat.st_rdev);
        minor = minor(stat.st_rdev);
 
        if (minor != 0) {
-               errmsg("\"%s\" is not an UBI character device", node);
                errno = EINVAL;
-               return -1;
+               return errmsg("\"%s\" is not an UBI character device", node);
        }
 
        if (ubi_get_info((libubi_t *)lib, &info))
@@ -576,8 +536,7 @@ libubi_t libubi_open(void)
        }
 
        if (close(fd)) {
-               errmsg("close failed on \"%s\"", lib->sysfs_ubi);
-               perror("close");
+               sys_errmsg("close failed on \"%s\"", lib->sysfs_ubi);
                goto out_error;
        }
 
@@ -865,29 +824,27 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
         * devices are present.
         */
        sysfs_ubi = opendir(lib->sysfs_ubi);
-       if (!sysfs_ubi) {
-               errmsg("cannot open %s", lib->sysfs_ubi);
-               perror("opendir");
-               return -1;
-       }
+       if (!sysfs_ubi)
+               return sys_errmsg("cannot open %s", lib->sysfs_ubi);
 
        info->lowest_dev_num = INT_MAX;
        while (1) {
                int dev_num, ret;
+               char tmp_buf[256];
 
                errno = 0;
                dirent = readdir(sysfs_ubi);
                if (!dirent)
                        break;
-               /*
-                * Make sure this direntry is a directory and not a symlink -
-                * Linux puts symlinks to UBI volumes on this UBI device to the
-                * same sysfs directory.
-                */
-               if (!dent_is_dir(lib->sysfs_ubi, dirent->d_name))
-                       continue;
 
-               ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT, &dev_num);
+               if (strlen(dirent->d_name) > 256) {
+                       errmsg("invalid entry in %s: \"%s\"",
+                              lib->sysfs_ubi, dirent->d_name);
+                       goto out_close;
+               }
+
+               ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT"%s",
+                            &dev_num, tmp_buf);
                if (ret == 1) {
                        info->dev_count += 1;
                        if (dev_num > info->highest_dev_num)
@@ -898,16 +855,12 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
        }
 
        if (!dirent && errno) {
-               errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
-               perror("readdir");
+               sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
                goto out_close;
        }
 
-       if (closedir(sysfs_ubi)) {
-               errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
-               perror("closedir");
-               return -1;
-       }
+       if (closedir(sysfs_ubi))
+               return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
 
        if (info->lowest_dev_num == INT_MAX)
                info->lowest_dev_num = 0;
@@ -1012,6 +965,21 @@ int ubi_update_start(libubi_t desc, int fd, long long bytes)
        return 0;
 }
 
+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype)
+{
+       struct ubi_leb_change_req req;
+
+       desc = desc;
+       memset(&req, 0, sizeof(struct ubi_leb_change_req));
+       req.lnum = lnum;
+       req.bytes = bytes;
+       req.dtype = dtype;
+
+       if (ioctl(fd, UBI_IOCEBCH, &req))
+               return -1;
+       return 0;
+}
+
 int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
 {
        DIR *sysfs_ubi;
@@ -1029,12 +997,20 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
 
        while (1) {
                int vol_id, ret, devno;
+               char tmp_buf[256];
 
                errno = 0;
                dirent = readdir(sysfs_ubi);
                if (!dirent)
                        break;
-               ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT, &devno, &vol_id);
+
+               if (strlen(dirent->d_name) > 256) {
+                       errmsg("invalid entry in %s: \"%s\"",
+                              lib->sysfs_ubi, dirent->d_name);
+                       goto out_close;
+               }
+
+               ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT"%s", &devno, &vol_id, tmp_buf);
                if (ret == 2 && devno == dev_num) {
                        info->vol_count += 1;
                        if (vol_id > info->highest_vol_num)
@@ -1045,16 +1021,12 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
        }
 
        if (!dirent && errno) {
-               errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
-               perror("readdir");
+               sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
                goto out_close;
        }
 
-       if (closedir(sysfs_ubi)) {
-               errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
-               perror("closedir");
-               return -1;
-       }
+       if (closedir(sysfs_ubi))
+               return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
 
        if (info->lowest_vol_num == INT_MAX)
                info->lowest_vol_num = 0;
similarity index 89%
rename from ubi-utils/old-tools/src/libubi_int.h
rename to ubi-utils/new-utils/src/libubi_int.h
index 649086443ca094bc0c24648f1878ee57fd3ccd7d..dab3e6251f4cc5d8a1e2fd7d20738198f54f8108 100644 (file)
 #ifndef __LIBUBI_INT_H__
 #define __LIBUBI_INT_H__
 
+#include <string.h>
+#include <errno.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /* Error messages */
-#define errmsg(fmt, ...) do {                                      \
+#define errmsg(fmt, ...)  ({                                       \
         fprintf(stderr, "libubi error: " fmt "\n", ##__VA_ARGS__); \
-} while(0)
+       -1;                                                        \
+})
+
+/* System error messages */
+#define sys_errmsg(fmt, ...)  ({                                   \
+       int _err = errno;                                          \
+       fprintf(stderr, "libubi error: " fmt "\n", ##__VA_ARGS__); \
+       fprintf(stderr, "error %d (%s)\n", _err, strerror(_err));  \
+       -1;                                                        \
+})
 
 /*
  * The below are pre-define UBI file and directory names.
diff --git a/ubi-utils/new-utils/src/libubigen.c b/ubi-utils/new-utils/src/libubigen.c
new file mode 100644 (file)
index 0000000..8d71fde
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ */
+
+/*
+ * Generating UBI images.
+ *
+ * Authors: Oliver Lohmann
+ *          Artem Bityutskiy
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <mtd/ubi-header.h>
+#include <libubigen.h>
+#include "crc32.h"
+#include "common.h"
+
+#define PROGRAM_NAME "libubigen"
+
+/**
+ * ubigen_info_init - initialize libubigen.
+ * @ui: libubigen information
+ * @peb_size: flash physical eraseblock size
+ * @min_io_size: flash minimum input/output unit size
+ * @subpage_size: flash sub-page, if present (has to be equivalent to
+ *                @min_io_size if does not exist)
+ * @vid_hdr_offs: offset of the VID header
+ * @ubi_ver: UBI version
+ * @ec: initial erase counter
+ */
+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)
+{
+       if (!vid_hdr_offs)
+               vid_hdr_offs = subpage_size;
+
+       ui->peb_size = peb_size;
+       ui->min_io_size = min_io_size;
+       ui->vid_hdr_offs = vid_hdr_offs;
+       ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1;
+       ui->data_offs /= min_io_size;
+       ui->data_offs *= 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.
+ * @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.
+ */
+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)
+               return errmsg("too high volume id %d, max. volumes is %d",
+                             vi->id, ui->max_volumes);
+
+       if (vi->alignment >= ui->leb_size)
+               return errmsg("too large alignment %d, max is %d (LEB size)",
+                             vi->alignment, ui->leb_size);
+
+       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);
+       vtbl_rec->alignment = cpu_to_be32(vi->alignment);
+       vtbl_rec->vol_type = vi->type;
+       tmp = ui->leb_size % vi->alignment;
+       vtbl_rec->data_pad = cpu_to_be32(tmp);
+       vtbl_rec->flags = vi->flags;
+
+       memcpy(vtbl_rec->name, vi->name, vi->name_len);
+       vtbl_rec->name[vi->name_len] = '\0';
+       vtbl_rec->name_len = cpu_to_be16(vi->name_len);
+
+       tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
+       vtbl_rec->crc =  cpu_to_be32(tmp);
+       return 0;
+}
+
+/**
+ * init_ec_hdr - initialize EC header.
+ * @ui: libubigen information
+ * @hdr: the EC header to initialize
+ */
+static void init_ec_hdr(const struct ubigen_info *ui,
+                       struct ubi_ec_hdr *hdr)
+{
+       uint32_t crc;
+
+       memset(hdr, '\0', sizeof(struct ubi_ec_hdr));
+
+       hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
+       hdr->version = ui->ubi_ver;
+       hdr->ec = cpu_to_be64(ui->ec);
+       hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs);
+
+       hdr->data_offset = cpu_to_be32(ui->data_offs);
+
+       crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+       hdr->hdr_crc = cpu_to_be32(crc);
+}
+
+/**
+ * init_vid_hdr - initialize VID header.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @hdr: the VID header to initialize
+ * @lnum: logical eraseblock number
+ * @data: the contents of the LEB (static volumes only)
+ * @data_size: amount of data in this LEB (static volumes only)
+ *
+ * Note, @used_ebs, @data and @data_size are ignored in case of dynamic
+ * volumes.
+ */
+static void init_vid_hdr(const struct ubigen_info *ui,
+                        const struct ubigen_vol_info *vi,
+                        struct ubi_vid_hdr *hdr, int lnum,
+                        const void *data, int data_size)
+{
+       uint32_t crc;
+
+       memset(hdr, '\0', sizeof(struct ubi_vid_hdr));
+
+       hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
+       hdr->version = ui->ubi_ver;
+       hdr->vol_type = vi->type;
+       hdr->vol_id = cpu_to_be32(vi->id);
+       hdr->lnum = cpu_to_be32(lnum);
+       hdr->data_pad = cpu_to_be32(vi->data_pad);
+       hdr->compat = vi->compat;
+
+       if (vi->type == UBI_VID_STATIC) {
+               hdr->data_size = cpu_to_be32(data_size);
+               hdr->used_ebs = cpu_to_be32(vi->used_ebs);
+               crc = crc32(UBI_CRC32_INIT, data, data_size);
+               hdr->data_crc = cpu_to_be32(crc);
+       }
+
+       crc = crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
+       hdr->hdr_crc = cpu_to_be32(crc);
+}
+
+/**
+ * ubigen_write_volume - write UBI volume.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @bytes: volume size in bytes
+ * @in: input file descriptor (has to be properly seeked)
+ * @out: output file descriptor
+ *
+ * This function reads the contents of the volume from the input file @in and
+ * writes the UBI volume to the output file @out. Returns zero on success and
+ * %-1 on failure.
+ */
+int ubigen_write_volume(const struct ubigen_info *ui,
+                       const struct ubigen_vol_info *vi,
+                       long long bytes, FILE *in, FILE *out)
+{
+       int len = vi->usable_leb_size, rd, lnum = 0;
+       char inbuf[ui->leb_size], outbuf[ui->peb_size];
+
+       if (vi->id >= ui->max_volumes)
+               return errmsg("too high volume id %d, max. volumes is %d",
+                             vi->id, ui->max_volumes);
+
+       if (vi->alignment >= ui->leb_size)
+               return errmsg("too large alignment %d, max is %d (LEB size)",
+                             vi->alignment, ui->leb_size);
+
+       memset(outbuf, 0xFF, ui->data_offs);
+       init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf);
+
+       while (bytes) {
+               int l;
+               struct ubi_vid_hdr *vid_hdr;
+
+               if (bytes < len)
+                       len = bytes;
+               bytes -= len;
+
+               l = len;
+               do {
+                       rd = fread(inbuf + len - l, 1, l, in);
+                       if (rd == 0) {
+                               if (ferror(in))
+                                       return errmsg("cannot read %d bytes from the input file", l);
+                               else
+                                       return errmsg("not enough data in the input file");
+                       }
+
+                       l -= rd;
+               } while (l);
+
+               vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+               init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len);
+
+               memcpy(outbuf + ui->data_offs, inbuf, len);
+               memset(outbuf + ui->data_offs + len, 0xFF,
+                      ui->peb_size - ui->data_offs - len);
+
+               if (fwrite(outbuf, 1, ui->peb_size, out) != ui->peb_size)
+                       return errmsg("cannot write %d bytes from the output file", l);
+
+               lnum += 1;
+       }
+
+       return 0;
+}
+
+/**
+ * ubigen_write_layout_vol - write UBI layout volume
+ * @ui: libubigen information
+ * @vtbl: volume table
+ * @out: output file stream
+ *
+ * This function creates the UBI layout volume which contains 2 copies of the
+ * volume table. Returns zero in case of success and %-1 in case of failure.
+ */
+int ubigen_write_layout_vol(const struct ubigen_info *ui,
+                           struct ubi_vtbl_record *vtbl, FILE *out)
+{
+       int size = ui->leb_size;
+       struct ubigen_vol_info vi;
+       char outbuf[ui->peb_size];
+       struct ubi_vid_hdr *vid_hdr;
+
+       if (size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE)
+               size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE;
+
+       vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
+       vi.id = UBI_LAYOUT_VOLUME_ID;
+       vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
+       vi.data_pad =  ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
+       vi.usable_leb_size = ui->leb_size - vi.data_pad;
+       vi.data_pad = ui->leb_size - vi.usable_leb_size;
+       vi.type = UBI_LAYOUT_VOLUME_TYPE;
+       vi.name = UBI_LAYOUT_VOLUME_NAME;
+       vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
+       vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
+
+       memset(outbuf, 0xFF, ui->data_offs);
+       vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+       init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf);
+       memcpy(outbuf + ui->data_offs, vtbl, size);
+       memset(outbuf + ui->data_offs + size, 0xFF,
+              ui->peb_size - ui->data_offs - size);
+
+       init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
+       size = fwrite(outbuf, 1, ui->peb_size, out);
+       if (size == ui->peb_size) {
+               init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
+               size = fwrite(outbuf, 1, ui->peb_size, out);
+               if (size != ui->peb_size)
+                       return sys_errmsg("cannot write %d bytes", ui->peb_size);
+       }
+
+       return 0;
+}
similarity index 99%
rename from ubi-utils/src/ubiattach.c
rename to ubi-utils/new-utils/src/ubi-attach.c
index b3d768a2f4796f6d4be75da8e2aa8201b0b1711d..7b231a634a12a118b25b50ce79e003fdfba69760 100644 (file)
@@ -31,7 +31,7 @@
 #include "common.h"
 
 #define PROGRAM_VERSION "1.0"
-#define PROGRAM_NAME    "ubiattach"
+#define PROGRAM_NAME    "ubi-attach"
 
 /* The variables below are set by command line arguments */
 struct args {
diff --git a/ubi-utils/new-utils/src/ubi-crc32.c b/ubi-utils/new-utils/src/ubi-crc32.c
new file mode 100644 (file)
index 0000000..d3d3136
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+/*
+ * Calculate CRC32 with UBI start value (0xFFFFFFFF) for a given binary image.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <argp.h>
+#include <unistd.h>
+#include <mtd/ubi-header.h>
+
+#include "crc32.h"
+#include "common.h"
+
+#define BUFSIZE 4096
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME    "ubi-crc32"
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+                        " - a tool to calculate CRC32 with UBI start value (0xFFFFFFFF)";
+
+static const char *optionsstr =
+"-h, --help                    print help message\n"
+"-V, --version                 print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <file to calculate CRC32 for> [-h] [--help]";
+
+static const struct option long_options[] = {
+       { .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;
+
+               key = getopt_long(argc, argv, "hV", long_options, NULL);
+               if (key == -1)
+                       break;
+
+               switch (key) {
+               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 ':':
+                       return errmsg("parameter is missing");
+
+               default:
+                       fprintf(stderr, "Use -h for help\n");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+       int err = 0;
+       uint32_t crc = UBI_CRC32_INIT;
+       char buf[BUFSIZE];
+       FILE *fp;
+
+       if (argc > 1) {
+               fp = fopen(argv[1], "r");
+               if (!fp)
+                       return sys_errmsg("cannot open \"%s\"", argv[1]);
+       } else
+               fp = stdin;
+
+       err = parse_opt(argc, argv);
+       if (err)
+               return err;
+
+       while (!feof(fp)) {
+               size_t read;
+
+               read = fread(buf, 1, BUFSIZE, fp);
+               if (ferror(fp)) {
+                       sys_errmsg("cannot read input file");
+                       err = -1;
+                       goto out_close;
+               }
+               crc = crc32(crc, buf, read);
+       }
+
+       printf("0x%08x\n", crc);
+
+out_close:
+       if (fp != stdin)
+               fclose(fp);
+       return err;
+}
similarity index 99%
rename from ubi-utils/src/ubidetach.c
rename to ubi-utils/new-utils/src/ubi-detach.c
index cd4836811e97991673a3d7f60f15a496c3f5a365..0ee7954c552e739f2ab565cf417dd2018c58f136 100644 (file)
@@ -31,7 +31,7 @@
 #include "common.h"
 
 #define PROGRAM_VERSION "1.0"
-#define PROGRAM_NAME    "ubidetach"
+#define PROGRAM_NAME    "ubi-detach"
 
 /* The variables below are set by command line arguments */
 struct args {
similarity index 99%
rename from ubi-utils/src/ubinfo.c
rename to ubi-utils/new-utils/src/ubi-info.c
index 185caae9643b0e5438465c946427b96b95bcc530..d469a1a6e9477eadb1d1e3f0a34c6dc4c39fc264 100644 (file)
@@ -31,7 +31,7 @@
 #include "common.h"
 
 #define PROGRAM_VERSION "1.0"
-#define PROGRAM_NAME    "ubinfo"
+#define PROGRAM_NAME    "ubi-nfo"
 
 /* The variables below are set by command line arguments */
 struct args {
diff --git a/ubi-utils/new-utils/src/ubi-mkvol.c b/ubi-utils/new-utils/src/ubi-mkvol.c
new file mode 100644 (file)
index 0000000..49d1905
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * 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 create UBI volumes.
+ *
+ * Authors: Artem Bityutskiy <dedekind@infradead.org>
+ *          Frank Haverkamp <haver@vnet.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME    "ubi-mkvol"
+
+/* The variables below are set by command line arguments */
+struct args {
+       int vol_id;
+       int vol_type;
+       long long bytes;
+       int lebs;
+       int alignment;
+       const char *name;
+       int nlen;
+       const char *node;
+       int maxavs;
+};
+
+static struct args args = {
+       .vol_type = UBI_DYNAMIC_VOLUME,
+       .bytes = -1,
+       .lebs = -1,
+       .alignment = 1,
+       .vol_id = UBI_VOL_NUM_AUTO,
+       .name = NULL,
+       .nlen = 0,
+       .node = NULL,
+       .maxavs = 0,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+                        " - a tool to create UBI volumes.";
+
+static const char *optionsstr =
+"-a, --alignment=<alignment>   volume alignment (default is 1)\n"
+"-n, --vol_id=<volume ID>      UBI volume ID, if not specified, the volume ID\n"
+"                              will be assigned automatically\n"
+"-N, --name=<name>             volume name\n"
+"-s, --size=<bytes>            volume size volume size in bytes, kilobytes (KiB)\n"
+"                              or megabytes (MiB)\n"
+"-S, --lebs=<LEBs count>       alternative way to give volume size in logical\n"
+"                              eraseblocks\n"
+"-m, --maxavsize               set volume size to maximum available size\n"
+"-t, --type=<static|dynamic>   volume type (dynamic, static), default is dynamic\n"
+"-h, --help                    print help message\n"
+"-V, --version                 print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI device node file name> [-h] [-a <alignment>] [-n <volume ID>] [-N <name>]\n"
+"\t\t\t[-s <bytes>] [-S <LEBs>] [-t <static|dynamic>] [-V] [-m]\n"
+"\t\t\t[--alignment=<alignment>][--vol_id=<volume ID>] [--name=<name>]\n"
+"\t\t\t[--size=<bytes>] [--lebs=<LEBs>] [--type=<static|dynamic>] [--help]\n"
+"\t\t\t[--version] [--maxavsize]\n\n"
+"Example: " PROGRAM_NAME "/dev/ubi0 -s 20MiB -N config_data - create a 20 Megabytes volume\n"
+"         named \"config_data\" on UBI device /dev/ubi0.";
+
+static const struct option long_options[] = {
+       { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'a' },
+       { .name = "vol_id",    .has_arg = 1, .flag = NULL, .val = 'n' },
+       { .name = "name",      .has_arg = 1, .flag = NULL, .val = 'N' },
+       { .name = "size",      .has_arg = 1, .flag = NULL, .val = 's' },
+       { .name = "lebs",      .has_arg = 1, .flag = NULL, .val = 'S' },
+       { .name = "type",      .has_arg = 1, .flag = NULL, .val = 't' },
+       { .name = "help",      .has_arg = 0, .flag = NULL, .val = 'h' },
+       { .name = "version",   .has_arg = 0, .flag = NULL, .val = 'V' },
+       { .name = "maxavsize", .has_arg = 0, .flag = NULL, .val = 'm' },
+       { NULL, 0, NULL, 0},
+};
+
+static int param_sanity_check(void)
+{
+       int len;
+
+       if (args.bytes == -1 && !args.maxavs && args.lebs == -1)
+               return errmsg("volume size was not specified (use -h for help)");
+
+       if ((args.bytes != -1 && (args.maxavs || args.lebs != -1))  ||
+           (args.lebs != -1  && (args.maxavs || args.bytes != -1)) ||
+           (args.maxavs && (args.bytes != -1 || args.lebs != -1)))
+               return errmsg("size specified with more then one option");
+
+       if (args.name == NULL)
+               return errmsg("volume name was not specified (use -h for help)");
+
+       len = strlen(args.name);
+       if (len > UBI_MAX_VOLUME_NAME)
+               return errmsg("too long name (%d symbols), max is %d", len, UBI_MAX_VOLUME_NAME);
+
+       return 0;
+}
+
+static int parse_opt(int argc, char * const argv[])
+{
+       while (1) {
+               int key;
+               char *endp;
+
+               key = getopt_long(argc, argv, "a:n:N:s:S:t:hVm", long_options, NULL);
+               if (key == -1)
+                       break;
+
+               switch (key) {
+               case 't':
+                       if (!strcmp(optarg, "dynamic"))
+                               args.vol_type = UBI_DYNAMIC_VOLUME;
+                       else if (!strcmp(optarg, "static"))
+                               args.vol_type = UBI_STATIC_VOLUME;
+                       else
+                               return errmsg("bad volume type: \"%s\"", optarg);
+                       break;
+
+               case 's':
+                       args.bytes = ubiutils_get_bytes(optarg);
+                       if (args.bytes <= 0)
+                               return errmsg("bad volume size: \"%s\"", optarg);
+                       break;
+
+               case 'S':
+                       args.lebs = strtoull(optarg, &endp, 0);
+                       if (endp == optarg || args.lebs <= 0 || *endp != '\0')
+                               return errmsg("bad LEB count: \"%s\"", optarg);
+                       break;
+
+               case 'a':
+                       args.alignment = strtoul(optarg, &endp, 0);
+                       if (*endp != '\0' || endp == optarg || args.alignment <= 0)
+                               return errmsg("bad volume alignment: \"%s\"", optarg);
+                       break;
+
+               case 'n':
+                       args.vol_id = strtoul(optarg, &endp, 0);
+                       if (*endp != '\0' || endp == optarg || args.vol_id < 0)
+                               return errmsg("bad volume ID: " "\"%s\"", optarg);
+                       break;
+
+               case 'N':
+                       args.name = optarg;
+                       args.nlen = strlen(args.name);
+                       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 'm':
+                       args.maxavs = 1;
+                       break;
+
+               case ':':
+                       return errmsg("parameter is missing");
+
+               default:
+                       fprintf(stderr, "Use -h for help\n");
+                       return -1;
+               }
+       }
+
+       if (optind == argc)
+               return errmsg("UBI device name was not specified (use -h for help)");
+       else if (optind != argc - 1)
+               return errmsg("more then one UBI device specified (use -h for help)");
+
+       args.node = argv[optind];
+
+       if (param_sanity_check())
+               return -1;
+
+       return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+       int err;
+       libubi_t libubi;
+       struct ubi_dev_info dev_info;
+       struct ubi_vol_info vol_info;
+       struct ubi_mkvol_request req;
+
+       err = parse_opt(argc, argv);
+       if (err)
+               return err;
+
+       libubi = libubi_open();
+       if (!libubi)
+               return sys_errmsg("cannot open libubi");
+
+       err = ubi_node_type(libubi, args.node);
+       if (err == 2) {
+               errmsg("\"%s\" is an UBI volume node, not an UBI device node",
+                      args.node);
+               goto out_libubi;
+       } else if (err < 0) {
+               errmsg("\"%s\" is not an UBI device node", args.node);
+               goto out_libubi;
+       }
+
+       err = ubi_get_dev_info(libubi, args.node, &dev_info);
+       if (err) {
+               sys_errmsg("cannot get information about UBI device \"%s\"",
+                          args.node);
+               goto out_libubi;
+       }
+
+       if (args.maxavs) {
+               args.bytes = dev_info.avail_bytes;
+               printf("Set volume size to %lld\n", req.bytes);
+       }
+
+       if (args.lebs != -1) {
+               args.bytes = dev_info.leb_size;
+               args.bytes -= dev_info.leb_size % args.alignment;
+               args.bytes *= args.lebs;
+       }
+
+       req.vol_id = args.vol_id;
+       req.alignment = args.alignment;
+       req.bytes = args.bytes;
+       req.vol_type = args.vol_type;
+       req.name = args.name;
+
+       err = ubi_mkvol(libubi, args.node, &req);
+       if (err < 0) {
+               sys_errmsg("cannot UBI create volume");
+               goto out_libubi;
+       }
+
+       args.vol_id = req.vol_id;
+
+       /* Print information about the created device */
+       err = ubi_get_vol_info1(libubi, dev_info.dev_num, args.vol_id, &vol_info);
+       if (err) {
+               sys_errmsg("cannot get information about newly created UBI volume");
+               goto out_libubi;
+       }
+
+       printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs);
+       ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+       printf("), LEB size ");
+       ubiutils_print_bytes(vol_info.leb_size, 1);
+       printf(", %s, name \"%s\", alignment %d\n",
+              req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static",
+              vol_info.name, vol_info.alignment);
+
+       libubi_close(libubi);
+       return 0;
+
+out_libubi:
+       libubi_close(libubi);
+       return -1;
+}
similarity index 99%
rename from ubi-utils/src/ubinize.c
rename to ubi-utils/new-utils/src/ubi-nize.c
index 47dc5711ad64957ce1c08c731281da877c30a67c..8041df4c9ebd06912f31dfe80d24c3cff2d028e2 100644 (file)
@@ -36,8 +36,8 @@
 #include <libiniparser.h>
 #include "common.h"
 
-#define PROGRAM_VERSION "1.5"
-#define PROGRAM_NAME    "ubinize"
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME    "ubi-nize"
 
 static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
 " - a tool to generate UBI images. An UBI image may contain one or more UBI "
diff --git a/ubi-utils/new-utils/src/ubi-rmvol.c b/ubi-utils/new-utils/src/ubi-rmvol.c
new file mode 100644 (file)
index 0000000..72bf069
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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 remove UBI volumes.
+ *
+ * Authors: Artem Bityutskiy <dedekind@infradead.org>
+ *          Frank Haverkamp <haver@vnet.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME    "ubi-rmvol"
+
+/* The variables below are set by command line arguments */
+struct args {
+       int vol_id;
+       const char *node;
+};
+
+static struct args args = {
+       .vol_id = -1,
+       .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+                                " - a tool to remove UBI volumes.";
+
+static const char *optionsstr =
+"  -n, --vol_id=<volume id>   volume ID to remove\n"
+"  -h, --help                 print help message\n"
+"  -V, --version              print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI device node file name> [-n <volume id>] [--vol_id=<volume id>] [-h] [--help]\n\n"
+"Example: " PROGRAM_NAME "/dev/ubi0 -n 1 - remove UBI volume 1 from UBI device corresponding\n"
+"         to the node file /dev/ubi0.";
+
+static const struct option long_options[] = {
+       { .name = "vol_id",  .has_arg = 1, .flag = NULL, .val = 'n' },
+       { .name = "help",    .has_arg = 0, .flag = NULL, .val = 'h' },
+       { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+       { NULL, 0, NULL, 0},
+};
+
+static int param_sanity_check(void)
+{
+       if (args.vol_id == -1) {
+               errmsg("volume ID is was not specified");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int parse_opt(int argc, char * const argv[])
+{
+       while (1) {
+               int key;
+               char *endp;
+
+               key = getopt_long(argc, argv, "n:hV", long_options, NULL);
+               if (key == -1)
+                       break;
+
+               switch (key) {
+
+               case 'n':
+                       args.vol_id = strtoul(optarg, &endp, 0);
+                       if (*endp != '\0' || endp == optarg || args.vol_id < 0) {
+                               errmsg("bad volume ID: " "\"%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 (optind == argc) {
+               errmsg("UBI device name was not specified (use -h for help)");
+               return -1;
+       } else if (optind != argc - 1) {
+               errmsg("more then one UBI device specified (use -h for help)");
+               return -1;
+       }
+
+       args.node = argv[optind];
+
+       if (param_sanity_check())
+               return -1;
+
+       return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+       int err;
+       libubi_t libubi;
+
+       err = parse_opt(argc, argv);
+       if (err)
+               return -1;
+
+       libubi = libubi_open();
+       if (libubi == NULL)
+               return sys_errmsg("cannot open libubi");
+
+       err = ubi_node_type(libubi, args.node);
+       if (err == 2) {
+               errmsg("\"%s\" is an UBI volume node, not an UBI device node",
+                      args.node);
+               goto out_libubi;
+       } else if (err < 0) {
+               errmsg("\"%s\" is not an UBI device node", args.node);
+               goto out_libubi;
+       }
+
+       err = ubi_rmvol(libubi, args.node, args.vol_id);
+       if (err) {
+               sys_errmsg("cannot UBI remove volume");
+               goto out_libubi;
+       }
+
+       libubi_close(libubi);
+       return 0;
+
+out_libubi:
+       libubi_close(libubi);
+       return -1;
+}
similarity index 98%
rename from ubi-utils/src/ubiupdate.c
rename to ubi-utils/new-utils/src/ubi-update.c
index c17b3c5b6657169156f8e814f8ab92b54ac88a1a..bf548a977ba07a7a52938ef831cb46f29720497f 100644 (file)
@@ -37,8 +37,8 @@
 #include <libubi.h>
 #include "common.h"
 
-#define PROGRAM_VERSION "1.3"
-#define PROGRAM_NAME    "ubiupdate"
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME    "ubi-update"
 
 struct args {
        int truncate;
diff --git a/ubi-utils/old-tools/Makefile b/ubi-utils/old-tools/Makefile
deleted file mode 100644 (file)
index d4c908b..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-# Makefile for ubi-utils
-#
-
-OPTFLAGS := -O2 -Wall
-KERNELHDR := ../../include
-DESTDIR := /usr/local
-SBINDIR=/usr/sbin
-MANDIR=/usr/man
-INCLUDEDIR=/usr/include
-
-CC := $(CROSS)gcc
-CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror \
-       -Wwrite-strings -W -std=gnu99 -DPACKAGE_VERSION=\"1.0\"
-
-PERLPROGS = mkpfi ubicrc32.pl
-TARGETS = pfiflash pddcustomize ubimirror \
-       bin2nand nand2bin ubigen mkbootenv unubi pfi2bin
-
-vpath   %.c ./src
-
-%: %.o
-       $(CC) $(LDFLAGS) -g -o $@ $^
-
-%.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 $@ $^
-
-ubidetach: ubidetach.o common.o libubi.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-ubiattach: ubiattach.o common.o libubi.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-ubinfo: ubinfo.o common.o libubi.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-ubiupdate: ubiupdate.o common.o libubi.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-ubimkvol: ubimkvol.o common.o libubi.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-ubirmvol: ubirmvol.o common.o libubi.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \
-               libubi.o crc32.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \
-               bootenv.o hashmap.o pfi.o libubi.o crc32.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \
-               libubi.o crc32.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-nand2bin: nand2bin.o nandecc.o nandcorr.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-bin2nand: bin2nand.o error.o nandecc.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-ubigen: ubigen.o libubigen.o crc32.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-unubi: unubi.o crc32.o unubi_analyze.o eb_chain.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-pfi2bin: pfi2bin.o peb.o error.o list.o crc32.o libubigen.o bootenv.o \
-               hashmap.o reader.o pfi.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-ubicrc32: ubicrc32.o crc32.o
-       $(CC) $(LDFLAGS) -o $@ $^
-
-install: ${TARGETS}
-       mkdir -p ${DESTDIR}/${SBINDIR}
-       install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
-       (cd perl && install ${PERLPROGS} ${DESTDIR}/${SBINDIR}/)
-
-uninstall:
-       for file in ${TARGETS} ${PERLPROGS}; do \
-               $(RM) ${DESTDIR}/${SBINDIR}/$$file; \
-       done
diff --git a/ubi-utils/old-tools/inc/libubi.h b/ubi-utils/old-tools/inc/libubi.h
deleted file mode 100644 (file)
index 0cdb67c..0000000
+++ /dev/null
@@ -1,340 +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: Artem B. Bityutskiy
- *
- * UBI (Unsorted Block Images) library.
- */
-
-#ifndef __LIBUBI_H__
-#define __LIBUBI_H__
-
-#include <stdint.h>
-#include <mtd/ubi-user.h>
-#include <ctype.h>
-#include <mtd/ubi-header.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* UBI version libubi is made for */
-#define LIBUBI_UBI_VERSION 1
-
-/* UBI library descriptor */
-typedef void * libubi_t;
-
-/**
- * struct ubi_attach_request - MTD device attachement request.
- * @dev_num: number to assigne to the newly created UBI device
- *           (%UBI_DEV_NUM_AUTO should be used to automatically assign the
- *           number)
- * @mtd_num: MTD device number to attach
- * @vid_hdr_offset: VID header offset (%0 means default offset and this is what
- *                  most of the users want)
- */
-struct ubi_attach_request
-{
-       int dev_num;
-       int mtd_num;
-       int vid_hdr_offset;
-};
-
-/**
- * struct ubi_mkvol_request - volume creation request.
- * @vol_id: ID to assign to the new volume (%UBI_VOL_NUM_AUTO should be used to
- *          automatically assign ID)
- * @alignment: volume alignment
- * @bytes: volume size in bytes
- * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @name: volume name
- */
-struct ubi_mkvol_request
-{
-       int vol_id;
-       int alignment;
-       long long bytes;
-       int vol_type;
-       const char *name;
-};
-
-/**
- * struct ubi_info - general UBI information.
- * @dev_count: count of UBI devices in system
- * @lowest_dev_num: lowest UBI device number
- * @highest_dev_num: highest UBI device number
- * @version: UBI version
- * @ctrl_major: major number of the UBI control device
- * @ctrl_minor: minor number of the UBI control device
- */
-struct ubi_info
-{
-       int dev_count;
-       int lowest_dev_num;
-       int highest_dev_num;
-       int version;
-       int ctrl_major;
-       int ctrl_minor;
-};
-
-/**
- * struct ubi_dev_info - UBI device information.
- * @vol_count: count of volumes on this UBI device
- * @lowest_vol_num: lowest volume number
- * @highest_vol_num: highest volume number
- * @major: major number of corresponding character device
- * @minor: minor number of corresponding character device
- * @total_lebs: total number of logical eraseblocks on this UBI device
- * @avail_lebs: how many logical eraseblocks are not used and available for new
- *             volumes
- * @total_bytes: @total_lebs * @leb_size
- * @avail_bytes: @avail_lebs * @leb_size
- * @bad_count: count of bad physical eraseblocks
- * @leb_size: logical eraseblock size
- * @max_ec: current highest erase counter value
- * @bad_rsvd: how many physical eraseblocks of the underlying flash device are
- *            reserved for bad eraseblocks handling
- * @max_vol_count: maximum possible number of volumes on this UBI device
- * @min_io_size: minimum input/output unit size of the UBI device
- */
-struct ubi_dev_info
-{
-       int dev_num;
-       int vol_count;
-       int lowest_vol_num;
-       int highest_vol_num;
-       int major;
-       int minor;
-       int total_lebs;
-       int avail_lebs;
-       long long total_bytes;
-       long long avail_bytes;
-       int bad_count;
-       int leb_size;
-       long long max_ec;
-       int bad_rsvd;
-       int max_vol_count;
-       int min_io_size;
-};
-
-/**
- * struct ubi_vol_info - UBI volume information.
- * @dev_num: UBI device number the volume resides on
- * @vol_id: ID of this volume
- * @major: major number of corresponding volume character device
- * @minor: minor number of corresponding volume character device
- * @dev_major: major number of corresponding UBI device character device
- * @dev_minor: minor number of corresponding UBI device character device
- * @type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @alignment: alignemnt of this volume
- * @data_bytes: how many data bytes are stored on this volume (equivalent to
- *              @rsvd_bytes for dynamic volumes)
- * @rsvd_bytes: how many bytes are reserved for this volume
- * @rsvd_lebs: how many logical eraseblocks are reserved for this volume
- * @leb_size: logical eraseblock size of this volume (may be less then
- *           device's logical eraseblock size due to alignment)
- * @corrupted: non-zero if the volume is corrupted
- * @name: volume name (null-terminated)
- */
-struct ubi_vol_info
-{
-       int dev_num;
-       int vol_id;
-       int major;
-       int minor;
-       int dev_major;
-       int dev_minor;
-       int type;
-       int alignment;
-       long long data_bytes;
-       long long rsvd_bytes;
-       int rsvd_lebs;
-       int leb_size;
-       int corrupted;
-       char name[UBI_VOL_NAME_MAX + 1];
-};
-
-/**
- * libubi_open - open UBI library.
- * This function initializes and opens the UBI library and returns UBI library
- * descriptor in case of success and %NULL in case of failure.
- */
-libubi_t libubi_open(void);
-
-/**
- * libubi_close - close UBI library.
- * @desc UBI library descriptor
- */
-void libubi_close(libubi_t desc);
-
-/**
- * ubi_get_info - get general UBI information.
- * @desc: UBI library descriptor
- * @info: pointer to the &struct ubi_info object to fill
- *
- * This function fills the passed @info object with general UBI information and
- * returns %0 in case of success and %-1 in case of failure.
- */
-int ubi_get_info(libubi_t desc, struct ubi_info *info);
-
-/**
- * ubi_attach_mtd - attach MTD device to UBI.
- * @desc: UBI library descriptor
- * @node: name of the UBI control character device node
- * @req: MTD attach request.
- *
- * This function creates a new UBI device by attaching an MTD device as
- * described by @req. Returns %0 in case of success and %-1 in case of failure.
- * The newly created UBI device number is returned in @req->dev_num.
- */
-int ubi_attach_mtd(libubi_t desc, const char *node,
-                  struct ubi_attach_request *req);
-
-/**
- * ubi_detach_mtd - detach an MTD device.
- * @desc: UBI library descriptor
- * @node: name of the UBI control character device node
- * @mtd_num: MTD device number to detach
- *
- * This function detaches MTD device number @mtd_num from UBI, which means the
- * corresponding UBI device is removed. Returns zero in case of success and %-1
- * in case of failure.
- */
-int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num);
-
-/**
- * ubi_remove_dev - remove an UBI device.
- * @desc: UBI library descriptor
- * @node: name of the UBI control character device node
- * @ubi_dev: UBI device number to remove
- *
- * This function removes UBI device number @ubi_dev and returns zero in case of
- * success and %-1 in case of failure.
- */
-int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev);
-
-/**
- * ubi_mkvol - create an UBI volume.
- * @desc: UBI library descriptor
- * @node: name of the UBI character device to create a volume at
- * @req: UBI volume creation request
- *
- * This function creates a UBI volume as described at @req and returns %0 in
- * case of success and %-1 in case of failure. The assigned volume ID is
- * returned in @req->vol_id.
- */
-int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req);
-
-/**
- * ubi_rmvol - remove a UBI volume.
- * @desc: UBI library descriptor
- * @node: name of the UBI character device to remove a volume from
- * @vol_id: ID of the volume to remove
- *
- * This function removes volume @vol_id from UBI device @node and returns %0 in
- * case of success and %-1 in case of failure.
- */
-int ubi_rmvol(libubi_t desc, const char *node, int vol_id);
-
-/**
- * ubi_rsvol - re-size UBI volume.
- * @desc: UBI library descriptor
- * @node: name of the UBI character device owning the volume which should be
- *        re-sized
- * @vol_id: volume ID to re-size
- * @bytes: new volume size in bytes
- *
- * This function returns %0 in case of success and %-1 in case of error.
- */
-int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes);
-
-/**
- * ubi_node_type - test UBI node type.
- * @desc: UBI library descriptor
- * @node: the node to test
- *
- * This function tests whether @node is a UBI device or volume node and returns
- * %1 if this is an UBI device node, %2 if this is a volume node, and %-1 if
- * this is not an UBI node or if an error occurred (the latter is indicated by
- * a non-zero errno).
- */
-int ubi_node_type(libubi_t desc, const char *node);
-
-/**
- * ubi_get_dev_info - get UBI device information.
- * @desc: UBI library descriptor
- * @node: name of the UBI character device to fetch information about
- * @info: pointer to the &struct ubi_dev_info object to fill
- *
- * This function fills the passed @info object with UBI device information and
- * returns %0 in case of success and %-1 in case of failure.
- */
-int ubi_get_dev_info(libubi_t desc, const char *node,
-                    struct ubi_dev_info *info);
-
-/**
- * ubi_get_dev_info1 - get UBI device information.
- * @desc: UBI library descriptor
- * @dev_num: UBI device number to fetch information about
- * @info: pointer to the &struct ubi_dev_info object to fill
- *
- * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI
- * device number, not UBI character device.
- */
-int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info);
-
-/**
- * ubi_get_vol_info - get UBI volume information.
- * @desc: UBI library descriptor
- * @node: name of the UBI volume character device to fetch information about
- * @info: pointer to the &struct ubi_vol_info object to fill
- *
- * This function fills the passed @info object with UBI volume information and
- * returns %0 in case of success and %-1 in case of failure.
- */
-int ubi_get_vol_info(libubi_t desc, const char *node,
-                    struct ubi_vol_info *info);
-
-/**
- * ubi_get_vol_info1 - get UBI volume information.
- * @desc: UBI library descriptor
- * @dev_num: UBI device number
- * @vol_id: ID of the UBI volume to fetch information about
- * @info: pointer to the &struct ubi_vol_info object to fill
- *
- * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI
- * volume number, not UBI volume character device.
- */
-int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
-                     struct ubi_vol_info *info);
-
-/**
- * ubi_update_start - start UBI volume update.
- * @desc: UBI library descriptor
- * @fd: volume character devie file descriptor
- * @bytes: how many bytes will be written to the volume
- *
- * This function initiates UBI volume update and returns %0 in case of success
- * and %-1 in case of error.
- */
-int ubi_update_start(libubi_t desc, int fd, long long bytes);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !__LIBUBI_H__ */
diff --git a/ubi-utils/old-tools/src/common.c b/ubi-utils/old-tools/src/common.c
deleted file mode 100644 (file)
index 7ed1ade..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) Artem Bityutskiy, 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.
- */
-
-/*
- * This file contains various common stuff used by UBI utilities.
- *
- * Author: Artem Bityutskiy
- */
-
-#include <stdio.h>
-#include <string.h>
-
-/**
- * ubiutils_bytes_multiplier - convert size specifier to an integer
- *                             multiplier.
- *
- * @str: the size specifier string
- *
- * This function parses the @str size specifier, which may be one of
- * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
- * size multiplier in case of success and %-1 in case of failure.
- */
-int ubiutils_get_multiplier(const char *str)
-{
-       if (!str)
-               return 1;
-
-       /* Remove spaces before the specifier */
-       while (*str == ' ' || *str == '\t')
-               str += 1;
-
-       if (!strcmp(str, "KiB"))
-               return 1024;
-       if (!strcmp(str, "MiB"))
-               return 1024 * 1024;
-       if (!strcmp(str, "GiB"))
-               return 1024 * 1024 * 1024;
-
-       return -1;
-}
-
-/**
- * ubiutils_print_bytes - print bytes.
- * @bytes: variable to print
- * @bracket: whether brackets have to be put or not
- *
- * This is a helper function which prints amount of bytes in a human-readable
- * form, i.e., it prints the exact amount of bytes following by the approximate
- * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
- * is.
- */
-void ubiutils_print_bytes(long long bytes, int bracket)
-{
-       const char *p;
-
-       if (bracket)
-               p = " (";
-       else
-               p = ", ";
-
-       printf("%lld bytes", bytes);
-
-       if (bytes > 1024 * 1024 * 1024)
-               printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024));
-       else if (bytes > 1024 * 1024)
-               printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024));
-       else if (bytes > 1024)
-               printf("%s%.1f KiB", p, (double)bytes / 1024);
-       else
-               return;
-
-       if (bracket)
-               printf(")");
-}
diff --git a/ubi-utils/old-tools/src/common.h b/ubi-utils/old-tools/src/common.h
deleted file mode 100644 (file)
index 06ae623..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) Artem Bityutskiy, 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 __UBI_UTILS_COMMON_H__
-#define __UBI_UTILS_COMMON_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Error messages */
-#define errmsg(fmt, ...) do {                                             \
-        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__); \
-} while(0)
-
-int ubiutils_get_multiplier(const char *str);
-void ubiutils_print_bytes(long long bytes, int bracket);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !__UBI_UTILS_COMMON_H__ */
diff --git a/ubi-utils/old-tools/src/crc32.c b/ubi-utils/old-tools/src/crc32.c
deleted file mode 100644 (file)
index 666e217..0000000
+++ /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/old-tools/src/crc32.h b/ubi-utils/old-tools/src/crc32.h
deleted file mode 100644 (file)
index 31362b0..0000000
+++ /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/old-tools/src/ecclayouts.h b/ubi-utils/old-tools/src/ecclayouts.h
deleted file mode 100644 (file)
index a1c7823..0000000
+++ /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/old-tools/src/libubigen.c b/ubi-utils/old-tools/src/libubigen.c
deleted file mode 100644 (file)
index d2cd087..0000000
+++ /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/old-tools/src/ubiupdate.c b/ubi-utils/old-tools/src/ubiupdate.c
deleted file mode 100644 (file)
index 75222d4..0000000
+++ /dev/null
@@ -1,318 +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 update UBI volumes.
- *
- * Authors: Frank Haverkamp
- *          Joshua W. Boyer
- *          Artem Bityutskiy
- */
-
-#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/stat.h>
-
-#include <libubi.h>
-#include "common.h"
-
-#define PROGRAM_VERSION "1.3"
-#define PROGRAM_NAME    "ubiupdate"
-
-struct args {
-       int truncate;
-       const char *node;
-       const char *img;
-};
-
-static struct args myargs = {
-       .truncate = 0,
-       .node = NULL,
-       .img = NULL,
-};
-
-static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
-                        " - a tool to write data to UBI volumes.";
-
-static const char *optionsstr =
-"-n, --vol_id=<volume id>   ID of UBI volume to update\n"
-"-t, --truncate             truncate volume (wipe it out)\n"
-"-h, --help                 print help message\n"
-"-V, --version              print program version";
-
-static const char *usage =
-"Usage: " PROGRAM_NAME " <UBI volume node file name> [-t] [-h] [-V] [--truncate] [--help]\n"
-"\t\t[--version] <image file>\n\n"
-"Example 1: " PROGRAM_NAME " /dev/ubi0_1 fs.img - write file \"fs.img\" to UBI volume /dev/ubi0_1\n"
-"Example 2: " PROGRAM_NAME " /dev/ubi0_1 -t - wipe out UBI volume /dev/ubi0_1";
-
-struct option long_options[] = {
-       { .name = "truncate", .has_arg = 0, .flag = NULL, .val = 't' },
-       { .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;
-
-               key = getopt_long(argc, argv, "n:thV", long_options, NULL);
-               if (key == -1)
-                       break;
-
-               switch (key) {
-               case 't':
-                       myargs.truncate = 1;
-                       break;
-
-               case 'h':
-                       fprintf(stderr, "%s\n\n", doc);
-                       fprintf(stderr, "%s\n\n", usage);
-                       fprintf(stderr, "%s\n", optionsstr);
-                       exit(0);
-
-               case 'V':
-                       fprintf(stderr, "%s\n", PROGRAM_VERSION);
-                       exit(0);
-
-               case ':':
-                       errmsg("parameter is missing");
-                       return -1;
-
-               default:
-                       fprintf(stderr, "Use -h for help\n");
-                       exit(-1);
-               }
-       }
-
-       if (optind == argc) {
-               errmsg("UBI device name was not specified (use -h for help)");
-               return -1;
-       } else if (optind != argc - 2) {
-               errmsg("specify UBI device name and image file name as first 2 "
-                      "parameters (use -h for help)");
-               return -1;
-       }
-
-       myargs.node = argv[optind];
-       myargs.img  = argv[optind + 1];
-
-       return 0;
-}
-
-static int truncate_volume(libubi_t libubi)
-{
-       int err, fd;
-
-       fd = open(myargs.node, O_RDWR);
-       if (fd == -1) {
-               errmsg("cannot open \"%s\"", myargs.node);
-               perror("open");
-               return -1;
-       }
-
-       err = ubi_update_start(libubi, fd, 0);
-       if (err) {
-               errmsg("cannot truncate volume \"%s\"", myargs.node);
-               perror("ubi_update_start");
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-static int ubi_write(int fd, const void *buf, int len)
-{
-       int ret;
-
-       while (len) {
-               ret = write(fd, buf, len);
-               if (ret < 0) {
-                       if (errno == EINTR) {
-                               warnmsg("do not interrupt me!");
-                               continue;
-                       }
-                       errmsg("cannot write %d bytes to volume \"%s\"",
-                              len, myargs.node);
-                       perror("write");
-                       return -1;
-               }
-
-               if (ret == 0) {
-                       errmsg("cannot write %d bytes to volume \"%s\"",
-                              len, myargs.node);
-                       return -1;
-               }
-
-               len -= ret;
-               buf += ret;
-       }
-
-       return 0;
-}
-
-static int update_volume(libubi_t libubi, struct ubi_vol_info *vol_info)
-{
-       int err, fd, ifd;
-       long long bytes;
-       struct stat st;
-       char *buf;
-
-       buf = malloc(vol_info->leb_size);
-       if (!buf) {
-               errmsg("cannot allocate %d bytes of memory", vol_info->leb_size);
-               return -1;
-       }
-
-       err = stat(myargs.img, &st);
-       if (err < 0) {
-               errmsg("stat failed on \"%s\"", myargs.node);
-               goto out_free;
-       }
-
-       bytes = st.st_size;
-       if (bytes > vol_info->rsvd_bytes) {
-               errmsg("\"%s\" (size %lld) will not fit volume \"%s\" (size %lld)",
-                      myargs.img, bytes, myargs.node, vol_info->rsvd_bytes);
-               goto out_free;
-       }
-
-       fd = open(myargs.node, O_RDWR);
-       if (fd == -1) {
-               errmsg("cannot open UBI volume \"%s\"", myargs.node);
-               perror("open");
-               goto out_free;
-       }
-
-       ifd = open(myargs.img, O_RDONLY);
-       if (ifd == -1) {
-               errmsg("cannot open \"%s\"", myargs.img);
-               perror("open");
-               goto out_close1;
-       }
-
-       err = ubi_update_start(libubi, fd, bytes);
-       if (err) {
-               errmsg("cannot start volume \"%s\" update", myargs.node);
-               perror("ubi_update_start");
-               goto out_close;
-       }
-
-       while (bytes) {
-               int tocopy = vol_info->leb_size;
-
-               if (tocopy > bytes)
-                       tocopy = bytes;
-
-               err = read(ifd, buf, tocopy);
-               if (err != tocopy) {
-                       if (errno == EINTR) {
-                               warnmsg("do not interrupt me!");
-                               continue;
-                       } else {
-                               errmsg("cannot read %d bytes from \"%s\"",
-                                      tocopy, myargs.img);
-                               perror("read");
-                               goto out_close;
-                       }
-               }
-
-               err = ubi_write(fd, buf, tocopy);
-               if (err)
-                       goto out_close;
-               bytes -= tocopy;
-       }
-
-       close(ifd);
-       close(fd);
-       free(buf);
-       return 0;
-
-out_close:
-       close(ifd);
-out_close1:
-       close(fd);
-out_free:
-       free(buf);
-       return -1;
-}
-
-int main(int argc, char * const argv[])
-{
-       int err;
-       libubi_t libubi;
-       struct ubi_vol_info vol_info;
-
-       err = parse_opt(argc, argv);
-       if (err)
-               return -1;
-
-       if (!myargs.img && !myargs.truncate) {
-               errmsg("incorrect arguments, use -h for help");
-               return -1;
-       }
-
-       libubi = libubi_open();
-       if (libubi == NULL) {
-               perror("Cannot open libubi");
-               goto out_libubi;
-       }
-
-       err = ubi_node_type(libubi, myargs.node);
-       if (err == 1) {
-               errmsg("\"%s\" is an UBI device node, not an UBI volume node",
-                      myargs.node);
-               goto out_libubi;
-       } else if (err < 0) {
-               errmsg("\"%s\" is not an UBI volume node", myargs.node);
-               goto out_libubi;
-       }
-
-       err = ubi_get_vol_info(libubi, myargs.node, &vol_info);
-       if (err) {
-               errmsg("cannot get information about UBI volume \"%s\"",
-                      myargs.node);
-               perror("ubi_get_dev_info");
-               goto out_libubi;
-       }
-
-       if (myargs.truncate)
-               err = truncate_volume(libubi);
-       else
-               err = update_volume(libubi, &vol_info);
-       if (err)
-               goto out_libubi;
-
-       libubi_close(libubi);
-       return 0;
-
-out_libubi:
-       libubi_close(libubi);
-       return -1;
-}
similarity index 92%
rename from ubi-utils/old-tools/scripts/f128_nand_sample.cfg
rename to ubi-utils/perl/f128_nand_sample.cfg
index bb6260062d27fe8d2aea68a1b884fa551839dbf8..e468d9d03c3973a407db44602b071929b43d8f91 100644 (file)
@@ -3,10 +3,10 @@ complete=ipl,spl,bootenv,kernel,rootfs
 bootcode=spl,bootenv
 
 # Build sections
-[ipl]
+[ipl] 
 image=ipl.bin
 raw_starts=0x00000000
-raw_total_size=128kiB
+raw_total_size=128kiB 
 
 [spl]
 image=u-boot.bin
@@ -33,6 +33,6 @@ ubi_names=kernel_0,kernel_1
 image=rootfs.bin
 ubi_ids=8,9
 ubi_alignment=2kiB
-ubi_size=16MiB
+ubi_size=16MiB 
 ubi_type=dynamic
 ubi_names=rootfs_0,rootfs_1
similarity index 91%
rename from ubi-utils/old-tools/scripts/f64_nor_sample.cfg
rename to ubi-utils/perl/f64_nor_sample.cfg
index 889d4c2138b85cd568f187768230d21b9b1b0f83..fd44e2773c0818e25fd2234504cedc0a17369e07 100644 (file)
@@ -4,10 +4,10 @@ bootcode=spl,bootenv
 rootfs=rootfs
 
 # Build sections
-[ipl]
+[ipl] 
 image=ipl.bin
 raw_starts=0x02FE0000, 0x03FE0000
-raw_total_size=128kiB
+raw_total_size=128kiB 
 
 [spl]
 image=u-boot.bin
@@ -34,6 +34,6 @@ ubi_names=kernel_0,kernel_1
 image=rootfs.bin
 ubi_ids=8,9
 ubi_alignment=2kiB
-ubi_size=16128kiB
+ubi_size=16128kiB 
 ubi_type=dynamic
 ubi_names=rootfs_0,rootfs_1
old mode 100644 (file)
new mode 100755 (executable)
similarity index 100%
rename from ubi-utils/old-tools/scripts/mkpfi
rename to ubi-utils/perl/mkpfi
old mode 100644 (file)
new mode 100755 (executable)
similarity index 99%
rename from ubi-utils/old-tools/scripts/ubicrc32.pl
rename to ubi-utils/perl/ubicrc32.pl
index 92711cb..add5f9d
@@ -62,7 +62,7 @@ sub crc32_on_file
            my $file;
            open $file, "<", $path
                or die "Error opening '$path'.\n";
-
+           
            &crc32_on_file($file)
                or die "Error reading from '$path'.\n";
            close $file;
similarity index 70%
rename from ubi-utils/old-tools/scripts/Makefile
rename to ubi-utils/scripts/Makefile
index b8e3c961ac39c235c3b705899f1e798aef6b5d1d..ebd9bc6c083b3ae2450f4450f33db243bd66dbe7 100644 (file)
@@ -39,23 +39,7 @@ 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
+all: $(compl_pfi) $(compl_nand2048_mif)
 
 $(compl_pfi): $(vmlinux_bin) $(rootfs_bin) $(spl_bin)
        $(mkpfi) -c $(mkpfi_cfg)
@@ -85,7 +69,7 @@ $(vmlinux_bin) $(rootfs_bin) $(spl_bin):
        $(dd) if=/dev/urandom of=$@ bs=1M count=1
 
 clean:
-       $(RM) *.pfi *~ testblock* oob.bin
+       $(RM) *.pfi *~
 
 distclean: clean
        $(RM) *.bin *.mif *.oob *.img
similarity index 78%
rename from ubi-utils/old-tools/scripts/README
rename to ubi-utils/scripts/README
index 01c74531ea7adaeb9c06657ae257795ea379b7ce..899b4a18f6c1616ed8d3393a76f1c5d799fbd318 100644 (file)
@@ -9,6 +9,3 @@ We should try not forget to run these tests before we release
 a new version of UBI.
 
 Frank
-
-Please guys, clean up this and move the tests to mtd-utils/tests/
-Artem.
diff --git a/ubi-utils/scripts/TODO b/ubi-utils/scripts/TODO
new file mode 100644 (file)
index 0000000..f093e77
--- /dev/null
@@ -0,0 +1,5 @@
+TODO
+====
+
+ * Range checking is broken, reserving 2M and offering 3M binary data
+   ... works!? No!
similarity index 80%
rename from ubi-utils/old-tools/scripts/bin2nand2bin_test.sh
rename to ubi-utils/scripts/bin2nand2bin_test.sh
index 51f048cc58b0313b9e2524a8576fa8e694ea7551..a17c91bf0134d9fc210cade971d37ba207e3007f 100644 (file)
@@ -1,8 +1,5 @@
 #!/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.
 #
 #    bin -> bin2nand -> mif -> nand2bin -> img
 #
 
-inject_biterror=./inject_biterror.pl
+inject_biterror=./scripts/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 "Test conversion without bitflips ..."
 
 echo -n "Convert bin to mif ... "
 bin2nand --pagesize=${pagesize} -o testblock.mif testblock.bin
@@ -77,7 +44,7 @@ else
     echo "ok"
 fi
 
-echo "*** Test conversion with uncorrectable ECC erors ..."
+echo "Test conversion with uncorrectable ECC erors ..."
 echo -n "Inject biterror at offset $ioffs ... "
 ${inject_biterror} --offset=0 --bitmask=0x81 \
     --input=testblock.mif \
@@ -109,7 +76,7 @@ else
     exit 1
 fi
 
-echo "*** Test bitflips in data ... "
+echo "Test bitflips in data ... "
 for offs in `seq 0 255` ; do
 
     cp testblock.mif testblock_bitflip.mif
@@ -175,7 +142,7 @@ for offs in `seq 0 255` ; do
     fi
 done
 
-echo "*** Test bitflips in OOB data ... "
+echo "Test bitflips in OOB data ... "
 for offs in `seq 0 $oobsize` ; do
 
     let ioffs=$pagesize+$offs
@@ -214,3 +181,4 @@ for offs in `seq 0 $oobsize` ; do
        echo "ok"
     fi
 done
+
similarity index 89%
rename from tests/ubi-tests/ubi_jffs2_test.sh
rename to ubi-utils/scripts/ubi_jffs2_test.sh
index a6172babac6a23da571b9f52e29cd0cae7b9b3b5..883903dbee3ea18052c2bd9dd3d274ec44c9f50b 100755 (executable)
 #     Tue Oct 31 14:14:54 CET 2006
 #
 
-# Make sure we have UBI utilities in the PATH
-export PATH=../../ubi-utils:$PATH
-
 VERSION="1.1"
+
+export PATH=$PATH:/bin:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/
+
 ITERATIONS=250
 ALIGNMENT=2048
 
-UBIMKVOL="ubimkvol"
-UBIRMVOL="ubirmvol"
-# This test script uses special program to update volumes
-UBIUPDATEVOL="helpers/ubiupdatevol"
+UBIMKVOL="ubimkvol -a $ALIGNMENT"
+UBIRMVOL=ubirmvol
+UBIUPDATEVOL=ubiupdatevol
 
 SIZE_512K=524288
 SIZE_1M=1310720
@@ -91,11 +90,23 @@ fix_sysfs_issue ()
 }
 
 #
-# Wait for while udev creates device nodes
+# FIXME Udev needs some time until the device nodes are created.
+#       This will cause trouble if after ubimkvol an update attempt
+#       is started immediately, since the device node is not yet
+#       available. We should either fix the tools with inotify or
+#       other ideas or figure out a different way to solve the problem
+#       e.g. to use ubi0 and make the volume device nodes obsolete...
 #
 udev_wait ()
 {
-       udevsettle || sleep 2;
+    echo -n "FIXME Waiting for udev to create/delete device node "
+    grep 2\.6\.5 /proc/version > /dev/null
+    if [ $? -eq "0" ]; then
+       for i in `seq 0 5`; do
+           sleep 1; echo -n ".";
+       done
+       echo " ok"
+    fi
 }
 
 # delete_volume - Delete a volume. If it does not exist, do not try
@@ -120,7 +131,7 @@ delete_volume ()
        passed
 
        echo -n "*** Delete volume if it exists ... "
-       $UBIRMVOL $UBI_DEVICE -n$volume
+       $UBIRMVOL -d0 -n$volume
        if [ $? -ne "0" ] ; then
            exit_failure
        fi
@@ -148,8 +159,8 @@ writevol_test ()
     delete_volume $volume
 
     echo "*** Try to create volume"
-    echo "    $UBIMKVOL $UBI_DEVICE -a $ALIGNMENT -n$volume -t$type -NNEW$volume -s $size ... "
-    $UBIMKVOL $UBI_DEVICE -n$volume -t$type -N"NEW$volume" -s $size
+    echo "    $UBIMKVOL -d0 -n$volume -t$type -NNEW$volume -s $size ... "
+    $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size
     if [ $? -ne "0" ] ; then
        exit_failure
     fi
@@ -158,7 +169,7 @@ writevol_test ()
 
 ### Try to create same volume again
     echo -n "*** Try to create some volume again, this must fail ... "
-    $UBIMKVOL $UBI_DEVICE -a $ALIGNMENT -n$volume -t$type -N"NEW$volume" -s $size
+    $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size
     if [ $? -eq "0" ] ; then
        exit_failure
     fi
@@ -373,13 +384,6 @@ if [ $? -ne "0" ]; then
     exit_failure
 fi
 
-if [ "x$1" == "x" ]; then
-       echo "Please, specify ubi device to test, e.g., $0 /dev/ubi0";
-       exit_failure;
-fi
-
-UBI_DEVICE=$1
-
 # Set to zero if not running on example hardware
 grep 1142 /proc/cpuinfo > /dev/null
 if [ $? -eq "0" ]; then
similarity index 68%
rename from ubi-utils/old-tools/src/bin2nand.c
rename to ubi-utils/src/bin2nand.c
index 83f50cc06699151771a0618937bbb165a50220a7..c7c7ccc8bbe41cb80c08b0c5c2fcaa0c5941bd37 100644 (file)
@@ -28,8 +28,7 @@
  * 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)
+ * 1.6 written variable not initialized (-j did not work) (haver)
  */
 
 #include <unistd.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 PROGRAM_VERSION "1.6"
 
 #define CHECK_ENDP(option, endp) do {                  \
        if (*endp) {                                    \
@@ -78,9 +74,8 @@ static char doc[] = "\nVersion: " PROGRAM_VERSION "\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"
+"  -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"
@@ -99,33 +94,30 @@ struct option long_options[] = {
        { .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";
+static const char copyright [] __attribute__((unused)) =
+       "Copyright IBM Corp. 2006";
 
-struct args {
+typedef struct myargs {
        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;
+       char *file_out_data; /* Either: Data and OOB interleaved
+                               or plain data */
+       char *file_out_oob; /* OOB Data only. */
 
        /* special stuff needed to get additional arguments */
        char *arg1;
        char **options;                 /* [STRING...] */
-};
+} myargs;
 
 
 static int ustrtoull(const char *cp, char **endp, unsigned int base)
@@ -148,53 +140,49 @@ static int ustrtoull(const char *cp, char **endp, unsigned int base)
 }
 
 static int
-parse_opt(int argc, char **argv, struct args *args)
+parse_opt(int argc, char **argv, myargs *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);
+               key = getopt_long(argc, argv, "cj: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);
+                       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 '?': /* help */
+                               printf("%s", doc);
+                               printf("%s", 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);
                }
        }
 
@@ -206,55 +194,46 @@ parse_opt(int argc, char **argv, struct args *args)
                }
        }
 
-       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)
+process_page(uint8_t* buf, size_t pagesize,
+       FILE *fp_data, FILE* fp_oob, size_t* written)
 {
-       int eccpoi;
+       int eccpoi, oobsize;
        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];
+
+       switch(pagesize) {
+       case 2048: oobsize = 64; eccpoi = 64 / 2; break;
+       case 512:  oobsize = 16; eccpoi = 16 / 2; break;
+       default:
+               err_msg("Unsupported page size: %d\n", pagesize);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < pagesize; i += 256, eccpoi += 3) {
+               oobbuf[eccpoi++] = 0x0;
+               /* Calculate ECC */
+               nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]);
        }
 
        /* write data */
-       *written += fwrite(buf, 1, args->pagesize, fp_data);
+       *written += fwrite(buf, 1, pagesize, fp_data);
 
        /* either separate oob or interleave with data */
        if (fp_oob) {
-               i = fwrite(oobbuf, 1, args->oobsize, fp_oob);
+               i = fwrite(oobbuf, 1, oobsize, fp_oob);
                if (ferror(fp_oob)) {
                        err_msg("IO error\n");
                        return -EIO;
                }
        }
        else {
-               i = fwrite(oobbuf, 1, args->oobsize, fp_data);
+               i = fwrite(oobbuf, 1, oobsize, fp_data);
                if (ferror(fp_data)) {
                        err_msg("IO error\n");
                        return -EIO;
@@ -269,14 +248,13 @@ int main (int argc, char** argv)
        int rc = -1;
        int res = 0;
        size_t written = 0, read;
-       struct args args = {
+       myargs 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;
@@ -328,16 +306,16 @@ int main (int argc, char** argv)
                        goto err;
                }
 
-               res = process_page(&args, buf, fp_out_data, fp_out_oob,
-                                  &written);
+               res = process_page(buf, args.pagesize, 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);
+               res = process_page(buf, args.pagesize, fp_out_data,
+                               fp_out_oob, &written);
                if (res != 0)
                        goto err;
        }
index 6b1e50c42d9b646c4eba4d591bfb4b0941ac3c17..666e2171f83dd8ac3e1da989c2b3bf8246395e9e 100644 (file)
@@ -1,95 +1,83 @@
 /*
- *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
- *  code or tables extracted from it, as desired without restriction.
+ * Copyright (c) International Business Machines Corp., 2006
  *
- *  First, the polynomial itself and its table of feedback terms.  The
- *  polynomial is
- *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ * 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.
  *
- *  Note that we take it "backwards" and put the highest-order term in
- *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
- *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
- *  the MSB being 1
+ * 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.
  *
- *  Note that the usual hardware shift register implementation, which
- *  is what we're using (we're merely optimizing it by doing eight-bit
- *  chunks at a time) shifts bits into the lowest-order term.  In our
- *  implementation, that means shifting towards the right.  Why do we
- *  do it this way?  Because the calculated CRC must be transmitted in
- *  order from highest-order term to lowest-order term.  UARTs transmit
- *  characters in order from LSB to MSB.  By storing the CRC this way
- *  we hand it to the UART in the order low-byte to high-byte; the UART
- *  sends each low-bit to hight-bit; and the result is transmission bit
- *  by bit from highest- to lowest-order term without requiring any bit
- *  shuffling on our part.  Reception works similarly
+ * 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.
  *
- *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ * Author: Thomas Gleixner
+ */
+
+/*
+ * CRC32 functions
  *
- *      The table can be generated at runtime if desired; code to do so
- *      is shown later.  It might not be obvious, but the feedback
- *      terms simply represent the results of eight shift/xor opera
- *      tions for all combinations of data and CRC register values
+ * 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.
  *
- *      The values must be right-shifted by eight bits by the "updcrc
- *      logic; the shift must be unsigned (bring in zeroes).  On some
- *      hardware you could probably optimize the shift in assembler by
- *      using byte-swap instructions
- *      polynomial $edb88320
  */
 
 #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;
 
-const uint32_t crc32_table[256] = {
-       0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
-       0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
-       0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
-       0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
-       0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
-       0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
-       0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
-       0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
-       0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
-       0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
-       0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
-       0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
-       0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
-       0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
-       0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
-       0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
-       0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
-       0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
-       0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
-       0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
-       0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
-       0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
-       0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
-       0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
-       0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
-       0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
-       0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
-       0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
-       0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
-       0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
-       0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
-       0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
-       0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
-       0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
-       0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
-       0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
-       0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
-       0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
-       0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
-       0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
-       0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
-       0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
-       0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
-       0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
-       0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
-       0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
-       0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
-       0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
-       0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
-       0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
-       0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
-       0x2d02ef8dL
-};
+       while(--len >= 0)
+               crc = table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+       return crc;
+}
index ee3145bc1597a05344c694d9bc3ba6639086a36f..31362b0944c15c0104f1c0d5ad1cc8c5e0181394 100644 (file)
@@ -1,19 +1,36 @@
-#ifndef CRC32_H
-#define CRC32_H
+#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>
 
-extern const uint32_t crc32_table[256];
+void init_crc32_table(uint32_t *table);
+uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len);
 
-/* Return a 32-bit CRC of the contents of the buffer. */
-
-       static inline uint32_t
-crc32(uint32_t val, const void *ss, int len)
-{
-       const unsigned char *s = ss;
-       while (--len >= 0)
-               val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
-       return val;
-}
-
-#endif
+#endif /* __CRC32_H__ */
index b53f18c0db92d3c41cd82d9f35cdc8cc4ffe4eb7..a028fc6dde7aca2e2464e34484fb0ebdb9d5379d 100644 (file)
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <dirent.h>
+#include <errno.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <limits.h>
 #include "libubi.h"
 #include "libubi_int.h"
 
-/**
- * mkpath - compose full path from 2 given components.
- * @path: the first component
- * @name: the second component
- *
- * This function returns the resulting path in case of success and %NULL in
- * case of failure.
- */
-static char *mkpath(const char *path, const char *name)
-{
-       char *n;
-       int len1 = strlen(path);
-       int len2 = strlen(name);
-
-       n = malloc(len1 + len2 + 2);
-       if (!n) {
-               sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2);
-               return NULL;
-       }
-
-       memcpy(n, path, len1);
-       if (n[len1 - 1] != '/')
-               n[len1++] = '/';
-
-       memcpy(n + len1, name, len2 + 1);
-       return n;
-}
-
-/**
- * read_positive_ll - read a positive 'long long' value from a file.
- * @file: the file to read from
- * @value: the result is stored here
- *
- * This function reads file @file and interprets its contents as a positive
- * 'long long' integer. If this is not true, it fails with %EINVAL error code.
- * Returns %0 in case of success and %-1 in case of failure.
- */
-static int read_positive_ll(const char *file, long long *value)
-{
-       int fd, rd;
-       char buf[50];
-
-       fd = open(file, O_RDONLY);
-       if (fd == -1)
-               return -1;
-
-       rd = read(fd, buf, 50);
-       if (rd == -1) {
-               sys_errmsg("cannot read \"%s\"", file);
-               goto out_error;
-       }
-       if (rd == 50) {
-               errmsg("contents of \"%s\" is too long", file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (sscanf(buf, "%lld\n", value) != 1) {
-               /* This must be a UBI bug */
-               errmsg("cannot read integer from \"%s\"\n", file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (*value < 0) {
-               errmsg("negative value %lld in \"%s\"", *value, file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (close(fd))
-               return sys_errmsg("close failed on \"%s\"", file);
-
-       return 0;
-
-out_error:
-       close(fd);
-       return -1;
-}
-
-/**
- * read_positive_int - read a positive 'int' value from a file.
- * @file: the file to read from
- * @value: the result is stored here
- *
- * This function is the same as 'read_positive_ll()', but it reads an 'int'
- * value, not 'long long'.
- */
-static int read_positive_int(const char *file, int *value)
-{
-       long long res;
-
-       if (read_positive_ll(file, &res))
-               return -1;
-
-       /* Make sure the value is not too big */
-       if (res > INT_MAX) {
-               errmsg("value %lld read from file \"%s\" is out of range",
-                      res, file);
-               errno = EINVAL;
-               return -1;
-       }
-
-       *value = res;
-       return 0;
-}
-
-/**
- * read_data - read data from a file.
- * @file: the file to read from
- * @buf: the buffer to read to
- * @buf_len: buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure. Note, if the file contains more then @buf_len bytes of
- * date, this function fails with %EINVAL error code.
- */
-static int read_data(const char *file, void *buf, int buf_len)
-{
-       int fd, rd, tmp, tmp1;
-
-       fd = open(file, O_RDONLY);
-       if (fd == -1)
-               return -1;
-
-       rd = read(fd, buf, buf_len);
-       if (rd == -1) {
-               sys_errmsg("cannot read \"%s\"", file);
-               goto out_error;
-       }
-
-       /* Make sure all data is read */
-       tmp1 = read(fd, &tmp, 1);
-       if (tmp1 == 1) {
-               sys_errmsg("cannot read \"%s\"", file);
-               goto out_error;
-       }
-       if (tmp1) {
-               errmsg("file \"%s\" contains too much data (> %d bytes)",
-                      file, buf_len);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (close(fd)) {
-               sys_errmsg("close failed on \"%s\"", file);
-               return -1;
-       }
-
-       return rd;
-
-out_error:
-       close(fd);
-       return -1;
-}
-
-/**
- * read_major - read major and minor numbers from a file.
- * @file: name of the file to read from
- * @major: major number is returned here
- * @minor: minor number is returned here
- *
- * This function returns % in case of succes, and %-1 in case of failure.
- */
-static int read_major(const char *file, int *major, int *minor)
-{
-       int ret;
-       char buf[50];
-
-       ret = read_data(file, buf, 50);
-       if (ret < 0)
-               return ret;
-
-       ret = sscanf(buf, "%d:%d\n", major, minor);
-       if (ret != 2) {
-               errno = EINVAL;
-               return errmsg("\"%s\" does not have major:minor format", file);
-       }
-
-       if (*major < 0 || *minor < 0) {
-               errno = EINVAL;
-               return errmsg("bad major:minor %d:%d in \"%s\"",
-                             *major, *minor, file);
-       }
-
-       return 0;
-}
-
-/**
- * dev_read_int - read a positive 'int' value from an UBI device sysfs file.
- * @patt: file pattern to read from
- * @dev_num:  UBI device number
- * @value: the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_int(const char *patt, int dev_num, int *value)
-{
-       char file[strlen(patt) + 50];
-
-       sprintf(file, patt, dev_num);
-       return read_positive_int(file, value);
-}
-
-/**
- * vol_read_int - read a positive 'int' value from an UBI volume sysfs file.
- * @patt: file pattern to read from
- * @dev_num: UBI device number
- * @vol_id: volume ID
- * @value: the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
-{
-       char file[strlen(patt) + 100];
-
-       sprintf(file, patt, dev_num, vol_id);
-       return read_positive_int(file, value);
-}
-
-/**
- * dev_read_ll - read a positive 'long long' value from an UBI device sysfs file.
- * @patt: file pattern to read from
- * @dev_num: UBI device number
- * @value: the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_ll(const char *patt, int dev_num, long long *value)
-{
-       char file[strlen(patt) + 50];
-
-       sprintf(file, patt, dev_num);
-       return read_positive_ll(file, value);
-}
-
-/**
- * vol_read_ll - read a positive 'long long' value from an UBI volume sysfs file.
- * @patt: file pattern to read from
- * @dev_num: UBI device number
- * @vol_id: volume ID
- * @value: the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int vol_read_ll(const char *patt, int dev_num, int vol_id,
-                      long long *value)
-{
-       char file[strlen(patt) + 100];
-
-       sprintf(file, patt, dev_num, vol_id);
-       return read_positive_ll(file, value);
-}
-
-/**
- * vol_read_data - read data from an UBI volume's sysfs file.
- * @patt: file pattern to read from
- * @dev_num: UBI device number
- * @vol_id: volume ID
- * @buf: buffer to read to
- * @buf_len: buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure.
- */
-static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
-                        int buf_len)
-{
-       char file[strlen(patt) + 100];
-
-       sprintf(file, patt, dev_num, vol_id);
-       return read_data(file, buf, buf_len);
-}
-
-/**
- * dev_get_major - get major and minor numbers of an UBI device.
- * @lib: libubi descriptor
- * @dev_num: UBI device number
- * @major: major number is returned here
- * @minor: minor number is returned here
- *
- * This function returns zero in case of succes and %-1 in case of failure.
- */
-static int dev_get_major(struct libubi *lib, int dev_num, int *major, int *minor)
-{
-       char file[strlen(lib->dev_dev) + 50];
-
-       sprintf(file, lib->dev_dev, dev_num);
-       return read_major(file, major, minor);
-}
-
-/**
- * vol_get_major - get major and minor numbers of an UBI volume.
- * @lib: libubi descriptor
- * @dev_num: UBI device number
- * @vol_id: volume ID
- * @major: major number is returned here
- * @minor: minor number is returned here
- *
- * This function returns zero in case of succes and %-1 in case of failure.
- */
-static int vol_get_major(struct libubi *lib, int dev_num, int vol_id,
-                        int *major, int *minor)
-{
-       char file[strlen(lib->vol_dev) + 100];
-
-       sprintf(file, lib->vol_dev, dev_num, vol_id);
-       return read_major(file, major, minor);
-}
-
-/**
- * vol_node2nums - find UBI device number and volume ID by volume device node
- *                 file.
- * @lib: UBI library descriptor
- * @node: UBI character device node name
- * @dev_num: UBI device number is returned here
- * @vol_id: volume ID is returned hers
- *
- * This function returns zero in case of succes and %-1 in case of failure.
- */
-static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num,
-                        int *vol_id)
-{
-       struct stat st;
-       struct ubi_info info;
-       int i, fd, major, minor;
-       char file[strlen(lib->ubi_vol) + 100];
-
-       if (lstat(node, &st))
-               return -1;
-
-       if (!S_ISCHR(st.st_mode)) {
-               errno = EINVAL;
-               return errmsg("\"%s\" is not a character device", node);
-       }
-
-       major = major(st.st_rdev);
-       minor = minor(st.st_rdev);
-
-       if (minor == 0) {
-               errno = EINVAL;
-               return errmsg("\"%s\" is not a volume character device", node);
-       }
-
-       if (ubi_get_info((libubi_t *)lib, &info))
-               return -1;
-
-       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
-               int major1, minor1, ret;
-
-               ret = dev_get_major(lib, i, &major1, &minor1);
-               if (ret) {
-                       if (errno == ENOENT)
-                               continue;
-                       return -1;
-               }
-
-               if (major1 == major)
-                       break;
-       }
-
-       if (i > info.highest_dev_num) {
-               errno = ENODEV;
-               return -1;
-       }
-
-       /* Make sure this UBI volume exists */
-       sprintf(file, lib->ubi_vol, i, minor - 1);
-       fd = open(file, O_RDONLY);
-       if (fd == -1) {
-               errno = ENODEV;
-               return -1;
-       }
-
-       *dev_num = i;
-       *vol_id = minor - 1;
-       errno = 0;
-       return 0;
-}
-
-/**
- * dev_node2num - find UBI device number by its character device node.
- * @lib: UBI library descriptor
- * @node: UBI character device node name
- *
- * This function returns positive UBI device number in case of success and %-1
- * in case of failure.
- */
-static int dev_node2num(struct libubi *lib, const char *node, int *dev_num)
-{
-       struct stat stat;
-       struct ubi_info info;
-       int i, major, minor;
-
-       if (lstat(node, &stat))
-               return -1;
-
-       if (!S_ISCHR(stat.st_mode)) {
-               errno = EINVAL;
-               return errmsg("\"%s\" is not a character device", node);
-       }
-
-       major = major(stat.st_rdev);
-       minor = minor(stat.st_rdev);
-
-       if (minor != 0) {
-               errno = EINVAL;
-               return errmsg("\"%s\" is not an UBI character device", node);
-       }
-
-       if (ubi_get_info((libubi_t *)lib, &info))
-               return -1;
-
-       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
-               int major1, minor1, ret;
-
-               ret = dev_get_major(lib, i, &major1, &minor1);
-               if (ret) {
-                       if (errno == ENOENT)
-                               continue;
-                       return -1;
-               }
-
-               if (major1 == major) {
-                       if (minor1 != 0) {
-                               errmsg("UBI character device minor number is "
-                                      "%d, but must be 0", minor1);
-                               errno = EINVAL;
-                               return -1;
-                       }
-                       errno = 0;
-                       *dev_num = i;
-                       return 0;
-               }
-       }
-
-       errno = ENODEV;
-       return -1;
-}
-
-static int mtd_num2ubi_dev(struct libubi *lib, int mtd_num, int *dev_num)
-{
-       struct ubi_info info;
-       int i, ret, mtd_num1;
-
-       if (ubi_get_info((libubi_t *)lib, &info))
-               return -1;
-
-       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
-               ret = dev_read_int(lib->dev_mtd_num, i, &mtd_num1);
-               if (ret) {
-                       if (errno == ENOENT)
-                               continue;
-                       return -1;
-               }
-
-               if (mtd_num1 == mtd_num) {
-                       errno = 0;
-                       *dev_num = i;
-                       return 0;
-               }
-       }
-
-       errno = ENODEV;
-       return -1;
-}
-
 libubi_t libubi_open(void)
 {
        int fd, version;
@@ -513,130 +46,132 @@ libubi_t libubi_open(void)
        /* TODO: this must be discovered instead */
        lib->sysfs = strdup("/sys");
        if (!lib->sysfs)
-               goto out_error;
-
-       lib->sysfs_ctrl = mkpath(lib->sysfs, SYSFS_CTRL);
-       if (!lib->sysfs_ctrl)
-               goto out_error;
-
-       lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV);
-       if (!lib->ctrl_dev)
-               goto out_error;
+               goto error;
 
        lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI);
        if (!lib->sysfs_ubi)
-               goto out_error;
+               goto error;
 
        /* Make sure UBI is present */
        fd = open(lib->sysfs_ubi, O_RDONLY);
-       if (fd == -1) {
-               errmsg("cannot open \"%s\", UBI does not seem to exist in system",
-                      lib->sysfs_ubi);
-               goto out_error;
-       }
-
-       if (close(fd)) {
-               sys_errmsg("close failed on \"%s\"", lib->sysfs_ubi);
-               goto out_error;
-       }
+       if (fd == -1)
+               goto error;
+       close(fd);
 
        lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT);
        if (!lib->ubi_dev)
-               goto out_error;
+               goto error;
 
        lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER);
        if (!lib->ubi_version)
-               goto out_error;
+               goto error;
 
        lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV);
        if (!lib->dev_dev)
-               goto out_error;
+               goto error;
 
        lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS);
        if (!lib->dev_avail_ebs)
-               goto out_error;
+               goto error;
 
        lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS);
        if (!lib->dev_total_ebs)
-               goto out_error;
+               goto error;
 
        lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT);
        if (!lib->dev_bad_count)
-               goto out_error;
+               goto error;
 
        lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE);
        if (!lib->dev_eb_size)
-               goto out_error;
+               goto error;
 
        lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC);
        if (!lib->dev_max_ec)
-               goto out_error;
+               goto error;
 
        lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD);
        if (!lib->dev_bad_rsvd)
-               goto out_error;
+               goto error;
 
        lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS);
        if (!lib->dev_max_vols)
-               goto out_error;
+               goto error;
 
        lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE);
        if (!lib->dev_min_io_size)
-               goto out_error;
-
-       lib->dev_mtd_num = mkpath(lib->ubi_dev, DEV_MTD_NUM);
-       if (!lib->dev_mtd_num)
-               goto out_error;
+               goto error;
 
        lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT);
        if (!lib->ubi_vol)
-               goto out_error;
+               goto error;
 
        lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE);
        if (!lib->vol_type)
-               goto out_error;
+               goto error;
 
        lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV);
        if (!lib->vol_dev)
-               goto out_error;
+               goto error;
 
        lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT);
        if (!lib->vol_alignment)
-               goto out_error;
+               goto error;
 
        lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES);
        if (!lib->vol_data_bytes)
-               goto out_error;
+               goto error;
 
        lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS);
        if (!lib->vol_rsvd_ebs)
-               goto out_error;
+               goto error;
 
        lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE);
        if (!lib->vol_eb_size)
-               goto out_error;
+               goto error;
 
        lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED);
        if (!lib->vol_corrupted)
-               goto out_error;
+               goto error;
 
        lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
        if (!lib->vol_name)
-               goto out_error;
+               goto error;
 
-       if (read_positive_int(lib->ubi_version, &version))
-               goto out_error;
+       if (read_int(lib->ubi_version, &version))
+               goto error;
        if (version != LIBUBI_UBI_VERSION) {
                fprintf(stderr, "LIBUBI: this library was made for UBI version "
                                "%d, but UBI version %d is detected\n",
                        LIBUBI_UBI_VERSION, version);
-               goto out_error;
+               goto error;
        }
 
        return lib;
 
-out_error:
-       libubi_close((libubi_t)lib);
+error:
+       free(lib->vol_corrupted);
+       free(lib->vol_eb_size);
+       free(lib->vol_rsvd_ebs);
+       free(lib->vol_data_bytes);
+       free(lib->vol_alignment);
+       free(lib->vol_dev);
+       free(lib->vol_type);
+       free(lib->ubi_vol);
+       free(lib->dev_min_io_size);
+       free(lib->dev_max_vols);
+       free(lib->dev_bad_rsvd);
+       free(lib->dev_max_ec);
+       free(lib->dev_eb_size);
+       free(lib->dev_bad_count);
+       free(lib->dev_total_ebs);
+       free(lib->dev_avail_ebs);
+       free(lib->dev_dev);
+       free(lib->ubi_version);
+       free(lib->ubi_dev);
+       free(lib->sysfs_ubi);
+       free(lib->sysfs);
+       free(lib);
        return NULL;
 }
 
@@ -653,7 +188,6 @@ void libubi_close(libubi_t desc)
        free(lib->vol_dev);
        free(lib->vol_type);
        free(lib->ubi_vol);
-       free(lib->dev_mtd_num);
        free(lib->dev_min_io_size);
        free(lib->dev_max_vols);
        free(lib->dev_bad_rsvd);
@@ -666,478 +200,716 @@ void libubi_close(libubi_t desc)
        free(lib->ubi_version);
        free(lib->ubi_dev);
        free(lib->sysfs_ubi);
-       free(lib->ctrl_dev);
-       free(lib->sysfs_ctrl);
        free(lib->sysfs);
        free(lib);
 }
 
-int ubi_attach_mtd(libubi_t desc, const char *node,
-                  struct ubi_attach_request *req)
+int ubi_get_info(libubi_t desc, struct ubi_info *info)
+{
+       DIR *sysfs_ubi;
+       struct dirent *dirent;
+       struct libubi *lib = (struct libubi *)desc;
+
+       memset(info, '\0', sizeof(struct ubi_info));
+
+       /*
+        * We have to scan the UBI sysfs directory to identify how many UBI
+        * devices are present.
+        */
+       sysfs_ubi = opendir(lib->sysfs_ubi);
+       if (!sysfs_ubi)
+               return -1;
+
+       info->lowest_dev_num = INT_MAX;
+       while ((dirent = readdir(sysfs_ubi))) {
+               char *name = &dirent->d_name[0];
+               int dev_num, ret;
+
+               ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num);
+               if (ret == 1) {
+                       info->dev_count += 1;
+                       if (dev_num > info->highest_dev_num)
+                               info->highest_dev_num = dev_num;
+                       if (dev_num < info->lowest_dev_num)
+                               info->lowest_dev_num = dev_num;
+               }
+       }
+
+       if (info->lowest_dev_num == INT_MAX)
+               info->lowest_dev_num = 0;
+
+       if (read_int(lib->ubi_version, &info->version))
+               goto close;
+
+       return closedir(sysfs_ubi);
+
+close:
+       closedir(sysfs_ubi);
+       return -1;
+}
+
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
+{
+       int fd, ret;
+       struct ubi_mkvol_req r;
+       size_t n;
+
+       desc = desc;
+       r.vol_id = req->vol_id;
+       r.alignment = req->alignment;
+       r.bytes = req->bytes;
+       r.vol_type = req->vol_type;
+
+       n = strlen(req->name);
+       if (n > UBI_MAX_VOLUME_NAME)
+               return -1;
+
+       strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1);
+       r.name_len = n;
+
+       fd = open(node, O_RDONLY);
+       if (fd == -1)
+               return -1;
+
+       ret = ioctl(fd, UBI_IOCMKVOL, &r);
+       if (!ret)
+               req->vol_id = r.vol_id;
+
+       close(fd);
+       return ret;
+}
+
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
 {
        int fd, ret;
-       struct ubi_attach_req r;
-
-       memset(&r, sizeof(struct ubi_attach_req), '\0');
 
        desc = desc;
-       r.ubi_num = req->dev_num;
-       r.mtd_num = req->mtd_num;
-       r.vid_hdr_offset = req->vid_hdr_offset;
-
        fd = open(node, O_RDONLY);
        if (fd == -1)
                return -1;
 
-       ret = ioctl(fd, UBI_IOCATT, &r);
+       ret = ioctl(fd, UBI_IOCRMVOL, &vol_id);
        close(fd);
-       if (ret == -1)
-               return -1;
+       return ret;
+}
 
-       req->dev_num = r.ubi_num;
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
+{
+       int fd, ret;
+       struct ubi_rsvol_req req;
 
-#ifdef UDEV_SETTLE_HACK
-       if (system("udevsettle") == -1)
-               return -1;
-       if (system("udevsettle") == -1)
+       desc = desc;
+       fd = open(node, O_RDONLY);
+       if (fd == -1)
                return -1;
-#endif
 
+       req.bytes = bytes;
+       req.vol_id = vol_id;
+
+       ret = ioctl(fd, UBI_IOCRSVOL, &req);
+       close(fd);
        return ret;
 }
 
-int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num)
+int ubi_update_start(libubi_t desc, int fd, long long bytes)
+{
+       desc = desc;
+       if (ioctl(fd, UBI_IOCVOLUP, &bytes))
+               return -1;
+       return 0;
+}
+
+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
 {
-       int ret, ubi_dev;
+       int dev_num;
+       struct libubi *lib = (struct libubi *)desc;
 
-       ret = mtd_num2ubi_dev(desc, mtd_num, &ubi_dev);
-       if (ret == -1)
-               return ret;
+       dev_num = find_dev_num(lib, node);
+       if (dev_num == -1)
+               return -1;
 
-       return ubi_remove_dev(desc, node, ubi_dev);
+       return ubi_get_dev_info1(desc, dev_num, info);
 }
 
-int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev)
+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
 {
-       int fd, ret;
+       DIR *sysfs_ubi;
+       struct dirent *dirent;
+       struct libubi *lib = (struct libubi *)desc;
 
-       desc = desc;
+       memset(info, '\0', sizeof(struct ubi_dev_info));
+       info->dev_num = dev_num;
 
-       fd = open(node, O_RDONLY);
-       if (fd == -1)
+       sysfs_ubi = opendir(lib->sysfs_ubi);
+       if (!sysfs_ubi)
                return -1;
-       ret = ioctl(fd, UBI_IOCDET, &ubi_dev);
-       if (ret == -1)
-               goto out_close;
 
-#ifdef UDEV_SETTLE_HACK
-       if (system("udevsettle") == -1)
+       info->lowest_vol_num = INT_MAX;
+       while ((dirent = readdir(sysfs_ubi))) {
+               char *name = &dirent->d_name[0];
+               int vol_id, ret, devno;
+
+               ret = sscanf(name, UBI_VOL_NAME_PATT, &devno, &vol_id);
+               if (ret == 2 && devno == dev_num) {
+                       info->vol_count += 1;
+                       if (vol_id > info->highest_vol_num)
+                               info->highest_vol_num = vol_id;
+                       if (vol_id < info->lowest_vol_num)
+                               info->lowest_vol_num = vol_id;
+               }
+       }
+
+       closedir(sysfs_ubi);
+
+       if (info->lowest_vol_num == INT_MAX)
+               info->lowest_vol_num = 0;
+
+       if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs))
+               return -1;
+       if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs))
+               return -1;
+       if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
+               return -1;
+       if (dev_read_int(lib->dev_eb_size, dev_num, &info->eb_size))
+               return -1;
+       if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
+               return -1;
+       if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec))
+               return -1;
+       if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count))
+               return -1;
+       if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size))
                return -1;
-#endif
 
-out_close:
-       close(fd);
-       return ret;
+       info->avail_bytes = info->avail_ebs * info->eb_size;
+       info->total_bytes = info->total_ebs * info->eb_size;
+
+       return 0;
 }
 
-int ubi_node_type(libubi_t desc, const char *node)
+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
 {
-       struct stat st;
-       struct ubi_info info;
-       int i, fd, major, minor;
+       int vol_id, dev_num;
        struct libubi *lib = (struct libubi *)desc;
-       char file[strlen(lib->ubi_vol) + 100];
 
-       if (lstat(node, &st))
+       dev_num = find_dev_num_vol(lib, node);
+       if (dev_num == -1)
                return -1;
 
-       if (!S_ISCHR(st.st_mode)) {
-               errno = EINVAL;
+       vol_id = find_vol_num(lib, dev_num, node);
+       if (vol_id == -1)
                return -1;
-       }
-
-       major = major(st.st_rdev);
-       minor = minor(st.st_rdev);
 
-       if (ubi_get_info((libubi_t *)lib, &info))
-               return -1;
+       return ubi_get_vol_info1(desc, dev_num, vol_id, info);
+}
 
-       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
-               int major1, minor1, ret;
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+                     struct ubi_vol_info *info)
+{
+       int ret;
+       struct libubi *lib = (struct libubi *)desc;
+       char buf[50];
 
-               ret = dev_get_major(lib, i, &major1, &minor1);
-               if (ret) {
-                       if (errno == ENOENT)
-                               continue;
-                       return -1;
-               }
+       memset(info, '\0', sizeof(struct ubi_vol_info));
+       info->dev_num = dev_num;
+       info->vol_id = vol_id;
 
-               if (major1 == major)
-                       break;
-       }
+       ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50);
+       if (ret < 0)
+               return -1;
 
-       if (i > info.highest_dev_num) {
-               /*
-                * The character device node does not correspond to any
-                * existing UBI device or volume, but we do not want to return
-                * any error number in this case, to indicate the fact that it
-                * could be a UBI device/volume, but it doesn't.
-                */
-               errno = 0;
+       if (strncmp(&buf[0], "static\n", ret) == 0)
+               info->type = UBI_STATIC_VOLUME;
+       else if (strncmp(&buf[0], "dynamic\n", ret) == 0)
+               info->type = UBI_DYNAMIC_VOLUME;
+       else {
+               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+               errno = EINVAL;
                return -1;
        }
 
-       if (minor == 0)
-               return 1;
+       ret = vol_read_int(lib->vol_alignment, dev_num, vol_id,
+                          &info->alignment);
+       if (ret)
+               return -1;
+       ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id,
+                         &info->data_bytes);
+       if (ret)
+               return -1;
+       ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_ebs);
+       if (ret)
+               return -1;
+       ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->eb_size);
+       if (ret)
+               return -1;
+       ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
+                          &info->corrupted);
+       if (ret)
+               return -1;
+       info->rsvd_bytes = info->eb_size * info->rsvd_ebs;
 
-       /* This is supposdely an UBI volume device node */
-       sprintf(file, lib->ubi_vol, i, minor - 1);
-       fd = open(file, O_RDONLY);
-       if (fd == -1) {
-               errno = 0;
+       ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
+                           UBI_VOL_NAME_MAX + 2);
+       if (ret < 0)
                return -1;
-       }
 
-       return 2;
+       info->name[ret - 1] = '\0';
+       return 0;
 }
 
-int ubi_get_info(libubi_t desc, struct ubi_info *info)
+/**
+ * read_int - read an 'int' value from a file.
+ *
+ * @file   the file to read from
+ * @value  the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_int(const char *file, int *value)
 {
-       DIR *sysfs_ubi;
-       struct dirent *dirent;
-       struct libubi *lib = (struct libubi *)desc;
+       int fd, rd;
+       char buf[50];
 
-       memset(info, '\0', sizeof(struct ubi_info));
+       fd = open(file, O_RDONLY);
+       if (fd == -1)
+               return -1;
+
+       rd = read(fd, &buf[0], 50);
+       if (rd == -1)
+               goto error;
 
-       if (read_major(lib->ctrl_dev, &info->ctrl_major, &info->ctrl_minor)) {
-               /*
-                * Older UBI versions did not have control device, so we do not
-                * panic here for compatibility reasons. May be few years later
-                * we could return -1 here, but for now just set major:minor to
-                * -1.
-                */
-               info->ctrl_major = info->ctrl_minor = -1;
+       if (sscanf(&buf[0], "%d\n", value) != 1) {
+               /* This must be a UBI bug */
+               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+               errno = EINVAL;
+               goto error;
        }
 
-       /*
-        * We have to scan the UBI sysfs directory to identify how many UBI
-        * devices are present.
-        */
-       sysfs_ubi = opendir(lib->sysfs_ubi);
-       if (!sysfs_ubi)
-               return sys_errmsg("cannot open %s", lib->sysfs_ubi);
+       close(fd);
+       return 0;
 
-       info->lowest_dev_num = INT_MAX;
-       while (1) {
-               int dev_num, ret;
-               char tmp_buf[256];
+error:
+       close(fd);
+       return -1;
+}
 
-               errno = 0;
-               dirent = readdir(sysfs_ubi);
-               if (!dirent)
-                       break;
+/**
+ * dev_read_int - read an 'int' value from an UBI device's sysfs file.
+ *
+ * @patt     the file pattern to read from
+ * @dev_num  UBI device number
+ * @value    the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_int(const char *patt, int dev_num, int *value)
+{
+       int fd, rd;
+       char buf[50];
+       char file[strlen(patt) + 50];
 
-               if (strlen(dirent->d_name) > 256) {
-                       errmsg("invalid entry in %s: \"%s\"",
-                              lib->sysfs_ubi, dirent->d_name);
-                       goto out_close;
-               }
+       sprintf(&file[0], patt, dev_num);
+       fd = open(&file[0], O_RDONLY);
+       if (fd == -1)
+               return -1;
 
-               ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT"%s",
-                            &dev_num, tmp_buf);
-               if (ret == 1) {
-                       info->dev_count += 1;
-                       if (dev_num > info->highest_dev_num)
-                               info->highest_dev_num = dev_num;
-                       if (dev_num < info->lowest_dev_num)
-                               info->lowest_dev_num = dev_num;
-               }
-       }
+       rd = read(fd, &buf[0], 50);
+       if (rd == -1)
+               goto error;
 
-       if (!dirent && errno) {
-               sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
-               goto out_close;
+       if (sscanf(&buf[0], "%d\n", value) != 1) {
+               /* This must be a UBI bug */
+               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+               errno = EINVAL;
+               goto error;
        }
 
-       if (closedir(sysfs_ubi))
-               return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+       close(fd);
+       return 0;
 
-       if (info->lowest_dev_num == INT_MAX)
-               info->lowest_dev_num = 0;
+error:
+       close(fd);
+       return -1;
+}
+
+/**
+ * dev_read_ll - read a 'long long' value from an UBI device's sysfs file.
+ *
+ * @patt     the file pattern to read from
+ * @dev_num  UBI device number
+ * @value    the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_ll(const char *patt, int dev_num, long long *value)
+{
+       int fd, rd;
+       char buf[50];
+       char file[strlen(patt) + 50];
 
-       if (read_positive_int(lib->ubi_version, &info->version))
+       sprintf(&file[0], patt, dev_num);
+       fd = open(&file[0], O_RDONLY);
+       if (fd == -1)
                return -1;
 
+       rd = read(fd, &buf[0], 50);
+       if (rd == -1)
+               goto error;
+
+       if (sscanf(&buf[0], "%lld\n", value) != 1) {
+               /* This must be a UBI bug */
+               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+               errno = EINVAL;
+               goto error;
+       }
+
+       close(fd);
        return 0;
 
-out_close:
-       closedir(sysfs_ubi);
+error:
+       close(fd);
        return -1;
 }
 
-int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
+/**
+ * dev_read_data - read data from an UBI device's sysfs file.
+ *
+ * @patt     the file pattern to read from
+ * @dev_num  UBI device number
+ * @buf      buffer to read data to
+ * @buf_len  buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len)
 {
-       int fd, ret;
-       struct ubi_mkvol_req r;
-       size_t n;
-
-       memset(&r, sizeof(struct ubi_mkvol_req), '\0');
+       int fd, rd;
+       char file[strlen(patt) + 50];
 
-       desc = desc;
-       r.vol_id = req->vol_id;
-       r.alignment = req->alignment;
-       r.bytes = req->bytes;
-       r.vol_type = req->vol_type;
+       sprintf(&file[0], patt, dev_num);
+       fd = open(&file[0], O_RDONLY);
+       if (fd == -1)
+               return -1;
 
-       n = strlen(req->name);
-       if (n > UBI_MAX_VOLUME_NAME)
+       rd = read(fd, buf, buf_len);
+       if (rd == -1) {
+               close(fd);
                return -1;
+       }
 
-       strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1);
-       r.name_len = n;
+       close(fd);
+       return rd;
+}
+
+/**
+ * vol_read_int - read an 'int' value from an UBI volume's sysfs file.
+ *
+ * @patt     the file pattern to read from
+ * @dev_num  UBI device number
+ * @vol_id   volume identifier
+ * @value    the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
+{
+       int fd, rd;
+       char buf[50];
+       char file[strlen(patt) + 100];
 
-       fd = open(node, O_RDONLY);
+       sprintf(&file[0], patt, dev_num, vol_id);
+       fd = open(&file[0], O_RDONLY);
        if (fd == -1)
                return -1;
 
-       ret = ioctl(fd, UBI_IOCMKVOL, &r);
-       if (ret == -1)
-               goto out_close;
+       rd = read(fd, &buf[0], 50);
+       if (rd == -1)
+               goto error;
 
-       req->vol_id = r.vol_id;
+       if (sscanf(&buf[0], "%d\n", value) != 1) {
+               /* This must be a UBI bug */
+               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+               errno = EINVAL;
+               goto error;
+       }
 
-#ifdef UDEV_SETTLE_HACK
-       if (system("udevsettle") == -1)
-               return -1;
-#endif
+       close(fd);
+       return 0;
 
-out_close:
+error:
        close(fd);
-       return ret;
+       return -1;
 }
 
-int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
+/**
+ * vol_read_ll - read a 'long long' value from an UBI volume's sysfs file.
+ *
+ * @patt     the file pattern to read from
+ * @dev_num  UBI device number
+ * @vol_id   volume identifier
+ * @value    the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_ll(const char *patt, int dev_num, int vol_id,
+                      long long *value)
 {
-       int fd, ret;
+       int fd, rd;
+       char buf[50];
+       char file[strlen(patt) + 100];
 
-       desc = desc;
-       fd = open(node, O_RDONLY);
+       sprintf(&file[0], patt, dev_num, vol_id);
+       fd = open(&file[0], O_RDONLY);
        if (fd == -1)
                return -1;
 
-       ret = ioctl(fd, UBI_IOCRMVOL, &vol_id);
-       if (ret == -1)
-               goto out_close;
+       rd = read(fd, &buf[0], 50);
+       if (rd == -1)
+               goto error;
 
-#ifdef UDEV_SETTLE_HACK
-       if (system("udevsettle") == -1)
-               return -1;
-#endif
+       if (sscanf(&buf[0], "%lld\n", value) != 1) {
+               /* This must be a UBI bug */
+               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+               errno = EINVAL;
+               goto error;
+       }
 
-out_close:
        close(fd);
-       return ret;
+       return 0;
+
+error:
+       close(fd);
+       return -1;
 }
 
-int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
+/**
+ * vol_read_data - read data from an UBI volume's sysfs file.
+ *
+ * @patt     the file pattern to read from
+ * @dev_num  UBI device number
+ * @vol_id   volume identifier
+ * @buf      buffer to read to
+ * @buf_len  buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
+                        int buf_len)
 {
-       int fd, ret;
-       struct ubi_rsvol_req req;
+       int fd, rd;
+       char file[strlen(patt) + 100];
 
-       desc = desc;
-       fd = open(node, O_RDONLY);
+       sprintf(&file[0], patt, dev_num, vol_id);
+       fd = open(&file[0], O_RDONLY);
        if (fd == -1)
                return -1;
 
-       req.bytes = bytes;
-       req.vol_id = vol_id;
+       rd = read(fd, buf, buf_len);
+       if (rd == -1) {
+               close(fd);
+               return -1;
+       }
 
-       ret = ioctl(fd, UBI_IOCRSVOL, &req);
        close(fd);
-       return ret;
+       return rd;
 }
 
-int ubi_update_start(libubi_t desc, int fd, long long bytes)
+/**
+ * mkpath - compose full path from 2 given components.
+ *
+ * @path  first component
+ * @name  second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
 {
-       desc = desc;
-       if (ioctl(fd, UBI_IOCVOLUP, &bytes))
-               return -1;
-       return 0;
-}
+       char *n;
+       int len1 = strlen(path);
+       int len2 = strlen(name);
 
-int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype)
-{
-       struct ubi_leb_change_req req;
+       n = malloc(len1 + len2 + 2);
+       if (!n)
+               return NULL;
 
-       desc = desc;
-       memset(&req, 0, sizeof(struct ubi_leb_change_req));
-       req.lnum = lnum;
-       req.bytes = bytes;
-       req.dtype = dtype;
+       memcpy(n, path, len1);
+       if (n[len1 - 1] != '/')
+               n[len1++] = '/';
 
-       if (ioctl(fd, UBI_IOCEBCH, &req))
-               return -1;
-       return 0;
+       memcpy(n + len1, name, len2 + 1);
+       return n;
 }
 
-int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
+/**
+ * find_dev_num - find UBI device number by its character device node.
+ *
+ * @lib   UBI library descriptor
+ * @node  UBI character device node name
+ *
+ * This function returns positive UBI device number in case of success and %-1
+ * in case of failure.
+ */
+static int find_dev_num(struct libubi *lib, const char *node)
 {
-       DIR *sysfs_ubi;
-       struct dirent *dirent;
-       struct libubi *lib = (struct libubi *)desc;
+       struct stat stat;
+       struct ubi_info info;
+       int i, major, minor;
 
-       memset(info, '\0', sizeof(struct ubi_dev_info));
-       info->dev_num = dev_num;
+       if (lstat(node, &stat))
+               return -1;
 
-       sysfs_ubi = opendir(lib->sysfs_ubi);
-       if (!sysfs_ubi)
+       if (!S_ISCHR(stat.st_mode)) {
+               errno = EINVAL;
                return -1;
+       }
 
-       info->lowest_vol_num = INT_MAX;
+       major = major(stat.st_rdev);
+       minor = minor(stat.st_rdev);
 
-       while (1) {
-               int vol_id, ret, devno;
-               char tmp_buf[256];
+       if (minor != 0) {
+               errno = -EINVAL;
+               return -1;
+       }
 
-               errno = 0;
-               dirent = readdir(sysfs_ubi);
-               if (!dirent)
-                       break;
+       if (ubi_get_info((libubi_t *)lib, &info))
+               return -1;
 
-               if (strlen(dirent->d_name) > 256) {
-                       errmsg("invalid entry in %s: \"%s\"",
-                              lib->sysfs_ubi, dirent->d_name);
-                       goto out_close;
-               }
+       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+               int major1, minor1, ret;
+               char buf[50];
 
-               ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT"%s", &devno, &vol_id, tmp_buf);
-               if (ret == 2 && devno == dev_num) {
-                       info->vol_count += 1;
-                       if (vol_id > info->highest_vol_num)
-                               info->highest_vol_num = vol_id;
-                       if (vol_id < info->lowest_vol_num)
-                               info->lowest_vol_num = vol_id;
+               ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
+               if (ret < 0)
+                       return -1;
+
+               ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
+               if (ret != 2) {
+                       fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+                       errno = EINVAL;
+                       return -1;
                }
-       }
 
-       if (!dirent && errno) {
-               sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
-               goto out_close;
+               if (minor1 == minor && major1 == major)
+                       return i;
        }
 
-       if (closedir(sysfs_ubi))
-               return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+       errno = ENOENT;
+       return -1;
+}
 
-       if (info->lowest_vol_num == INT_MAX)
-               info->lowest_vol_num = 0;
+/**
+ * find_dev_num_vol - find UBI device number by volume character device node.
+ *
+ * @lib   UBI library descriptor
+ * @node  UBI character device node name
+ *
+ * This function returns positive UBI device number in case of success and %-1
+ * in case of failure.
+ */
+static int find_dev_num_vol(struct libubi *lib, const char *node)
+{
+       struct stat stat;
+       struct ubi_info info;
+       int i, major;
 
-       if (dev_get_major(lib, dev_num, &info->major, &info->minor))
+       if (lstat(node, &stat))
                return -1;
 
-       if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_lebs))
-               return -1;
-       if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_lebs))
-               return -1;
-       if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
-               return -1;
-       if (dev_read_int(lib->dev_eb_size, dev_num, &info->leb_size))
-               return -1;
-       if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
-               return -1;
-       if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec))
-               return -1;
-       if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count))
+       if (!S_ISCHR(stat.st_mode)) {
+               errno = EINVAL;
                return -1;
-       if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size))
+       }
+
+       major = major(stat.st_rdev);
+
+       if (minor(stat.st_rdev) == 0) {
+               errno = -EINVAL;
                return -1;
+       }
 
-       info->avail_bytes = info->avail_lebs * info->leb_size;
-       info->total_bytes = info->total_lebs * info->leb_size;
+       if (ubi_get_info((libubi_t *)lib, &info))
+               return -1;
 
-       return 0;
+       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+               int major1, minor1, ret;
+               char buf[50];
 
-out_close:
-       closedir(sysfs_ubi);
-       return -1;
-}
+               ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
+               if (ret < 0)
+                       return -1;
 
-int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
-{
-       int dev_num;
-       struct libubi *lib = (struct libubi *)desc;
+               ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
+               if (ret != 2) {
+                       fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+                       errno = EINVAL;
+                       return -1;
+               }
 
-       if (dev_node2num(lib, node, &dev_num))
-               return -1;
+               if (major1 == major)
+                       return i;
+       }
 
-       return ubi_get_dev_info1(desc, dev_num, info);
+       errno = ENOENT;
+       return -1;
 }
 
-int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
-                     struct ubi_vol_info *info)
+/**
+ * find_vol_num - find UBI volume number by its character device node.
+ *
+ * @lib      UBI library descriptor
+ * @dev_num  UBI device number
+ * @node     UBI volume character device node name
+ *
+ * This function returns positive UBI volume number in case of success and %-1
+ * in case of failure.
+ */
+static int find_vol_num(struct libubi *lib, int dev_num, const char *node)
 {
-       int ret;
-       struct libubi *lib = (struct libubi *)desc;
-       char buf[50];
-
-       memset(info, '\0', sizeof(struct ubi_vol_info));
-       info->dev_num = dev_num;
-       info->vol_id = vol_id;
-
-       if (dev_get_major(lib, dev_num, &info->dev_major, &info->dev_minor))
-               return -1;
-       if (vol_get_major(lib, dev_num, vol_id, &info->major, &info->minor))
-               return -1;
+       struct stat stat;
+       struct ubi_dev_info info;
+       int i, major, minor;
 
-       ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50);
-       if (ret < 0)
+       if (lstat(node, &stat))
                return -1;
 
-       if (strncmp(buf, "static\n", ret) == 0)
-               info->type = UBI_STATIC_VOLUME;
-       else if (strncmp(buf, "dynamic\n", ret) == 0)
-               info->type = UBI_DYNAMIC_VOLUME;
-       else {
-               errmsg("bad value at \"%s\"", buf);
+       if (!S_ISCHR(stat.st_mode)) {
                errno = EINVAL;
                return -1;
        }
 
-       ret = vol_read_int(lib->vol_alignment, dev_num, vol_id,
-                          &info->alignment);
-       if (ret)
-               return -1;
-       ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id,
-                         &info->data_bytes);
-       if (ret)
-               return -1;
-       ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_lebs);
-       if (ret)
-               return -1;
-       ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->leb_size);
-       if (ret)
-               return -1;
-       ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
-                          &info->corrupted);
-       if (ret)
+       major = major(stat.st_rdev);
+       minor = minor(stat.st_rdev);
+
+       if (minor == 0) {
+               errno = -EINVAL;
                return -1;
-       info->rsvd_bytes = info->leb_size * info->rsvd_lebs;
+       }
 
-       ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
-                           UBI_VOL_NAME_MAX + 2);
-       if (ret < 0)
+       if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info))
                return -1;
 
-       info->name[ret - 1] = '\0';
-       return 0;
-}
+       for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) {
+               int major1, minor1, ret;
+               char buf[50];
 
-int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
-{
-       int vol_id, dev_num;
-       struct libubi *lib = (struct libubi *)desc;
+               ret = vol_read_data(lib->vol_dev,  dev_num, i, &buf[0], 50);
+               if (ret < 0)
+                       return -1;
 
-       if (vol_node2nums(lib, node, &dev_num, &vol_id))
-               return -1;
+               ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
+               if (ret != 2) {
+                       fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+                       errno = EINVAL;
+                       return -1;
+               }
 
-       return ubi_get_vol_info1(desc, dev_num, vol_id, info);
+               if (minor1 == minor && major1 == major)
+                       return i;
+       }
+
+       errno = ENOENT;
+       return -1;
 }
index dab3e6251f4cc5d8a1e2fd7d20738198f54f8108..e68b79121cb5824ab1fde14b194932db3c9f0ad3 100644 (file)
 #ifndef __LIBUBI_INT_H__
 #define __LIBUBI_INT_H__
 
-#include <string.h>
-#include <errno.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* Error messages */
-#define errmsg(fmt, ...)  ({                                       \
-        fprintf(stderr, "libubi error: " fmt "\n", ##__VA_ARGS__); \
-       -1;                                                        \
-})
-
-/* System error messages */
-#define sys_errmsg(fmt, ...)  ({                                   \
-       int _err = errno;                                          \
-       fprintf(stderr, "libubi error: " fmt "\n", ##__VA_ARGS__); \
-       fprintf(stderr, "error %d (%s)\n", _err, strerror(_err));  \
-       -1;                                                        \
-})
-
 /*
+ * UBI heavily makes use of the sysfs file system to interact with users-pace.
  * The below are pre-define UBI file and directory names.
- *
- * Note, older kernels put 'ubiX_Y' directories straight to '/sys/class/ubi/'.
- * New kernels puts 'ubiX_Y' directories to '/sys/class/ubi/ubiX/', which is
- * saner. And for compatibility reasons it also puts symlinks to 'ubiX_Y'
- * directories to '/sys/class/ubi/'. For now libubi assumes old layout.
  */
 
 #define SYSFS_UBI         "class/ubi"
-#define SYSFS_CTRL        "class/misc/ubi_ctrl/"
-
-#define CTRL_DEV          "dev"
-
-#define UBI_VER           "version"
 #define UBI_DEV_NAME_PATT "ubi%d"
-
+#define UBI_VER           "version"
 #define DEV_DEV           "dev"
+#define UBI_VOL_NAME_PATT "ubi%d_%d"
 #define DEV_AVAIL_EBS     "avail_eraseblocks"
 #define DEV_TOTAL_EBS     "total_eraseblocks"
 #define DEV_BAD_COUNT     "bad_peb_count"
@@ -70,9 +45,6 @@ extern "C" {
 #define DEV_MAX_RSVD      "reserved_for_bad"
 #define DEV_MAX_VOLS      "max_vol_count"
 #define DEV_MIN_IO_SIZE   "min_io_size"
-#define DEV_MTD_NUM       "mtd_num"
-
-#define UBI_VOL_NAME_PATT "ubi%d_%d"
 #define VOL_TYPE          "type"
 #define VOL_DEV           "dev"
 #define VOL_ALIGNMENT     "alignment"
@@ -84,37 +56,34 @@ extern "C" {
 
 /**
  * libubi - UBI library description data structure.
- * @sysfs: sysfs file system path
- * @sysfs_ctrl: UBI control device directory in sysfs
- * @ctrl_dev: UBI control device major/minor numbers sysfs file
- * @sysfs_ubi: UBI directory in sysfs
- * @ubi_dev: UBI device sysfs directory pattern
- * @ubi_version: UBI version file sysfs path
- * @dev_dev: UBI device major/minor numbers file pattern
- * @dev_avail_ebs: count of available eraseblocks sysfs path pattern
- * @dev_total_ebs: total eraseblocks count sysfs path pattern
- * @dev_bad_count: count of bad eraseblocks sysfs path pattern
- * @dev_eb_size: size of UBI device's eraseblocks sysfs path pattern
- * @dev_max_ec: maximum erase counter sysfs path pattern
- * @dev_bad_rsvd: count of physical eraseblock reserved for bad eraseblocks
- *                handling
- * @dev_max_vols: maximum volumes number count sysfs path pattern
- * @dev_min_io_size: minimum I/O unit size sysfs path pattern
- * @ubi_vol: UBI volume sysfs directory pattern
- * @vol_type: volume type sysfs path pattern
- * @vol_dev: volume major/minor numbers file pattern
- * @vol_alignment: volume alignment sysfs path pattern
- * @vol_data_bytes: volume data size sysfs path pattern
- * @vol_rsvd_ebs: volume reserved size sysfs path pattern
- * @vol_eb_size: volume eraseblock size sysfs path pattern
- * @vol_corrupted: volume corruption flag sysfs path pattern
- * @vol_name: volume name sysfs path pattern
+ *
+ * @sysfs            sysfs file system path
+ * @sysfs_ubi        UBI directory in sysfs
+ * @ubi_dev          UBI device sysfs directory pattern
+ * @ubi_version      UBI version file sysfs path
+ * @dev_dev          UBI device's major/minor numbers file pattern
+ * @dev_avail_ebs    count of available eraseblocks sysfs path pattern
+ * @dev_total_ebs    total eraseblocks count sysfs path pattern
+ * @dev_bad_count    count of bad eraseblocks sysfs path pattern
+ * @dev_eb_size      size of UBI device's eraseblocks sysfs path pattern
+ * @dev_max_ec       maximum erase counter sysfs path pattern
+ * @dev_bad_rsvd     count of physical eraseblock reserved for bad eraseblocks
+ *                   handling
+ * @dev_max_vols     maximum volumes number count sysfs path pattern
+ * @dev_min_io_size  minimum I/O unit size sysfs path pattern
+ * @ubi_vol          UBI volume sysfs directory pattern
+ * @vol_type         volume type sysfs path pattern
+ * @vol_dev          volume's major/minor numbers file pattern
+ * @vol_alignment    volume alignment sysfs path pattern
+ * @vol_data_bytes   volume data size sysfs path pattern
+ * @vol_rsvd_ebs     volume reserved size sysfs path pattern
+ * @vol_eb_size      volume eraseblock size sysfs path pattern
+ * @vol_corrupted    volume corruption flag sysfs path pattern
+ * @vol_name         volume name sysfs path pattern
  */
 struct libubi
 {
        char *sysfs;
-       char *sysfs_ctrl;
-       char *ctrl_dev;
        char *sysfs_ubi;
        char *ubi_dev;
        char *ubi_version;
@@ -127,7 +96,6 @@ struct libubi
        char *dev_bad_rsvd;
        char *dev_max_vols;
        char *dev_min_io_size;
-       char *dev_mtd_num;
        char *ubi_vol;
        char *vol_type;
        char *vol_dev;
@@ -140,6 +108,20 @@ struct libubi
        char *vol_max_count;
 };
 
+static int read_int(const char *file, int *value);
+static int dev_read_int(const char *patt, int dev_num, int *value);
+static int dev_read_ll(const char *patt, int dev_num, long long *value);
+static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len);
+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value);
+static int vol_read_ll(const char *patt, int dev_num, int vol_id,
+                      long long *value);
+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
+                        int buf_len);
+static char *mkpath(const char *path, const char *name);
+static int find_dev_num(struct libubi *lib, const char *node);
+static int find_dev_num_vol(struct libubi *lib, const char *node);
+static int find_vol_num(struct libubi *lib, int dev_num, const char *node);
+
 #ifdef __cplusplus
 }
 #endif
index 8d71fdee4a220aedad6e2ba74ec795240fa49c26..1fce3f9c3e73eaa11f4720c1e6a9ee25e9e50574 100644 (file)
@@ -1,6 +1,5 @@
 /*
  * 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
  * 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.
- */
-
-/*
- * Generating UBI images.
  *
- * Authors: Oliver Lohmann
- *          Artem Bityutskiy
+ * Author: Oliver Lohmann
+ *
+ * Add UBI headers to binary data.
  */
 
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdio.h>
-#include <unistd.h>
+#include <errno.h>
 #include <string.h>
-
 #include <mtd/ubi-header.h>
-#include <libubigen.h>
+#include <mtd_swab.h>
+
+#include "config.h"
+#include "ubigen.h"
 #include "crc32.h"
-#include "common.h"
-
-#define PROGRAM_NAME "libubigen"
-
-/**
- * ubigen_info_init - initialize libubigen.
- * @ui: libubigen information
- * @peb_size: flash physical eraseblock size
- * @min_io_size: flash minimum input/output unit size
- * @subpage_size: flash sub-page, if present (has to be equivalent to
- *                @min_io_size if does not exist)
- * @vid_hdr_offs: offset of the VID header
- * @ubi_ver: UBI version
- * @ec: initial erase counter
- */
-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)
+
+#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 eb_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 eb_size)
 {
-       if (!vid_hdr_offs)
-               vid_hdr_offs = subpage_size;
-
-       ui->peb_size = peb_size;
-       ui->min_io_size = min_io_size;
-       ui->vid_hdr_offs = vid_hdr_offs;
-       ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1;
-       ui->data_offs /= min_io_size;
-       ui->data_offs *= 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;
+       return (byte % eb_size) == 0
+               ? (byte / eb_size)
+               : (byte / eb_size) + 1;
 }
 
-/**
- * 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)
+static int
+validate_ubi_info(ubi_info_t u)
 {
-       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;
+       if ((u->v->vol_type != UBI_VID_DYNAMIC) &&
+           (u->v->vol_type != UBI_VID_STATIC)) {
+               return EUBIGEN_INVALID_TYPE;
        }
 
-       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);
+       if (be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) {
+               return EUBIGEN_INVALID_HDR_OFFSET;
        }
 
-       return vtbl;
+       return 0;
 }
 
-/**
- * ubigen_add_volume - add a volume to the volume table.
- * @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.
- */
-int ubigen_add_volume(const struct ubigen_info *ui,
-                      const struct ubigen_vol_info *vi,
-                      struct ubi_vtbl_record *vtbl)
+static int
+skip_blks(ubi_info_t u, uint32_t blks)
 {
-       struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
-       uint32_t tmp;
-
-       if (vi->id >= ui->max_volumes)
-               return errmsg("too high volume id %d, max. volumes is %d",
-                             vi->id, ui->max_volumes);
-
-       if (vi->alignment >= ui->leb_size)
-               return errmsg("too large alignment %d, max is %d (LEB size)",
-                             vi->alignment, ui->leb_size);
-
-       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);
-       vtbl_rec->alignment = cpu_to_be32(vi->alignment);
-       vtbl_rec->vol_type = vi->type;
-       tmp = ui->leb_size % vi->alignment;
-       vtbl_rec->data_pad = cpu_to_be32(tmp);
-       vtbl_rec->flags = vi->flags;
-
-       memcpy(vtbl_rec->name, vi->name, vi->name_len);
-       vtbl_rec->name[vi->name_len] = '\0';
-       vtbl_rec->name_len = cpu_to_be16(vi->name_len);
-
-       tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
-       vtbl_rec->crc =  cpu_to_be32(tmp);
+       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;
 }
 
-/**
- * init_ec_hdr - initialize EC header.
- * @ui: libubigen information
- * @hdr: the EC header to initialize
- */
-static void init_ec_hdr(const struct ubigen_info *ui,
-                       struct ubi_ec_hdr *hdr)
+static void
+clear_buf(ubi_info_t u)
 {
-       uint32_t crc;
+       memset(u->buf, 0xff, u->eb_size);
+}
 
-       memset(hdr, '\0', sizeof(struct ubi_ec_hdr));
+static void
+write_ec_hdr(ubi_info_t u)
+{
+       memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE);
+}
 
-       hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
-       hdr->version = ui->ubi_ver;
-       hdr->ec = cpu_to_be64(ui->ec);
-       hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs);
+static int
+fill_data_buffer_from_file(ubi_info_t u, size_t* read)
+{
+       size_t to_read = 0;
 
-       hdr->data_offset = cpu_to_be32(ui->data_offs);
+       if (u-> fp_in == NULL)
+               return -EIO;
 
-       crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
-       hdr->hdr_crc = cpu_to_be32(crc);
+       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;
 }
 
-/**
- * init_vid_hdr - initialize VID header.
- * @ui: libubigen information
- * @vi: volume information
- * @hdr: the VID header to initialize
- * @lnum: logical eraseblock number
- * @data: the contents of the LEB (static volumes only)
- * @data_size: amount of data in this LEB (static volumes only)
- *
- * Note, @used_ebs, @data and @data_size are ignored in case of dynamic
- * volumes.
- */
-static void init_vid_hdr(const struct ubigen_info *ui,
-                        const struct ubigen_vol_info *vi,
-                        struct ubi_vid_hdr *hdr, int lnum,
-                        const void *data, int data_size)
+static void
+add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action)
 {
-       uint32_t crc;
+       uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
+                                u->ptr_data, data_size);
 
-       memset(hdr, '\0', sizeof(struct ubi_vid_hdr));
-
-       hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
-       hdr->version = ui->ubi_ver;
-       hdr->vol_type = vi->type;
-       hdr->vol_id = cpu_to_be32(vi->id);
-       hdr->lnum = cpu_to_be32(lnum);
-       hdr->data_pad = cpu_to_be32(vi->data_pad);
-       hdr->compat = vi->compat;
-
-       if (vi->type == UBI_VID_STATIC) {
-               hdr->data_size = cpu_to_be32(data_size);
-               hdr->used_ebs = cpu_to_be32(vi->used_ebs);
-               crc = crc32(UBI_CRC32_INIT, data, data_size);
-               hdr->data_crc = cpu_to_be32(crc);
+       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);
        }
+}
 
-       crc = crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
-       hdr->hdr_crc = cpu_to_be32(crc);
+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);
 }
 
-/**
- * ubigen_write_volume - write UBI volume.
- * @ui: libubigen information
- * @vi: volume information
- * @bytes: volume size in bytes
- * @in: input file descriptor (has to be properly seeked)
- * @out: output file descriptor
- *
- * This function reads the contents of the volume from the input file @in and
- * writes the UBI volume to the output file @out. Returns zero on success and
- * %-1 on failure.
- */
-int ubigen_write_volume(const struct ubigen_info *ui,
-                       const struct ubigen_vol_info *vi,
-                       long long bytes, FILE *in, FILE *out)
+static int
+write_to_output_stream(ubi_info_t u)
 {
-       int len = vi->usable_leb_size, rd, lnum = 0;
-       char inbuf[ui->leb_size], outbuf[ui->peb_size];
+       size_t written;
 
-       if (vi->id >= ui->max_volumes)
-               return errmsg("too high volume id %d, max. volumes is %d",
-                             vi->id, ui->max_volumes);
+       written = fwrite(u->buf, 1, u->eb_size, u->fp_out);
+       if (written != u->eb_size) {
+               return -EIO;
+       }
+       return 0;
+}
 
-       if (vi->alignment >= ui->leb_size)
-               return errmsg("too large alignment %d, max is %d (LEB size)",
-                             vi->alignment, ui->leb_size);
+int
+ubigen_write_leb(ubi_info_t u, ubigen_action_t action)
+{
+       int rc = 0;
+       size_t read = 0;
 
-       memset(outbuf, 0xFF, ui->data_offs);
-       init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf);
+       clear_buf(u);
+       write_ec_hdr(u);
 
-       while (bytes) {
-               int l;
-               struct ubi_vid_hdr *vid_hdr;
+       rc = fill_data_buffer_from_file(u, &read);
+       if (rc != 0)
+               return rc;
 
-               if (bytes < len)
-                       len = bytes;
-               bytes -= len;
+       if (u->v->vol_type == UBI_VID_STATIC)  {
+               add_static_info(u, read, action);
+       }
 
-               l = len;
-               do {
-                       rd = fread(inbuf + len - l, 1, l, in);
-                       if (rd == 0) {
-                               if (ferror(in))
-                                       return errmsg("cannot read %d bytes from the input file", l);
-                               else
-                                       return errmsg("not enough data in the input file");
-                       }
+       u->v->lnum = cpu_to_be32(u->blks_written);
 
-                       l -= rd;
-               } while (l);
+       if (action & MARK_AS_UPDATE) {
+               u->v->copy_flag = (u->v->copy_flag)++;
+       }
 
-               vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
-               init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len);
+       write_vid_hdr(u, action);
+       rc = write_to_output_stream(u);
+       if (rc != 0)
+               return rc;
 
-               memcpy(outbuf + ui->data_offs, inbuf, len);
-               memset(outbuf + ui->data_offs + len, 0xFF,
-                      ui->peb_size - ui->data_offs - len);
+       /* Update current handle */
+       u->bytes_read += read;
+       u->blks_written++;
+       return 0;
+}
 
-               if (fwrite(outbuf, 1, ui->peb_size, out) != ui->peb_size)
-                       return errmsg("cannot write %d bytes from the output file", l);
+int
+ubigen_write_complete(ubi_info_t u)
+{
+       size_t i;
+       int rc = 0;
 
-               lnum += 1;
+       for (i = 0; i < u->leb_total; i++) {
+               rc = ubigen_write_leb(u,  NO_ERROR);
+               if (rc != 0)
+                       return rc;
        }
 
        return 0;
 }
 
-/**
- * ubigen_write_layout_vol - write UBI layout volume
- * @ui: libubigen information
- * @vtbl: volume table
- * @out: output file stream
- *
- * This function creates the UBI layout volume which contains 2 copies of the
- * volume table. Returns zero in case of success and %-1 in case of failure.
- */
-int ubigen_write_layout_vol(const struct ubigen_info *ui,
-                           struct ubi_vtbl_record *vtbl, FILE *out)
+int
+ubigen_write_broken_update(ubi_info_t u, uint32_t blk)
 {
-       int size = ui->leb_size;
-       struct ubigen_vol_info vi;
-       char outbuf[ui->peb_size];
-       struct ubi_vid_hdr *vid_hdr;
-
-       if (size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE)
-               size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE;
-
-       vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
-       vi.id = UBI_LAYOUT_VOLUME_ID;
-       vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
-       vi.data_pad =  ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
-       vi.usable_leb_size = ui->leb_size - vi.data_pad;
-       vi.data_pad = ui->leb_size - vi.usable_leb_size;
-       vi.type = UBI_LAYOUT_VOLUME_TYPE;
-       vi.name = UBI_LAYOUT_VOLUME_NAME;
-       vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
-       vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
-
-       memset(outbuf, 0xFF, ui->data_offs);
-       vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
-       init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf);
-       memcpy(outbuf + ui->data_offs, vtbl, size);
-       memset(outbuf + ui->data_offs + size, 0xFF,
-              ui->peb_size - ui->data_offs - size);
-
-       init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
-       size = fwrite(outbuf, 1, ui->peb_size, out);
-       if (size == ui->peb_size) {
-               init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
-               size = fwrite(outbuf, 1, ui->peb_size, out);
-               if (size != ui->peb_size)
-                       return sys_errmsg("cannot write %d bytes", ui->peb_size);
+       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, "eb_size      : 0x%08x\n", u->eb_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 eb_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->eb_size = eb_size ? eb_size : DEFAULT_BLOCKSIZE;
+       res->data_pad = (res->eb_size - data_offset) % alignment;
+       res->leb_size = res->eb_size - data_offset - res->data_pad;
+       res->leb_total = byte_to_blk(data_size, res->leb_size);
+       res->alignment = alignment;
+
+       if ((res->eb_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->eb_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;
 }
similarity index 74%
rename from ubi-utils/old-tools/src/nand2bin.c
rename to ubi-utils/src/nand2bin.c
index 8c95b27b041d0dc98918412f7a5052eaa1fca7ab..be62e3077193f3168def7269cda39cd92e89e652 100644 (file)
@@ -25,9 +25,6 @@
  * 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 "config.h"
 #include "nandecc.h"
-#include "ecclayouts.h"
 
-#define PROGRAM_VERSION "1.7"
+#define PROGRAM_VERSION "1.6"
 
-#define ARRAY_SIZE(a)    (sizeof(a) / sizeof((a)[0]))
 #define MAXPATH                1024
 #define MIN(x,y)       ((x)<(y)?(x):(y))
 
@@ -58,13 +53,10 @@ 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;
@@ -76,7 +68,6 @@ static struct args myargs = {
        .oob_file = "oob.bin",
        .pagesize = 2048,
        .blocksize = 128 * 1024,
-       .nand_oob = &ibm_nand_oob_64,
        .in_len = 0,
        .split_blocks = 0,
        .correct_ecc = 0,
@@ -88,7 +79,6 @@ 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"
@@ -107,7 +97,6 @@ static const char *usage =
 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' },
@@ -155,52 +144,56 @@ static uint32_t str_to_num(char *str)
  */
 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);
+               key = getopt_long(argc, argv, "b:eo:O:p:sv?", long_options, NULL);
                if (key == -1)
                        break;
 
                switch (key) {
+               case 'p': /* --pagesize<pagesize> */
+                       args->pagesize = str_to_num(optarg);
+                       break;
+
                case 'b': /* --blocksize<blocksize> */
                        args->blocksize = str_to_num(optarg);
                        break;
+
+               case 'v': /* --verbose */
+                       verbose++;
+                       break;
+
+               case 's': /* --split-blocks */
+                       args->split_blocks = 1;
+                       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("%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);
@@ -210,44 +203,17 @@ static int parse_opt(int argc, char **argv, struct args *args)
        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)
+static int calc_oobsize(size_t pagesize)
 {
-       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;
+       switch (pagesize) {
+       case 512:  return 16;
+       case 2048: return 64;
+       default:
+               exit(EXIT_FAILURE);
+       }
        return 0;
 }
 
@@ -262,38 +228,65 @@ static inline void hexdump(FILE *fp, const uint8_t *buf, ssize_t size)
        }
 }
 
-static int process_page(struct args *args, uint8_t *buf, uint8_t *oobbuf)
+static int process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize)
 {
-       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];
+       int eccpoi, oobsize;
+       size_t i;
+
+       switch (pagesize) {
+       case 2048: oobsize = 64; eccpoi = 64 / 2; break;
+       case 512:  oobsize = 16; eccpoi = 16 / 2; break;
+       default:
+               fprintf(stderr, "Unsupported page size: %zd\n", pagesize);
+               return -EINVAL;
+       }
+       memset(oobbuf, 0xff, oobsize);
+
+       for (i = 0; i < pagesize; i += 256, eccpoi += 3) {
+               oobbuf[eccpoi++] = 0x0;
+               /* Calculate ECC */
+               nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]);
        }
        return 0;
 }
 
+static int bad_marker_offs_in_oob(int pagesize)
+{
+       switch (pagesize) {
+       case 2048: return 0;
+       case 512:  return 5;
+       }
+       return -EINVAL;
+}
+
 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;
+       size_t oobsize = calc_oobsize(args->pagesize);
        uint8_t *buf = malloc(args->pagesize);
-       uint8_t *oob = malloc(args->oobsize);
-       uint8_t *calc_oob = malloc(args->oobsize);
+       uint8_t *oob = malloc(oobsize);
+       uint8_t *calc_oob = malloc(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 */
+       int eccpoi = 0, eccpoi_start;
+       unsigned int i;
+       int badpos = bad_marker_offs_in_oob(args->pagesize);
+
+       switch (args->pagesize) {
+       case 2048: eccpoi_start = 64 / 2; break;
+       case 512:  eccpoi_start = 16 / 2; break;
+       default:   exit(EXIT_FAILURE);
+       }
 
-       if (!buf || !oob || !calc_oob || !calc_buf)
+       if (!buf)
+               exit(EXIT_FAILURE);
+       if (!oob)
+               exit(EXIT_FAILURE);
+       if (!calc_oob)
+               exit(EXIT_FAILURE);
+       if (!calc_buf)
                exit(EXIT_FAILURE);
 
        while (!feof(in_fp)) {
@@ -306,7 +299,7 @@ static int decompose_image(struct args *args, FILE *in_fp,
                if (read != (ssize_t)args->pagesize)
                        break;
 
-               read = fread(oob, 1, args->oobsize, in_fp);
+               read = fread(oob, 1, oobsize, in_fp);
                if (ferror(in_fp)) {
                        fprintf(stderr, "I/O Error.");
                        exit(EXIT_FAILURE);
@@ -323,31 +316,37 @@ static int decompose_image(struct args *args, FILE *in_fp,
                if (args->correct_ecc)
                        page_buf = calc_buf;
 
-               process_page(args, buf, calc_oob);
+               process_page(buf, calc_oob, args->pagesize);
                memcpy(calc_buf, buf, args->pagesize);
 
-               if (verbose && oob_cmp(args->nand_oob, oob, calc_oob) != 0) {
+               /*
+                * Our oob format uses only the last 3 bytes out of 4.
+                * The first byte is 0x00 when the ECC is generated by
+                * our toolset and 0xff when generated by Linux. This
+                * is to be fixed when we want nand2bin work for other
+                * ECC layouts too.
+                */
+               for (i = 0, eccpoi = eccpoi_start; i < args->pagesize;
+                    i += 256, eccpoi += 4)
+                       oob[eccpoi] = calc_oob[eccpoi] = 0xff;
+
+               if (verbose && memcmp(oob, calc_oob, oobsize) != 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);
+                       hexdump(stdout, oob, oobsize);
 
                        printf("Calculated OOB Data:\n");
-                       hexdump(stdout, calc_oob, args->oobsize);
+                       hexdump(stdout, calc_oob, 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);
+               for (i = 0, eccpoi = eccpoi_start; i < args->pagesize;
+                    i += 256, eccpoi += 4) {
+                       rc = nand_correct_data(calc_buf + i, &oob[eccpoi + 1],
+                                              &calc_oob[eccpoi + 1]);
+
                        if (rc == -1)
                                fprintf(stdout, "Uncorrectable ECC error at "
                                        "block %d page %d/%d\n",
@@ -366,7 +365,7 @@ static int decompose_image(struct args *args, FILE *in_fp,
                        fprintf(stderr, "I/O Error.");
                        exit(EXIT_FAILURE);
                }
-               rc = fwrite(oob, 1, args->oobsize, oob_fp);
+               rc = fwrite(oob, 1, oobsize, oob_fp);
                if (ferror(bin_fp)) {
                        fprintf(stderr, "I/O Error.");
                        exit(EXIT_FAILURE);
@@ -384,11 +383,12 @@ static int decompose_image(struct args *args, FILE *in_fp,
 static int split_blocks(struct args *args, FILE *in_fp)
 {
        uint8_t *buf;
+       size_t oobsize = calc_oobsize(args->pagesize);
        int pages_per_block = args->blocksize / args->pagesize;
-       int block_len = pages_per_block * (args->pagesize + args->oobsize);
+       int block_len = pages_per_block * (args->pagesize + oobsize);
        int blocks = args->in_len / block_len;
        char bname[256] = { 0, };
-       int badpos = args->bad_marker_offs_in_oob;
+       int badpos = bad_marker_offs_in_oob(args->pagesize);
        int bad_blocks = 0, i, bad_block = 0;
        ssize_t rc;
        FILE *b;
@@ -409,16 +409,16 @@ static int split_blocks(struct args *args, FILE *in_fp)
                /* do block analysis */
                bad_block = 0;
                if ((buf[args->pagesize + badpos] != 0xff) ||
-                   (buf[2 * args->pagesize + args->oobsize + badpos] != 0xff)) {
+                   (buf[2 * args->pagesize + 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);
+                       hexdump(stdout, buf + args->pagesize, oobsize);
                        printf("--\n");
                        hexdump(stdout, buf + 2 * args->pagesize +
-                               args->oobsize, args->oobsize);
+                               oobsize, oobsize);
                }
 
                /* write complete block out */
similarity index 96%
rename from ubi-utils/old-tools/src/peb.c
rename to ubi-utils/src/peb.c
index 160a46342d68e9151a8a562d87c18b083b886042..08b770f43019474d47dce1b31b5a6416d87cf38f 100644 (file)
@@ -36,7 +36,7 @@ peb_cmp(peb_t eb_1, peb_t eb_2)
 }
 
 int
-peb_new(uint32_t eb_num, uint32_t peb_size, peb_t *peb)
+peb_new(uint32_t eb_num, uint32_t eb_size, peb_t *peb)
 {
        int rc = 0;
 
@@ -47,7 +47,7 @@ peb_new(uint32_t eb_num, uint32_t peb_size, peb_t *peb)
        }
 
        res->num  = eb_num;
-       res->size = peb_size;
+       res->size = eb_size;
        res->data = (uint8_t*) malloc(res->size * sizeof(uint8_t));
        if (!res->data) {
                rc = -ENOMEM;
similarity index 99%
rename from ubi-utils/old-tools/src/pfi2bin.c
rename to ubi-utils/src/pfi2bin.c
index 3300df2a8ce3c96c8b4662431daf684dba8ad737..a8c76a3dbe165e76aa2b3e14e29da8dfbdbbbc0f 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <ubigen.h>
 #include <mtd/ubi-header.h>
+#include <mtd_swab.h>
 
 #include "config.h"
 #include "list.h"
index 5c7a8ba8979cbc1057ee52b76faa7d98cf01bde2..7e3f04597b3cf2f0cd8ab48039b411d9630590d6 100644 (file)
  * 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.
- */
-
-/*
- * Calculate CRC32 with UBI start value (0xFFFFFFFF) for a given binary image.
  *
  * Author: Oliver Lohmann
+ *
+ * Calculate CRC32 with UBI start value for a given binary image.
  */
 
 #include <stdio.h>
 #include <getopt.h>
 #include <argp.h>
 #include <unistd.h>
+#include <errno.h>
 #include <mtd/ubi-header.h>
 
+#include "config.h"
 #include "crc32.h"
-#include "common.h"
 
 #define BUFSIZE 4096
 
-#define PROGRAM_VERSION "1.2"
-#define PROGRAM_NAME    "ubicrc32"
+const char *argp_program_version = PACKAGE_VERSION;
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+static char doc[] = "\nVersion: " PACKAGE_VERSION "\n"
+       "ubicrc32 - calculates the UBI CRC32 value and prints it to stdout.\n";
 
-static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
-                        " - a tool to calculate CRC32 with UBI start value (0xFFFFFFFF)";
+static const char copyright [] __attribute__((unused)) =
+       "FIXME: insert license type"; /* FIXME */
 
-static const char *optionsstr =
-"-h, --help                    print help message\n"
-"-V, --version                 print program version";
 
-static const char *usage =
-"Usage: " PROGRAM_NAME " <file to calculate CRC32 for> [-h] [--help]";
+static struct argp_option options[] = {
+       { name: "copyright", key: 'c', arg: NULL,    flags: 0,
+         doc: "Print copyright information.",
+         group: 1 },
 
-static const struct option long_options[] = {
-       { .name = "help",      .has_arg = 0, .flag = NULL, .val = 'h' },
-       { .name = "version",   .has_arg = 0, .flag = NULL, .val = 'V' },
-       { NULL, 0, NULL, 0},
+       { name: NULL, key: 0, arg: NULL, flags: 0, doc: NULL, group: 0 },
 };
 
-static int parse_opt(int argc, char * const argv[])
+typedef struct myargs {
+       FILE* fp_in;
+
+       char *arg1;
+       char **options;                 /* [STRING...] */
+} myargs;
+
+static error_t
+parse_opt(int key, char *arg, struct argp_state *state)
 {
-       while (1) {
-               int key;
-
-               key = getopt_long(argc, argv, "hV", long_options, NULL);
-               if (key == -1)
-                       break;
-
-               switch (key) {
-               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 ':':
-                       return errmsg("parameter is missing");
-
-               default:
-                       fprintf(stderr, "Use -h for help\n");
-                       return -1;
+       int err = 0;
+
+       myargs *args = state->input;
+
+       switch (key) {
+       case 'c':
+               fprintf(stderr, "%s\n", copyright);
+               exit(0);
+               break;
+       case ARGP_KEY_ARG:
+               args->fp_in = fopen(arg, "rb");
+               if ((args->fp_in) == NULL) {
+                       fprintf(stderr,
+                       "Cannot open file %s for input\n", arg);
+                       exit(1);
+               }
+               args->arg1 = arg;
+               args->options = &state->argv[state->next];
+               state->next = state->argc;
+               break;
+       case ARGP_KEY_END:
+               if (err) {
+                       fprintf(stderr, "\n");
+                       argp_usage(state);
+                       exit(1);
                }
+               break;
+       default:
+               return(ARGP_ERR_UNKNOWN);
        }
 
        return 0;
 }
 
-int main(int argc, char * const argv[])
-{
-       int err = 0;
-       uint32_t crc = UBI_CRC32_INIT;
-       char buf[BUFSIZE];
-       FILE *fp;
-
-       if (argc > 1) {
-               fp = fopen(argv[1], "r");
-               if (!fp)
-                       return sys_errmsg("cannot open \"%s\"", argv[1]);
-       } else
-               fp = stdin;
-
-       err = parse_opt(argc, argv);
-       if (err)
-               return err;
-
-       while (!feof(fp)) {
-               size_t read;
-
-               read = fread(buf, 1, BUFSIZE, fp);
-               if (ferror(fp)) {
-                       sys_errmsg("cannot read input file");
-                       err = -1;
-                       goto out_close;
+static struct argp argp = {
+       options:     options,
+       parser:      parse_opt,
+       args_doc:    "[file]",
+       doc:         doc,
+       children:    NULL,
+       help_filter: NULL,
+       argp_domain: NULL,
+};
+
+int
+main(int argc, char **argv) {
+       int rc = 0;
+       uint32_t crc32_table[256];
+       uint8_t buf[BUFSIZE];
+       size_t read;
+       uint32_t crc32;
+
+       myargs args = {
+               .fp_in = stdin,
+               .arg1 = NULL,
+               .options = NULL,
+       };
+
+       argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &args);
+
+       init_crc32_table(crc32_table);
+       crc32 = UBI_CRC32_INIT;
+       while (!feof(args.fp_in)) {
+               read = fread(buf, 1, BUFSIZE, args.fp_in);
+               if (ferror(args.fp_in)) {
+                       fprintf(stderr, "I/O Error.");
+                       exit(EXIT_FAILURE);
                }
-               crc = crc32(crc, buf, read);
+               crc32 = clc_crc32(crc32_table, crc32, buf, read);
        }
 
-       printf("0x%08x\n", crc);
+       if (args.fp_in != stdin) {
+               fclose(args.fp_in);
+       }
 
-out_close:
-       if (fp != stdin)
-               fclose(fp);
-       return err;
+       fprintf(stdout, "0x%08x\n", crc32);
+       return rc;
 }
similarity index 99%
rename from ubi-utils/old-tools/src/ubigen.h
rename to ubi-utils/src/ubigen.h
index 07f845f2c6af1a347e685451d35a2dde442c2dd9..0f43a46460173c4d1631cb96a18ec1eb565253e7 100644 (file)
@@ -25,7 +25,6 @@
 #include <stdio.h> /* FILE */
 #include <stdint.h>
 #include <mtd/ubi-header.h>
-#include <mtd_swab.h>
 
 #ifdef __cplusplus
 extern "C" {
index 75c180dcbdd94f1ef2d7b94a38d5b0a0f5e3869c..bff6068e83862182af226964a930d7e64122b335 100644 (file)
 /*
  * An utility to create UBI volumes.
  *
- * Authors: Artem Bityutskiy <dedekind@infradead.org>
- *          Frank Haverkamp <haver@vnet.ibm.com>
+ * Author: Artem B. Bityutskiy <dedekind@linutronix.de>
+ *         Frank Haverkamp <haver@vnet.ibm.com>
+ *
+ * 1.0 Initial release
+ * 1.1 Does not support erase blocks anymore. This is replaced by
+ *     the number of bytes.
+ * 1.2 Reworked the user-interface to use argp.
+ * 1.3 Removed argp because we want to use uClibc.
+ * 1.4 Minor cleanups
+ * 1.5 Use a different libubi
  */
 
 #include <stdio.h>
 #include <getopt.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
+#include <config.h>
 #include <libubi.h>
-#include "common.h"
 
-#define PROGRAM_VERSION "1.6"
-#define PROGRAM_NAME    "ubimkvol"
+#define PROGRAM_VERSION "1.5"
 
-/* The variables below are set by command line arguments */
+/*
+ * The variables below are set by command line arguments.
+ */
 struct args {
+       int devn;
        int vol_id;
        int vol_type;
        long long bytes;
-       int lebs;
        int alignment;
-       const char *name;
+       char *name;
        int nlen;
-       const char *node;
+       char node[256];
        int maxavs;
+
+       /* special stuff needed to get additional arguments */
+       char *arg1;
+       char **options;         /* [STRING...] */
 };
 
-static struct args args = {
+static struct args myargs = {
        .vol_type = UBI_DYNAMIC_VOLUME,
-       .bytes = -1,
-       .lebs = -1,
+       .devn = -1,
+       .bytes = 0,
        .alignment = 1,
        .vol_id = UBI_VOL_NUM_AUTO,
        .name = NULL,
        .nlen = 0,
-       .node = NULL,
        .maxavs = 0,
 };
 
-static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
-                        " - a tool to create UBI volumes.";
+static int param_sanity_check(struct args *args, libubi_t libubi);
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+       "ubinkvol - make UBI Volume.\n";
 
 static const char *optionsstr =
-"-a, --alignment=<alignment>   volume alignment (default is 1)\n"
-"-n, --vol_id=<volume ID>      UBI volume ID, if not specified, the volume ID\n"
-"                              will be assigned automatically\n"
-"-N, --name=<name>             volume name\n"
-"-s, --size=<bytes>            volume size volume size in bytes, kilobytes (KiB)\n"
-"                              or megabytes (MiB)\n"
-"-S, --lebs=<LEBs count>       alternative way to give volume size in logical\n"
-"                              eraseblocks\n"
-"-m, --maxavsize               set volume size to maximum available size\n"
-"-t, --type=<static|dynamic>   volume type (dynamic, static), default is dynamic\n"
-"-h, --help                    print help message\n"
-"-V, --version                 print program version";
+"  -a, --alignment=<alignment>   volume alignment (default is 1)\n"
+"  -d, --devn=<devn>          UBI device\n"
+"  -n, --vol_id=<volume id>   UBI volume id, if not specified, the volume ID\n"
+"                             will be assigned automatically\n"
+"  -N, --name=<name>          volume name\n"
+"  -s, --size=<bytes>         volume size volume size in bytes, kilobytes (KiB)\n"
+"                             or megabytes (MiB)\n"
+"  -m, --maxavsize            set volume size to maximum available size\n"
+"  -t, --type=<static|dynamic>   volume type (dynamic, static), default is\n"
+"                             dynamic\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: " PROGRAM_NAME " <UBI device node file name> [-h] [-a <alignment>] [-n <volume ID>] [-N <name>]\n"
-"\t\t\t[-s <bytes>] [-S <LEBs>] [-t <static|dynamic>] [-V] [-m]\n"
-"\t\t\t[--alignment=<alignment>][--vol_id=<volume ID>] [--name=<name>]\n"
-"\t\t\t[--size=<bytes>] [--lebs=<LEBs>] [--type=<static|dynamic>] [--help]\n"
-"\t\t\t[--version] [--maxavsize]\n\n"
-"Example: " PROGRAM_NAME "/dev/ubi0 -s 20MiB -N config_data - create a 20 Megabytes volume\n"
-"         named \"config_data\" on UBI device /dev/ubi0.";
-
-static const struct option long_options[] = {
+"Usage: ubimkvol [-?V] [-a <alignment>] [-d <devn>] [-n <volume id>]\n"
+"            [-N <name>] [-s <bytes>] [-t <static|dynamic>] [-m]\n"
+"            [--alignment=<alignment>] [--devn=<devn>] [--vol_id=<volume id>]\n"
+"            [--name=<name>] [--size=<bytes>] [--type=<static|dynamic>] [--help]\n"
+"            [--usage] [--version] [--maxavsize]\n";
+
+struct option long_options[] = {
        { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'a' },
-       { .name = "vol_id",    .has_arg = 1, .flag = NULL, .val = 'n' },
-       { .name = "name",      .has_arg = 1, .flag = NULL, .val = 'N' },
-       { .name = "size",      .has_arg = 1, .flag = NULL, .val = 's' },
-       { .name = "lebs",      .has_arg = 1, .flag = NULL, .val = 'S' },
-       { .name = "type",      .has_arg = 1, .flag = NULL, .val = 't' },
-       { .name = "help",      .has_arg = 0, .flag = NULL, .val = 'h' },
-       { .name = "version",   .has_arg = 0, .flag = NULL, .val = 'V' },
+       { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+       { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+       { .name = "name", .has_arg = 1, .flag = NULL, .val = 'N' },
+       { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' },
+       { .name = "type", .has_arg = 1, .flag = NULL, .val = 't' },
+       { .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' },
        { .name = "maxavsize", .has_arg = 0, .flag = NULL, .val = 'm' },
-       { NULL, 0, NULL, 0},
+       { NULL, 0, NULL, 0}
 };
 
-static int param_sanity_check(void)
+/*
+ * @brief Parse the arguments passed into the test case.
+ *
+ * @param argc          The number of arguments
+ * @param argv          The list of arguments
+ * @param args          Pointer to argument structure
+ *
+ * @return error
+ *
+ */
+static int
+parse_opt(int argc, char **argv, struct args *args)
 {
-       int len;
-
-       if (args.bytes == -1 && !args.maxavs && args.lebs == -1)
-               return errmsg("volume size was not specified (use -h for help)");
-
-       if ((args.bytes != -1 && (args.maxavs || args.lebs != -1))  ||
-           (args.lebs != -1  && (args.maxavs || args.bytes != -1)) ||
-           (args.maxavs && (args.bytes != -1 || args.lebs != -1)))
-               return errmsg("size specified with more then one option");
-
-       if (args.name == NULL)
-               return errmsg("volume name was not specified (use -h for help)");
-
-       len = strlen(args.name);
-       if (len > UBI_MAX_VOLUME_NAME)
-               return errmsg("too long name (%d symbols), max is %d", len, UBI_MAX_VOLUME_NAME);
-
-       return 0;
-}
+       char *endp;
 
-static int parse_opt(int argc, char * const argv[])
-{
        while (1) {
                int key;
-               char *endp;
 
-               key = getopt_long(argc, argv, "a:n:N:s:S:t:hVm", long_options, NULL);
+               key = getopt_long(argc, argv, "a:d:n:N:s:t:?Vm", long_options, NULL);
                if (key == -1)
                        break;
 
                switch (key) {
-               case 't':
-                       if (!strcmp(optarg, "dynamic"))
-                               args.vol_type = UBI_DYNAMIC_VOLUME;
-                       else if (!strcmp(optarg, "static"))
-                               args.vol_type = UBI_STATIC_VOLUME;
-                       else
-                               return errmsg("bad volume type: \"%s\"", optarg);
-                       break;
-
-               case 's':
-                       args.bytes = ubiutils_get_bytes(optarg);
-                       if (args.bytes <= 0)
-                               return errmsg("bad volume size: \"%s\"", optarg);
-                       break;
-
-               case 'S':
-                       args.lebs = strtoull(optarg, &endp, 0);
-                       if (endp == optarg || args.lebs <= 0 || *endp != '\0')
-                               return errmsg("bad LEB count: \"%s\"", optarg);
-                       break;
-
-               case 'a':
-                       args.alignment = strtoul(optarg, &endp, 0);
-                       if (*endp != '\0' || endp == optarg || args.alignment <= 0)
-                               return errmsg("bad volume alignment: \"%s\"", optarg);
-                       break;
-
-               case 'n':
-                       args.vol_id = strtoul(optarg, &endp, 0);
-                       if (*endp != '\0' || endp == optarg || args.vol_id < 0)
-                               return errmsg("bad volume ID: " "\"%s\"", optarg);
-                       break;
-
-               case 'N':
-                       args.name = optarg;
-                       args.nlen = strlen(args.name);
-                       break;
-
-               case 'h':
-                       fprintf(stderr, "%s\n\n", doc);
-                       fprintf(stderr, "%s\n\n", usage);
-                       fprintf(stderr, "%s\n", optionsstr);
-                       exit(EXIT_SUCCESS);
+                       case 't':
+                               if (!strcmp(optarg, "dynamic"))
+                                       args->vol_type = UBI_DYNAMIC_VOLUME;
+                               else if (!strcmp(optarg, "static"))
+                                       args->vol_type = UBI_STATIC_VOLUME;
+                               else {
+                                       fprintf(stderr,
+                                               "Bad volume type: \"%s\"\n",
+                                               optarg);
+                                       goto out;
+                               }
+                               break;
+                       case 's':
+                               args->bytes = strtoull(optarg, &endp, 0);
+                               if (endp == optarg || args->bytes < 0) {
+                                       fprintf(stderr,
+                                               "Bad volume size: \"%s\"\n",
+                                               optarg);
+                                       goto out;
+                               }
+                               if (endp != '\0') {
+                                       if (strcmp(endp, "KiB") == 0)
+                                               args->bytes *= 1024;
+                                       else if (strcmp(endp, "MiB") == 0)
+                                               args->bytes *= 1024*1024;
+                               }
+                               break;
+                       case 'a':
+                               args->alignment = strtoul(optarg, &endp, 0);
+                               if (*endp != '\0' || endp == optarg ||
+                                               args->alignment <= 0) {
+                                       fprintf(stderr, "Bad volume alignment: "
+                                                       "\"%s\"\n", optarg);
+                                       goto out;
+                               }
+                               break;
+                       case 'd': /* --devn=<device number> */
+                               args->devn = strtoul(optarg, &endp, 0);
+                               if (*endp != '\0' || endp == optarg ||
+                                       args->devn < 0) {
+                                       fprintf(stderr,
+                                               "Bad UBI device number: "
+                                               "\"%s\"\n", optarg);
+                                       goto out;
+                               }
+                               sprintf(args->node, "/dev/ubi%d", args->devn);
+                               break;
+                       case 'n': /* --volid=<volume id> */
+                               args->vol_id = strtoul(optarg, &endp, 0);
+                               if (*endp != '\0' ||
+                                   endp == optarg ||
+                                   (args->vol_id < 0 &&
+                                    args->vol_id != UBI_DYNAMIC_VOLUME)) {
+                                       fprintf(stderr, "Bad volume ID: "
+                                               "\"%s\"\n", optarg);
+                                       goto out;
+                               }
+                               break;
+                       case 'N':
+                               args->name = optarg;
+                               args->nlen = strlen(args->name);
+                               break;
+
+                       case ':':
+                               fprintf(stderr, "Parameter is missing\n");
+                               goto out;
+
+                       case '?': /* help */
+                               fprintf(stderr,
+                                       "Usage: ubimkvol [OPTION...]\n");
+                               fprintf(stderr, "%s", doc);
+                               fprintf(stderr, "%s", optionsstr);
+                               fprintf(stderr, "\nReport bugs to %s\n",
+                                       PACKAGE_BUGREPORT);
+                               exit(0);
+                               break;
+
+                       case 'V':
+                               fprintf(stderr, "%s\n", PROGRAM_VERSION);
+                               exit(0);
+                               break;
+
+                       case 'm':
+                               args->maxavs = 1;
+                               break;
+
+                       default:
+                               fprintf(stderr, "%s", usage);
+                               exit(-1);
+               }
+       }
 
-               case 'V':
-                       fprintf(stderr, "%s\n", PROGRAM_VERSION);
-                       exit(EXIT_SUCCESS);
+       return 0;
+ out:
+       return -1;
+}
 
-               case 'm':
-                       args.maxavs = 1;
-                       break;
+static int param_sanity_check(struct args *args, libubi_t libubi)
+{
+       int err, len;
+       struct ubi_info ubi;
 
-               case ':':
-                       return errmsg("parameter is missing");
+       if (args->bytes == 0 && !args->maxavs) {
+               fprintf(stderr, "Volume size was not specified\n");
+               goto out;
+       }
 
-               default:
-                       fprintf(stderr, "Use -h for help\n");
-                       return -1;
-               }
+       if (args->name == NULL) {
+               fprintf(stderr, "Volume name was not specified\n");
+               goto out;
        }
 
-       if (optind == argc)
-               return errmsg("UBI device name was not specified (use -h for help)");
-       else if (optind != argc - 1)
-               return errmsg("more then one UBI device specified (use -h for help)");
+       err = ubi_get_info(libubi, &ubi);
+       if (err)
+               return -1;
 
-       args.node = argv[optind];
+       if (args->devn >= (int)ubi.dev_count) {
+               fprintf(stderr, "Device %d does not exist\n", args->devn);
+               goto out;
+       }
 
-       if (param_sanity_check())
-               return -1;
+       len = strlen(args->name);
+       if (len > UBI_MAX_VOLUME_NAME) {
+               fprintf(stderr, "Too long name (%d symbols), max is %d\n",
+                       len, UBI_MAX_VOLUME_NAME);
+               goto out;
+       }
 
        return 0;
+out:
+       errno = EINVAL;
+       return -1;
 }
 
 int main(int argc, char * const argv[])
 {
        int err;
        libubi_t libubi;
-       struct ubi_dev_info dev_info;
-       struct ubi_vol_info vol_info;
        struct ubi_mkvol_request req;
 
-       err = parse_opt(argc, argv);
-       if (err)
-               return err;
+       err = parse_opt(argc, (char **)argv, &myargs);
+       if (err) {
+               fprintf(stderr, "Wrong options ...\n");
+               return err == 1 ? 0 : -1;
+       }
 
-       libubi = libubi_open();
-       if (!libubi)
-               return sys_errmsg("cannot open libubi");
+       if (myargs.devn == -1) {
+               fprintf(stderr, "Device number was not specified\n");
+               fprintf(stderr, "Use -h option for help\n");
+               return -1;
+       }
 
-       err = ubi_node_type(libubi, args.node);
-       if (err == 2) {
-               errmsg("\"%s\" is an UBI volume node, not an UBI device node",
-                      args.node);
-               goto out_libubi;
-       } else if (err < 0) {
-               errmsg("\"%s\" is not an UBI device node", args.node);
-               goto out_libubi;
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               perror("Cannot open libubi");
+               return -1;
        }
 
-       err = ubi_get_dev_info(libubi, args.node, &dev_info);
+       err = param_sanity_check(&myargs, libubi);
        if (err) {
-               sys_errmsg("cannot get information about UBI device \"%s\"",
-                          args.node);
+               perror("Input parameters check");
+               fprintf(stderr, "Use -h option for help\n");
                goto out_libubi;
        }
 
-       if (args.maxavs) {
-               args.bytes = dev_info.avail_bytes;
-               printf("Set volume size to %lld\n", req.bytes);
-       }
+       req.vol_id = myargs.vol_id;
+       req.alignment = myargs.alignment;
 
-       if (args.lebs != -1) {
-               args.bytes = dev_info.leb_size;
-               args.bytes -= dev_info.leb_size % args.alignment;
-               args.bytes *= args.lebs;
-       }
+       if (myargs.maxavs) {
+               struct ubi_dev_info ubi_dev;
+
+               err = ubi_get_dev_info1(libubi, myargs.devn, &ubi_dev);
+               if (err) {
+                       perror("Can't get UBI device info");
+                       goto out_libubi;
+               }
+               req.bytes = ubi_dev.avail_bytes;
+               if (!req.bytes) {
+                       fprintf(stderr, "There is no available free space on device!\n");
+                       goto out_libubi;
+               }
+               printf("Setting the volume size to %lld\n", req.bytes);
+       } else
+               req.bytes = myargs.bytes;
 
-       req.vol_id = args.vol_id;
-       req.alignment = args.alignment;
-       req.bytes = args.bytes;
-       req.vol_type = args.vol_type;
-       req.name = args.name;
+       req.vol_type = myargs.vol_type;
+       req.name = myargs.name;
 
-       err = ubi_mkvol(libubi, args.node, &req);
+       err = ubi_mkvol(libubi, myargs.node, &req);
        if (err < 0) {
-               sys_errmsg("cannot UBI create volume");
+               perror("Cannot create volume");
+               fprintf(stderr, "  err=%d\n", err);
                goto out_libubi;
        }
 
-       args.vol_id = req.vol_id;
-
-       /* Print information about the created device */
-       err = ubi_get_vol_info1(libubi, dev_info.dev_num, args.vol_id, &vol_info);
-       if (err) {
-               sys_errmsg("cannot get information about newly created UBI volume");
-               goto out_libubi;
+       /*
+        * This is hacky, but we want to wait until udev has created device
+        * nodes. There is probably better way do do this, though.
+        */
+       if (system("udevsettle")) {
+               /* Well, this is to keep GCC silent */
        }
 
-       printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs);
-       ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
-       printf("), LEB size ");
-       ubiutils_print_bytes(vol_info.leb_size, 1);
-       printf(", %s, name \"%s\", alignment %d\n",
-              req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static",
-              vol_info.name, vol_info.alignment);
+       /* printf("Created volume %d, %lld bytes, type %s, name %s\n",
+          vol_id, bytes, vol_type == UBI_DYNAMIC_VOLUME ?
+          "dynamic" : "static", name); */
 
+       myargs.vol_id = err;
        libubi_close(libubi);
        return 0;
 
index c30446ad840ada4b60e7ada7d2d574094a1f666b..6dd16baaf6b0c325d37b27c58592cc445082a10a 100644 (file)
 /*
  * An utility to remove UBI volumes.
  *
- * Authors: Artem Bityutskiy <dedekind@infradead.org>
- *          Frank Haverkamp <haver@vnet.ibm.com>
+ * Author: Artem B. Bityutskiy <dedekind@linutronix.de>
+ *         Frank Haverkamp <haver@vnet.ibm.com>
+ *
+ * 1.1 Reworked the userinterface to use argp.
+ * 1.2 Removed argp because we want to use uClibc.
+ * 1.3 Minor cleanups
+ * 1.4 Use a different libubi
  */
 
 #include <stdio.h>
 #include <getopt.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
+#include <config.h>
 #include <libubi.h>
-#include "common.h"
 
-#define PROGRAM_VERSION "1.5"
-#define PROGRAM_NAME    "ubirmvol"
+#define PROGRAM_VERSION "1.4"
 
-/* The variables below are set by command line arguments */
+/*
+ * The below variables are set by command line options.
+ */
 struct args {
+       int devn;
        int vol_id;
-       const char *node;
+       char node[256];
+
+       /* special stuff needed to get additional arguments */
+       char *arg1;
+       char **options;         /* [STRING...] */
 };
 
-static struct args args = {
+static struct args myargs = {
+       .devn = -1,
        .vol_id = -1,
-       .node = NULL,
+
+       .arg1 = NULL,
+       .options = NULL,
 };
 
-static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
-                                " - a tool to remove UBI volumes.";
+static int param_sanity_check(struct args *args, libubi_t libubi);
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+       "ubirmvol - make UBI Volume.\n";
 
 static const char *optionsstr =
-"  -n, --vol_id=<volume id>   volume ID to remove\n"
-"  -h, --help                 print help message\n"
-"  -V, --version              print program version";
+"  -d, --devn=<devn>          UBI device\n"
+"  -n, --vol_id=<volume id>   UBI volume id, if not specified, the volume ID\n"
+"                             will be assigned automatically\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: " PROGRAM_NAME " <UBI device node file name> [-n <volume id>] [--vol_id=<volume id>] [-h] [--help]\n\n"
-"Example: " PROGRAM_NAME "/dev/ubi0 -n 1 - remove UBI volume 1 from UBI device corresponding\n"
-"         to the node file /dev/ubi0.";
-
-static const struct option long_options[] = {
-       { .name = "vol_id",  .has_arg = 1, .flag = NULL, .val = 'n' },
-       { .name = "help",    .has_arg = 0, .flag = NULL, .val = 'h' },
+"Usage: ubirmvol [-?V] [-d <devn>] [-n <volume id>] [--devn=<devn>]\n"
+"            [--vol_id=<volume id>] [--help] [--usage] [--version]\n";
+
+struct option long_options[] = {
+       { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+       { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+       { .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},
+       { NULL, 0, NULL, 0}
 };
 
-static int param_sanity_check(void)
+/*
+ * @brief Parse the arguments passed into the test case.
+ *
+ * @param argc          The number of arguments
+ * @param argv          The list of arguments
+ * @param args          Pointer to argument structure
+ *
+ * @return error
+ *
+ */
+static int
+parse_opt(int argc, char **argv, struct args *args)
 {
-       if (args.vol_id == -1) {
-               errmsg("volume ID is was not specified");
-               return -1;
-       }
-
-       return 0;
-}
+       char *endp;
 
-static int parse_opt(int argc, char * const argv[])
-{
        while (1) {
                int key;
-               char *endp;
 
-               key = getopt_long(argc, argv, "n:hV", long_options, NULL);
+               key = getopt_long(argc, argv, "d:n:?V", long_options, NULL);
                if (key == -1)
                        break;
 
                switch (key) {
+                       case 'd': /* --devn=<device number> */
+                               args->devn = strtoul(optarg, &endp, 0);
+                               if (*endp != '\0' || endp == optarg ||
+                                       args->devn < 0) {
+                                       fprintf(stderr,
+                                               "Bad UBI device number: "
+                                               "\"%s\"\n", optarg);
+                                       goto out;
+                               }
+                               sprintf(args->node, "/dev/ubi%d", args->devn);
+                               break;
+                       case 'n': /* --volid=<volume id> */
+                               args->vol_id = strtoul(optarg, &endp, 0);
+                               if (*endp != '\0' || endp == optarg ||
+                                   (args->vol_id < 0 &&
+                                    args->vol_id != UBI_DYNAMIC_VOLUME)) {
+                                       fprintf(stderr, "Bad volume ID: "
+                                                       "\"%s\"\n", optarg);
+                                       goto out;
+                               }
+                               break;
+                       case ':':
+                               fprintf(stderr, "Parameter is missing\n");
+                               goto out;
+                       case '?': /* help */
+                               fprintf(stderr,
+                                       "Usage: ubirmvol [OPTION...]\n");
+                               fprintf(stderr, "%s", doc);
+                               fprintf(stderr, "%s", optionsstr);
+                               fprintf(stderr, "\nReport bugs to %s\n",
+                                       PACKAGE_BUGREPORT);
+                               exit(0);
+                               break;
+                       case 'V':
+                               fprintf(stderr, "%s\n", PROGRAM_VERSION);
+                               exit(0);
+                               break;
+                       default:
+                               fprintf(stderr, "%s", usage);
+                               exit(-1);
+               }
+       }
 
-               case 'n':
-                       args.vol_id = strtoul(optarg, &endp, 0);
-                       if (*endp != '\0' || endp == optarg || args.vol_id < 0) {
-                               errmsg("bad volume ID: " "\"%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);
+       return 0;
+ out:
+       return -1;
+}
 
-               case ':':
-                       errmsg("parameter is missing");
-                       return -1;
+static int param_sanity_check(struct args *args, libubi_t libubi)
+{
+       int err;
+       struct ubi_info ubi;
 
-               default:
-                       fprintf(stderr, "Use -h for help\n");
-                       return -1;
-               }
+       if (args->vol_id == -1) {
+               fprintf(stderr, "Volume ID was not specified\n");
+               goto out;
        }
 
-       if (optind == argc) {
-               errmsg("UBI device name was not specified (use -h for help)");
-               return -1;
-       } else if (optind != argc - 1) {
-               errmsg("more then one UBI device specified (use -h for help)");
+       err = ubi_get_info(libubi, &ubi);
+       if (err)
                return -1;
-       }
 
-       args.node = argv[optind];
-
-       if (param_sanity_check())
-               return -1;
+       if (args->devn >= (int)ubi.dev_count) {
+               fprintf(stderr, "Device %d does not exist\n", args->devn);
+               goto out;
+       }
 
        return 0;
+
+out:
+       errno = EINVAL;
+       return -1;
 }
 
 int main(int argc, char * const argv[])
 {
-       int err;
+       int err, old_errno;
        libubi_t libubi;
 
-       err = parse_opt(argc, argv);
+       err = parse_opt(argc, (char **)argv, &myargs);
        if (err)
+               return err == 1 ? 0 : -1;
+
+       if (myargs.devn == -1) {
+               fprintf(stderr, "Device number was not specified\n");
+               fprintf(stderr, "Use -h option for help\n");
                return -1;
+       }
 
        libubi = libubi_open();
-       if (libubi == NULL)
-               return sys_errmsg("cannot open libubi");
+       if (libubi == NULL) {
+               perror("Cannot open libubi");
+               return -1;
+       }
 
-       err = ubi_node_type(libubi, args.node);
-       if (err == 2) {
-               errmsg("\"%s\" is an UBI volume node, not an UBI device node",
-                      args.node);
-               goto out_libubi;
-       } else if (err < 0) {
-               errmsg("\"%s\" is not an UBI device node", args.node);
+       err = param_sanity_check(&myargs, libubi);
+       if (err) {
+               perror("Input parameters check");
+               fprintf(stderr, "Use -h option for help\n");
                goto out_libubi;
        }
 
-       err = ubi_rmvol(libubi, args.node, args.vol_id);
-       if (err) {
-               sys_errmsg("cannot UBI remove volume");
+       err = ubi_rmvol(libubi, myargs.node, myargs.vol_id);
+       old_errno = errno;
+       if (err < 0) {
+               perror("Cannot remove volume");
+               fprintf(stderr, "    err=%d errno=%d\n", err, old_errno);
                goto out_libubi;
        }
 
similarity index 98%
rename from tests/ubi-tests/helpers/ubiupdatevol.c
rename to ubi-utils/src/ubiupdatevol.c
index 6863e2a2b755ce0d99d7b59a219bd0c883d386cc..807b9616bcde8da19fec17a58e72687b5e718a78 100644 (file)
@@ -39,6 +39,7 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
+#include <config.h>
 #include <libubi.h>
 
 #define PROGRAM_VERSION "1.3"
@@ -141,8 +142,9 @@ parse_opt(int argc, char **argv, struct args *args)
 
                        case '?': /* help */
                                fprintf(stderr, "Usage: "
-                                       "ubiupdatevol [OPTION...] <image file>\n%s%s\n",
-                                       doc, optionsstr);
+                                       "ubiupdatevol [OPTION...] <image file>\n%s%s"
+                                       "\nReport bugs to %s\n",
+                                       doc, optionsstr, PACKAGE_BUGREPORT);
                                exit(EXIT_SUCCESS);
                                break;
 
@@ -182,7 +184,6 @@ ubi_truncate_volume(struct args *args, int64_t bytes,libubi_t libubi)
        ofd = open(path, O_RDWR);
        if (ofd < 0) {
                fprintf(stderr, "Cannot open volume %s\n", path);
-               perror("open");
                exit(EXIT_FAILURE);
        }
        rc = ubi_update_start(libubi, ofd, bytes);
diff --git a/ubi-utils/testcases.txt b/ubi-utils/testcases.txt
new file mode 100644 (file)
index 0000000..dcc1c35
--- /dev/null
@@ -0,0 +1,9 @@
+1. Start some large update, but write there byte-by-byte
+
+2. start update for N bytes, write N-x bytes, then write y bytes, y>x.
+   You have to see that at the last write only x bytes were written,
+   but y-x bytes were not. we may vary x a bit. good number would be
+   1, 128, 128Ki-128...
+
+3. Try to start update for x bytes, write x bytes, then try to write more.
+   Check that it is impossible to write more.
diff --git a/ubi-utils/tests/Makefile b/ubi-utils/tests/Makefile
new file mode 100644 (file)
index 0000000..1b17f81
--- /dev/null
@@ -0,0 +1,40 @@
+
+INCLUDE1=../inc
+INCLUDE2=../../include
+LIB=.
+
+CC := $(CROSS)gcc
+
+ALL_FILES=libubi.a io_update
+ALL_FILES+=io_paral io_read io_basic mkvol_basic mkvol_bad mkvol_paral rsvol
+ALL_FILES+=integ
+
+CFLAGS += -Wall -I$(INCLUDE1) -I$(INCLUDE2) -L$(LIB) -ggdb
+
+all: $(ALL_FILES)
+
+libubi.a: ../src/libubi.c  ../inc/libubi.h  ../src/libubi_int.h
+       $(CC) $(CFLAGS) -c ../src/libubi.c -o libubi.o
+       ar cr libubi.a libubi.o
+
+io_paral: io_paral.c common.c
+       $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@
+io_update: io_update.c common.c
+       $(CC) $(CFLAGS) $^ -lubi -o $@
+io_read: io_read.c common.c
+       $(CC) $(CFLAGS) $^ -lubi -o $@
+io_basic: io_basic.c common.c
+       $(CC) $(CFLAGS) $^ -lubi -o $@
+mkvol_basic: mkvol_basic.c common.c
+       $(CC) $(CFLAGS) $^ -lubi -o $@
+mkvol_bad: mkvol_bad.c common.c
+       $(CC) $(CFLAGS) $^ -lubi -o $@
+mkvol_paral: mkvol_paral.c common.c
+       $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@
+rsvol: rsvol.c common.c
+       $(CC) $(CFLAGS) $^ -lubi -o $@
+integ: integ.c
+       $(CC) $(CFLAGS) $^ -lubi -o $@
+
+clean:
+       rm -rf $(ALL_FILES) $(addsuffix .o, $(ALL_FILES))
diff --git a/ubi-utils/tests/README.udev b/ubi-utils/tests/README.udev
new file mode 100644 (file)
index 0000000..a4ff9c5
--- /dev/null
@@ -0,0 +1,19 @@
+There is a problem with udev: when a volume is created, there is a delay
+before corresponding /dev/ubiX_Y device node is created by udev, so some
+tests fail because of this. The symptom is error messages like
+"cannot open /dev/ubi0_0".
+
+One possible solution of this problem is to pre-create UBI device and volume
+nodes. there is even a script which may be used for this in ubi-utils/scripts/.
+But this is not enough because udev will still remove and re-create the nodes
+and tests will still fail. So you need to stop removing device nodes using
+the following udev rule:
+
+       KERNEL=="ubi*_*", ACTION=="remove", OPTIONS+="ignore_device"
+
+In our Ubuntu distribution we put that to new file:
+/etc/udev/rules.d/50-local.rules
+
+Another possibility is to call udevsettle utility in libubi after the volume
+has been created See src/libubi.c - the call is there but is commented out.
+This is anyway an ugly hack, but works, although makes the tests slower.
diff --git a/ubi-utils/tests/common.c b/ubi-utils/tests/common.c
new file mode 100644 (file)
index 0000000..cb63e77
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * The stuff which is common for many tests.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#include "common.h"
+
+/**
+ * __initial_check - check that common prerequisites which are required to run
+ * tests.
+ *
+ * @test  test name
+ * @argc  count of command-line arguments
+ * @argv  command-line arguments
+ *
+ * This function returns %0 if all is fine and test may be run and %-1 if not.
+ */
+int __initial_check(const char *test, int argc, char * const argv[])
+{
+       libubi_t libubi;
+       struct ubi_dev_info dev_info;
+
+       /*
+        * All tests require UBI character device name as the first parameter,
+        * check this.
+        */
+       if (argc < 2) {
+               __err_msg(test, __FUNCTION__, __LINE__,
+                         "UBI character device node is not specified");
+               return -1;
+       }
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               __failed(test, __FUNCTION__, __LINE__, "libubi_open");
+               return -1;
+       }
+
+       if (ubi_get_dev_info(libubi, argv[1], &dev_info)) {
+               __failed(test, __FUNCTION__, __LINE__, "ubi_get_dev_info");
+               goto close;
+       }
+
+       if (dev_info.avail_ebs < MIN_AVAIL_EBS) {
+               __err_msg(test, __FUNCTION__, __LINE__,
+                         "insufficient available eraseblocks %d on UBI "
+                         "device, required %d",
+                         dev_info.avail_ebs, MIN_AVAIL_EBS);
+               goto close;
+       }
+
+       if (dev_info.vol_count != 0) {
+               __err_msg(test, __FUNCTION__, __LINE__,
+                         "device %s is not empty", argv[1]);
+               goto close;
+       }
+
+       libubi_close(libubi);
+       return 0;
+
+close:
+       libubi_close(libubi);
+       return -1;
+}
+
+/**
+ * __err_msg - print a message to stderr.
+ *
+ * @test  test name
+ * @func  function name
+ * @line  line number
+ * @fmt   format string
+ */
+void __err_msg(const char *test, const char *func, int line,
+              const char *fmt, ...)
+{
+       va_list args;
+
+       fprintf(stderr, "[%s] %s():%d: ", test, func, line);
+       va_start(args, fmt);
+       vfprintf(stderr, fmt, args);
+       fprintf(stderr, "\n");
+       va_end(args);
+}
+
+/**
+ * __failed - print function fail message.
+ *
+ * @test    test name
+ * @func    calling function name
+ * @line    line number
+ * @failed  failed function name
+ */
+void __failed(const char *test, const char *func, int line,
+             const char *failed)
+{
+       fprintf(stderr, "[%s] %s():%d: function %s() failed with error %d (%s)\n",
+               test, func, line, failed, errno, strerror(errno));
+}
+
+/**
+ * __check_volume - check volume information.
+ *
+ * @libubi    libubi descriptor
+ * @dev_info  UBI device description
+ * @test      test name
+ * @func      function name
+ * @line      line number
+ * @vol_id    ID of existing volume to check
+ * @req       volume creation request to compare with
+ *
+ * This function checks if a volume created using @req request has exactly the
+ * requested characteristics. Returns 0 in case of success and %-1 in case of
+ * error.
+ */
+int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info,
+                  const char *test, const char *func, int line, int vol_id,
+                  const struct ubi_mkvol_request *req)
+{
+       int ret;
+       struct ubi_vol_info vol_info;
+       int eb_size;
+       long long rsvd_bytes;
+
+       ret = ubi_get_vol_info1(libubi, dev_info->dev_num, vol_id, &vol_info);
+       if (ret) {
+               __failed(test, func, line, "ubi_get_vol_info");
+               return -1;
+       }
+
+       if (req->alignment != vol_info.alignment) {
+               __err_msg(test, func, line,
+                         "bad alignment: requested %d, got %d",
+                         req->alignment, vol_info.alignment);
+               return -1;
+       }
+       if (req->vol_type != vol_info.type) {
+               __err_msg(test, func, line, "bad type: requested %d, got %d",
+                         req->vol_type, vol_info.type);
+               return -1;
+       }
+       if (strlen(req->name) != strlen(&vol_info.name[0]) ||
+           strcmp(req->name, &vol_info.name[0]) != 0) {
+               __err_msg(test, func, line,
+                         "bad name: requested \"%s\", got \"%s\"",
+                         req->name, &vol_info.name[0]);
+               return -1;
+       }
+       if (vol_info.corrupted) {
+               __err_msg(test, func, line, "corrupted new volume");
+               return -1;
+       }
+
+       eb_size = dev_info->eb_size - (dev_info->eb_size % req->alignment);
+       if (eb_size != vol_info.eb_size) {
+               __err_msg(test, func, line,
+                         "bad usable LEB size %d, should be %d",
+                         vol_info.eb_size, eb_size);
+               return -1;
+       }
+
+       rsvd_bytes = req->bytes;
+       if (rsvd_bytes % eb_size)
+               rsvd_bytes += eb_size - (rsvd_bytes % eb_size);
+
+       if (rsvd_bytes != vol_info.rsvd_bytes) {
+               __err_msg(test, func, line,
+                         "bad reserved bytes %lld, should be %lld",
+                         vol_info.rsvd_bytes, rsvd_bytes);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * __check_vol_patt - check that volume contains certain data
+ *
+ * @libubi    libubi descriptor
+ * @dev_info  UBI device description
+ * @test    test name
+ * @func    function name
+ * @line    line number
+ * @node    volume character device node
+ * @byte    data pattern to check
+ *
+ * This function returns %0 if the volume contains only @byte bytes, and %-1 if
+ * not.
+ */
+int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info,
+                    const char *test, const char *func, int line,
+                    const char *node, uint8_t byte)
+{
+       int ret, fd;
+       long long bytes = 0;
+       struct ubi_vol_info vol_info;
+       unsigned char buf[512];
+
+       fd = open(node, O_RDONLY);
+       if (fd == -1) {
+               __failed(test, func, line, "open");
+               __err_msg(test, func, line, "cannot open \"%s\"\n", node);
+               return -1;
+       }
+
+       ret = ubi_get_vol_info(libubi, node, &vol_info);
+       if (ret) {
+               __failed(test, func, line, "ubi_get_vol_info");
+               goto close;
+       }
+
+       while (bytes < vol_info.data_bytes) {
+               int i;
+
+               memset(&buf[0], ~byte, 512);
+               ret = read(fd, &buf[0], 512);
+               if (ret == -1) {
+                       __failed(test, func, line, "read");
+                       __err_msg(test, func, line, "bytes = %lld, ret = %d",
+                                 bytes, ret);
+                       goto close;
+               }
+
+               if (ret == 0 && bytes + ret < vol_info.data_bytes) {
+                       __err_msg(test, func, line,
+                                 "EOF, but read only %lld bytes of %lld",
+                                 bytes + ret, vol_info.data_bytes);
+                       goto close;
+               }
+
+               for (i = 0; i < ret; i++)
+                       if (buf[i] != byte) {
+                               __err_msg(test, func, line,
+                                         "byte at %lld is not %#x but %#x",
+                                         bytes + i, byte, (int)buf[i]);
+                               goto close;
+                       }
+
+               bytes += ret;
+       }
+
+       close(fd);
+       return 0;
+
+close:
+       close(fd);
+       return -1;
+}
+
+/**
+ * __update_vol_patt - update volume using a certain byte pattern
+ *
+ * @libubi    libubi descriptor
+ * @dev_info  UBI device description
+ * @test      test name
+ * @func      function name
+ * @line      line number
+ * @node      volume character device node
+ * @byte      data pattern to check
+ *
+ * This function returns %0 in case of success, and %-1 if in case of failure.
+ */
+int __update_vol_patt(libubi_t libubi, const char *test, const char *func,
+                     int line, const char *node, long long bytes, uint8_t byte)
+{
+       int ret, fd;
+       long long written = 0;
+       unsigned char buf[512];
+
+       fd = open(node, O_RDWR);
+       if (fd == -1) {
+               __failed(test, func, line, "open");
+               __err_msg(test, func, line, "cannot open \"%s\"\n", node);
+               return -1;
+       }
+
+       if (ubi_update_start(libubi, fd, bytes)) {
+               __failed(test, func, line, "ubi_update_start");
+               __err_msg(test, func, line, "bytes = %lld", bytes);
+               goto close;
+       }
+
+       memset(&buf[0], byte, 512);
+
+       while (written != bytes) {
+               ret = write(fd, &buf[0], 512);
+               if (ret == -1) {
+                       __failed(test, func, line, "write");
+                       __err_msg(test, func, line, "written = %lld, ret = %d",
+                                 written, ret);
+                       goto close;
+               }
+               written += ret;
+
+               if (written > bytes) {
+                       __err_msg(test, func, line, "update length %lld bytes, "
+                                 "but %lld bytes are already written",
+                                 bytes, written);
+                       goto close;
+               }
+       }
+
+       close(fd);
+       return 0;
+
+close:
+       close(fd);
+       return -1;
+}
diff --git a/ubi-utils/tests/common.h b/ubi-utils/tests/common.h
new file mode 100644 (file)
index 0000000..3e8ada8
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * The stuff which is common for many tests.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UBI_VOLUME_PATTERN "/dev/ubi%d_%d"
+#define MIN_AVAIL_EBS 5
+#define PAGE_SIZE 4096
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+#define err_msg(fmt, ...)                                                      \
+       __err_msg(TESTNAME, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+#define failed(name)                                                           \
+       __failed(TESTNAME, __FUNCTION__, __LINE__, name)
+
+#define initial_check(argc, argv)                                              \
+       __initial_check(TESTNAME, argc, argv)
+
+#define check_volume(vol_id, req)                                              \
+       __check_volume(libubi, &dev_info, TESTNAME, __FUNCTION__,              \
+                      __LINE__, vol_id, req)
+
+#define check_vol_patt(node, byte)                                             \
+       __check_vol_patt(libubi, &dev_info, TESTNAME, __FUNCTION__, __LINE__,  \
+                        node, byte)
+
+#define update_vol_patt(node, bytes, byte)                                     \
+       __update_vol_patt(libubi, TESTNAME, __FUNCTION__, __LINE__,            \
+                         node, bytes, byte)
+
+#define check_failed(ret, error, func, fmt, ...) ({                            \
+       int __ret;                                                             \
+                                                                              \
+       if (!ret) {                                                            \
+               err_msg("%s() returned success but should have failed", func); \
+               err_msg(fmt, ##__VA_ARGS__);                                   \
+               __ret = -1;                                                    \
+       }                                                                      \
+       if (errno != (error)) {                                                \
+               err_msg("%s failed with error %d (%s), expected %d (%s)",      \
+                       func, errno, strerror(errno), error, strerror(error)); \
+               err_msg(fmt, ##__VA_ARGS__);                                   \
+               __ret = -1;                                                    \
+       }                                                                      \
+       __ret = 0;                                                             \
+})
+
+/* Alignments to test, @s is eraseblock size */
+#define ALIGNMENTS(s)                                                          \
+       {3, 5, 27, 666, 512, 1024, 2048, (s)/2-3, (s)/2-2, (s)/2-1, (s)/2+1,   \
+        (s)/2+2, (s)/2+3, (s)/3-3, (s)/3-2, (s)/3-1, (s)/3+1, (s)/3+2,        \
+        (s)/3+3, (s)/4-3, (s)/4-2, (s)/4-1, (s)/4+1, (s)/4+2, (s)/4+3,        \
+        (s)/5-3, (s)/5-2, (s)/5-1, (s)/5+1, (s)/5+2, (s)/5+3, (s)-17, (s)-9,  \
+        (s)-8, (s)-6, (s)-4, (s)-1, (s)};
+
+extern void __err_msg(const char *test, const char *func, int line,
+                     const char *fmt, ...);
+void __failed(const char *test, const char *func, int line,
+             const char *failed);
+int __initial_check(const char *test, int argc, char * const argv[]);
+int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info,
+                  const char *test, const char *func, int line, int vol_id,
+                  const struct ubi_mkvol_request *req);
+int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info,
+                    const char *test, const char *func, int line,
+                    const char *node, uint8_t byte);
+int __update_vol_patt(libubi_t libubi, const char *test, const char *func,
+                     int line, const char *node, long long bytes,
+                     uint8_t byte);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__COMMON_H__ */
diff --git a/ubi-utils/tests/integ.c b/ubi-utils/tests/integ.c
new file mode 100644 (file)
index 0000000..4da7121
--- /dev/null
@@ -0,0 +1,783 @@
+#define _LARGEFILE64_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include "libubi.h"
+
+struct erase_block_info;
+struct volume_info;
+struct ubi_device_info;
+
+struct write_info
+{
+       struct write_info *next;
+       struct erase_block_info *erase_block;
+       int offset_within_block; /* Offset within erase block */
+       off64_t offset; /* Offset within volume */
+       int size;
+       int random_seed;
+};
+
+struct erase_block_info
+{
+       struct volume_info *volume;
+       int block_number;
+       off64_t offset; /* Offset within volume */
+       off64_t top_of_data;
+       int touched; /* Have we done anything at all with this erase block */
+       int erased; /* This erased block is currently erased */
+       struct write_info *writes;
+};
+
+struct volume_fd
+{
+       struct volume_fd *next;
+       struct volume_info *volume;
+       int fd;
+};
+
+struct volume_info
+{
+       struct volume_info *next;
+       struct ubi_device_info *ubi_device;
+       struct volume_fd *fds;
+       struct erase_block_info *erase_blocks;
+       const char *device_file_name;
+       struct ubi_vol_info info;
+};
+
+struct ubi_device_info
+{
+       struct volume_info *volumes;
+       const char *device_file_name;
+       struct ubi_dev_info info;
+};
+
+struct open_volume_fd
+{
+       struct open_volume_fd *next;
+       struct volume_fd *vol_fd;
+};
+
+#define MAX_UBI_DEVICES 64
+
+static libubi_t libubi;
+
+static struct ubi_info info;
+static struct ubi_device_info ubi_array[MAX_UBI_DEVICES];
+
+static uint64_t total_written = 0;
+static uint64_t total_space = 0;
+
+static struct open_volume_fd *open_volumes;
+static size_t open_volume_count = 0;
+
+static const char *ubi_module_load_string;
+
+static unsigned char *write_buffer = NULL;
+static unsigned char *read_buffer = NULL;
+
+static long long max_ebs_per_vol = 0; /* max number of ebs per vol (zero => no max) */
+
+static unsigned long next_seed = 1;
+
+static unsigned get_next_seed()
+{
+       next_seed = next_seed * 1103515245 + 12345;
+       return ((unsigned) (next_seed / 65536) % 32768);
+}
+
+static void error_exit(const char *msg)
+{
+       int eno = errno;
+       fprintf(stderr,"UBI Integrity Test Error: %s\n",msg);
+       if (eno) {
+               fprintf(stderr, "errno = %d\n", eno);
+               fprintf(stderr, "strerror = %s\n", strerror(eno));
+       }
+       exit(1);
+}
+
+static void *allocate(size_t n)
+{
+       void *p = malloc(n);
+       if (!p)
+               error_exit("Memory allocation failure");
+       memset(p, 0, n);
+       return p;
+}
+
+static unsigned get_random_number(unsigned n)
+{
+       uint64_t r, b;
+
+       if (n < 1)
+               return 0;
+       r = rand();
+       r *= n;
+       b = RAND_MAX;
+       b += 1;
+       r /= b;
+       return r;
+}
+
+static struct volume_fd *open_volume(struct volume_info *vol)
+{
+       struct volume_fd *s;
+       struct open_volume_fd *ofd;
+       int fd;
+
+       if (vol->fds) {
+               /* If already open dup it */
+               fd = dup(vol->fds->fd);
+               if (fd == -1)
+                       error_exit("Failed to dup volume device file des");
+       } else {
+               fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE);
+               if (fd == -1)
+                       error_exit("Failed to open volume device file");
+       }
+       s = allocate(sizeof(*s));
+       s->fd = fd;
+       s->volume = vol;
+       s->next = vol->fds;
+       vol->fds = s;
+       /* Add to open volumes list */
+       ofd = allocate(sizeof(*ofd));
+       ofd->vol_fd = s;
+       ofd->next = open_volumes;
+       open_volumes = ofd;
+       open_volume_count += 1;
+       return 0;
+}
+
+static void close_volume(struct volume_fd *vol_fd)
+{
+       struct volume_fd *vfd, *vfd_last;
+       struct open_volume_fd *ofd, *ofd_last;
+       int fd = vol_fd->fd;
+
+       /* Remove from open volumes list */
+       ofd_last = NULL;
+       ofd = open_volumes;
+       while (ofd) {
+               if (ofd->vol_fd == vol_fd) {
+                       if (ofd_last)
+                               ofd_last->next = ofd->next;
+                       else
+                               open_volumes = ofd->next;
+                       free(ofd);
+                       open_volume_count -= 1;
+                       break;
+               }
+               ofd_last = ofd;
+               ofd = ofd->next;
+       }
+       /* Remove from volume fd list */
+       vfd_last = NULL;
+       vfd = vol_fd->volume->fds;
+       while (vfd) {
+               if (vfd == vol_fd) {
+                       if (vfd_last)
+                               vfd_last->next = vfd->next;
+                       else
+                               vol_fd->volume->fds = vfd->next;
+                       free(vfd);
+                       break;
+               }
+               vfd_last = vfd;
+               vfd = vfd->next;
+       }
+       /* Close volume device file */
+       if (close(fd) == -1)
+               error_exit("Failed to close volume file descriptor");
+}
+
+static void set_random_data(unsigned seed, unsigned char *buf, int size)
+{
+       int i;
+       unsigned r;
+
+       r = rand();
+       srand(seed);
+       for (i = 0; i < size; ++i)
+               buf[i] = rand();
+       srand(r);
+}
+
+#if 0
+static void print_write_info(struct write_info *w)
+{
+       printf("Offset: %lld  Size:%d  Seed:%u\n", w->offset, w->size, w->random_seed);
+       fflush(stdout);
+}
+#endif
+
+static void check_erase_block(struct erase_block_info *erase_block, int fd)
+{
+       struct write_info *w;
+       off64_t gap_end;
+       int eb_size = erase_block->volume->info.eb_size;
+       ssize_t bytes_read;
+
+       w = erase_block->writes;
+       gap_end = erase_block->offset + eb_size;
+       while (w) {
+               if (w->offset + w->size < gap_end) {
+                       /* There is a gap. Check all 0xff */
+                       off64_t gap_start = w->offset + w->size;
+                       size_t size = gap_end - gap_start;
+                       if (lseek64(fd, gap_start, SEEK_SET) != gap_start)
+                               error_exit("lseek64 failed");
+                       memset(read_buffer, 0 , size);
+                       errno = 0;
+                       bytes_read = read(fd, read_buffer, size);
+                       if (bytes_read != size)
+                               error_exit("read failed in gap");
+                       while (size)
+                               if (read_buffer[--size] != 0xff) {
+                                       fprintf(stderr, "block no. = %d\n" , erase_block->block_number);
+                                       fprintf(stderr, "offset = %lld\n" , (long long) gap_start);
+                                       fprintf(stderr, "size = %ld\n" , (long) bytes_read);
+                                       error_exit("verify 0xff failed");
+                               }
+               }
+               if (lseek64(fd, w->offset, SEEK_SET) != w->offset)
+                       error_exit("lseek64 failed");
+               memset(read_buffer, 0 , w->size);
+               errno = 0;
+               bytes_read = read(fd, read_buffer, w->size);
+               if (bytes_read != w->size) {
+                       fprintf(stderr, "offset = %lld\n" , (long long) w->offset);
+                       fprintf(stderr, "size = %ld\n" , (long) w->size);
+                       fprintf(stderr, "bytes_read = %ld\n" , (long) bytes_read);
+                       error_exit("read failed");
+               }
+               set_random_data(w->random_seed, write_buffer, w->size);
+               if (memcmp(read_buffer, write_buffer, w->size))
+                       error_exit("verify failed");
+               gap_end = w->offset;
+               w = w->next;
+       }
+       if (gap_end > erase_block->offset) {
+               /* Check all 0xff */
+               off64_t gap_start = erase_block->offset;
+               size_t size = gap_end - gap_start;
+               if (lseek64(fd, gap_start, SEEK_SET) != gap_start)
+                       error_exit("lseek64 failed");
+               memset(read_buffer, 0 , size);
+               errno = 0;
+               bytes_read = read(fd, read_buffer, size);
+               if (bytes_read != size)
+                       error_exit("read failed in gap");
+               while (size)
+                       if (read_buffer[--size] != 0xff) {
+                               fprintf(stderr, "block no. = %d\n" , erase_block->block_number);
+                               fprintf(stderr, "offset = %lld\n" , (long long) gap_start);
+                               fprintf(stderr, "size = %ld\n" , (long) bytes_read);
+                               error_exit("verify 0xff failed!");
+                       }
+       }
+}
+
+static int write_to_erase_block(struct erase_block_info *erase_block, int fd)
+{
+       int page_size = erase_block->volume->ubi_device->info.min_io_size;
+       int eb_size = erase_block->volume->info.eb_size;
+       int next_offset = 0;
+       int space, size;
+       off64_t offset;
+       unsigned seed;
+       struct write_info *w;
+
+       if (erase_block->writes)
+               next_offset = erase_block->writes->offset_within_block + erase_block->writes->size;
+       space = eb_size - next_offset;
+       if (space <= 0)
+               return 0; /* No space */
+       if (!get_random_number(10)) {
+               /* 1 time in 10 leave a gap */
+               next_offset += get_random_number(space);
+               next_offset = (next_offset / page_size) * page_size;
+               space = eb_size - next_offset;
+       }
+       if (get_random_number(2))
+               size = 1 * page_size;
+       else if (get_random_number(2))
+               size = 2 * page_size;
+       else if (get_random_number(2))
+               size = 3 * page_size;
+       else if (get_random_number(2))
+               size = 4 * page_size;
+       else {
+               if (get_random_number(4))
+                       size = get_random_number(space);
+               else
+                       size = space;
+               size = (size / page_size) * page_size;
+       }
+       if (size == 0 || size > space)
+               size = page_size;
+       if (next_offset + size > eb_size)
+               error_exit("internal error");
+       offset = erase_block->offset + next_offset;
+       if (offset < erase_block->top_of_data)
+               error_exit("internal error!");
+       if (lseek64(fd, offset, SEEK_SET) != offset)
+               error_exit("lseek64 failed");
+       /* Do write */
+       seed = get_next_seed();
+       if (!seed)
+               seed = 1;
+       set_random_data(seed, write_buffer, size);
+       if (write(fd, write_buffer, size) != size)
+               error_exit("write failed");
+       erase_block->top_of_data = offset + size;
+       /* Make write info and add to eb */
+       w = allocate(sizeof(*w));
+       w->offset_within_block = next_offset;
+       w->offset = offset;
+       w->size = size;
+       w->random_seed = seed;
+       w->next = erase_block->writes;
+       erase_block->writes = w;
+       erase_block->touched = 1;
+       erase_block->erased = 0;
+       total_written += size;
+       return 1;
+}
+
+static void erase_erase_block(struct erase_block_info *erase_block, int fd)
+{
+       struct write_info *w;
+       uint32_t eb_no;
+       int res;
+
+       eb_no = erase_block->block_number;
+       res = ioctl(fd, UBI_IOCEBER, &eb_no);
+       if (res)
+               error_exit("Failed to erase an erase block");
+       /* Remove writes from this eb */
+       while (erase_block->writes) {
+               w = erase_block->writes;
+               erase_block->writes = erase_block->writes->next;
+               free(w);
+       }
+       erase_block->erased = 1;
+       erase_block->touched = 1;
+       erase_block->top_of_data = erase_block->offset;
+}
+
+static void operate_on_erase_block(struct erase_block_info *erase_block, int fd)
+{
+       /*
+       Possible operations:
+               read from it and verify
+               write to it
+               erase it
+       */
+       int work_done = 1;
+       static int no_work_done_count = 0;
+
+       if (!get_random_number(10) && no_work_done_count <= 5) {
+               check_erase_block(erase_block, fd);
+               work_done = 0;
+       } else if (get_random_number(100)) {
+               if (!write_to_erase_block(erase_block, fd)) {
+                       /* The erase block was full */
+                       if (get_random_number(2) || no_work_done_count > 5)
+                               erase_erase_block(erase_block, fd);
+                       else
+                               work_done = 0;
+               }
+       } else
+               erase_erase_block(erase_block, fd);
+       if (work_done)
+               no_work_done_count = 0;
+       else
+               no_work_done_count += 1;
+}
+
+static void operate_on_open_volume(struct volume_fd *vol_fd)
+{
+       /*
+       Possible operations:
+               operate on an erase block
+               close volume
+       */
+       if (get_random_number(100) == 0)
+               close_volume(vol_fd);
+       else {
+               /* Pick an erase block at random */
+               int eb_no = get_random_number(vol_fd->volume->info.rsvd_ebs);
+               operate_on_erase_block(&vol_fd->volume->erase_blocks[eb_no], vol_fd->fd);
+       }
+}
+
+static void operate_on_volume(struct volume_info *vol)
+{
+       /*
+       Possible operations:
+               open it
+               resize it (must close fd's first) <- TODO
+               delete it (must close fd's first) <- TODO
+       */
+       open_volume(vol);
+}
+
+static int ubi_major(const char *device_file_name)
+{
+       struct stat buf;
+       static int maj = 0;
+
+       if (maj)
+               return maj;
+       if (stat(device_file_name, &buf) == -1)
+               error_exit("Failed to stat ubi device file");
+       maj = major(buf.st_rdev);
+       return maj;
+}
+
+static void operate_on_ubi_device(struct ubi_device_info *ubi_device)
+{
+       /*
+       TODO:
+       Possible operations:
+               create a new volume
+               operate on existing volume
+       */
+       /*
+       Simplified operation (i.e. only have 1 volume):
+               If there are no volumes create 1 volumne
+               Then operate on the volume
+       */
+       if (ubi_device->info.vol_count == 0) {
+               /* Create the one-and-only volume we will use */
+               char dev_name[1024];
+               int i, n, maj, fd;
+               struct volume_info *s;
+               struct ubi_mkvol_request req;
+
+               req.vol_id = UBI_VOL_NUM_AUTO;
+               req.alignment = 1; /* TODO: What is this? */
+               req.bytes = ubi_device->info.eb_size * max_ebs_per_vol;
+               if (req.bytes == 0 || req.bytes > ubi_device->info.avail_bytes)
+                       req.bytes = ubi_device->info.avail_bytes;
+               req.vol_type = UBI_DYNAMIC_VOLUME;
+               req.name = "integ-test-vol";
+               if (ubi_mkvol(libubi, ubi_device->device_file_name, &req))
+                       error_exit("ubi_mkvol failed");
+               s = allocate(sizeof(*s));
+               s->ubi_device = ubi_device;
+               if (ubi_get_vol_info1(libubi, ubi_device->info.dev_num, req.vol_id, &s->info))
+                       error_exit("ubi_get_vol_info failed");
+               n = s->info.rsvd_ebs;
+               s->erase_blocks = allocate(sizeof(struct erase_block_info) * n);
+               for (i = 0; i < n; ++i) {
+                       s->erase_blocks[i].volume = s;
+                       s->erase_blocks[i].block_number = i;
+                       s->erase_blocks[i].offset = i * (off64_t) s->info.eb_size;
+                       s->erase_blocks[i].top_of_data = s->erase_blocks[i].offset;
+               }
+               /* FIXME: Correctly get device file name */
+               sprintf(dev_name, "%s_%d", ubi_device->device_file_name, req.vol_id);
+               s->device_file_name = strdup(dev_name);
+               ubi_device->volumes = s;
+               ubi_device->info.vol_count += 1;
+               sleep(1);
+               fd = open(s->device_file_name, O_RDONLY);
+               if (fd == -1) {
+                       /* FIXME: Correctly make node */
+                       maj = ubi_major(ubi_device->device_file_name);
+                       sprintf(dev_name, "mknod %s c %d %d", s->device_file_name, maj, req.vol_id + 1);
+                       system(dev_name);
+               } else if (close(fd) == -1)
+                       error_exit("Failed to close volume device file");
+       }
+       operate_on_volume(ubi_device->volumes);
+}
+
+static void do_an_operation(void)
+{
+       int too_few = (open_volume_count < info.dev_count * 3);
+       int too_many = (open_volume_count > info.dev_count * 5);
+
+       if (too_many || (!too_few && get_random_number(1000) > 0)) {
+               /* Operate on an open volume */
+               size_t pos;
+               struct open_volume_fd *ofd;
+               pos = get_random_number(open_volume_count);
+               for (ofd = open_volumes; pos && ofd && ofd->next; --pos)
+                       ofd = ofd->next;
+               operate_on_open_volume(ofd->vol_fd);
+       } else if (info.dev_count > 0) {
+               /* Operate on a ubi device */
+               size_t ubi_pos = 0;
+               if (info.dev_count > 1)
+                       ubi_pos = get_random_number(info.dev_count - 1);
+               operate_on_ubi_device(&ubi_array[ubi_pos]);
+       } else
+               error_exit("Internal error");
+}
+
+static void get_ubi_devices_info(void)
+{
+       int i, ubi_pos = 0;
+       char dev_name[1024];
+       size_t buf_size = 1024 * 128;
+
+       if (ubi_get_info(libubi, &info))
+               error_exit("ubi_get_info failed");
+       if (info.dev_count > MAX_UBI_DEVICES)
+               error_exit("Too many ubi devices");
+       for (i = info.lowest_dev_num; i <= info.highest_dev_num; ++i) {
+               struct ubi_device_info *s;
+               s = &ubi_array[ubi_pos++];
+               if (ubi_get_dev_info1(libubi, i, &s->info))
+                       error_exit("ubi_get_dev_info1 failed");
+               if (s->info.vol_count)
+                       error_exit("There are existing volumes");
+               /* FIXME: Correctly get device file name */
+               sprintf(dev_name, "/dev/ubi%d", i);
+               s->device_file_name = strdup(dev_name);
+               if (buf_size < s->info.eb_size)
+                       buf_size = s->info.eb_size;
+               if (max_ebs_per_vol && s->info.eb_size * max_ebs_per_vol < s->info.avail_bytes)
+                       total_space += s->info.eb_size * max_ebs_per_vol;
+               else
+                       total_space += s->info.avail_bytes;
+       }
+       write_buffer = allocate(buf_size);
+       read_buffer = allocate(buf_size);
+}
+
+static void load_ubi(void)
+{
+       system("rmmod ubi");
+       if (system(ubi_module_load_string) != 0)
+               error_exit("Failed to load UBI module");
+       sleep(1);
+}
+
+static void do_some_operations(void)
+{
+       unsigned i = 0;
+       total_written = 0;
+       printf("Total space: %llu\n", (unsigned long long) total_space);
+       while (total_written < total_space * 3) {
+               do_an_operation();
+               if (i++ % 10000 == 0)
+                       printf("Total written: %llu\n", (unsigned long long) total_written);
+       }
+       printf("Total written: %llu\n", (unsigned long long) total_written);
+}
+
+static void reload_ubi(void)
+{
+       /* Remove module */
+       if (system("rmmod ubi") != 0)
+               error_exit("Failed to remove UBI module");
+       /* Install module */
+       if (system(ubi_module_load_string) != 0)
+               error_exit("Failed to load UBI module");
+       sleep(1);
+}
+
+static void check_volume(struct volume_info *vol)
+{
+       struct erase_block_info *eb = vol->erase_blocks;
+       int pos;
+       int fd;
+
+       fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE);
+       if (fd == -1)
+               error_exit("Failed to open volume device file");
+       for (pos = 0; pos < vol->info.rsvd_ebs; ++pos)
+               check_erase_block(eb++, fd);
+       if (close(fd) == -1)
+               error_exit("Failed to close volume device file");
+}
+
+static void check_ubi_device(struct ubi_device_info *ubi_device)
+{
+       struct volume_info *vol;
+
+       vol = ubi_device->volumes;
+       while (vol) {
+               check_volume(vol);
+               vol = vol->next;
+       }
+}
+
+static void check_ubi(void)
+{
+       int i;
+
+       for (i = 0; i < info.dev_count; ++i)
+               check_ubi_device(&ubi_array[i]);
+}
+
+static int is_all_digits(const char *s)
+{
+       const char *digits = "0123456789";
+       if (!s || !*s)
+               return 0;
+       for (;*s;++s)
+               if (!strchr(digits,*s))
+                       return 0;
+       return 1;
+}
+
+static int get_short_arg(int *pos,const char *name,long long *result,int argc,char *argv[])
+{
+       const char *p = NULL;
+       int i = *pos;
+       size_t n = strlen(name);
+
+       if (strlen(argv[i]) > n)
+               p = argv[i] + n;
+       else if (++i < argc)
+               p = argv[i];
+       if (!is_all_digits(p))
+               return 1;
+       *result = atoll(p);
+       *pos = i;
+       return 0;
+}
+
+static int get_long_arg(int *pos,const char *name,long long *result,int argc,char *argv[])
+{
+       const char *p = NULL;
+       int i = *pos;
+       size_t n = strlen(name);
+
+       if (strlen(argv[i]) > n)
+               p = argv[i] + n;
+       else if (++i < argc)
+               p = argv[i];
+       if (p && *p == '=') {
+               p += 1;
+               if (!*p && ++i < argc)
+                       p = argv[i];
+       }
+       if (!is_all_digits(p))
+               return 1;
+       *result = atoll(p);
+       *pos = i;
+       return 0;
+}
+
+static int remove_all_volumes(void)
+{
+       int i;
+
+       for (i = 0; i < info.dev_count; ++i) {
+               struct ubi_device_info *ubi_device = &ubi_array[i];
+               struct volume_info *vol;
+               vol = ubi_device->volumes;
+               while (vol) {
+                       int res = ubi_rmvol(libubi,
+                                           ubi_device->device_file_name,
+                                           vol->info.vol_id);
+                       if (res)
+                               return res;
+                       vol = vol->next;
+               }
+       }
+       return 0;
+}
+
+int main(int argc,char *argv[])
+{
+       int i;
+       long long r, repeat = 1;
+       int initial_seed = 1, args_ok = 1;
+
+       printf("UBI Integrity Test\n");
+
+       /* Get arguments */
+       ubi_module_load_string = 0;
+       for (i = 1; i < argc; ++i) {
+               if (strncmp(argv[i], "-h", 2) == 0)
+                       args_ok = 0;
+               else if (strncmp(argv[i], "--help", 6) == 0)
+                       args_ok = 0;
+               else if (strncmp(argv[i], "-n", 2) == 0) {
+                       if (get_short_arg(&i, "-n", &repeat, argc, argv))
+                               args_ok = 0;
+               } else if (strncmp(argv[i], "--repeat", 8) == 0) {
+                       if (get_long_arg(&i, "--repeat", &repeat, argc, argv))
+                               args_ok = 0;
+               } else if (strncmp(argv[i], "-m", 2) == 0) {
+                       if (get_short_arg(&i,"-m", &max_ebs_per_vol, argc, argv))
+                               args_ok = 0;
+               } else if (strncmp(argv[i], "--maxebs", 8) == 0) {
+                       if (get_long_arg(&i, "--maxebs", &max_ebs_per_vol, argc, argv))
+                               args_ok = 0;
+               } else if (!ubi_module_load_string)
+                       ubi_module_load_string = argv[i];
+               else
+                       args_ok = 0;
+       }
+       if (!args_ok || !ubi_module_load_string) {
+               fprintf(stderr, "Usage is: ubi_integ [<options>] <UBI Module load command>\n");
+               fprintf(stderr, "    Options: \n");
+               fprintf(stderr, "        -h, --help              Help\n");
+               fprintf(stderr, "        -n arg, --repeat=arg    Repeat test arg times\n");
+               fprintf(stderr, "        -m arg, --maxebs=arg    Max no. of erase blocks\n");
+               return 1;
+       }
+
+       initial_seed = getpid();
+       printf("Initial seed = %u\n", (unsigned) initial_seed);
+       next_seed = initial_seed;
+       srand(initial_seed);
+       load_ubi();
+
+       libubi = libubi_open();
+       if (!libubi)
+               error_exit("Failed to open libubi");
+
+       get_ubi_devices_info();
+
+       r = 0;
+       while (repeat == 0 || r++ < repeat) {
+               printf("Cycle %lld\n", r);
+               do_some_operations();
+
+               /* Close all volumes */
+               while (open_volumes)
+                       close_volume(open_volumes->vol_fd);
+
+               check_ubi();
+
+               libubi_close(libubi);
+
+               reload_ubi();
+
+               libubi = libubi_open();
+               if (!libubi)
+                       error_exit("Failed to open libubi");
+
+               check_ubi();
+       }
+
+       if (remove_all_volumes())
+               error_exit("Failed to remove all volumes");
+
+       libubi_close(libubi);
+
+       printf("UBI Integrity Test completed ok\n");
+       return 0;
+}
diff --git a/ubi-utils/tests/io_basic.c b/ubi-utils/tests/io_basic.c
new file mode 100644 (file)
index 0000000..2e8809a
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * Test basic UBI volume I/O capabilities.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "io_basic"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+static int test_basic(int type);
+static int test_aligned(int type);
+
+int main(int argc, char * const argv[])
+{
+       if (initial_check(argc, argv))
+               return 1;
+
+       node = argv[1];
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               failed("libubi_open");
+               return 1;
+       }
+
+       if (ubi_get_dev_info(libubi, node, &dev_info)) {
+               failed("ubi_get_dev_info");
+               goto close;
+       }
+
+       if (test_basic(UBI_DYNAMIC_VOLUME))
+               goto close;
+       if (test_basic(UBI_STATIC_VOLUME))
+               goto close;
+       if (test_aligned(UBI_DYNAMIC_VOLUME))
+               goto close;
+       if (test_aligned(UBI_STATIC_VOLUME))
+               goto close;
+
+       libubi_close(libubi);
+       return 0;
+
+close:
+       libubi_close(libubi);
+       return 1;
+}
+
+/**
+ * test_basic - check basic volume read and update capabilities.
+ *
+ * @type  volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_basic(int type)
+{
+       struct ubi_mkvol_request req;
+       const char *name = TESTNAME ":test_basic()";
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+
+       req.vol_id = UBI_VOL_NUM_AUTO;
+       req.alignment = 1;
+       req.bytes = dev_info.avail_bytes;
+       req.vol_type = type;
+       req.name = name;
+
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               return -1;
+       }
+
+       sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id);
+
+       /* Make sure newly created volume contains only 0xFF bytes */
+       if (check_vol_patt(&vol_node[0], 0xFF))
+               goto remove;
+
+       /* Write 0xA5 bytes to the volume */
+       if (update_vol_patt(&vol_node[0], dev_info.avail_bytes, 0xA5))
+               goto remove;
+       if (check_vol_patt(&vol_node[0], 0xA5))
+               goto remove;
+
+       if (ubi_rmvol(libubi, node, req.vol_id)) {
+               failed("ubi_rmvol");
+               return -1;
+       }
+
+       return 0;
+
+remove:
+       ubi_rmvol(libubi, node, req.vol_id);
+       return -1;
+}
+
+/**
+ * test_aligned - test volume alignment feature.
+ *
+ * @type  volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_aligned(int type)
+{
+       int i, ebsz;
+       struct ubi_mkvol_request req;
+       const char *name = TESTNAME ":test_aligned()";
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       int alignments[] = ALIGNMENTS(dev_info.eb_size);
+
+       req.vol_type = type;
+       req.name = name;
+
+       for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+               req.vol_id = UBI_VOL_NUM_AUTO;
+
+               req.alignment = alignments[i];
+               req.alignment -= req.alignment % dev_info.min_io_size;
+               if (req.alignment == 0)
+                       req.alignment = dev_info.min_io_size;
+
+               ebsz = dev_info.eb_size - dev_info.eb_size % req.alignment;
+               req.bytes = MIN_AVAIL_EBS * ebsz;
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       failed("ubi_mkvol");
+                       return -1;
+               }
+
+               sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id);
+
+               /* Make sure newly created volume contains only 0xFF bytes */
+               if (check_vol_patt(&vol_node[0], 0xFF))
+                       goto remove;
+
+               /* Write 0xA5 bytes to the volume */
+               if (update_vol_patt(&vol_node[0], req.bytes, 0xA5))
+                       goto remove;
+               if (check_vol_patt(&vol_node[0], 0xA5))
+                       goto remove;
+
+               if (ubi_rmvol(libubi, node, req.vol_id)) {
+                       failed("ubi_rmvol");
+                       return -1;
+               }
+       }
+
+       return 0;
+
+remove:
+       ubi_rmvol(libubi, node, req.vol_id);
+       return -1;
+}
diff --git a/ubi-utils/tests/io_paral.c b/ubi-utils/tests/io_paral.c
new file mode 100644 (file)
index 0000000..4857bf8
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * This test does a lot of I/O to volumes in parallel.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "io_paral"
+#include "common.h"
+
+#define THREADS_NUM 3
+#define ITERATIONS  100
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+static int iterations = ITERATIONS;
+int total_bytes;
+
+static void * the_thread(void *ptr);
+
+static long long memory_limit(void)
+{
+       long long result = 0;
+       FILE *f;
+
+       f = fopen("/proc/meminfo", "r");
+       if (!f)
+               return 0;
+       fscanf(f, "%*s %lld", &result);
+       fclose(f);
+       return result * 1024 / 4;
+}
+
+int main(int argc, char * const argv[])
+{
+       int i, ret;
+       pthread_t threads[THREADS_NUM];
+       struct ubi_mkvol_request req;
+       long long mem_limit;
+
+       if (initial_check(argc, argv))
+               return 1;
+
+       node = argv[1];
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               failed("libubi_open");
+               return 1;
+       }
+
+       if (ubi_get_dev_info(libubi, node, &dev_info)) {
+               failed("ubi_get_dev_info");
+               goto close;
+       }
+
+       req.alignment = 1;
+       mem_limit = memory_limit();
+       if (mem_limit && mem_limit < dev_info.avail_bytes)
+               total_bytes = req.bytes =
+                               (mem_limit / dev_info.eb_size / THREADS_NUM)
+                               * dev_info.eb_size;
+       else
+               total_bytes = req.bytes =
+                               ((dev_info.avail_ebs - 3) / THREADS_NUM)
+                               * dev_info.eb_size;
+       for (i = 0; i < THREADS_NUM; i++) {
+               char name[100];
+
+               req.vol_id = i;
+               sprintf(&name[0], TESTNAME":%d", i);
+               req.name = &name[0];
+               req.vol_type = (i & 1) ? UBI_STATIC_VOLUME : UBI_DYNAMIC_VOLUME;
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       failed("ubi_mkvol");
+                       goto remove;
+               }
+       }
+
+       /* Create one volume with static data to make WL work more */
+       req.vol_id = THREADS_NUM;
+       req.name = TESTNAME ":static";
+       req.vol_type = UBI_DYNAMIC_VOLUME;
+       req.bytes = 3*dev_info.eb_size;
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               goto remove;
+       }
+
+       for (i = 0; i < THREADS_NUM; i++) {
+               ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i);
+               if (ret) {
+                       failed("pthread_create");
+                       goto remove;
+               }
+       }
+
+       for (i = 0; i < THREADS_NUM; i++)
+               pthread_join(threads[i], NULL);
+
+       for (i = 0; i <= THREADS_NUM; i++) {
+               if (ubi_rmvol(libubi, node, i)) {
+                       failed("ubi_rmvol");
+                       goto remove;
+               }
+       }
+
+       libubi_close(libubi);
+       return 0;
+
+remove:
+       for (i = 0; i <= THREADS_NUM; i++)
+               ubi_rmvol(libubi, node, i);
+
+close:
+       libubi_close(libubi);
+       return 1;
+}
+
+/**
+ * the_thread - the testing thread.
+ *
+ * @ptr  thread number
+ */
+static void * the_thread(void *ptr)
+{
+       int fd, iter = iterations, vol_id = (int)ptr;
+       unsigned char *wbuf, *rbuf;
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+
+       wbuf = malloc(total_bytes);
+       rbuf = malloc(total_bytes);
+       if (!wbuf || !rbuf) {
+               failed("malloc");
+               goto free;
+       }
+
+       sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, vol_id);
+
+       while (iter--) {
+               int i, ret, written = 0, rd = 0;
+               int bytes = (random() % (total_bytes - 1)) + 1;
+
+               fd = open(vol_node, O_RDWR);
+               if (fd == -1) {
+                       failed("open");
+                       err_msg("cannot open \"%s\"\n", node);
+                       goto free;
+               }
+
+               for (i = 0; i < bytes; i++)
+                       wbuf[i] = random() % 255;
+               memset(rbuf, '\0', bytes);
+
+               do {
+                       ret = ubi_update_start(libubi, fd, bytes);
+                       if (ret && errno != EBUSY) {
+                               failed("ubi_update_start");
+                               err_msg("vol_id %d", vol_id);
+                               goto close;
+                       }
+               } while (ret);
+
+               while (written < bytes) {
+                       int to_write = random() % (bytes - written);
+
+                       if (to_write == 0)
+                               to_write = 1;
+
+                       ret = write(fd, wbuf, to_write);
+                       if (ret != to_write) {
+                               failed("write");
+                               err_msg("failed to write %d bytes at offset %d "
+                                       "of volume %d", to_write, written,
+                                       vol_id);
+                               err_msg("update: %d bytes", bytes);
+                               goto close;
+                       }
+
+                       written += to_write;
+               }
+
+               close(fd);
+
+               fd = open(vol_node, O_RDONLY);
+               if (fd == -1) {
+                       failed("open");
+                       err_msg("cannot open \"%s\"\n", node);
+                       goto free;
+               }
+
+               /* read data back and check */
+               while (rd < bytes) {
+                       int to_read = random() % (bytes - rd);
+
+                       if (to_read == 0)
+                               to_read = 1;
+
+                       ret = read(fd, rbuf, to_read);
+                       if (ret != to_read) {
+                               failed("read");
+                               err_msg("failed to read %d bytes at offset %d "
+                                       "of volume %d", to_read, rd, vol_id);
+                               goto close;
+                       }
+
+                       rd += to_read;
+               }
+
+               close(fd);
+
+       }
+
+       free(wbuf);
+       free(rbuf);
+       return NULL;
+
+close:
+       close(fd);
+free:
+       free(wbuf);
+       free(rbuf);
+       return NULL;
+}
diff --git a/ubi-utils/tests/io_read.c b/ubi-utils/tests/io_read.c
new file mode 100644 (file)
index 0000000..c5d1da7
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * Test UBI volume read.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "io_basic"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+static int test_static(void);
+static int test_read(int type);
+
+int main(int argc, char * const argv[])
+{
+       if (initial_check(argc, argv))
+               return 1;
+
+       node = argv[1];
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               failed("libubi_open");
+               return 1;
+       }
+
+       if (ubi_get_dev_info(libubi, node, &dev_info)) {
+               failed("ubi_get_dev_info");
+               goto close;
+       }
+
+       if (test_static())
+               goto close;
+       if (test_read(UBI_DYNAMIC_VOLUME))
+               goto close;
+       if (test_read(UBI_STATIC_VOLUME))
+               goto close;
+
+       libubi_close(libubi);
+       return 0;
+
+close:
+       libubi_close(libubi);
+       return 1;
+}
+
+/**
+ * test_static - test static volume-specific features.
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_static(void)
+{
+       struct ubi_mkvol_request req;
+       const char *name = TESTNAME ":io_basic()";
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       struct ubi_vol_info vol_info;
+       int fd, ret;
+       char buf[20];
+
+       req.vol_id = UBI_VOL_NUM_AUTO;
+       req.alignment = 1;
+       req.bytes = dev_info.avail_bytes;
+       req.vol_type = UBI_STATIC_VOLUME;
+       req.name = name;
+
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               return -1;
+       }
+
+       sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id);
+
+       fd = open(vol_node, O_RDWR);
+       if (fd == -1) {
+               failed("open");
+               err_msg("cannot open \"%s\"\n", node);
+               goto remove;
+       }
+
+       if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+               failed("ubi_get_vol_info");
+               goto close;
+       }
+
+       /* Make sure new static volume contains no data */
+       if (vol_info.data_bytes != 0) {
+               err_msg("data_bytes = %lld, not zero", vol_info.data_bytes);
+               goto close;
+       }
+
+       /* Ensure read returns EOF */
+       ret = read(fd, &buf[0], 1);
+       if (ret < 0) {
+               failed("read");
+               goto close;
+       }
+       if (ret != 0) {
+               err_msg("read data from free static volume");
+               goto close;
+       }
+
+       if (ubi_update_start(libubi, fd, 10)) {
+               failed("ubi_update_start");
+               goto close;
+       }
+
+       ret = write(fd, &buf[0], 10);
+       if (ret < 0) {
+               failed("write");
+               goto close;
+       }
+       if (ret != 10) {
+               err_msg("written %d bytes", ret);
+               goto close;
+       }
+
+       if (lseek(fd, 0, SEEK_SET) != 0) {
+               failed("seek");
+               goto close;
+       }
+       ret = read(fd, &buf[0], 20);
+       if (ret < 0) {
+               failed("read");
+               goto close;
+       }
+       if (ret != 10) {
+               err_msg("read %d bytes", ret);
+               goto close;
+       }
+
+       close(fd);
+       if (ubi_rmvol(libubi, node, req.vol_id)) {
+               failed("ubi_rmvol");
+               return -1;
+       }
+
+       return 0;
+
+close:
+       close(fd);
+remove:
+       ubi_rmvol(libubi, node, req.vol_id);
+       return -1;
+}
+
+static int test_read1(struct ubi_vol_info *vol_info);
+
+/**
+ * test_read - test UBI volume reading from different offsets.
+ *
+ * @type  volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_read(int type)
+{
+       const char *name = TESTNAME ":test_read()";
+       int alignments[] = ALIGNMENTS(dev_info.eb_size);
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       struct ubi_mkvol_request req;
+       int i;
+
+       for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+               int eb_size;
+               struct ubi_vol_info vol_info;
+
+               req.vol_id = UBI_VOL_NUM_AUTO;
+               req.vol_type = type;
+               req.name = name;
+
+               req.alignment = alignments[i];
+               req.alignment -= req.alignment % dev_info.min_io_size;
+               if (req.alignment == 0)
+                       req.alignment = dev_info.min_io_size;
+
+               eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment;
+               req.bytes =  MIN_AVAIL_EBS * eb_size;
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       failed("ubi_mkvol");
+                       return -1;
+               }
+
+               sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num,
+                       req.vol_id);
+
+               if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+                       failed("ubi_get_vol_info");
+                       goto remove;
+               }
+
+               if (test_read1(&vol_info)) {
+                       err_msg("alignment = %d", req.alignment);
+                       goto remove;
+               }
+
+               if (ubi_rmvol(libubi, node, req.vol_id)) {
+                       failed("ubi_rmvol");
+                       return -1;
+               }
+       }
+
+       return 0;
+
+remove:
+       ubi_rmvol(libubi, node, req.vol_id);
+       return -1;
+}
+
+static int test_read2(const struct ubi_vol_info *vol_info, int len);
+
+static int fd;
+
+/* Data lengthes to test, @io - minimal I/O unit size, @s - eraseblock size */
+#define LENGTHES(io, s)                                                        \
+       {1, (io), (io)+1, 2*(io), 3*(io)-1, 3*(io),                            \
+        PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io),           \
+        (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s),        \
+        2*(s)+(io), 3*(s), 3*(s)+(io)};
+
+/*
+ * A helper function for test_read().
+ */
+static int test_read1(struct ubi_vol_info *vol_info)
+{
+       int i, written = 0;
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       int lengthes[] = LENGTHES(dev_info.min_io_size, vol_info->eb_size);
+
+       sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num,
+               vol_info->vol_id);
+
+       fd = open(vol_node, O_RDWR);
+       if (fd == -1) {
+               failed("open");
+               err_msg("cannot open \"%s\"\n", node);
+               return -1;
+       }
+
+       /* Write some pattern to the volume */
+       if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) {
+               failed("ubi_update_start");
+               err_msg("bytes = %lld", vol_info->rsvd_bytes);
+               goto close;
+       }
+
+       while (written < vol_info->rsvd_bytes) {
+               int i, ret;
+               unsigned char buf[512];
+
+               for (i = 0; i < 512; i++)
+                       buf[i] = (unsigned char)(written + i);
+
+               ret = write(fd, &buf[0], 512);
+               if (ret == -1) {
+                       failed("write");
+                       err_msg("written = %d, ret = %d", written, ret);
+                       goto close;
+               }
+               written += ret;
+       }
+
+       close(fd);
+
+       if (ubi_get_vol_info(libubi, vol_node, vol_info)) {
+               failed("ubi_get_vol_info");
+               return -1;
+       }
+
+       fd = open(vol_node, O_RDONLY);
+       if (fd == -1) {
+               failed("open");
+               err_msg("cannot open \"%s\"\n", node);
+               return -1;
+       }
+
+       for (i = 0; i < sizeof(lengthes)/sizeof(int); i++) {
+               if (test_read2(vol_info, lengthes[i])) {
+                       err_msg("length = %d", lengthes[i]);
+                       goto close;
+               }
+       }
+
+       close(fd);
+       return 0;
+
+close:
+       close(fd);
+       return -1;
+}
+
+static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off);
+
+/*
+ * Offsets to test, @io - minimal I/O unit size, @s - eraseblock size, @sz -
+ * volume size.
+ */
+#define OFFSETS(io, s, sz)                                                     \
+       {0, (io)-1, (io), (io)+1, 2*(io)-1, 2*(io), 3*(io)-1, 3*(io),          \
+        PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io),           \
+        (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s),        \
+        2*(s)+(io), 3*(s), (sz)-(s)-1, (sz)-(io)-1, (sz)-PAGE_SIZE-1};
+
+/*
+ * A helper function for test_read1().
+ */
+static int test_read2(const struct ubi_vol_info *vol_info, int len)
+{
+       int i;
+       off_t offsets[] = OFFSETS(dev_info.min_io_size, vol_info->eb_size,
+                                 vol_info->data_bytes);
+
+       for (i = 0; i < sizeof(offsets)/sizeof(off_t); i++) {
+               if (test_read3(vol_info, len, offsets[i])) {
+                       err_msg("offset = %d", offsets[i]);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * A helper function for test_read2().
+ */
+static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off)
+{
+       int i, len1;
+       unsigned char ck_buf[len], buf[len];
+       off_t new_off;
+
+       if (off + len > vol_info->data_bytes)
+               len1 = vol_info->data_bytes - off;
+       else
+               len1 = len;
+
+       if (lseek(fd, off, SEEK_SET) != off) {
+               failed("seek");
+               err_msg("len = %d", len);
+               return -1;
+       }
+       if (read(fd, &buf[0], len) != len1) {
+               failed("read");
+               err_msg("len = %d", len);
+               return -1;
+       }
+
+       new_off = lseek(fd, 0, SEEK_CUR);
+       if (new_off != off + len1) {
+               if (new_off == -1)
+                       failed("lseek");
+               else
+                       err_msg("read %d bytes from %lld, but resulting "
+                               "offset is %lld", len1, (long long) off, (long long) new_off);
+               return -1;
+       }
+
+       for (i = 0; i < len1; i++)
+               ck_buf[i] = (unsigned char)(off + i);
+
+       if (memcmp(&buf[0], &ck_buf[0], len1)) {
+               err_msg("incorrect data read from offset %lld",
+                       (long long)off);
+               err_msg("len = %d", len);
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/ubi-utils/tests/io_update.c b/ubi-utils/tests/io_update.c
new file mode 100644 (file)
index 0000000..2e3422a
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * Test UBI volume update.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "io_update"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+static int test_update(int type);
+static int test_update_ff(void);
+
+int main(int argc, char * const argv[])
+{
+       if (initial_check(argc, argv))
+               return 1;
+
+       node = argv[1];
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               failed("libubi_open");
+               return 1;
+       }
+
+       if (ubi_get_dev_info(libubi, node, &dev_info)) {
+               failed("ubi_get_dev_info");
+               goto close;
+       }
+
+       if (test_update(UBI_DYNAMIC_VOLUME))
+               goto close;
+       if (test_update(UBI_STATIC_VOLUME))
+               goto close;
+       if (test_update_ff())
+               goto close;
+
+       libubi_close(libubi);
+       return 0;
+
+close:
+       libubi_close(libubi);
+       return 1;
+}
+
+static int test_update1(struct ubi_vol_info *vol_info);
+
+/**
+ * test_update - check volume update capabilities.
+ *
+ * @type  volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_update(int type)
+{
+       struct ubi_mkvol_request req;
+       const char *name = TESTNAME ":io_update()";
+       int alignments[] = ALIGNMENTS(dev_info.eb_size);
+       struct ubi_vol_info vol_info;
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       int i;
+
+       for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+               int eb_size;
+
+               req.vol_id = UBI_VOL_NUM_AUTO;
+               req.vol_type = type;
+               req.name = name;
+
+               req.alignment = alignments[i];
+               req.alignment -= req.alignment % dev_info.min_io_size;
+               if (req.alignment == 0)
+                       req.alignment = dev_info.min_io_size;
+
+               eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment;
+               req.bytes =  MIN_AVAIL_EBS * eb_size;
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       failed("ubi_mkvol");
+                       return -1;
+               }
+
+               sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num,
+                       req.vol_id);
+               if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+                       failed("ubi_get_vol_info");
+                       goto remove;
+               }
+
+               if (test_update1(&vol_info)) {
+                       err_msg("alignment = %d", req.alignment);
+                       goto remove;
+               }
+
+               if (ubi_rmvol(libubi, node, req.vol_id)) {
+                       failed("ubi_rmvol");
+                       return -1;
+               }
+       }
+
+       return 0;
+
+remove:
+       ubi_rmvol(libubi, node, req.vol_id);
+       return -1;
+}
+
+#define SEQUENCES(io, s) {           \
+       {3*(s)-(io)-1, 1},           \
+       {512},                       \
+       {666},                       \
+       {2048},                      \
+       {(io), (io), PAGE_SIZE},     \
+       {(io)+1, (io)+1, PAGE_SIZE}, \
+       {PAGE_SIZE},                 \
+       {PAGE_SIZE-1},               \
+       {PAGE_SIZE+(io)},            \
+       {(s)},                       \
+       {(s)-1},                     \
+       {(s)+1},                     \
+       {(io), (s)+1},               \
+       {(s)+(io), PAGE_SIZE},       \
+       {2*(s), PAGE_SIZE},          \
+       {PAGE_SIZE, 2*(s), 1},       \
+       {PAGE_SIZE, 2*(s)},          \
+       {2*(s)-1, 2*(s)-1},          \
+       {3*(s), PAGE_SIZE + 1},      \
+       {1, PAGE_SIZE},              \
+       {(io), (s)}                  \
+}
+#define SEQ_SZ 21
+
+/*
+ * test_update1 - helper function for test_update().
+ */
+static int test_update1(struct ubi_vol_info *vol_info)
+{
+       int sequences[SEQ_SZ][3] = SEQUENCES(dev_info.min_io_size,
+                                            vol_info->eb_size);
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       unsigned char buf[vol_info->rsvd_bytes];
+       int fd, i, j;
+
+       sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num,
+               vol_info->vol_id);
+
+       for (i = 0; i < vol_info->rsvd_bytes; i++)
+               buf[i] = (unsigned char)i;
+
+       fd = open(vol_node, O_RDWR);
+       if (fd == -1) {
+               failed("open");
+               err_msg("cannot open \"%s\"\n", node);
+               return -1;
+       }
+
+       for (i = 0; i < SEQ_SZ; i++) {
+               int ret, stop = 0, len;
+               off_t off = 0;
+               unsigned char buf1[vol_info->rsvd_bytes];
+
+               if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) {
+                       failed("ubi_update_start");
+                       goto close;
+               }
+
+               for (j = 0; off < vol_info->rsvd_bytes; j++) {
+                       if (!stop) {
+                               if (sequences[i][j] != 0)
+                                       len = sequences[i][j];
+                               else
+                                       stop = 1;
+                       }
+
+                       ret = write(fd, &buf[off], len);
+                       if (ret < 0) {
+                               failed("write");
+                               err_msg("failed to write %d bytes at offset "
+                                       "%lld", len, (long long) off);
+                               goto close;
+                       }
+                       if (off + len > vol_info->rsvd_bytes)
+                               len = vol_info->rsvd_bytes - off;
+                       if (ret != len) {
+                               err_msg("failed to write %d bytes at offset "
+                                       "%lld, wrote %d", len, (long long) off, ret);
+                               goto close;
+                       }
+                       off += len;
+               }
+
+               /* Check data */
+               if ((ret = lseek(fd, SEEK_SET, 0)) != 0) {
+                       if (ret < 0)
+                               failed("lseek");
+                       err_msg("cannot seek to 0");
+                       goto close;
+               }
+               memset(&buf1[0], 0x01, vol_info->rsvd_bytes);
+               ret = read(fd, &buf1[0], vol_info->rsvd_bytes + 1);
+               if (ret < 0) {
+                       failed("read");
+                       err_msg("failed to read %d bytes",
+                               vol_info->rsvd_bytes + 1);
+                       goto close;
+               }
+               if (ret != vol_info->rsvd_bytes) {
+                       err_msg("failed to read %d bytes, read %d",
+                               vol_info->rsvd_bytes, ret);
+                       goto close;
+               }
+               if (memcmp(&buf[0], &buf1[0], vol_info->rsvd_bytes)) {
+                       err_msg("data corruption");
+                       goto close;
+               }
+       }
+
+       close(fd);
+       return 0;
+
+close:
+       close(fd);
+       return -1;
+}
+
+/**
+ * test_update_ff - check volume with 0xFF data
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_update_ff(void)
+{
+       struct ubi_mkvol_request req;
+       const char *name = TESTNAME ":io_update()";
+       struct ubi_vol_info vol_info;
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       int i, fd, ret, types[2];
+       int upd_len = MIN_AVAIL_EBS * dev_info.eb_size;
+       char buf[upd_len], buf1[upd_len];
+
+       for(i = 0; i < MIN_AVAIL_EBS; i++) {
+               if (i % 1)
+                       memset(&buf[0], 0xAB, upd_len);
+               else
+                       memset(&buf[0], 0xFF, upd_len);
+       }
+
+       types[0] = UBI_DYNAMIC_VOLUME;
+       types[1] = UBI_STATIC_VOLUME;
+
+       for (i = 0; i < 2; i++) {
+               req.vol_id = UBI_VOL_NUM_AUTO;
+               req.vol_type = types[i];
+               req.name = name;
+
+               req.alignment = 1;
+               req.bytes = upd_len;
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       failed("ubi_mkvol");
+                       return -1;
+               }
+
+               sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num,
+                       req.vol_id);
+               if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+                       failed("ubi_get_vol_info");
+                       goto remove;
+               }
+
+               fd = open(vol_node, O_RDWR);
+               if (fd == -1) {
+                       failed("open");
+                       err_msg("cannot open \"%s\"\n", node);
+                       goto remove;
+               }
+
+               if (ubi_update_start(libubi, fd, upd_len)) {
+                       failed("ubi_update_start");
+                       goto close;
+               }
+
+
+               ret = write(fd, &buf[0], upd_len);
+               if (ret < 0 || ret != upd_len) {
+                       failed("write");
+                       err_msg("failed to write %d bytes", upd_len);
+                       goto close;
+               }
+
+               /* Check data */
+               if ((ret = lseek(fd, SEEK_SET, 0)) != 0) {
+                       if (ret < 0)
+                               failed("lseek");
+                       err_msg("cannot seek to 0");
+                       goto close;
+               }
+
+               close(fd);
+
+               fd = open(vol_node, O_RDWR);
+               if (fd == -1) {
+                       failed("open");
+                       err_msg("cannot open \"%s\"\n", node);
+                       goto remove;
+               }
+
+               memset(&buf1[0], 0x00, upd_len);
+               ret = read(fd, &buf1[0], upd_len);
+               if (ret < 0) {
+                       failed("read");
+                       err_msg("failed to read %d bytes", upd_len);
+                       goto close;
+               }
+               if (ret != upd_len) {
+                       err_msg("failed to read %d bytes, read %d",
+                               upd_len, ret);
+                       goto close;
+               }
+               if (memcmp(&buf[0], &buf1[0], upd_len)) {
+                       err_msg("data corruption");
+                       goto close;
+               }
+
+               close(fd);
+
+               if (ubi_rmvol(libubi, node, req.vol_id)) {
+                       failed("ubi_rmvol");
+                       return -1;
+               }
+       }
+
+       return 0;
+
+close:
+       close(fd);
+remove:
+       ubi_rmvol(libubi, node, req.vol_id);
+       return -1;
+}
diff --git a/ubi-utils/tests/mkvol_bad.c b/ubi-utils/tests/mkvol_bad.c
new file mode 100644 (file)
index 0000000..023b06b
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * Test UBI volume creation and deletion ioctl()s with bad input and in case of
+ * incorrect usage.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "libubi.h"
+#define TESTNAME "mkvol_bad"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+static int test_mkvol(void);
+static int test_rmvol(void);
+
+int main(int argc, char * const argv[])
+{
+       if (initial_check(argc, argv))
+               return 1;
+
+       node = argv[1];
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               failed("libubi_open");
+               return 1;
+       }
+
+       if (ubi_get_dev_info(libubi, node, &dev_info)) {
+               failed("ubi_get_dev_info");
+               goto close;
+       }
+
+       if (test_mkvol())
+               goto close;
+
+       if (test_rmvol())
+               goto close;
+
+       libubi_close(libubi);
+       return 0;
+
+close:
+       libubi_close(libubi);
+       return 1;
+}
+
+/**
+ * test_mkvol - test that UBI mkvol ioctl rejects bad input parameters.
+ *
+ * This function returns %0 if the test passed and %-1 if not.
+ */
+static int test_mkvol(void)
+{
+       int ret, i;
+       struct ubi_mkvol_request req;
+       const char *name = TESTNAME ":test_mkvol()";
+
+       req.alignment = 1;
+       req.bytes = dev_info.avail_bytes;
+       req.vol_type = UBI_DYNAMIC_VOLUME;
+       req.name = name;
+
+       /* Bad volume ID */
+       req.vol_id = -2;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id))
+               return -1;
+
+       req.vol_id = dev_info.max_vol_count;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id))
+               return -1;
+
+       /* Bad alignment */
+       req.vol_id = 0;
+       req.alignment = 0;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d",
+                        req.alignment))
+               return -1;
+
+       req.alignment = -1;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d",
+                        req.alignment))
+               return -1;
+
+       req.alignment = dev_info.eb_size + 1;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d",
+                        req.alignment))
+               return -1;
+
+       if (dev_info.min_io_size > 1) {
+               req.alignment = dev_info.min_io_size + 1;
+               ret = ubi_mkvol(libubi, node, &req);
+               if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d",
+                                req.alignment))
+                       return -1;
+       }
+
+       /* Bad bytes */
+       req.alignment = 1;
+       req.bytes = -1;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes))
+               return -1;
+
+       req.bytes = 0;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes))
+               return -1;
+
+       req.bytes = dev_info.avail_bytes + 1;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes))
+               return -1;
+
+       req.alignment = dev_info.eb_size - dev_info.min_io_size;
+       req.bytes = (dev_info.eb_size - dev_info.eb_size % req.alignment) *
+                   dev_info.avail_ebs + 1;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes))
+               return -1;
+
+       /* Bad vol_type */
+       req.alignment = 1;
+       req.bytes = dev_info.eb_size;
+       req.vol_type = UBI_DYNAMIC_VOLUME + UBI_STATIC_VOLUME;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_type = %d",
+                        req.vol_type))
+               return -1;
+
+       req.vol_type = UBI_DYNAMIC_VOLUME;
+
+       /* Too long name */
+       {
+               char name[UBI_VOL_NAME_MAX + 5];
+
+               memset(&name[0], 'x', UBI_VOL_NAME_MAX + 1);
+               name[UBI_VOL_NAME_MAX + 1] = '\0';
+
+               req.name = &name[0];
+               ret = ubi_mkvol(libubi, node, &req);
+               if (check_failed(ret, EINVAL, "ubi_mkvol", "name_len = %d",
+                                UBI_VOL_NAME_MAX + 1))
+               return -1;
+       }
+
+       /* Try to create 2 volumes with the same ID and name */
+       req.name = name;
+       req.vol_id = 0;
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               return -1;
+       }
+
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EEXIST, "ubi_mkvol",
+                        "volume with ID 0 created twice"))
+               return -1;
+
+       req.vol_id = 1;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EEXIST, "ubi_mkvol",
+                        "volume with name \"%s\" created twice", name))
+               return -1;
+
+       if (ubi_rmvol(libubi, node, 0)) {
+               failed("ubi_rmvol");
+               return -1;
+       }
+
+       /* Try to use too much space */
+       req.vol_id = 0;
+       req.bytes = dev_info.avail_bytes;
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               return -1;
+       }
+
+       req.bytes = 1;
+       req.vol_id = 1;
+       ret = ubi_mkvol(libubi, node, &req);
+       if (check_failed(ret, EEXIST, "ubi_mkvol",
+                        "created volume of maximum size %lld, but still "
+                        "can create more volumes", dev_info.avail_bytes))
+               return -1;
+
+       if (ubi_rmvol(libubi, node, 0)) {
+               failed("ubi_rmvol");
+               return -1;
+       }
+
+       /* Try to create too many volumes */
+       for (i = 0; i < dev_info.max_vol_count; i++) {
+               char nm[strlen(name) + 50];
+
+               req.vol_id = UBI_VOL_NUM_AUTO;
+               req.alignment = 1;
+               req.bytes = 1;
+               req.vol_type = UBI_STATIC_VOLUME;
+
+               sprintf(&nm[0], "%s:%d", name, i);
+               req.name = &nm[0];
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       /*
+                        * Note, because of gluebi we may be unable to create
+                        * dev_info.max_vol_count devices (MTD restrictions).
+                        */
+                       if (errno == ENFILE)
+                               break;
+                       failed("ubi_mkvol");
+                       err_msg("vol_id %d", i);
+                       goto remove;
+               }
+       }
+
+       for (i = 0; i < dev_info.max_vol_count + 1; i++)
+               ubi_rmvol(libubi, node, i);
+
+       return 0;
+
+remove:
+       for (i = 0; i < dev_info.max_vol_count + 1; i++)
+               ubi_rmvol(libubi, node, i);
+       return -1;
+}
+
+/**
+ * test_rmvol - test that UBI rmvol ioctl rejects bad input parameters.
+ *
+ * This function returns %0 if the test passed and %-1 if not.
+ */
+static int test_rmvol(void)
+{
+       int ret;
+       struct ubi_mkvol_request req;
+       const char *name = TESTNAME ":test_rmvol()";
+
+       /* Bad vol_id */
+       ret = ubi_rmvol(libubi, node, -1);
+       if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = -1"))
+               return -1;
+
+       ret = ubi_rmvol(libubi, node, dev_info.max_vol_count);
+       if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = %d",
+                        dev_info.max_vol_count))
+               return -1;
+
+       /* Try to remove non-existing volume */
+       ret = ubi_rmvol(libubi, node, 0);
+       if (check_failed(ret, ENODEV, "ubi_rmvol",
+                        "removed non-existing volume 0"))
+               return -1;
+
+       /* Try to remove volume twice */
+       req.vol_id = UBI_VOL_NUM_AUTO;
+       req.alignment = 1;
+       req.bytes = dev_info.avail_bytes;
+       req.vol_type = UBI_DYNAMIC_VOLUME;
+       req.name = name;
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               return -1;
+       }
+
+       if (ubi_rmvol(libubi, node, req.vol_id)) {
+               failed("ubi_rmvol");
+               return -1;
+       }
+
+       ret = ubi_rmvol(libubi, node, req.vol_id);
+       if (check_failed(ret, ENODEV, "ubi_rmvol", "volume %d removed twice",
+                        req.vol_id))
+               return -1;
+
+       return 0;
+}
diff --git a/ubi-utils/tests/mkvol_basic.c b/ubi-utils/tests/mkvol_basic.c
new file mode 100644 (file)
index 0000000..e2120e9
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * Test test checks basic volume creation and deletion capabilities.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "libubi.h"
+#define TESTNAME "mkvol_basic"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+static int mkvol_basic(void);
+static int mkvol_alignment(void);
+static int mkvol_multiple(void);
+
+int main(int argc, char * const argv[])
+{
+       if (initial_check(argc, argv))
+               return 1;
+
+       node = argv[1];
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               failed("libubi_open");
+               return 1;
+       }
+
+       if (ubi_get_dev_info(libubi, node, &dev_info)) {
+               failed("ubi_get_dev_info");
+               goto close;
+       }
+
+       if (mkvol_basic())
+               goto close;
+
+       if (mkvol_alignment())
+               goto close;
+
+       if (mkvol_multiple())
+               goto close;
+
+       libubi_close(libubi);
+       return 0;
+
+close:
+       libubi_close(libubi);
+       return 1;
+}
+
+/**
+ * mkvol_alignment - create volumes with different alignments.
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int mkvol_alignment(void)
+{
+       struct ubi_mkvol_request req;
+       int i, vol_id, ebsz;
+       const char *name = TESTNAME ":mkvol_alignment()";
+       int alignments[] = ALIGNMENTS(dev_info.eb_size);
+
+       for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+               req.vol_id = UBI_VOL_NUM_AUTO;
+
+               /* Alignment should actually be multiple of min. I/O size */
+               req.alignment = alignments[i];
+               req.alignment -= req.alignment % dev_info.min_io_size;
+               if (req.alignment == 0)
+                       req.alignment = dev_info.min_io_size;
+
+               /* Bear in mind alignment reduces EB size */
+               ebsz = dev_info.eb_size - dev_info.eb_size % req.alignment;
+               req.bytes = dev_info.avail_ebs * ebsz;
+
+               req.vol_type = UBI_DYNAMIC_VOLUME;
+               req.name = name;
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       failed("ubi_mkvol");
+                       err_msg("alignment %d", req.alignment);
+                       return -1;
+               }
+
+               vol_id = req.vol_id;
+               if (check_volume(vol_id, &req))
+                       goto remove;
+
+               if (ubi_rmvol(libubi, node, vol_id)) {
+                       failed("ubi_rmvol");
+                       return -1;
+               }
+       }
+
+       return 0;
+
+remove:
+       ubi_rmvol(libubi, node, vol_id);
+       return -1;
+}
+
+/**
+ * mkvol_basic - simple test that checks basic volume creation capability.
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int mkvol_basic(void)
+{
+       struct ubi_mkvol_request req;
+       struct ubi_vol_info vol_info;
+       int vol_id, ret;
+       const char *name = TESTNAME ":mkvol_basic()";
+
+       /* Create dynamic volume of maximum size */
+       req.vol_id = UBI_VOL_NUM_AUTO;
+       req.alignment = 1;
+       req.bytes = dev_info.avail_bytes;
+       req.vol_type = UBI_DYNAMIC_VOLUME;
+       req.name = name;
+
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               return -1;
+       }
+
+       vol_id = req.vol_id;
+       if (check_volume(vol_id, &req))
+               goto remove;
+
+       if (ubi_rmvol(libubi, node, vol_id)) {
+               failed("ubi_rmvol");
+               return -1;
+       }
+
+       /* Create static volume of maximum size */
+       req.vol_id = UBI_VOL_NUM_AUTO;
+       req.alignment = 1;
+       req.bytes = dev_info.avail_bytes;
+       req.vol_type = UBI_STATIC_VOLUME;
+       req.name = name;
+
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               return -1;
+       }
+
+       vol_id = req.vol_id;
+       if (check_volume(vol_id, &req))
+               goto remove;
+
+       if (ubi_rmvol(libubi, node, vol_id)) {
+               failed("ubi_rmvol");
+               return -1;
+       }
+
+       /* Make sure volume does not exist */
+       ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info);
+       if (ret == 0) {
+               err_msg("removed volume %d exists", vol_id);
+               goto remove;
+       }
+
+       return 0;
+
+remove:
+       ubi_rmvol(libubi, node, vol_id);
+       return -1;
+}
+
+/**
+ * mkvol_multiple - test multiple volumes creation
+ *
+ * Thus function returns %0 if the test passed and %-1 if not.
+ */
+static int mkvol_multiple(void)
+{
+       struct ubi_mkvol_request req;
+       int i, ret, max = dev_info.max_vol_count;
+       const char *name = TESTNAME ":mkvol_multiple()";
+
+       /* Create maximum number of volumes */
+       for (i = 0; i < max; i++) {
+               char nm[strlen(name) + 50];
+
+               req.vol_id = UBI_VOL_NUM_AUTO;
+               req.alignment = 1;
+               req.bytes = 1;
+               req.vol_type = UBI_STATIC_VOLUME;
+
+               sprintf(&nm[0], "%s:%d", name, i);
+               req.name = &nm[0];
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       if (errno == ENFILE) {
+                               max = i;
+                               break;
+                       }
+                       failed("ubi_mkvol");
+                       err_msg("vol_id %d", i);
+                       goto remove;
+               }
+
+               if (check_volume(req.vol_id, &req)) {
+                       err_msg("vol_id %d", i);
+                       goto remove;
+               }
+       }
+
+       for (i = 0; i < max; i++) {
+               struct ubi_vol_info vol_info;
+
+               if (ubi_rmvol(libubi, node, i)) {
+                       failed("ubi_rmvol");
+                       return -1;
+               }
+
+               /* Make sure volume does not exist */
+               ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info);
+               if (ret == 0) {
+                       err_msg("removed volume %d exists", i);
+                       goto remove;
+               }
+       }
+
+       return 0;
+
+remove:
+       for (i = 0; i < dev_info.max_vol_count + 1; i++)
+               ubi_rmvol(libubi, node, i);
+       return -1;
+}
diff --git a/ubi-utils/tests/mkvol_paral.c b/ubi-utils/tests/mkvol_paral.c
new file mode 100644 (file)
index 0000000..faf085c
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * This test creates and deletes volumes in parallel.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "libubi.h"
+#define TESTNAME "mkvol_paral"
+#include "common.h"
+
+#define THREADS_NUM 4
+#define ITERATIONS  500
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+static int iterations = ITERATIONS;
+
+static void * the_thread(void *ptr);
+
+int main(int argc, char * const argv[])
+{
+       int i, ret;
+       pthread_t threads[THREADS_NUM];
+
+       if (initial_check(argc, argv))
+               return 1;
+
+       node = argv[1];
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               failed("libubi_open");
+               return 1;
+       }
+
+       if (ubi_get_dev_info(libubi, node, &dev_info)) {
+               failed("ubi_get_dev_info");
+               goto close;
+       }
+
+       for (i = 0; i < THREADS_NUM; i++) {
+               ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i);
+               if (ret) {
+                       failed("pthread_create");
+                       goto close;
+               }
+       }
+
+       for (i = 0; i < THREADS_NUM; i++)
+               pthread_join(threads[i], NULL);
+
+       libubi_close(libubi);
+       return 0;
+
+close:
+       libubi_close(libubi);
+       return 1;
+}
+
+/**
+ * the_thread - the testing thread.
+ *
+ * @ptr  thread number
+ */
+static void * the_thread(void *ptr)
+{
+       int n = (int)ptr, iter = iterations;
+       struct ubi_mkvol_request req;
+       const char *name =  TESTNAME ":the_thread()";
+       char nm[strlen(name) + 50];
+
+       req.alignment = 1;
+       req.bytes = dev_info.avail_bytes/ITERATIONS;
+       req.vol_type = UBI_DYNAMIC_VOLUME;
+       sprintf(&nm[0], "%s:%d", name, n);
+       req.name = &nm[0];
+
+       while (iter--) {
+               req.vol_id = UBI_VOL_NUM_AUTO;
+               if (ubi_mkvol(libubi, node, &req)) {
+                       failed("ubi_mkvol");
+                       return NULL;
+               }
+               if (ubi_rmvol(libubi, node, req.vol_id)) {
+                       failed("ubi_rmvol");
+                       return NULL;
+               }
+       }
+
+       return NULL;
+}
diff --git a/ubi-utils/tests/rsvol.c b/ubi-utils/tests/rsvol.c
new file mode 100644 (file)
index 0000000..7a9e5ea
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * 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: Artem B. Bityutskiy
+ *
+ * Tes UBI volume re-size.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "rsvol"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+static int test_basic(int type);
+static int test_rsvol(int type);
+
+int main(int argc, char * const argv[])
+{
+       if (initial_check(argc, argv))
+               return 1;
+
+       node = argv[1];
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               failed("libubi_open");
+               return 1;
+       }
+
+       if (ubi_get_dev_info(libubi, node, &dev_info)) {
+               failed("ubi_get_dev_info");
+               goto close;
+       }
+
+       if (test_basic(UBI_DYNAMIC_VOLUME))
+               goto close;
+       if (test_basic(UBI_STATIC_VOLUME))
+               goto close;
+       if (test_rsvol(UBI_DYNAMIC_VOLUME))
+               goto close;
+       if (test_rsvol(UBI_STATIC_VOLUME))
+               goto close;
+
+       libubi_close(libubi);
+       return 0;
+
+close:
+       libubi_close(libubi);
+       return 1;
+}
+
+/**
+ * test_basic - check volume re-size capability.
+ *
+ * @type  volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_basic(int type)
+{
+       struct ubi_mkvol_request req;
+       const char *name = TESTNAME ":test_basic()";
+
+       req.vol_id = UBI_VOL_NUM_AUTO;
+       req.alignment = 1;
+       req.bytes = MIN_AVAIL_EBS * dev_info.eb_size;
+       req.vol_type = type;
+       req.name = name;
+
+       if (ubi_mkvol(libubi, node, &req)) {
+               failed("ubi_mkvol");
+               return -1;
+       }
+
+       req.bytes = dev_info.eb_size;
+       if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) {
+               failed("ubi_rsvol");
+               goto remove;
+       }
+
+       if (check_volume(req.vol_id, &req))
+               goto remove;
+
+       req.bytes = (MIN_AVAIL_EBS + 1) * dev_info.eb_size;
+       if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) {
+               failed("ubi_rsvol");
+               goto remove;
+       }
+
+       if (check_volume(req.vol_id, &req))
+               goto remove;
+
+       req.bytes -= 1;
+       if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) {
+               failed("ubi_rsvol");
+               goto remove;
+       }
+
+       if (check_volume(req.vol_id, &req))
+               goto remove;
+
+       if (ubi_rmvol(libubi, node, req.vol_id)) {
+               failed("ubi_rmvol");
+               return -1;
+       }
+
+       return 0;
+
+remove:
+       ubi_rmvol(libubi, node, req.vol_id);
+       return -1;
+}
+
+static int test_rsvol1(struct ubi_vol_info *vol_info);
+
+/**
+ * test_rsvol - test UBI volume re-size.
+ *
+ * @type  volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_rsvol(int type)
+{
+       const char *name = TESTNAME "test_rsvol:()";
+       int alignments[] = ALIGNMENTS(dev_info.eb_size);
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       struct ubi_mkvol_request req;
+       int i;
+
+       for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+               int eb_size;
+               struct ubi_vol_info vol_info;
+
+               req.vol_id = UBI_VOL_NUM_AUTO;
+               req.vol_type = type;
+               req.name = name;
+
+               req.alignment = alignments[i];
+               req.alignment -= req.alignment % dev_info.min_io_size;
+               if (req.alignment == 0)
+                       req.alignment = dev_info.min_io_size;
+
+               eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment;
+               req.bytes =  MIN_AVAIL_EBS * eb_size;
+
+               if (ubi_mkvol(libubi, node, &req)) {
+                       failed("ubi_mkvol");
+                       return -1;
+               }
+
+               sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num,
+                       req.vol_id);
+
+               if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+                       failed("ubi_get_vol_info");
+                       goto remove;
+               }
+
+               if (test_rsvol1(&vol_info)) {
+                       err_msg("alignment = %d", req.alignment);
+                       goto remove;
+               }
+
+               if (ubi_rmvol(libubi, node, req.vol_id)) {
+                       failed("ubi_rmvol");
+                       return -1;
+               }
+       }
+
+       return 0;
+
+remove:
+       ubi_rmvol(libubi, node, req.vol_id);
+       return -1;
+}
+
+/*
+ * Helper function for test_rsvol().
+ */
+static int test_rsvol1(struct ubi_vol_info *vol_info)
+{
+       long long bytes;
+       struct ubi_vol_info vol_info1;
+       char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+       unsigned char buf[vol_info->rsvd_bytes];
+       int fd, i, ret;
+
+       /* Make the volume smaller and check basic volume I/O */
+       bytes = vol_info->rsvd_bytes - vol_info->eb_size;
+       if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes - 1)) {
+               failed("ubi_rsvol");
+               return -1;
+       }
+
+       if (ubi_get_vol_info1(libubi, vol_info->dev_num, vol_info->vol_id,
+                            &vol_info1)) {
+               failed("ubi_get_vol_info");
+               return -1;
+       }
+
+       if (vol_info1.rsvd_bytes != bytes) {
+               err_msg("rsvd_bytes %lld, must be %lld",
+                       vol_info1.rsvd_bytes, bytes);
+               return -1;
+       }
+
+       if (vol_info1.rsvd_ebs != vol_info->rsvd_ebs - 1) {
+               err_msg("rsvd_ebs %d, must be %d",
+                       vol_info1.rsvd_ebs, vol_info->rsvd_ebs - 1);
+               return -1;
+       }
+
+       /* Write data to the volume */
+       sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num,
+                       vol_info->vol_id);
+
+       fd = open(vol_node, O_RDWR);
+       if (fd == -1) {
+               failed("open");
+               err_msg("cannot open \"%s\"\n", vol_node);
+               return -1;
+       }
+
+       bytes = vol_info->rsvd_bytes - vol_info->eb_size - 1;
+       if (ubi_update_start(libubi, fd, bytes)) {
+               failed("ubi_update_start");
+               goto close;
+       }
+
+       for (i = 0; i < bytes; i++)
+               buf[i] = (unsigned char)i;
+
+       ret = write(fd, &buf[0], bytes);
+       if (ret != bytes) {
+               failed("write");
+               goto close;
+       }
+
+       close(fd);
+
+       if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes)) {
+               failed("ubi_rsvol");
+               return -1;
+       }
+
+       if (ubi_rsvol(libubi, node, vol_info->vol_id,
+                     vol_info->eb_size * dev_info.avail_ebs)) {
+               failed("ubi_rsvol");
+               return -1;
+       }
+
+       fd = open(vol_node, O_RDWR);
+       if (fd == -1) {
+               failed("open");
+               err_msg("cannot open \"%s\"\n", vol_node);
+               return -1;
+       }
+
+       /* Read data back */
+       if (lseek(fd, 0, SEEK_SET) != 0) {
+               failed("seek");
+               goto close;
+       }
+       memset(&buf[0], 0, bytes);
+       ret = read(fd, &buf[0], bytes);
+       if (ret != bytes) {
+               failed("read");
+               goto close;
+       }
+
+       for (i = 0; i < bytes; i++) {
+               if (buf[i] != (unsigned char)i) {
+                       err_msg("bad data");
+                       goto close;
+               }
+       }
+
+       close(fd);
+       return 0;
+
+close:
+       close(fd);
+       return -1;
+}
diff --git a/ubi-utils/tests/runtests.pl b/ubi-utils/tests/runtests.pl
new file mode 100755 (executable)
index 0000000..8005716
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/perl -w
+
+sub usage;
+
+my @tests = ("mkvol_basic", "mkvol_bad", "mkvol_paral", "rsvol",
+            "io_basic", "io_read", "io_update", "io_paral");
+
+if (not defined @ARGV) {
+       usage();
+       exit;
+}
+
+foreach (@ARGV) {
+       -c or die "Error: $_ is not character device\n";
+}
+
+my $dev;
+foreach $dev (@ARGV) {
+       foreach (@tests) {
+               print "Running: $_ $dev";
+               system "./$_ $dev" and die;
+               print "\tSUCCESS\n";
+       }
+}
+
+sub usage
+{
+       print "Usage:\n";
+       print "$0 <UBI device 1> <UBI device 2> ...\n";
+}
diff --git a/ubi-utils/tests/runtests.sh b/ubi-utils/tests/runtests.sh
new file mode 100755 (executable)
index 0000000..f993bc0
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+ubidev="$1"
+ubiloadcmd="$2"
+tests="mkvol_basic mkvol_bad mkvol_paral rsvol io_basic io_read io_update io_paral"
+
+if test -z "$ubidev" || test -z "$ubiloadcmd";
+then
+       echo "Usage:"
+       echo "$0 <UBI device> <ubi module load command>"
+       exit 1
+fi
+
+ubiname=`echo $ubidev | cut -d/ -f3`
+
+major=`cat /sys/class/ubi/$ubiname/dev | cut -d: -f1`
+
+for minor in `seq 0 4`; do
+       if test ! -e ${ubidev}_${minor} ;
+       then
+               mknod ${ubidev}_${minor} c $major $(($minor + 1))
+       fi
+done
+
+if ! test -c "$ubidev";
+then
+       echo "Error: $ubidev is not character device"
+       exit 1
+fi
+
+for t in `echo $tests`;
+do
+       echo "Running $t $ubidev"
+       "./$t" "$ubidev" || exit 1
+done
+
+./integ "$ubiloadcmd" || exit 1
+
+echo SUCCESS
+
+exit 0