diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-02-19 14:54:17 +0200 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-02-19 16:41:16 +0200 |
commit | 86dd9696d3a1acb036d65909d93d73455b8aed3a (patch) | |
tree | 9e8bb6797b3bebd0bf83ae1fab2151a6dfeafe6a /ubi-utils | |
parent | ef644090223e5983ca2492850354c1390e3368d1 (diff) |
Revert ubi-tools changes
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>
Diffstat (limited to 'ubi-utils')
-rw-r--r-- | ubi-utils/Makefile | 95 | ||||
-rw-r--r-- | ubi-utils/README | 236 | ||||
-rw-r--r-- | ubi-utils/UBI.TXT (renamed from ubi-utils/old-tools/README) | 51 | ||||
-rw-r--r-- | ubi-utils/doc/unubi.roff | 123 | ||||
-rw-r--r-- | ubi-utils/inc/libubi.h | 268 | ||||
-rw-r--r-- | ubi-utils/lib/Makefile.am | 58 | ||||
-rw-r--r-- | ubi-utils/new-utils/LICENSE.libiniparser (renamed from ubi-utils/LICENSE.libiniparser) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/Makefile | 63 | ||||
-rw-r--r-- | ubi-utils/new-utils/README | 56 | ||||
-rw-r--r-- | ubi-utils/new-utils/include/libiniparser.h (renamed from ubi-utils/include/libiniparser.h) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/include/libubi.h (renamed from ubi-utils/include/libubi.h) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/include/libubigen.h (renamed from ubi-utils/include/libubigen.h) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/common.c (renamed from ubi-utils/src/common.c) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/common.h (renamed from ubi-utils/src/common.h) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/crc32.c | 95 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/crc32.h | 19 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/dictionary.c (renamed from ubi-utils/src/dictionary.c) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/dictionary.h (renamed from ubi-utils/src/dictionary.h) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/libiniparser.c (renamed from ubi-utils/src/libiniparser.c) | 0 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/libubi.c (renamed from ubi-utils/old-tools/src/libubi.c) | 140 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/libubi_int.h (renamed from ubi-utils/old-tools/src/libubi_int.h) | 16 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/libubigen.c | 321 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/ubi-attach.c (renamed from ubi-utils/src/ubiattach.c) | 2 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/ubi-crc32.c | 125 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/ubi-detach.c (renamed from ubi-utils/src/ubidetach.c) | 2 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/ubi-info.c (renamed from ubi-utils/src/ubinfo.c) | 2 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/ubi-mkvol.c | 288 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/ubi-nize.c (renamed from ubi-utils/src/ubinize.c) | 4 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/ubi-rmvol.c | 170 | ||||
-rw-r--r-- | ubi-utils/new-utils/src/ubi-update.c (renamed from ubi-utils/src/ubiupdate.c) | 4 | ||||
-rw-r--r-- | ubi-utils/old-tools/Makefile | 99 | ||||
-rw-r--r-- | ubi-utils/old-tools/inc/libubi.h | 340 | ||||
-rw-r--r-- | ubi-utils/old-tools/src/common.c | 89 | ||||
-rw-r--r-- | ubi-utils/old-tools/src/common.h | 43 | ||||
-rw-r--r-- | ubi-utils/old-tools/src/crc32.c | 83 | ||||
-rw-r--r-- | ubi-utils/old-tools/src/crc32.h | 36 | ||||
-rw-r--r-- | ubi-utils/old-tools/src/ecclayouts.h | 66 | ||||
-rw-r--r-- | ubi-utils/old-tools/src/libubigen.c | 486 | ||||
-rw-r--r-- | ubi-utils/old-tools/src/ubiupdate.c | 318 | ||||
-rw-r--r-- | ubi-utils/perl/f128_nand_sample.cfg (renamed from ubi-utils/old-tools/scripts/f128_nand_sample.cfg) | 6 | ||||
-rw-r--r-- | ubi-utils/perl/f64_nor_sample.cfg (renamed from ubi-utils/old-tools/scripts/f64_nor_sample.cfg) | 6 | ||||
-rwxr-xr-x[-rw-r--r--] | ubi-utils/perl/mkpfi (renamed from ubi-utils/old-tools/scripts/mkpfi) | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | ubi-utils/perl/ubicrc32.pl (renamed from ubi-utils/old-tools/scripts/ubicrc32.pl) | 2 | ||||
-rw-r--r-- | ubi-utils/scripts/Makefile (renamed from ubi-utils/old-tools/scripts/Makefile) | 20 | ||||
-rw-r--r-- | ubi-utils/scripts/README (renamed from ubi-utils/old-tools/scripts/README) | 3 | ||||
-rw-r--r-- | ubi-utils/scripts/TODO | 5 | ||||
-rw-r--r-- | ubi-utils/scripts/bin2nand2bin_test.sh (renamed from ubi-utils/old-tools/scripts/bin2nand2bin_test.sh) | 46 | ||||
-rw-r--r-- | ubi-utils/scripts/inject_biterror.pl (renamed from ubi-utils/old-tools/scripts/inject_biterror.pl) | 0 | ||||
-rwxr-xr-x | ubi-utils/scripts/jffs2_test.sh (renamed from ubi-utils/old-tools/scripts/jffs2_test.sh) | 0 | ||||
-rwxr-xr-x | ubi-utils/scripts/mkdevs.pl (renamed from ubi-utils/old-tools/scripts/mkdevs.pl) | 0 | ||||
-rw-r--r-- | ubi-utils/scripts/pdd.txt (renamed from ubi-utils/old-tools/scripts/pdd.txt) | 0 | ||||
-rwxr-xr-x | ubi-utils/scripts/run_all.sh (renamed from ubi-utils/old-tools/scripts/run_all.sh) | 0 | ||||
-rw-r--r-- | ubi-utils/scripts/test.cfg (renamed from ubi-utils/old-tools/scripts/test.cfg) | 0 | ||||
-rwxr-xr-x | ubi-utils/scripts/ubi_jffs2_test.sh | 411 | ||||
-rwxr-xr-x | ubi-utils/scripts/ubi_test.sh (renamed from ubi-utils/old-tools/scripts/ubi_test.sh) | 0 | ||||
-rwxr-xr-x | ubi-utils/scripts/ubi_tools_test.sh (renamed from ubi-utils/old-tools/scripts/ubi_tools_test.sh) | 0 | ||||
-rw-r--r-- | ubi-utils/scripts/unubi_test.sh (renamed from ubi-utils/old-tools/scripts/unubi_test.sh) | 0 | ||||
-rw-r--r-- | ubi-utils/src/bin2nand.c (renamed from ubi-utils/old-tools/src/bin2nand.c) | 156 | ||||
-rw-r--r-- | ubi-utils/src/bootenv.c (renamed from ubi-utils/old-tools/src/bootenv.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/bootenv.h (renamed from ubi-utils/old-tools/src/bootenv.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/config.h (renamed from ubi-utils/old-tools/src/config.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/crc32.c | 156 | ||||
-rw-r--r-- | ubi-utils/src/crc32.h | 47 | ||||
-rw-r--r-- | ubi-utils/src/eb_chain.c (renamed from ubi-utils/old-tools/src/eb_chain.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/error.c (renamed from ubi-utils/old-tools/src/error.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/error.h (renamed from ubi-utils/old-tools/src/error.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/example_ubi.h (renamed from ubi-utils/old-tools/src/example_ubi.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/hashmap.c (renamed from ubi-utils/old-tools/src/hashmap.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/hashmap.h (renamed from ubi-utils/old-tools/src/hashmap.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/libpfiflash.c (renamed from ubi-utils/old-tools/src/libpfiflash.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/libubi.c | 1318 | ||||
-rw-r--r-- | ubi-utils/src/libubi_int.h | 100 | ||||
-rw-r--r-- | ubi-utils/src/libubigen.c | 660 | ||||
-rw-r--r-- | ubi-utils/src/libubimirror.c (renamed from ubi-utils/old-tools/src/libubimirror.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/list.c (renamed from ubi-utils/old-tools/src/list.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/list.h (renamed from ubi-utils/old-tools/src/list.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/mkbootenv.c (renamed from ubi-utils/old-tools/src/mkbootenv.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/nand2bin.c (renamed from ubi-utils/old-tools/src/nand2bin.c) | 212 | ||||
-rw-r--r-- | ubi-utils/src/nandcorr.c (renamed from ubi-utils/old-tools/src/nandcorr.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/nandecc.c (renamed from ubi-utils/old-tools/src/nandecc.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/nandecc.h (renamed from ubi-utils/old-tools/src/nandecc.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/pddcustomize.c (renamed from ubi-utils/old-tools/src/pddcustomize.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/peb.c (renamed from ubi-utils/old-tools/src/peb.c) | 4 | ||||
-rw-r--r-- | ubi-utils/src/peb.h (renamed from ubi-utils/old-tools/src/peb.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/pfi.c (renamed from ubi-utils/old-tools/src/pfi.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/pfi.h (renamed from ubi-utils/old-tools/src/pfi.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/pfi2bin.c (renamed from ubi-utils/old-tools/src/pfi2bin.c) | 1 | ||||
-rw-r--r-- | ubi-utils/src/pfiflash.c (renamed from ubi-utils/old-tools/src/pfiflash.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/pfiflash.h (renamed from ubi-utils/old-tools/src/pfiflash.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/pfiflash_error.h (renamed from ubi-utils/old-tools/src/pfiflash_error.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/reader.c (renamed from ubi-utils/old-tools/src/reader.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/reader.h (renamed from ubi-utils/old-tools/src/reader.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/ubicrc32.c | 166 | ||||
-rw-r--r-- | ubi-utils/src/ubigen.c (renamed from ubi-utils/old-tools/src/ubigen.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/ubigen.h (renamed from ubi-utils/old-tools/src/ubigen.h) | 1 | ||||
-rw-r--r-- | ubi-utils/src/ubimirror.c (renamed from ubi-utils/old-tools/src/ubimirror.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/ubimirror.h (renamed from ubi-utils/old-tools/src/ubimirror.h) | 0 | ||||
-rw-r--r-- | ubi-utils/src/ubimkvol.c | 424 | ||||
-rw-r--r-- | ubi-utils/src/ubirmvol.c | 223 | ||||
-rw-r--r-- | ubi-utils/src/ubiupdatevol.c | 336 | ||||
-rw-r--r-- | ubi-utils/src/unubi.c (renamed from ubi-utils/old-tools/src/unubi.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/unubi_analyze.c (renamed from ubi-utils/old-tools/src/unubi_analyze.c) | 0 | ||||
-rw-r--r-- | ubi-utils/src/unubi_analyze.h (renamed from ubi-utils/old-tools/src/unubi_analyze.h) | 0 | ||||
-rw-r--r-- | ubi-utils/testcases.txt | 9 | ||||
-rw-r--r-- | ubi-utils/tests/Makefile | 40 | ||||
-rw-r--r-- | ubi-utils/tests/README.udev | 19 | ||||
-rw-r--r-- | ubi-utils/tests/common.c | 336 | ||||
-rw-r--r-- | ubi-utils/tests/common.h | 103 | ||||
-rw-r--r-- | ubi-utils/tests/integ.c | 783 | ||||
-rw-r--r-- | ubi-utils/tests/io_basic.c | 182 | ||||
-rw-r--r-- | ubi-utils/tests/io_paral.c | 251 | ||||
-rw-r--r-- | ubi-utils/tests/io_read.c | 398 | ||||
-rw-r--r-- | ubi-utils/tests/io_update.c | 370 | ||||
-rw-r--r-- | ubi-utils/tests/mkvol_bad.c | 304 | ||||
-rw-r--r-- | ubi-utils/tests/mkvol_basic.c | 253 | ||||
-rw-r--r-- | ubi-utils/tests/mkvol_paral.c | 112 | ||||
-rw-r--r-- | ubi-utils/tests/rsvol.c | 310 | ||||
-rwxr-xr-x | ubi-utils/tests/runtests.pl | 30 | ||||
-rwxr-xr-x | ubi-utils/tests/runtests.sh | 41 |
119 files changed, 8028 insertions, 3514 deletions
diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile index 8d4412d..7c573e0 100644 --- a/ubi-utils/Makefile +++ b/ubi-utils/Makefile @@ -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 index 0000000..d976a76 --- /dev/null +++ b/ubi-utils/README @@ -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 diff --git a/ubi-utils/old-tools/README b/ubi-utils/UBI.TXT index 39ed0e9..9a1c3c7 100644 --- a/ubi-utils/old-tools/README +++ b/ubi-utils/UBI.TXT @@ -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 index 0000000..6cebc46 --- /dev/null +++ b/ubi-utils/doc/unubi.roff @@ -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 index 0000000..d39c1b9 --- /dev/null +++ b/ubi-utils/inc/libubi.h @@ -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 index 0000000..1b0dc01 --- /dev/null +++ b/ubi-utils/lib/Makefile.am @@ -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/LICENSE.libiniparser b/ubi-utils/new-utils/LICENSE.libiniparser index dbfa45d..dbfa45d 100644 --- a/ubi-utils/LICENSE.libiniparser +++ b/ubi-utils/new-utils/LICENSE.libiniparser diff --git a/ubi-utils/new-utils/Makefile b/ubi-utils/new-utils/Makefile new file mode 100644 index 0000000..fe60ffe --- /dev/null +++ b/ubi-utils/new-utils/Makefile @@ -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 index 0000000..7113b69 --- /dev/null +++ b/ubi-utils/new-utils/README @@ -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/include/libiniparser.h b/ubi-utils/new-utils/include/libiniparser.h index be3c667..be3c667 100644 --- a/ubi-utils/include/libiniparser.h +++ b/ubi-utils/new-utils/include/libiniparser.h diff --git a/ubi-utils/include/libubi.h b/ubi-utils/new-utils/include/libubi.h index 7e0bfcd..7e0bfcd 100644 --- a/ubi-utils/include/libubi.h +++ b/ubi-utils/new-utils/include/libubi.h diff --git a/ubi-utils/include/libubigen.h b/ubi-utils/new-utils/include/libubigen.h index 058cf8a..058cf8a 100644 --- a/ubi-utils/include/libubigen.h +++ b/ubi-utils/new-utils/include/libubigen.h diff --git a/ubi-utils/src/common.c b/ubi-utils/new-utils/src/common.c index fec640d..fec640d 100644 --- a/ubi-utils/src/common.c +++ b/ubi-utils/new-utils/src/common.c diff --git a/ubi-utils/src/common.h b/ubi-utils/new-utils/src/common.h index a3fc51f..a3fc51f 100644 --- a/ubi-utils/src/common.h +++ b/ubi-utils/new-utils/src/common.h diff --git a/ubi-utils/new-utils/src/crc32.c b/ubi-utils/new-utils/src/crc32.c new file mode 100644 index 0000000..6b1e50c --- /dev/null +++ b/ubi-utils/new-utils/src/crc32.c @@ -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 index 0000000..ee3145b --- /dev/null +++ b/ubi-utils/new-utils/src/crc32.h @@ -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 diff --git a/ubi-utils/src/dictionary.c b/ubi-utils/new-utils/src/dictionary.c index b7c9ebf..b7c9ebf 100644 --- a/ubi-utils/src/dictionary.c +++ b/ubi-utils/new-utils/src/dictionary.c diff --git a/ubi-utils/src/dictionary.h b/ubi-utils/new-utils/src/dictionary.h index c7d1790..c7d1790 100644 --- a/ubi-utils/src/dictionary.h +++ b/ubi-utils/new-utils/src/dictionary.h diff --git a/ubi-utils/src/libiniparser.c b/ubi-utils/new-utils/src/libiniparser.c index 3bea51e..3bea51e 100644 --- a/ubi-utils/src/libiniparser.c +++ b/ubi-utils/new-utils/src/libiniparser.c diff --git a/ubi-utils/old-tools/src/libubi.c b/ubi-utils/new-utils/src/libubi.c index be06f70..b53f18c 100644 --- a/ubi-utils/old-tools/src/libubi.c +++ b/ubi-utils/new-utils/src/libubi.c @@ -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; @@ -320,31 +309,6 @@ static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, } /** - * 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 * @dev_num: UBI device number @@ -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; diff --git a/ubi-utils/old-tools/src/libubi_int.h b/ubi-utils/new-utils/src/libubi_int.h index 6490864..dab3e62 100644 --- a/ubi-utils/old-tools/src/libubi_int.h +++ b/ubi-utils/new-utils/src/libubi_int.h @@ -23,14 +23,26 @@ #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 index 0000000..8d71fde --- /dev/null +++ b/ubi-utils/new-utils/src/libubigen.c @@ -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; +} diff --git a/ubi-utils/src/ubiattach.c b/ubi-utils/new-utils/src/ubi-attach.c index b3d768a..7b231a6 100644 --- a/ubi-utils/src/ubiattach.c +++ b/ubi-utils/new-utils/src/ubi-attach.c @@ -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 index 0000000..d3d3136 --- /dev/null +++ b/ubi-utils/new-utils/src/ubi-crc32.c @@ -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; +} diff --git a/ubi-utils/src/ubidetach.c b/ubi-utils/new-utils/src/ubi-detach.c index cd48368..0ee7954 100644 --- a/ubi-utils/src/ubidetach.c +++ b/ubi-utils/new-utils/src/ubi-detach.c @@ -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 { diff --git a/ubi-utils/src/ubinfo.c b/ubi-utils/new-utils/src/ubi-info.c index 185caae..d469a1a 100644 --- a/ubi-utils/src/ubinfo.c +++ b/ubi-utils/new-utils/src/ubi-info.c @@ -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 index 0000000..49d1905 --- /dev/null +++ b/ubi-utils/new-utils/src/ubi-mkvol.c @@ -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; +} diff --git a/ubi-utils/src/ubinize.c b/ubi-utils/new-utils/src/ubi-nize.c index 47dc571..8041df4 100644 --- a/ubi-utils/src/ubinize.c +++ b/ubi-utils/new-utils/src/ubi-nize.c @@ -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 index 0000000..72bf069 --- /dev/null +++ b/ubi-utils/new-utils/src/ubi-rmvol.c @@ -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; +} diff --git a/ubi-utils/src/ubiupdate.c b/ubi-utils/new-utils/src/ubi-update.c index c17b3c5..bf548a9 100644 --- a/ubi-utils/src/ubiupdate.c +++ b/ubi-utils/new-utils/src/ubi-update.c @@ -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 index d4c908b..0000000 --- a/ubi-utils/old-tools/Makefile +++ /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 index 0cdb67c..0000000 --- a/ubi-utils/old-tools/inc/libubi.h +++ /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 index 7ed1ade..0000000 --- a/ubi-utils/old-tools/src/common.c +++ /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 index 06ae623..0000000 --- a/ubi-utils/old-tools/src/common.h +++ /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 index 666e217..0000000 --- a/ubi-utils/old-tools/src/crc32.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Thomas Gleixner - */ - -/* - * CRC32 functions - * - * Can be compiled as seperate object, but is included into the ipl source - * so gcc can inline the functions. We optimize for size so the omission of - * the function frame is helpful. - * - */ - -#include <stdint.h> -#include <crc32.h> - -/* CRC polynomial */ -#define CRC_POLY 0xEDB88320 - -/** - * init_crc32_table - Initialize crc table - * - * @table: pointer to the CRC table which must be initialized - * - * Create CRC32 table for given polynomial. The table is created with - * the lowest order term in the highest order bit. So the x^32 term - * has to implied in the crc calculation function. - */ -void init_crc32_table(uint32_t *table) -{ - uint32_t crc; - int i, j; - - for (i = 0; i < 256; i++) { - crc = i; - for (j = 8; j > 0; j--) { - if (crc & 1) - crc = (crc >> 1) ^ CRC_POLY; - else - crc >>= 1; - } - table[i] = crc; - } -} - -/** - * clc_crc32 - Calculate CRC32 over a buffer - * - * @table: pointer to the CRC table - * @crc: initial crc value - * @buf: pointer to the buffer - * @len: number of bytes to calc - * - * Returns the updated crc value. - * - * The algorithm resembles a hardware shift register, but calculates 8 - * bit at once. - */ -uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, - int len) -{ - const unsigned char *p = buf; - - while(--len >= 0) - crc = table[(crc ^ *p++) & 0xff] ^ (crc >> 8); - return crc; -} diff --git a/ubi-utils/old-tools/src/crc32.h b/ubi-utils/old-tools/src/crc32.h deleted file mode 100644 index 31362b0..0000000 --- a/ubi-utils/old-tools/src/crc32.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __CRC32_H__ -#define __CRC32_H__ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Author: Thomas Gleixner - * - * CRC32 functions - * - * Can be compiled as seperate object, but is included into the ipl source - * so gcc can inline the functions. We optimize for size so the omission of - * the function frame is helpful. - * - */ -#include <stdint.h> - -void init_crc32_table(uint32_t *table); -uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len); - -#endif /* __CRC32_H__ */ diff --git a/ubi-utils/old-tools/src/ecclayouts.h b/ubi-utils/old-tools/src/ecclayouts.h deleted file mode 100644 index a1c7823..0000000 --- a/ubi-utils/old-tools/src/ecclayouts.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __ECCLAYOUTS_H__ -#define __ECCLAYOUTS_H__ -/* - * Copyright (c) International Business Machines Corp., 2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <stdint.h> -#include <mtd/mtd-abi.h> - -/* Define default oob placement schemes for large and small page devices */ -static struct nand_ecclayout mtd_nand_oob_16 = { - .eccbytes = 6, - .eccpos = { 0, 1, 2, 3, 6, 7 }, - .oobfree = {{ .offset = 8, .length = 8 }} -}; - -static struct nand_ecclayout mtd_nand_oob_64 = { - .eccbytes = 24, - .eccpos = { 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63 }, - .oobfree = {{ .offset = 2, .length = 38 }} -}; - -/* Define IBM oob placement schemes */ -static struct nand_ecclayout ibm_nand_oob_16 = { - .eccbytes = 6, - .eccpos = { 9, 10, 11, 13, 14, 15 }, - .oobfree = {{ .offset = 8, .length = 8 }} -}; - -static struct nand_ecclayout ibm_nand_oob_64 = { - .eccbytes = 24, - .eccpos = { 33, 34, 35, 37, 38, 39, 41, 42, - 43, 45, 46, 47, 49, 50, 51, 53, - 54, 55, 57, 58, 59, 61, 62, 63 }, - .oobfree = {{ .offset = 2, .length = 30 }} -}; - -struct oob_placement { - const char *name; - struct nand_ecclayout *nand_oob[2]; -}; - -static struct oob_placement oob_placement[] = { - { .name = "IBM", - .nand_oob = { &ibm_nand_oob_16, &ibm_nand_oob_64 }}, - { .name = "MTD", - .nand_oob = { &mtd_nand_oob_16, &mtd_nand_oob_64 }}, -}; - -#endif diff --git a/ubi-utils/old-tools/src/libubigen.c b/ubi-utils/old-tools/src/libubigen.c deleted file mode 100644 index d2cd087..0000000 --- a/ubi-utils/old-tools/src/libubigen.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Oliver Lohmann - * - * Add UBI headers to binary data. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <mtd/ubi-header.h> - -#include "config.h" -#include "ubigen.h" -#include "crc32.h" - -#define UBI_NAME_SIZE 256 -#define DEFAULT_VID_OFFSET ((DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -static uint32_t crc32_table[256]; - -struct ubi_info { - struct ubi_vid_hdr* v; /* Volume ID header */ - struct ubi_ec_hdr* ec; /* Erase count header */ - - FILE* fp_in; /* Input Stream */ - FILE* fp_out; /* Output stream */ - - size_t peb_size; /* Physical EB size in bytes */ - size_t leb_size; /* Size of a logical EB in a physical EB */ - size_t leb_total; /* Total input size in logical EB */ - size_t alignment; /* Block alignment */ - size_t data_pad; /* Size of padding in each physical EB */ - - size_t bytes_total; /* Total input size in bytes */ - size_t bytes_read; /* Nymber of read bytes (total) */ - - uint32_t blks_written; /* Number of written logical EB */ - - uint8_t* buf; /* Allocated buffer */ - uint8_t* ptr_ec_hdr; /* Pointer to EC hdr in buf */ - uint8_t* ptr_vid_hdr; /* Pointer to VID hdr in buf */ - uint8_t* ptr_data; /* Pointer to data region in buf */ -}; - - -static uint32_t -byte_to_blk(uint64_t byte, uint32_t peb_size) -{ - return (byte % peb_size) == 0 - ? (byte / peb_size) - : (byte / peb_size) + 1; -} - -static int -validate_ubi_info(ubi_info_t u) -{ - if ((u->v->vol_type != UBI_VID_DYNAMIC) && - (u->v->vol_type != UBI_VID_STATIC)) { - return EUBIGEN_INVALID_TYPE; - } - - if (be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) { - return EUBIGEN_INVALID_HDR_OFFSET; - } - - return 0; -} - -static int -skip_blks(ubi_info_t u, uint32_t blks) -{ - uint32_t i; - size_t read = 0, to_read = 0; - - /* Step to a maximum of leb_total - 1 to keep the - restrictions. */ - for (i = 0; i < MIN(blks, u->leb_total-1); i++) { - /* Read in data */ - to_read = MIN(u->leb_size, - (u->bytes_total - u->bytes_read)); - read = fread(u->ptr_data, 1, to_read, u->fp_in); - if (read != to_read) { - return -EIO; - } - u->bytes_read += read; - u->blks_written++; - } - - return 0; -} - -static void -clear_buf(ubi_info_t u) -{ - memset(u->buf, 0xff, u->peb_size); -} - -static void -write_ec_hdr(ubi_info_t u) -{ - memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE); -} - -static int -fill_data_buffer_from_file(ubi_info_t u, size_t* read) -{ - size_t to_read = 0; - - if (u-> fp_in == NULL) - return -EIO; - - to_read = MIN(u->leb_size, (u->bytes_total - u->bytes_read)); - *read = fread(u->ptr_data, 1, to_read, u->fp_in); - if (*read != to_read) { - return -EIO; - } - return 0; -} - -static void -add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action) -{ - uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - u->ptr_data, data_size); - - u->v->data_size = cpu_to_be32(data_size); - u->v->data_crc = cpu_to_be32(crc); - - if (action & BROKEN_DATA_CRC) { - u->v->data_crc = - cpu_to_be32(be32_to_cpu(u->v->data_crc) + 1); - } - if (action & BROKEN_DATA_SIZE) { - u->v->data_size = - cpu_to_be32(be32_to_cpu(u->v->data_size) + 1); - } -} - -static void -write_vid_hdr(ubi_info_t u, ubigen_action_t action) -{ - uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - u->v, UBI_VID_HDR_SIZE_CRC); - /* Write VID header */ - u->v->hdr_crc = cpu_to_be32(crc); - if (action & BROKEN_HDR_CRC) { - u->v->hdr_crc = cpu_to_be32(be32_to_cpu(u->v->hdr_crc) + 1); - } - memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE); -} - -static int -write_to_output_stream(ubi_info_t u) -{ - size_t written; - - written = fwrite(u->buf, 1, u->peb_size, u->fp_out); - if (written != u->peb_size) { - return -EIO; - } - return 0; -} - -int -ubigen_write_leb(ubi_info_t u, ubigen_action_t action) -{ - int rc = 0; - size_t read = 0; - - clear_buf(u); - write_ec_hdr(u); - - rc = fill_data_buffer_from_file(u, &read); - if (rc != 0) - return rc; - - if (u->v->vol_type == UBI_VID_STATIC) { - add_static_info(u, read, action); - } - - u->v->lnum = cpu_to_be32(u->blks_written); - - if (action & MARK_AS_UPDATE) { - u->v->copy_flag = (u->v->copy_flag)++; - } - - write_vid_hdr(u, action); - rc = write_to_output_stream(u); - if (rc != 0) - return rc; - - /* Update current handle */ - u->bytes_read += read; - u->blks_written++; - return 0; -} - -int -ubigen_write_complete(ubi_info_t u) -{ - size_t i; - int rc = 0; - - for (i = 0; i < u->leb_total; i++) { - rc = ubigen_write_leb(u, NO_ERROR); - if (rc != 0) - return rc; - } - - return 0; -} - -int -ubigen_write_broken_update(ubi_info_t u, uint32_t blk) -{ - int rc = 0; - - rc = skip_blks(u, blk); - if (rc != 0) - return rc; - - rc = ubigen_write_leb(u, MARK_AS_UPDATE | BROKEN_DATA_CRC); - if (rc != 0) - return rc; - - - return 0; -} - -void -dump_info(ubi_info_t u ubi_unused) -{ -#ifdef DEBUG - int err = 0; - if (!u) { - fprintf(stderr, "<empty>"); - return; - } - if (!u->ec) { - fprintf(stderr, "<ec-empty>"); - err = 1; - } - if (!u->v) { - fprintf(stderr, "<v-empty>"); - err = 1; - } - if (err) return; - - fprintf(stderr, "ubi volume\n"); - fprintf(stderr, "version : %8d\n", u->v->version); - fprintf(stderr, "vol_id : %8d\n", be32_to_cpu(u->v->vol_id)); - fprintf(stderr, "vol_type : %8s\n", - u->v->vol_type == UBI_VID_STATIC ? - "static" : "dynamic"); - fprintf(stderr, "used_ebs : %8d\n", - be32_to_cpu(u->v->used_ebs)); - fprintf(stderr, "peb_size : 0x%08x\n", u->peb_size); - fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size); - fprintf(stderr, "data_pad : 0x%08x\n", - be32_to_cpu(u->v->data_pad)); - fprintf(stderr, "leb_total : %8d\n", u->leb_total); - fprintf(stderr, "header offs : 0x%08x\n", - be32_to_cpu(u->ec->vid_hdr_offset)); - fprintf(stderr, "bytes_total : %8d\n", u->bytes_total); - fprintf(stderr, " + in MiB : %8.2f M\n", - ((float)(u->bytes_total)) / 1024 / 1024); - fprintf(stderr, "-------------------------------\n\n"); -#else - return; -#endif -} - -int -ubigen_destroy(ubi_info_t *u) -{ - if (u == NULL) - return -EINVAL; - - ubi_info_t tmp = *u; - - if (tmp) { - if (tmp->v) - free(tmp->v); - if (tmp->ec) - free(tmp->ec); - if (tmp->buf) - free(tmp->buf); - free(tmp); - } - *u = NULL; - return 0; -} - -void -ubigen_init(void) -{ - init_crc32_table(crc32_table); -} - -int -ubigen_create(ubi_info_t* u, uint32_t vol_id, uint8_t vol_type, - uint32_t peb_size, uint64_t ec, uint32_t alignment, - uint8_t version, uint32_t vid_hdr_offset, uint8_t compat_flag, - size_t data_size, FILE* fp_in, FILE* fp_out) -{ - int rc = 0; - ubi_info_t res = NULL; - uint32_t crc; - uint32_t data_offset; - - if (alignment == 0) { - rc = EUBIGEN_INVALID_ALIGNMENT; - goto ubigen_create_err; - } - if ((fp_in == NULL) || (fp_out == NULL)) { - rc = -EINVAL; - goto ubigen_create_err; - } - - res = (ubi_info_t) calloc(1, sizeof(struct ubi_info)); - if (res == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - res->v = (struct ubi_vid_hdr*) calloc(1, sizeof(struct ubi_vid_hdr)); - if (res->v == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - res->ec = (struct ubi_ec_hdr*) calloc(1, sizeof(struct ubi_ec_hdr)); - if (res->ec == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - /* data which is needed in the general process */ - vid_hdr_offset = vid_hdr_offset ? vid_hdr_offset : DEFAULT_VID_OFFSET; - data_offset = vid_hdr_offset + UBI_VID_HDR_SIZE; - res->bytes_total = data_size; - res->peb_size = peb_size ? peb_size : DEFAULT_BLOCKSIZE; - res->data_pad = (res->peb_size - data_offset) % alignment; - res->leb_size = res->peb_size - data_offset - res->data_pad; - res->leb_total = byte_to_blk(data_size, res->leb_size); - res->alignment = alignment; - - if ((res->peb_size < (vid_hdr_offset + UBI_VID_HDR_SIZE))) { - rc = EUBIGEN_TOO_SMALL_EB; - goto ubigen_create_err; - } - res->fp_in = fp_in; - res->fp_out = fp_out; - - /* vid hdr data which doesn't change */ - res->v->magic = cpu_to_be32(UBI_VID_HDR_MAGIC); - res->v->version = version ? version : UBI_VERSION; - res->v->vol_type = vol_type; - res->v->vol_id = cpu_to_be32(vol_id); - res->v->compat = compat_flag; - res->v->data_pad = cpu_to_be32(res->data_pad); - - /* static only: used_ebs */ - if (res->v->vol_type == UBI_VID_STATIC) { - res->v->used_ebs = cpu_to_be32(byte_to_blk - (res->bytes_total, - res->leb_size)); - } - - /* ec hdr (fixed, doesn't change) */ - res->ec->magic = cpu_to_be32(UBI_EC_HDR_MAGIC); - res->ec->version = version ? version : UBI_VERSION; - res->ec->ec = cpu_to_be64(ec); - res->ec->vid_hdr_offset = cpu_to_be32(vid_hdr_offset); - - res->ec->data_offset = cpu_to_be32(data_offset); - - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec, - UBI_EC_HDR_SIZE_CRC); - res->ec->hdr_crc = cpu_to_be32(crc); - - /* prepare a read buffer */ - res->buf = (uint8_t*) malloc (res->peb_size * sizeof(uint8_t)); - if (res->buf == NULL) { - rc = -ENOMEM; - goto ubigen_create_err; - } - - /* point to distinct regions within the buffer */ - res->ptr_ec_hdr = res->buf; - res->ptr_vid_hdr = res->buf + be32_to_cpu(res->ec->vid_hdr_offset); - res->ptr_data = res->buf + be32_to_cpu(res->ec->vid_hdr_offset) - + UBI_VID_HDR_SIZE; - - rc = validate_ubi_info(res); - if (rc != 0) { - fprintf(stderr, "Volume validation failed: %d\n", rc); - goto ubigen_create_err; - } - - dump_info(res); - *u = res; - return rc; - - ubigen_create_err: - if (res) { - if (res->v) - free(res->v); - if (res->ec) - free(res->ec); - if (res->buf) - free(res->buf); - free(res); - } - *u = NULL; - return rc; -} - -int -ubigen_get_leb_size(ubi_info_t u, size_t* size) -{ - if (u == NULL) - return -EINVAL; - - *size = u->leb_size; - return 0; -} - - -int -ubigen_get_leb_total(ubi_info_t u, size_t* total) -{ - if (u == NULL) - return -EINVAL; - - *total = u->leb_total; - return 0; -} - -int -ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes, - const char* vol_name, struct ubi_vtbl_record *lvol_rec) -{ - uint32_t crc; - - if ((u == NULL) || (vol_name == NULL)) - return -EINVAL; - - memset(lvol_rec, 0x0, UBI_VTBL_RECORD_SIZE); - - lvol_rec->reserved_pebs = - cpu_to_be32(byte_to_blk(reserved_bytes, u->leb_size)); - lvol_rec->alignment = cpu_to_be32(u->alignment); - lvol_rec->data_pad = u->v->data_pad; - lvol_rec->vol_type = u->v->vol_type; - - lvol_rec->name_len = - cpu_to_be16((uint16_t)strlen((const char*)vol_name)); - - memcpy(lvol_rec->name, vol_name, UBI_VOL_NAME_MAX + 1); - - crc = clc_crc32(crc32_table, UBI_CRC32_INIT, - lvol_rec, UBI_VTBL_RECORD_SIZE_CRC); - lvol_rec->crc = cpu_to_be32(crc); - - return 0; -} diff --git a/ubi-utils/old-tools/src/ubiupdate.c b/ubi-utils/old-tools/src/ubiupdate.c deleted file mode 100644 index 75222d4..0000000 --- a/ubi-utils/old-tools/src/ubiupdate.c +++ /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; -} diff --git a/ubi-utils/old-tools/scripts/f128_nand_sample.cfg b/ubi-utils/perl/f128_nand_sample.cfg index bb62600..e468d9d 100644 --- a/ubi-utils/old-tools/scripts/f128_nand_sample.cfg +++ b/ubi-utils/perl/f128_nand_sample.cfg @@ -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 diff --git a/ubi-utils/old-tools/scripts/f64_nor_sample.cfg b/ubi-utils/perl/f64_nor_sample.cfg index 889d4c2..fd44e27 100644 --- a/ubi-utils/old-tools/scripts/f64_nor_sample.cfg +++ b/ubi-utils/perl/f64_nor_sample.cfg @@ -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 diff --git a/ubi-utils/old-tools/scripts/mkpfi b/ubi-utils/perl/mkpfi index 2cce587..2cce587 100644..100755 --- a/ubi-utils/old-tools/scripts/mkpfi +++ b/ubi-utils/perl/mkpfi diff --git a/ubi-utils/old-tools/scripts/ubicrc32.pl b/ubi-utils/perl/ubicrc32.pl index 92711cb..add5f9d 100644..100755 --- a/ubi-utils/old-tools/scripts/ubicrc32.pl +++ b/ubi-utils/perl/ubicrc32.pl @@ -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; diff --git a/ubi-utils/old-tools/scripts/Makefile b/ubi-utils/scripts/Makefile index b8e3c96..ebd9bc6 100644 --- a/ubi-utils/old-tools/scripts/Makefile +++ b/ubi-utils/scripts/Makefile @@ -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 diff --git a/ubi-utils/old-tools/scripts/README b/ubi-utils/scripts/README index 01c7453..899b4a1 100644 --- a/ubi-utils/old-tools/scripts/README +++ b/ubi-utils/scripts/README @@ -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 index 0000000..f093e77 --- /dev/null +++ b/ubi-utils/scripts/TODO @@ -0,0 +1,5 @@ +TODO +==== + + * Range checking is broken, reserving 2M and offering 3M binary data + ... works!? No! diff --git a/ubi-utils/old-tools/scripts/bin2nand2bin_test.sh b/ubi-utils/scripts/bin2nand2bin_test.sh index 51f048c..a17c91b 100644 --- a/ubi-utils/old-tools/scripts/bin2nand2bin_test.sh +++ b/ubi-utils/scripts/bin2nand2bin_test.sh @@ -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. # @@ -10,45 +7,15 @@ # 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 + diff --git a/ubi-utils/old-tools/scripts/inject_biterror.pl b/ubi-utils/scripts/inject_biterror.pl index b4a862a..b4a862a 100644 --- a/ubi-utils/old-tools/scripts/inject_biterror.pl +++ b/ubi-utils/scripts/inject_biterror.pl diff --git a/ubi-utils/old-tools/scripts/jffs2_test.sh b/ubi-utils/scripts/jffs2_test.sh index 0cc9f0c..0cc9f0c 100755 --- a/ubi-utils/old-tools/scripts/jffs2_test.sh +++ b/ubi-utils/scripts/jffs2_test.sh diff --git a/ubi-utils/old-tools/scripts/mkdevs.pl b/ubi-utils/scripts/mkdevs.pl index f0fd464..f0fd464 100755 --- a/ubi-utils/old-tools/scripts/mkdevs.pl +++ b/ubi-utils/scripts/mkdevs.pl diff --git a/ubi-utils/old-tools/scripts/pdd.txt b/ubi-utils/scripts/pdd.txt index a3ad915..a3ad915 100644 --- a/ubi-utils/old-tools/scripts/pdd.txt +++ b/ubi-utils/scripts/pdd.txt diff --git a/ubi-utils/old-tools/scripts/run_all.sh b/ubi-utils/scripts/run_all.sh index 040bcbd..040bcbd 100755 --- a/ubi-utils/old-tools/scripts/run_all.sh +++ b/ubi-utils/scripts/run_all.sh diff --git a/ubi-utils/old-tools/scripts/test.cfg b/ubi-utils/scripts/test.cfg index 0b5ec48..0b5ec48 100644 --- a/ubi-utils/old-tools/scripts/test.cfg +++ b/ubi-utils/scripts/test.cfg diff --git a/ubi-utils/scripts/ubi_jffs2_test.sh b/ubi-utils/scripts/ubi_jffs2_test.sh new file mode 100755 index 0000000..883903d --- /dev/null +++ b/ubi-utils/scripts/ubi_jffs2_test.sh @@ -0,0 +1,411 @@ +#!/bin/sh +# +# UBI Volume creation/deletion/write/read and JFFS2 on top of UBI +# testcases. +# +# Written in shell language to reduce dependencies to more sophisticated +# interpreters, which may not be available on some stupid platforms. +# +# Author: Frank Haverkamp <haver@vnet.ibm.com> +# +# 1.0 Initial version +# 1.1 Added fixup for delayed device node creation by udev +# This points to a problem in the tools, mabe in the desing +# Tue Oct 31 14:14:54 CET 2006 +# + +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 -a $ALIGNMENT" +UBIRMVOL=ubirmvol +UBIUPDATEVOL=ubiupdatevol + +SIZE_512K=524288 +SIZE_1M=1310720 + +MINVOL=10 +MAXVOL=12 + +TLOG=/dev/null + +# +# To have a standardized output I define the following function to be +# used when a test was ok or when it failed. +# +failed () +{ + echo "FAILED" +} + +passed () +{ + echo "PASSED" +} + +# +# Print sucess message. Consider to exit with zero as return code. +# +exit_success () +{ + echo "SUCCESS" + exit 0 +} + +# +# Print failure message. Consider to exit with non zero return code. +# +exit_failure () +{ + echo "FAILED" + exit 1 +} + +############################################################################### +# +# START +# +############################################################################### + +fix_sysfs_issue () +{ + echo "*** Fixing the sysfs issue with the /dev nodes ... " + + minor=0 + major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` + + rm -rf /dev/ubi0 + mknod /dev/ubi0 c $major 0 + + for minor in `seq $MINVOL $MAXVOL`; do + echo " -> mknod /dev/ubi0_$minor c $major $(($minor + 1))" + rm -rf /dev/ubi0_$minor + mknod /dev/ubi0_$minor c $major $(($minor + 1)) + done + passed +} + +# +# 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 () +{ + 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 +# to delete it. +# @id: volume id +# +delete_volume () +{ + volume=$1 + + ### FIXME broken sysfs!!!! + if [ -e /sys/class/ubi/$volume -o \ + -e /sys/class/ubi/ubi0/$volume -o \ + -e /sys/class/ubi/ubi0_$volume ]; then + + echo "*** Truncate volume if it exists ... " + echo " $UBIUPDATEVOL -d0 -n$volume -t" + $UBIUPDATEVOL -d0 -n$volume -t + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + echo -n "*** Delete volume if it exists ... " + $UBIRMVOL -d0 -n$volume + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + # udev_wait + fi +} + +# writevol_test - Tests volume creation and writing data to it. +# +# @volume: Volume number +# @size: Size of random data to write +# @type: Volume type static or dynamic +# +writevol_test () +{ + volume=$1 + size=$2 + type=$3 + + echo "*** Write volume test with size $size" + +### Make sure that volume exist, delete existing volume, create new + + delete_volume $volume + + echo "*** Try to create volume" + 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 + passed + udev_wait + +### Try to create same volume again + echo -n "*** Try to create some volume again, this must fail ... " + $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size + if [ $? -eq "0" ] ; then + exit_failure + fi + passed + +### Now create test data, write it, read it, compare it + echo -n "*** Create test data ... " + dd if=/dev/urandom of=testdata.bin bs=$size count=1 + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + echo "*** Now writing data to volume ... " + echo " $UBIUPDATEVOL -d0 -n$volume testdata.bin" + ls -l testdata.bin + $UBIUPDATEVOL -d0 -n$volume testdata.bin + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + echo "*** Download data with dd bs=1 ... " + dd if=/dev/ubi0_$volume of=readdata.bin bs=$size count=1 + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + echo -n "*** Comparing data ... " + cmp readdata.bin testdata.bin + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + echo -n "*** Now truncate volume ... " + $UBIUPDATEVOL -d0 -n$volume -t + if [ $? -ne "0" ] ; then + exit_failure + fi + passed +} + +jffs2_torture () +{ + cat /dev/null > TLOG + + echo "*** Torture test ... " + + for i in `seq $iterations`; do + dd if=/dev/urandom of=test.bin bs=$i count=1 2>> $TLOG + if [ $? -ne "0" ] ; then + echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " + exit_failure + fi + #passed + + dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG + if [ $? -ne "0" ] ; then + echo "dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG" + exit_failure + fi + #passed + + #echo "Comparing files ... " + cmp test.bin new.bin + dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG + if [ $? -ne "0" ] ; then + exit_failure + fi + #passed + #echo -n "." + done + + echo -n "step0:ok " + + for i in `seq $iterations`; do + dd if=/dev/urandom of=foo bs=$i count=1 2>> $TLOG + if [ $? -ne "0" ] ; then + echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " + exit_failure + fi + #passed + done + + echo -n "step1:ok " + + for i in `seq $iterations`; do + dd if=/dev/zero of=foo bs=1 count=$i 2>> $TLOG + if [ $? -ne "0" ] ; then + echo "Testing $i byte (dd if=/dev/zero of=foo bs=1 count=$i) ... " + exit_failure + fi + #passed + done + + echo -n "step2:ok " + + for i in `seq $iterations`; do + dd if=/dev/zero of=foo bs=$i count=16 2>> $TLOG + if [ $? -ne "0" ] ; then + echo "Testing $i byte (dd if=/dev/zero of=foo bs=$i count=1024) ... " + exit_failure + fi + #passed + done + + echo -n "step3:ok " + + passed +} + +# writevol_test - Tests volume creation and writing data to it. +# +# @volume: Volume number +# @size: Size of random data to write +# @type: Volume type static or dynamic +# +jffs2_test () +{ + name=$1 + iterations=$2 + directory=`pwd` + + ### Setup + ulimit -c unlimited + + echo -n "*** Create directory /mnt/$name ... " + mkdir -p /mnt/$name + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + echo -n "*** mount -t jffs2 mtd:$name /mnt/$name ... " + mount -t jffs2 mtd:$name /mnt/$name + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + echo -n "*** change directory ... " + cd /mnt/$name + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + ls + echo "*** list directory ... " + ls -la + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + ### Torture + echo -n "*** touch I_WAS_HERE ... " + touch I_WAS_HERE + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + jffs2_torture + + echo "*** list directory ... " + ls -la + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + ### Cleanup + echo -n "*** go back ... " + cd $directory + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + ### Still mounted, ubiupdatevol must fail! + + echo -n "*** $UBIUPDATEVOL -d0 -n$volume -t must fail! ..." + $UBIUPDATEVOL -d0 -n$volume -t + if [ $? -eq "0" ] ; then + exit_failure + fi + passed + + echo -n "*** umount /mnt/$name ... " + umount /mnt/$name + if [ $? -ne "0" ] ; then + exit_failure + fi + passed + + return +} + +echo "***********************************************************************" +echo "* UBI JFFS2 Testing starts now ... *" +echo "* Good luck! *" +echo "***********************************************************************" +echo "VERSION: $VERSION" + +# Set to zero if not running on example hardware +grep ubi /proc/devices > /dev/null +if [ $? -ne "0" ]; then + echo "No UBI found in /proc/devices! I am broken!" + exit_failure +fi + +# Set to zero if not running on example hardware +grep 1142 /proc/cpuinfo > /dev/null +if [ $? -eq "0" ]; then + echo "Running on example hardware" + mount -o remount,rw / / + sleep 1 + fix_sysfs_issue +else + echo "Running on Artems hardware" +fi + +for volume in `seq $MINVOL $MAXVOL`; do + echo -n "************ VOLUME $volume NEW$volume " + echo "******************************************" + writevol_test $volume $SIZE_1M dynamic + jffs2_test NEW$volume $ITERATIONS + delete_volume $volume +done + +echo "***********************************************************************" +echo "* Congratulations, no errors found! *" +echo "* Have fun with your cool UBI system! *" +echo "***********************************************************************" + +exit_success diff --git a/ubi-utils/old-tools/scripts/ubi_test.sh b/ubi-utils/scripts/ubi_test.sh index 73e4b19..73e4b19 100755 --- a/ubi-utils/old-tools/scripts/ubi_test.sh +++ b/ubi-utils/scripts/ubi_test.sh diff --git a/ubi-utils/old-tools/scripts/ubi_tools_test.sh b/ubi-utils/scripts/ubi_tools_test.sh index 7f121f1..7f121f1 100755 --- a/ubi-utils/old-tools/scripts/ubi_tools_test.sh +++ b/ubi-utils/scripts/ubi_tools_test.sh diff --git a/ubi-utils/old-tools/scripts/unubi_test.sh b/ubi-utils/scripts/unubi_test.sh index 40dc2e2..40dc2e2 100644 --- a/ubi-utils/old-tools/scripts/unubi_test.sh +++ b/ubi-utils/scripts/unubi_test.sh diff --git a/ubi-utils/old-tools/src/bin2nand.c b/ubi-utils/src/bin2nand.c index 83f50cc..c7c7ccc 100644 --- a/ubi-utils/old-tools/src/bin2nand.c +++ b/ubi-utils/src/bin2nand.c @@ -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> @@ -47,11 +46,8 @@ #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; } diff --git a/ubi-utils/old-tools/src/bootenv.c b/ubi-utils/src/bootenv.c index a6dd4de..a6dd4de 100644 --- a/ubi-utils/old-tools/src/bootenv.c +++ b/ubi-utils/src/bootenv.c diff --git a/ubi-utils/old-tools/src/bootenv.h b/ubi-utils/src/bootenv.h index 8fecdbf..8fecdbf 100644 --- a/ubi-utils/old-tools/src/bootenv.h +++ b/ubi-utils/src/bootenv.h diff --git a/ubi-utils/old-tools/src/config.h b/ubi-utils/src/config.h index 55e60f3..55e60f3 100644 --- a/ubi-utils/old-tools/src/config.h +++ b/ubi-utils/src/config.h diff --git a/ubi-utils/src/crc32.c b/ubi-utils/src/crc32.c index 6b1e50c..666e217 100644 --- a/ubi-utils/src/crc32.c +++ b/ubi-utils/src/crc32.c @@ -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; +} diff --git a/ubi-utils/src/crc32.h b/ubi-utils/src/crc32.h index ee3145b..31362b0 100644 --- a/ubi-utils/src/crc32.h +++ b/ubi-utils/src/crc32.h @@ -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__ */ diff --git a/ubi-utils/old-tools/src/eb_chain.c b/ubi-utils/src/eb_chain.c index 4647cf4..4647cf4 100644 --- a/ubi-utils/old-tools/src/eb_chain.c +++ b/ubi-utils/src/eb_chain.c diff --git a/ubi-utils/old-tools/src/error.c b/ubi-utils/src/error.c index 4aaedad..4aaedad 100644 --- a/ubi-utils/old-tools/src/error.c +++ b/ubi-utils/src/error.c diff --git a/ubi-utils/old-tools/src/error.h b/ubi-utils/src/error.h index 05d8078..05d8078 100644 --- a/ubi-utils/old-tools/src/error.h +++ b/ubi-utils/src/error.h diff --git a/ubi-utils/old-tools/src/example_ubi.h b/ubi-utils/src/example_ubi.h index 23c7b54..23c7b54 100644 --- a/ubi-utils/old-tools/src/example_ubi.h +++ b/ubi-utils/src/example_ubi.h diff --git a/ubi-utils/old-tools/src/hashmap.c b/ubi-utils/src/hashmap.c index 3511d56..3511d56 100644 --- a/ubi-utils/old-tools/src/hashmap.c +++ b/ubi-utils/src/hashmap.c diff --git a/ubi-utils/old-tools/src/hashmap.h b/ubi-utils/src/hashmap.h index 1b13e95..1b13e95 100644 --- a/ubi-utils/old-tools/src/hashmap.h +++ b/ubi-utils/src/hashmap.h diff --git a/ubi-utils/old-tools/src/libpfiflash.c b/ubi-utils/src/libpfiflash.c index 7e3d3b3..7e3d3b3 100644 --- a/ubi-utils/old-tools/src/libpfiflash.c +++ b/ubi-utils/src/libpfiflash.c diff --git a/ubi-utils/src/libubi.c b/ubi-utils/src/libubi.c index b53f18c..a028fc6 100644 --- a/ubi-utils/src/libubi.c +++ b/ubi-utils/src/libubi.c @@ -27,480 +27,13 @@ #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,141 +200,10 @@ 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 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); - close(fd); - if (ret == -1) - return -1; - - req->dev_num = r.ubi_num; - -#ifdef UDEV_SETTLE_HACK - if (system("udevsettle") == -1) - return -1; - if (system("udevsettle") == -1) - return -1; -#endif - - return ret; -} - -int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num) -{ - int ret, ubi_dev; - - ret = mtd_num2ubi_dev(desc, mtd_num, &ubi_dev); - if (ret == -1) - return ret; - - return ubi_remove_dev(desc, node, ubi_dev); -} - -int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev) -{ - int fd, ret; - - desc = desc; - - fd = open(node, O_RDONLY); - if (fd == -1) - return -1; - ret = ioctl(fd, UBI_IOCDET, &ubi_dev); - if (ret == -1) - goto out_close; - -#ifdef UDEV_SETTLE_HACK - if (system("udevsettle") == -1) - return -1; -#endif - -out_close: - close(fd); - return ret; -} - -int ubi_node_type(libubi_t desc, const char *node) -{ - struct stat st; - struct ubi_info info; - int i, fd, major, minor; - struct libubi *lib = (struct libubi *)desc; - char file[strlen(lib->ubi_vol) + 100]; - - if (lstat(node, &st)) - return -1; - - if (!S_ISCHR(st.st_mode)) { - errno = EINVAL; - return -1; - } - - major = major(st.st_rdev); - minor = minor(st.st_rdev); - - 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) { - /* - * 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; - return -1; - } - - if (minor == 0) - return 1; - - /* 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; - return -1; - } - - return 2; -} - int ubi_get_info(libubi_t desc, struct ubi_info *info) { DIR *sysfs_ubi; @@ -809,42 +212,20 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info) memset(info, '\0', sizeof(struct ubi_info)); - 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; - } - /* * 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); + return -1; info->lowest_dev_num = INT_MAX; - while (1) { + while ((dirent = readdir(sysfs_ubi))) { + char *name = &dirent->d_name[0]; int dev_num, ret; - char tmp_buf[256]; - - errno = 0; - dirent = readdir(sysfs_ubi); - if (!dirent) - break; - - 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); + ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num); if (ret == 1) { info->dev_count += 1; if (dev_num > info->highest_dev_num) @@ -854,23 +235,15 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info) } } - if (!dirent && errno) { - sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi); - goto out_close; - } - - 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; - if (read_positive_int(lib->ubi_version, &info->version)) - return -1; + if (read_int(lib->ubi_version, &info->version)) + goto close; - return 0; + return closedir(sysfs_ubi); -out_close: +close: closedir(sysfs_ubi); return -1; } @@ -881,8 +254,6 @@ int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req) struct ubi_mkvol_req r; size_t n; - memset(&r, sizeof(struct ubi_mkvol_req), '\0'); - desc = desc; r.vol_id = req->vol_id; r.alignment = req->alignment; @@ -901,17 +272,9 @@ int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req) return -1; ret = ioctl(fd, UBI_IOCMKVOL, &r); - if (ret == -1) - goto out_close; - - req->vol_id = r.vol_id; - -#ifdef UDEV_SETTLE_HACK - if (system("udevsettle") == -1) - return -1; -#endif + if (!ret) + req->vol_id = r.vol_id; -out_close: close(fd); return ret; } @@ -926,15 +289,6 @@ int ubi_rmvol(libubi_t desc, const char *node, int vol_id) return -1; ret = ioctl(fd, UBI_IOCRMVOL, &vol_id); - if (ret == -1) - goto out_close; - -#ifdef UDEV_SETTLE_HACK - if (system("udevsettle") == -1) - return -1; -#endif - -out_close: close(fd); return ret; } @@ -965,19 +319,16 @@ 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) +int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info) { - 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; + int dev_num; + struct libubi *lib = (struct libubi *)desc; - if (ioctl(fd, UBI_IOCEBCH, &req)) + dev_num = find_dev_num(lib, node); + if (dev_num == -1) return -1; - return 0; + + return ubi_get_dev_info1(desc, dev_num, info); } int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) @@ -994,23 +345,11 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) return -1; info->lowest_vol_num = INT_MAX; - - while (1) { + while ((dirent = readdir(sysfs_ubi))) { + char *name = &dirent->d_name[0]; int vol_id, ret, devno; - char tmp_buf[256]; - - errno = 0; - dirent = readdir(sysfs_ubi); - if (!dirent) - break; - 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); + 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) @@ -1020,27 +359,18 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) } } - if (!dirent && errno) { - sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi); - goto out_close; - } - - if (closedir(sysfs_ubi)) - return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi); + closedir(sysfs_ubi); if (info->lowest_vol_num == INT_MAX) info->lowest_vol_num = 0; - if (dev_get_major(lib, dev_num, &info->major, &info->minor)) - return -1; - - if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_lebs)) + 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_lebs)) + 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->leb_size)) + 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; @@ -1051,25 +381,26 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size)) return -1; - info->avail_bytes = info->avail_lebs * info->leb_size; - info->total_bytes = info->total_lebs * info->leb_size; + info->avail_bytes = info->avail_ebs * info->eb_size; + info->total_bytes = info->total_ebs * info->eb_size; return 0; - -out_close: - closedir(sysfs_ubi); - return -1; } -int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info) +int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info) { - int dev_num; + int vol_id, dev_num; struct libubi *lib = (struct libubi *)desc; - if (dev_node2num(lib, node, &dev_num)) + dev_num = find_dev_num_vol(lib, node); + if (dev_num == -1) return -1; - return ubi_get_dev_info1(desc, dev_num, info); + vol_id = find_vol_num(lib, dev_num, node); + if (vol_id == -1) + return -1; + + return ubi_get_vol_info1(desc, dev_num, vol_id, info); } int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, @@ -1083,21 +414,16 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, 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; - - ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50); + ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50); if (ret < 0) return -1; - if (strncmp(buf, "static\n", ret) == 0) + if (strncmp(&buf[0], "static\n", ret) == 0) info->type = UBI_STATIC_VOLUME; - else if (strncmp(buf, "dynamic\n", ret) == 0) + else if (strncmp(&buf[0], "dynamic\n", ret) == 0) info->type = UBI_DYNAMIC_VOLUME; else { - errmsg("bad value at \"%s\"", buf); + fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); errno = EINVAL; return -1; } @@ -1110,17 +436,17 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, &info->data_bytes); if (ret) return -1; - ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_lebs); + 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->leb_size); + 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->leb_size * info->rsvd_lebs; + info->rsvd_bytes = info->eb_size * info->rsvd_ebs; ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name, UBI_VOL_NAME_MAX + 2); @@ -1131,13 +457,459 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, return 0; } -int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_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) { - int vol_id, dev_num; - struct libubi *lib = (struct libubi *)desc; + int fd, rd; + char buf[50]; - if (vol_node2nums(lib, node, &dev_num, &vol_id)) + fd = open(file, O_RDONLY); + if (fd == -1) return -1; - return ubi_get_vol_info1(desc, dev_num, vol_id, info); + rd = read(fd, &buf[0], 50); + if (rd == -1) + goto error; + + 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; + } + + close(fd); + return 0; + +error: + close(fd); + return -1; +} + +/** + * 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]; + + 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], "%d\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; + +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]; + + 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; + +error: + close(fd); + return -1; +} + +/** + * 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, rd; + char file[strlen(patt) + 50]; + + sprintf(&file[0], patt, dev_num); + fd = open(&file[0], O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, buf, buf_len); + if (rd == -1) { + close(fd); + return -1; + } + + 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]; + + sprintf(&file[0], patt, dev_num, vol_id); + 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], "%d\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; + +error: + close(fd); + return -1; +} + +/** + * 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, rd; + char buf[50]; + char file[strlen(patt) + 100]; + + sprintf(&file[0], patt, dev_num, vol_id); + 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; + +error: + close(fd); + return -1; +} + +/** + * 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, rd; + char file[strlen(patt) + 100]; + + sprintf(&file[0], patt, dev_num, vol_id); + fd = open(&file[0], O_RDONLY); + if (fd == -1) + return -1; + + rd = read(fd, buf, buf_len); + if (rd == -1) { + close(fd); + return -1; + } + + close(fd); + return rd; +} + +/** + * 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) +{ + char *n; + int len1 = strlen(path); + int len2 = strlen(name); + + n = malloc(len1 + len2 + 2); + if (!n) + return NULL; + + memcpy(n, path, len1); + if (n[len1 - 1] != '/') + n[len1++] = '/'; + + memcpy(n + len1, name, len2 + 1); + return n; +} + +/** + * 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) +{ + 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 -1; + } + + major = major(stat.st_rdev); + minor = minor(stat.st_rdev); + + if (minor != 0) { + errno = -EINVAL; + return -1; + } + + 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; + char buf[50]; + + 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 (minor1 == minor && major1 == major) + return i; + } + + errno = ENOENT; + return -1; +} + +/** + * 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 (lstat(node, &stat)) + return -1; + + if (!S_ISCHR(stat.st_mode)) { + errno = EINVAL; + return -1; + } + + major = major(stat.st_rdev); + + if (minor(stat.st_rdev) == 0) { + errno = -EINVAL; + return -1; + } + + 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; + char buf[50]; + + 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 (major1 == major) + return i; + } + + errno = ENOENT; + return -1; +} + +/** + * 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) +{ + struct stat stat; + struct ubi_dev_info info; + int i, major, minor; + + if (lstat(node, &stat)) + return -1; + + if (!S_ISCHR(stat.st_mode)) { + errno = EINVAL; + return -1; + } + + major = major(stat.st_rdev); + minor = minor(stat.st_rdev); + + if (minor == 0) { + errno = -EINVAL; + return -1; + } + + if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info)) + return -1; + + for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) { + int major1, minor1, ret; + char buf[50]; + + ret = vol_read_data(lib->vol_dev, dev_num, 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 (minor1 == minor && major1 == major) + return i; + } + + errno = ENOENT; + return -1; } diff --git a/ubi-utils/src/libubi_int.h b/ubi-utils/src/libubi_int.h index dab3e62..e68b791 100644 --- a/ubi-utils/src/libubi_int.h +++ b/ubi-utils/src/libubi_int.h @@ -23,45 +23,20 @@ #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 diff --git a/ubi-utils/src/libubigen.c b/ubi-utils/src/libubigen.c index 8d71fde..1fce3f9 100644 --- a/ubi-utils/src/libubigen.c +++ b/ubi-utils/src/libubigen.c @@ -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 @@ -15,307 +14,474 @@ * 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; } diff --git a/ubi-utils/old-tools/src/libubimirror.c b/ubi-utils/src/libubimirror.c index d06770e..d06770e 100644 --- a/ubi-utils/old-tools/src/libubimirror.c +++ b/ubi-utils/src/libubimirror.c diff --git a/ubi-utils/old-tools/src/list.c b/ubi-utils/src/list.c index 6eb716b..6eb716b 100644 --- a/ubi-utils/old-tools/src/list.c +++ b/ubi-utils/src/list.c diff --git a/ubi-utils/old-tools/src/list.h b/ubi-utils/src/list.h index e8452a2..e8452a2 100644 --- a/ubi-utils/old-tools/src/list.h +++ b/ubi-utils/src/list.h diff --git a/ubi-utils/old-tools/src/mkbootenv.c b/ubi-utils/src/mkbootenv.c index 952f651..952f651 100644 --- a/ubi-utils/old-tools/src/mkbootenv.c +++ b/ubi-utils/src/mkbootenv.c diff --git a/ubi-utils/old-tools/src/nand2bin.c b/ubi-utils/src/nand2bin.c index 8c95b27..be62e30 100644 --- a/ubi-utils/old-tools/src/nand2bin.c +++ b/ubi-utils/src/nand2bin.c @@ -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> @@ -46,11 +43,9 @@ #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 */ diff --git a/ubi-utils/old-tools/src/nandcorr.c b/ubi-utils/src/nandcorr.c index caa07e2..caa07e2 100644 --- a/ubi-utils/old-tools/src/nandcorr.c +++ b/ubi-utils/src/nandcorr.c diff --git a/ubi-utils/old-tools/src/nandecc.c b/ubi-utils/src/nandecc.c index 71660ef..71660ef 100644 --- a/ubi-utils/old-tools/src/nandecc.c +++ b/ubi-utils/src/nandecc.c diff --git a/ubi-utils/old-tools/src/nandecc.h b/ubi-utils/src/nandecc.h index bcf1982..bcf1982 100644 --- a/ubi-utils/old-tools/src/nandecc.h +++ b/ubi-utils/src/nandecc.h diff --git a/ubi-utils/old-tools/src/pddcustomize.c b/ubi-utils/src/pddcustomize.c index 515efd6..515efd6 100644 --- a/ubi-utils/old-tools/src/pddcustomize.c +++ b/ubi-utils/src/pddcustomize.c diff --git a/ubi-utils/old-tools/src/peb.c b/ubi-utils/src/peb.c index 160a463..08b770f 100644 --- a/ubi-utils/old-tools/src/peb.c +++ b/ubi-utils/src/peb.c @@ -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; diff --git a/ubi-utils/old-tools/src/peb.h b/ubi-utils/src/peb.h index 246bce8..246bce8 100644 --- a/ubi-utils/old-tools/src/peb.h +++ b/ubi-utils/src/peb.h diff --git a/ubi-utils/old-tools/src/pfi.c b/ubi-utils/src/pfi.c index fa835e2..fa835e2 100644 --- a/ubi-utils/old-tools/src/pfi.c +++ b/ubi-utils/src/pfi.c diff --git a/ubi-utils/old-tools/src/pfi.h b/ubi-utils/src/pfi.h index 8c5cc07..8c5cc07 100644 --- a/ubi-utils/old-tools/src/pfi.h +++ b/ubi-utils/src/pfi.h diff --git a/ubi-utils/old-tools/src/pfi2bin.c b/ubi-utils/src/pfi2bin.c index 3300df2..a8c76a3 100644 --- a/ubi-utils/old-tools/src/pfi2bin.c +++ b/ubi-utils/src/pfi2bin.c @@ -37,6 +37,7 @@ #include <ubigen.h> #include <mtd/ubi-header.h> +#include <mtd_swab.h> #include "config.h" #include "list.h" diff --git a/ubi-utils/old-tools/src/pfiflash.c b/ubi-utils/src/pfiflash.c index 754fe33..754fe33 100644 --- a/ubi-utils/old-tools/src/pfiflash.c +++ b/ubi-utils/src/pfiflash.c diff --git a/ubi-utils/old-tools/src/pfiflash.h b/ubi-utils/src/pfiflash.h index 039705d..039705d 100644 --- a/ubi-utils/old-tools/src/pfiflash.h +++ b/ubi-utils/src/pfiflash.h diff --git a/ubi-utils/old-tools/src/pfiflash_error.h b/ubi-utils/src/pfiflash_error.h index 0f27f4a..0f27f4a 100644 --- a/ubi-utils/old-tools/src/pfiflash_error.h +++ b/ubi-utils/src/pfiflash_error.h diff --git a/ubi-utils/old-tools/src/reader.c b/ubi-utils/src/reader.c index 0ea8c6d..0ea8c6d 100644 --- a/ubi-utils/old-tools/src/reader.c +++ b/ubi-utils/src/reader.c diff --git a/ubi-utils/old-tools/src/reader.h b/ubi-utils/src/reader.h index 715e464..715e464 100644 --- a/ubi-utils/old-tools/src/reader.h +++ b/ubi-utils/src/reader.h diff --git a/ubi-utils/src/ubicrc32.c b/ubi-utils/src/ubicrc32.c index 5c7a8ba..7e3f045 100644 --- a/ubi-utils/src/ubicrc32.c +++ b/ubi-utils/src/ubicrc32.c @@ -14,12 +14,10 @@ * 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> @@ -28,98 +26,116 @@ #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; } diff --git a/ubi-utils/old-tools/src/ubigen.c b/ubi-utils/src/ubigen.c index 9fcafab..9fcafab 100644 --- a/ubi-utils/old-tools/src/ubigen.c +++ b/ubi-utils/src/ubigen.c diff --git a/ubi-utils/old-tools/src/ubigen.h b/ubi-utils/src/ubigen.h index 07f845f..0f43a46 100644 --- a/ubi-utils/old-tools/src/ubigen.h +++ b/ubi-utils/src/ubigen.h @@ -25,7 +25,6 @@ #include <stdio.h> /* FILE */ #include <stdint.h> #include <mtd/ubi-header.h> -#include <mtd_swab.h> #ifdef __cplusplus extern "C" { diff --git a/ubi-utils/old-tools/src/ubimirror.c b/ubi-utils/src/ubimirror.c index 2cc4596..2cc4596 100644 --- a/ubi-utils/old-tools/src/ubimirror.c +++ b/ubi-utils/src/ubimirror.c diff --git a/ubi-utils/old-tools/src/ubimirror.h b/ubi-utils/src/ubimirror.h index d7ae2ad..d7ae2ad 100644 --- a/ubi-utils/old-tools/src/ubimirror.h +++ b/ubi-utils/src/ubimirror.h diff --git a/ubi-utils/src/ubimkvol.c b/ubi-utils/src/ubimkvol.c index 75c180d..bff6068 100644 --- a/ubi-utils/src/ubimkvol.c +++ b/ubi-utils/src/ubimkvol.c @@ -19,8 +19,16 @@ /* * 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> @@ -28,257 +36,315 @@ #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; diff --git a/ubi-utils/src/ubirmvol.c b/ubi-utils/src/ubirmvol.c index c30446a..6dd16ba 100644 --- a/ubi-utils/src/ubirmvol.c +++ b/ubi-utils/src/ubirmvol.c @@ -19,8 +19,13 @@ /* * 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> @@ -28,136 +33,190 @@ #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; } diff --git a/ubi-utils/src/ubiupdatevol.c b/ubi-utils/src/ubiupdatevol.c new file mode 100644 index 0000000..807b961 --- /dev/null +++ b/ubi-utils/src/ubiupdatevol.c @@ -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. + */ + +/* + * An utility to update UBI volumes. + * + * Author: Frank Haverkamp + * Joshua W. Boyer + * + * 1.0 Reworked the userinterface to use argp. + * 1.1 Removed argp parsing because we want to use uClib. + * 1.2 Minor cleanups + * 1.3 Use a different libubi + */ + +#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 <config.h> +#include <libubi.h> + +#define PROGRAM_VERSION "1.3" + +#define MAXPATH 1024 +#define BUFSIZE 128 * 1024 +#define MIN(x,y) ((x)<(y)?(x):(y)) + +struct args { + int devn; + int vol_id; + int truncate; + int broken_update; + int bufsize; + + /* special stuff needed to get additional arguments */ + char *arg1; + char **options; /* [STRING...] */ +}; + +static struct args myargs = { + .devn = -1, + .vol_id = -1, + .truncate = 0, + .broken_update = 0, + .bufsize = BUFSIZE, + .arg1 = NULL, + .options = NULL, +}; + +static int verbose = 0; + +static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" + "ubiupdatevol - write to UBI Volume.\n"; + +static const char *optionsstr = +" -B, --broken-update broken update, this is for testing\n" +" -d, --devn=<devn> UBI device\n" +" -n, --vol_id=<volume id> UBI volume id\n" +" -t, --truncate truncate volume\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: ubiupdatevol [-Bt?V] [-d <devn>] [-n <volume id>] [--broken-update]\n" +" [--devn=<devn>] [--vol_id=<volume id>] [--truncate] [--help]\n" +" [--usage] [--version] <image file>\n"; + +struct option long_options[] = { + { .name = "broken-update", .has_arg = 0, .flag = NULL, .val = 'B' }, + { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, + { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' }, + { .name = "truncate", .has_arg = 0, .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' }, + { NULL, 0, NULL, 0} +}; + +/* + * @brief Parse the arguments passed into the test case. + */ +static int +parse_opt(int argc, char **argv, struct args *args) +{ + while (1) { + int key; + + key = getopt_long(argc, argv, "Bd:n:t?V", long_options, NULL); + if (key == -1) + break; + + switch (key) { + case 'v': /* --verbose=<level> */ + verbose = strtoul(optarg, (char **)NULL, 0); + break; + + case 'n': /* --vol_id=<volume id> */ + args->vol_id = strtol(optarg, (char **)NULL, 0); + break; + + case 'd': /* --devn=<device number> */ + args->devn = strtol(optarg, (char **)NULL, 0); + break; + + case 'b': /* --bufsize=<bufsize> */ + args->bufsize = strtol(optarg, (char **)NULL, 0); + if (args->bufsize <= 0) + args->bufsize = BUFSIZE; + break; + + case 't': /* --truncate */ + args->truncate = 1; + break; + + case 'B': /* --broken-update */ + args->broken_update = 1; + break; + + case '?': /* help */ + fprintf(stderr, "Usage: " + "ubiupdatevol [OPTION...] <image file>\n%s%s" + "\nReport bugs to %s\n", + doc, optionsstr, PACKAGE_BUGREPORT); + exit(EXIT_SUCCESS); + break; + + case 'V': + fprintf(stderr, "%s\n", PROGRAM_VERSION); + exit(0); + break; + + default: + fprintf(stderr, "%s", usage); + exit(EXIT_FAILURE); + } + } + + if (optind < argc) { + /* only one additional argument required */ + args->arg1 = argv[optind++]; + } + return 0; +} + +/** + * @bytes bytes must be always 0, if not 0 this is a testcase for a + * broken volume update where data is promissed to be written, but for + * some reason nothing is written. The volume is unusable after this. + */ +static int +ubi_truncate_volume(struct args *args, int64_t bytes,libubi_t libubi) +{ + int rc, ofd; + char path[MAXPATH]; + int old_errno; + + snprintf(path, MAXPATH-1, "/dev/ubi%d_%d", args->devn, args->vol_id); + path[MAXPATH-1] = '\0'; + + ofd = open(path, O_RDWR); + if (ofd < 0) { + fprintf(stderr, "Cannot open volume %s\n", path); + exit(EXIT_FAILURE); + } + rc = ubi_update_start(libubi, ofd, bytes); + old_errno = errno; + if (rc < 0) { + perror("UBI volume update ioctl"); + fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); + exit(EXIT_FAILURE); + } + close(ofd); + return 0; +} + +static ssize_t ubi_write(int fd, const void *buf, size_t count) +{ + int rc; + int len = count; + + while (len) { + rc = write(fd, buf, len); + if (rc == -1) { + if (errno == EINTR) + continue; /* try again */ + perror("write error"); + return rc; + } + + len -= rc; + buf += rc; + } + return count; +} + +static int +ubi_update_volume(struct args *args, libubi_t libubi) +{ + int rc, ofd; + FILE *ifp = NULL; + struct stat st; + int size = 0; + char *fname = args->arg1; + char path[MAXPATH]; + char *buf; + int64_t bytes = 0; + int old_errno; + + buf = malloc(args->bufsize); + if (!buf) { + perror("Out of memory"); + exit(EXIT_FAILURE); + } + + if (fname == NULL) { + fprintf(stderr, "Please specify an existing image file.\n"); + exit(EXIT_FAILURE); + } + + rc = stat(fname, &st); + if (rc < 0) { + fprintf(stderr, "Cannot stat input file %s\n", fname); + exit(EXIT_FAILURE); + } + bytes = size = st.st_size; + + ifp = fopen(fname, "r"); + if (!ifp) + exit(EXIT_FAILURE); + + snprintf(path, MAXPATH-1, "/dev/ubi%d_%d", args->devn, args->vol_id); + path[MAXPATH-1] = '\0'; + + ofd = open(path, O_RDWR); + if (ofd < 0) { + fprintf(stderr, "Cannot open UBI volume %s\n", path); + exit(EXIT_FAILURE); + } + + rc = ubi_update_start(libubi, ofd, bytes); + old_errno = errno; + if (rc < 0) { + perror("UBI volume update ioctl"); + fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); + exit(EXIT_FAILURE); + } + + while (size > 0) { + ssize_t tocopy = MIN(args->bufsize, size); + + rc = fread(buf, tocopy, 1, ifp); + if (rc != 1) { + perror("Could not read everything."); + exit(EXIT_FAILURE); + } + + rc = ubi_write(ofd, buf, tocopy); + old_errno = errno; + if (rc != tocopy) { + perror("Could not write to device"); + fprintf(stderr, " rc=%d errno=%d\n", rc, old_errno); + exit(EXIT_FAILURE); + } + size -= tocopy; + } + + free(buf); + fclose(ifp); + rc = close(ofd); + if (rc != 0) { + perror("UBI volume close failed"); + exit(EXIT_FAILURE); + } + return 0; +} + +int +main(int argc, char *argv[]) +{ + int rc; + libubi_t libubi; + + parse_opt(argc, argv, &myargs); + + libubi = libubi_open(); + if (libubi == NULL) { + perror("Cannot open libubi"); + return -1; + } + + if (myargs.truncate) { + rc = ubi_truncate_volume(&myargs, 0LL, libubi); + if (rc < 0) + goto out_libubi; + } + else if (myargs.broken_update) { + rc = ubi_truncate_volume(&myargs, 1LL, libubi); + if (rc < 0) + goto out_libubi; + } else { + rc = ubi_update_volume(&myargs, libubi); + if (rc < 0) + goto out_libubi; + } + + libubi_close(libubi); + return 0; + +out_libubi: + libubi_close(libubi); + return -1; +} diff --git a/ubi-utils/old-tools/src/unubi.c b/ubi-utils/src/unubi.c index 8a022a3..8a022a3 100644 --- a/ubi-utils/old-tools/src/unubi.c +++ b/ubi-utils/src/unubi.c diff --git a/ubi-utils/old-tools/src/unubi_analyze.c b/ubi-utils/src/unubi_analyze.c index 182100e..182100e 100644 --- a/ubi-utils/old-tools/src/unubi_analyze.c +++ b/ubi-utils/src/unubi_analyze.c diff --git a/ubi-utils/old-tools/src/unubi_analyze.h b/ubi-utils/src/unubi_analyze.h index 8588219..8588219 100644 --- a/ubi-utils/old-tools/src/unubi_analyze.h +++ b/ubi-utils/src/unubi_analyze.h diff --git a/ubi-utils/testcases.txt b/ubi-utils/testcases.txt new file mode 100644 index 0000000..dcc1c35 --- /dev/null +++ b/ubi-utils/testcases.txt @@ -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 index 0000000..1b17f81 --- /dev/null +++ b/ubi-utils/tests/Makefile @@ -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 index 0000000..a4ff9c5 --- /dev/null +++ b/ubi-utils/tests/README.udev @@ -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 index 0000000..cb63e77 --- /dev/null +++ b/ubi-utils/tests/common.c @@ -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 index 0000000..3e8ada8 --- /dev/null +++ b/ubi-utils/tests/common.h @@ -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 index 0000000..4da7121 --- /dev/null +++ b/ubi-utils/tests/integ.c @@ -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 index 0000000..2e8809a --- /dev/null +++ b/ubi-utils/tests/io_basic.c @@ -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 index 0000000..4857bf8 --- /dev/null +++ b/ubi-utils/tests/io_paral.c @@ -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 index 0000000..c5d1da7 --- /dev/null +++ b/ubi-utils/tests/io_read.c @@ -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 index 0000000..2e3422a --- /dev/null +++ b/ubi-utils/tests/io_update.c @@ -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 index 0000000..023b06b --- /dev/null +++ b/ubi-utils/tests/mkvol_bad.c @@ -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 index 0000000..e2120e9 --- /dev/null +++ b/ubi-utils/tests/mkvol_basic.c @@ -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 index 0000000..faf085c --- /dev/null +++ b/ubi-utils/tests/mkvol_paral.c @@ -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 index 0000000..7a9e5ea --- /dev/null +++ b/ubi-utils/tests/rsvol.c @@ -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 index 0000000..8005716 --- /dev/null +++ b/ubi-utils/tests/runtests.pl @@ -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 index 0000000..f993bc0 --- /dev/null +++ b/ubi-utils/tests/runtests.sh @@ -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 |