aboutsummaryrefslogtreecommitdiff
path: root/ubi-utils/new-utils
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-02-19 14:54:17 +0200
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-02-19 16:41:16 +0200
commit86dd9696d3a1acb036d65909d93d73455b8aed3a (patch)
tree9e8bb6797b3bebd0bf83ae1fab2151a6dfeafe6a /ubi-utils/new-utils
parentef644090223e5983ca2492850354c1390e3368d1 (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/new-utils')
-rw-r--r--ubi-utils/new-utils/LICENSE.libiniparser21
-rw-r--r--ubi-utils/new-utils/Makefile63
-rw-r--r--ubi-utils/new-utils/README56
-rw-r--r--ubi-utils/new-utils/include/libiniparser.h280
-rw-r--r--ubi-utils/new-utils/include/libubi.h355
-rw-r--r--ubi-utils/new-utils/include/libubigen.h112
-rw-r--r--ubi-utils/new-utils/src/common.c176
-rw-r--r--ubi-utils/new-utils/src/common.h71
-rw-r--r--ubi-utils/new-utils/src/crc32.c95
-rw-r--r--ubi-utils/new-utils/src/crc32.h19
-rw-r--r--ubi-utils/new-utils/src/dictionary.c405
-rw-r--r--ubi-utils/new-utils/src/dictionary.h174
-rw-r--r--ubi-utils/new-utils/src/libiniparser.c646
-rw-r--r--ubi-utils/new-utils/src/libubi.c1143
-rw-r--r--ubi-utils/new-utils/src/libubi_int.h147
-rw-r--r--ubi-utils/new-utils/src/libubigen.c321
-rw-r--r--ubi-utils/new-utils/src/ubi-attach.c205
-rw-r--r--ubi-utils/new-utils/src/ubi-crc32.c125
-rw-r--r--ubi-utils/new-utils/src/ubi-detach.c181
-rw-r--r--ubi-utils/new-utils/src/ubi-info.c409
-rw-r--r--ubi-utils/new-utils/src/ubi-mkvol.c288
-rw-r--r--ubi-utils/new-utils/src/ubi-nize.c549
-rw-r--r--ubi-utils/new-utils/src/ubi-rmvol.c170
-rw-r--r--ubi-utils/new-utils/src/ubi-update.c295
24 files changed, 6306 insertions, 0 deletions
diff --git a/ubi-utils/new-utils/LICENSE.libiniparser b/ubi-utils/new-utils/LICENSE.libiniparser
new file mode 100644
index 0000000..dbfa45d
--- /dev/null
+++ b/ubi-utils/new-utils/LICENSE.libiniparser
@@ -0,0 +1,21 @@
+Copyright (c) 2000-2007 by Nicolas Devillard.
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
diff --git a/ubi-utils/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/new-utils/include/libiniparser.h b/ubi-utils/new-utils/include/libiniparser.h
new file mode 100644
index 0000000..be3c667
--- /dev/null
+++ b/ubi-utils/new-utils/include/libiniparser.h
@@ -0,0 +1,280 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.h
+ @author N. Devillard
+ @date Sep 2007
+ @version 3.0
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: iniparser.h,v 1.24 2007-11-23 21:38:19 ndevilla Exp $
+ $Revision: 1.24 $
+*/
+
+#ifndef _INIPARSER_H_
+#define _INIPARSER_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The following #include is necessary on many Unixes but not Linux.
+ * It is not needed for Windows platforms.
+ * Uncomment it if needed.
+ */
+/* #include <unistd.h> */
+
+#include "dictionary.h"
+
+/*---------------------------------------------------------------------------
+ Macros
+ ---------------------------------------------------------------------------*/
+/** For backwards compatibility only */
+#define iniparser_getstr(d, k) iniparser_getstring(d, k, NULL)
+#define iniparser_setstr iniparser_setstring
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_getnsec(dictionary * d);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+char * iniparser_getsecname(dictionary * d, int n);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dump_ini(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to an int
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ Supported values for integers include the usual C notation
+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+ are supported. Examples:
+
+ - "42" -> 42
+ - "042" -> 34 (octal -> decimal)
+ - "0x42" -> 66 (hexa -> decimal)
+
+ Warning: the conversion may overflow in various ways. Conversion is
+ totally outsourced to strtol(), see the associated man page for overflow
+ handling.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, char * key, double notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ contain the provided value. If it cannot be found, -1 is returned.
+ It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_setstring(dictionary * ini, char * entry, char * val);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(dictionary * ini, char * entry) ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d);
+
+#endif
diff --git a/ubi-utils/new-utils/include/libubi.h b/ubi-utils/new-utils/include/libubi.h
new file mode 100644
index 0000000..7e0bfcd
--- /dev/null
+++ b/ubi-utils/new-utils/include/libubi.h
@@ -0,0 +1,355 @@
+/*
+ * 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 <ctype.h>
+#include <stdint.h>
+#include <mtd/ubi-user.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. The caller is assumed to write @bytes data to the
+ * volume @fd afterwards.
+ */
+int ubi_update_start(libubi_t desc, int fd, long long bytes);
+
+/**
+ * ubi_leb_change_start - start atomic LEB change.
+ * @desc: UBI library descriptor
+ * @fd: volume character devie file descriptor
+ * @lnum: LEB number to change
+ * @bytes: how many bytes of new data will be written to the LEB
+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ *
+ * This function initiates atomic LEB change operation and returns %0 in case
+ * of success and %-1 in case of error. he caller is assumed to write @bytes
+ * data to the volume @fd afterwards.
+ */
+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_H__ */
diff --git a/ubi-utils/new-utils/include/libubigen.h b/ubi-utils/new-utils/include/libubigen.h
new file mode 100644
index 0000000..058cf8a
--- /dev/null
+++ b/ubi-utils/new-utils/include/libubigen.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/*
+ * Authors: Frank Haverkamp
+ * Artem Bityutskiy
+ */
+
+#ifndef __LIBUBIGEN_H__
+#define __LIBUBIGEN_H__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <mtd_swab.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * struct ubigen_info - libubigen information.
+ * @leb_size: logical eraseblock size
+ * @peb_size: size of the physical eraseblock
+ * @min_io_size: minimum input/output unit size
+ * @vid_hdr_offs: offset of the VID header
+ * @data_offs: data offset
+ * @ubi_ver: UBI version
+ * @ec: initial erase counter
+ * @vtbl_size: volume table size
+ * @max_volumes: maximum amount of volumes
+ */
+struct ubigen_info
+{
+ int leb_size;
+ int peb_size;
+ int min_io_size;
+ int vid_hdr_offs;
+ int data_offs;
+ int ubi_ver;
+ long long ec;
+ int vtbl_size;
+ int max_volumes;
+};
+
+/**
+ * struct ubigen_vol_info - information about a volume.
+ * @id: volume id
+ * @type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ * eraseblock to satisfy the requested alignment
+ * @usable_leb_size: LEB size accessible for volume users
+ * @name: volume name
+ * @name_len: volume name length
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @used_ebs: total number of used logical eraseblocks in this volume (relevant
+ * for static volumes only)
+ * @bytes: size of the volume contents in bytes (relevant for static volumes
+ * only)
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ */
+struct ubigen_vol_info
+{
+ int id;
+ int type;
+ int alignment;
+ int data_pad;
+ int usable_leb_size;
+ const char *name;
+ int name_len;
+ int compat;
+ int used_ebs;
+ long long bytes;
+ uint8_t flags;
+};
+
+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
+ int subpage_size, int vid_hdr_offs, int ubi_ver,
+ long long ec);
+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui);
+int ubigen_get_vtbl_size(const struct ubigen_info *ui);
+int ubigen_add_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vtbl_record *vtbl);
+int ubigen_write_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ long long bytes, FILE *in, FILE *out);
+int ubigen_write_layout_vol(const struct ubigen_info *ui,
+ struct ubi_vtbl_record *vtbl, FILE *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBIGEN_H__ */
diff --git a/ubi-utils/new-utils/src/common.c b/ubi-utils/new-utils/src/common.c
new file mode 100644
index 0000000..fec640d
--- /dev/null
+++ b/ubi-utils/new-utils/src/common.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2007, 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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.
+ *
+ * Authors: Artem Bityutskiy
+ * Adrian Hunter
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/**
+ * get_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.
+ */
+static int 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_get_bytes - convert a string containing amount of bytes into an
+ * integer
+ * @str: string to convert
+ *
+ * This function parses @str which may have an onee of 'KiB', 'MiB', or 'GiB'
+ * size specifiers. Returns positive amount of bytes in case of success and %-1
+ * in case of failure.
+ */
+long long ubiutils_get_bytes(const char *str)
+{
+ char *endp;
+ long long bytes = strtoull(str, &endp, 0);
+
+ if (endp == str || bytes < 0) {
+ fprintf(stderr, "incorrect amount of bytes: \"%s\"", str);
+ return -1;
+ }
+
+ if (*endp != '\0') {
+ int mult = get_multiplier(endp);
+
+ if (mult == -1) {
+ fprintf(stderr, "bad size specifier: \"%s\" - "
+ "should be 'KiB', 'MiB' or 'GiB'", endp);
+ return -1;
+ }
+ bytes *= mult;
+ }
+
+ return bytes;
+}
+
+/**
+ * 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 && bytes != 0)
+ printf("%s%.1f KiB", p, (double)bytes / 1024);
+ else
+ return;
+
+ if (bracket)
+ printf(")");
+}
+
+/**
+ * ubiutils_print_text - print text and fold it.
+ * @stream: file stream to print to
+ * @text: text to print
+ * @width: maximum allowed text width
+ *
+ * Print text and fold it so that each line would not have more then @width
+ * characters.
+ */
+void ubiutils_print_text(FILE *stream, const char *text, int width)
+{
+ int pos, bpos = 0;
+ const char *p;
+ char line[1024];
+
+ if (width > 1023) {
+ fprintf(stream, "%s\n", text);
+ return;
+ }
+ p = text;
+ pos = 0;
+ while (p[pos]) {
+ while (!isspace(p[pos])) {
+ line[pos] = p[pos];
+ if (!p[pos])
+ break;
+ ++pos;
+ if (pos == width) {
+ line[pos] = '\0';
+ fprintf(stream, "%s\n", line);
+ p += pos;
+ pos = 0;
+ }
+ }
+ while (pos < width) {
+ line[pos] = p[pos];
+ if (!p[pos]) {
+ bpos = pos;
+ break;
+ }
+ if (isspace(p[pos]))
+ bpos = pos;
+ ++pos;
+ }
+ line[bpos] = '\0';
+ fprintf(stream, "%s\n", line);
+ p += bpos;
+ pos = 0;
+ while (p[pos] && isspace(p[pos]))
+ ++p;
+ }
+}
diff --git a/ubi-utils/new-utils/src/common.h b/ubi-utils/new-utils/src/common.h
new file mode 100644
index 0000000..a3fc51f
--- /dev/null
+++ b/ubi-utils/new-utils/src/common.h
@@ -0,0 +1,71 @@
+/*
+ * 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__
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MIN(a ,b) ((a) < (b) ? (a) : (b))
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/* Verbose messages */
+#define verbose(verbose, fmt, ...) do { \
+ if (verbose) \
+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+/* Normal messages */
+#define normsg(fmt, ...) do { \
+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+/* Error messages */
+#define errmsg(fmt, ...) ({ \
+ fprintf(stderr, PROGRAM_NAME " error: " fmt "\n", ##__VA_ARGS__); \
+ -1; \
+})
+
+/* System error messages */
+#define sys_errmsg(fmt, ...) ({ \
+ int _err = errno; \
+ fprintf(stderr, PROGRAM_NAME " error: " fmt "\n", ##__VA_ARGS__); \
+ fprintf(stderr, "error %d (%s)\n", _err, strerror(_err)); \
+ -1; \
+})
+
+/* Warnings */
+#define warnmsg(fmt, ...) do { \
+ fprintf(stderr, PROGRAM_NAME " warning: " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+long long ubiutils_get_bytes(const char *str);
+void ubiutils_print_bytes(long long bytes, int bracket);
+void ubiutils_print_text(FILE *stream, const char *txt, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__UBI_UTILS_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/new-utils/src/dictionary.c b/ubi-utils/new-utils/src/dictionary.c
new file mode 100644
index 0000000..b7c9ebf
--- /dev/null
+++ b/ubi-utils/new-utils/src/dictionary.c
@@ -0,0 +1,405 @@
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.c
+ @author N. Devillard
+ @date Sep 2007
+ @version $Revision: 1.27 $
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $
+ $Revision: 1.27 $
+*/
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+#include "dictionary.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/** Maximum value size for integers and doubles. */
+#define MAXVALSZ 1024
+
+/** Minimal allocated number of entries in a dictionary */
+#define DICTMINSZ 128
+
+/** Invalid key token */
+#define DICT_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private functions
+ ---------------------------------------------------------------------------*/
+
+/* Doubles the allocated size associated to a pointer */
+/* 'size' is the current allocated size. */
+static void * mem_double(void * ptr, int size)
+{
+ void * newptr ;
+
+ newptr = calloc(2*size, 1);
+ if (newptr==NULL) {
+ return NULL ;
+ }
+ memcpy(newptr, ptr, size);
+ free(ptr);
+ return newptr ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Duplicate a string
+ @param s String to duplicate
+ @return Pointer to a newly allocated string, to be freed with free()
+
+ This is a replacement for strdup(). This implementation is provided
+ for systems that do not have it.
+ */
+/*--------------------------------------------------------------------------*/
+static char * xstrdup(char * s)
+{
+ char * t ;
+ if (!s)
+ return NULL ;
+ t = malloc(strlen(s)+1) ;
+ if (t) {
+ strcpy(t,s);
+ }
+ return t ;
+}
+
+/*---------------------------------------------------------------------------
+ Function codes
+ ---------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key)
+{
+ int len ;
+ unsigned hash ;
+ int i ;
+
+ len = strlen(key);
+ for (hash=0, i=0 ; i<len ; i++) {
+ hash += (unsigned)key[i] ;
+ hash += (hash<<10);
+ hash ^= (hash>>6) ;
+ }
+ hash += (hash <<3);
+ hash ^= (hash >>11);
+ hash += (hash <<15);
+ return hash ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ it. If you do not know in advance (roughly) the number of entries in the
+ dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size)
+{
+ dictionary * d ;
+
+ /* If no size was specified, allocate space for DICTMINSZ */
+ if (size<DICTMINSZ) size=DICTMINSZ ;
+
+ if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
+ return NULL;
+ }
+ d->size = size ;
+ d->val = (char **)calloc(size, sizeof(char*));
+ d->key = (char **)calloc(size, sizeof(char*));
+ d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
+ return d ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * d)
+{
+ int i ;
+
+ if (d==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]!=NULL)
+ free(d->key[i]);
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ }
+ free(d->val);
+ free(d->key);
+ free(d->hash);
+ free(d);
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def)
+{
+ unsigned hash ;
+ int i ;
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ return d->val[i] ;
+ }
+ }
+ }
+ return def ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return int 0 if Ok, anything else otherwise
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+
+ This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * d, char * key, char * val)
+{
+ int i ;
+ unsigned hash ;
+
+ if (d==NULL || key==NULL) return -1 ;
+
+ /* Compute hash for this key */
+ hash = dictionary_hash(key) ;
+ /* Find if value is already in dictionary */
+ if (d->n>0) {
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (hash==d->hash[i]) { /* Same hash value */
+ if (!strcmp(key, d->key[i])) { /* Same key */
+ /* Found a value: modify and return */
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ d->val[i] = val ? xstrdup(val) : NULL ;
+ /* Value has been modified: return */
+ return 0 ;
+ }
+ }
+ }
+ }
+ /* Add a new value */
+ /* See if dictionary needs to grow */
+ if (d->n==d->size) {
+
+ /* Reached maximum size: reallocate dictionary */
+ d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
+ d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
+ d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
+ if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
+ /* Cannot grow dictionary */
+ return -1 ;
+ }
+ /* Double size */
+ d->size *= 2 ;
+ }
+
+ /* Insert key in the first empty slot */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL) {
+ /* Add key here */
+ break ;
+ }
+ }
+ /* Copy key */
+ d->key[i] = xstrdup(key);
+ d->val[i] = val ? xstrdup(val) : NULL ;
+ d->hash[i] = hash;
+ d->n ++ ;
+ return 0 ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key)
+{
+ unsigned hash ;
+ int i ;
+
+ if (key == NULL) {
+ return;
+ }
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ /* Found key */
+ break ;
+ }
+ }
+ }
+ if (i>=d->size)
+ /* Key not found */
+ return ;
+
+ free(d->key[i]);
+ d->key[i] = NULL ;
+ if (d->val[i]!=NULL) {
+ free(d->val[i]);
+ d->val[i] = NULL ;
+ }
+ d->hash[i] = 0 ;
+ d->n -- ;
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out)
+{
+ int i ;
+
+ if (d==NULL || out==NULL) return ;
+ if (d->n<1) {
+ fprintf(out, "empty dictionary\n");
+ return ;
+ }
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]) {
+ fprintf(out, "%20s\t[%s]\n",
+ d->key[i],
+ d->val[i] ? d->val[i] : "UNDEF");
+ }
+ }
+ return ;
+}
+
+
+/* Test code */
+#ifdef TESTDIC
+#define NVALS 20000
+int main(int argc, char *argv[])
+{
+ dictionary * d ;
+ char * val ;
+ int i ;
+ char cval[90] ;
+
+ /* Allocate dictionary */
+ printf("allocating...\n");
+ d = dictionary_new(0);
+
+ /* Set values in dictionary */
+ printf("setting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ dictionary_set(d, cval, "salut");
+ }
+ printf("getting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ val = dictionary_get(d, cval, DICT_INVALID_KEY);
+ if (val==DICT_INVALID_KEY) {
+ printf("cannot get value for key [%s]\n", cval);
+ }
+ }
+ printf("unsetting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ dictionary_unset(d, cval);
+ }
+ if (d->n != 0) {
+ printf("error deleting values\n");
+ }
+ printf("deallocating...\n");
+ dictionary_del(d);
+ return 0 ;
+}
+#endif
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/ubi-utils/new-utils/src/dictionary.h b/ubi-utils/new-utils/src/dictionary.h
new file mode 100644
index 0000000..c7d1790
--- /dev/null
+++ b/ubi-utils/new-utils/src/dictionary.h
@@ -0,0 +1,174 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.h
+ @author N. Devillard
+ @date Sep 2007
+ @version $Revision: 1.12 $
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: dictionary.h,v 1.12 2007-11-23 21:37:00 ndevilla Exp $
+ $Author: ndevilla $
+ $Date: 2007-11-23 21:37:00 $
+ $Revision: 1.12 $
+*/
+
+#ifndef _DICTIONARY_H_
+#define _DICTIONARY_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*---------------------------------------------------------------------------
+ New types
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dictionary object
+
+ This object contains a list of string/string associations. Each
+ association is identified by a unique string key. Looking up values
+ in the dictionary is speeded up by the use of a (hopefully collision-free)
+ hash function.
+ */
+/*-------------------------------------------------------------------------*/
+typedef struct _dictionary_ {
+ int n ; /** Number of entries in dictionary */
+ int size ; /** Storage size */
+ char ** val ; /** List of string values */
+ char ** key ; /** List of string keys */
+ unsigned * hash ; /** List of hash values for keys */
+} dictionary ;
+
+
+/*---------------------------------------------------------------------------
+ Function prototypes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ it. If you do not know in advance (roughly) the number of entries in the
+ dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * vd);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return int 0 if Ok, anything else otherwise
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+
+ This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * vd, char * key, char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out);
+
+#endif
diff --git a/ubi-utils/new-utils/src/libiniparser.c b/ubi-utils/new-utils/src/libiniparser.c
new file mode 100644
index 0000000..3bea51e
--- /dev/null
+++ b/ubi-utils/new-utils/src/libiniparser.c
@@ -0,0 +1,646 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.c
+ @author N. Devillard
+ @date Sep 2007
+ @version 3.0
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+/*
+ $Id: iniparser.c,v 2.18 2008-01-03 18:35:39 ndevilla Exp $
+ $Revision: 2.18 $
+ $Date: 2008-01-03 18:35:39 $
+*/
+/*---------------------------- Includes ------------------------------------*/
+#include <ctype.h>
+#include <libiniparser.h>
+
+/*---------------------------- Defines -------------------------------------*/
+#define ASCIILINESZ (1024)
+#define INI_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private to this module
+ ---------------------------------------------------------------------------*/
+/**
+ * This enum stores the status for each parsed line (internal use only).
+ */
+typedef enum _line_status_ {
+ LINE_UNPROCESSED,
+ LINE_ERROR,
+ LINE_EMPTY,
+ LINE_COMMENT,
+ LINE_SECTION,
+ LINE_VALUE
+} line_status ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to lowercase.
+ @param s String to convert.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string
+ containing a lowercased version of the input string. Do not free
+ or modify the returned string! Since the returned string is statically
+ allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strlwc(const char * s)
+{
+ static char l[ASCIILINESZ+1];
+ int i ;
+
+ if (s==NULL) return NULL ;
+ memset(l, 0, ASCIILINESZ+1);
+ i=0 ;
+ while (s[i] && i<ASCIILINESZ) {
+ l[i] = (char)tolower((int)s[i]);
+ i++ ;
+ }
+ l[ASCIILINESZ]=(char)0;
+ return l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Remove blanks at the beginning and the end of a string.
+ @param s String to parse.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string,
+ which is identical to the input string, except that all blank
+ characters at the end and the beg. of the string have been removed.
+ Do not free or modify the returned string! Since the returned string
+ is statically allocated, it will be modified at each function call
+ (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strstrip(char * s)
+{
+ static char l[ASCIILINESZ+1];
+ char * last ;
+
+ if (s==NULL) return NULL ;
+
+ while (isspace((int)*s) && *s) s++;
+ memset(l, 0, ASCIILINESZ+1);
+ strcpy(l, s);
+ last = l + strlen(l);
+ while (last > l) {
+ if (!isspace((int)*(last-1)))
+ break ;
+ last -- ;
+ }
+ *last = (char)0;
+ return (char*)l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getnsec(dictionary * d)
+{
+ int i ;
+ int nsec ;
+
+ if (d==NULL) return -1 ;
+ nsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ nsec ++ ;
+ }
+ }
+ return nsec ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getsecname(dictionary * d, int n)
+{
+ int i ;
+ int foundsec ;
+
+ if (d==NULL || n<0) return NULL ;
+ foundsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ foundsec++ ;
+ if (foundsec>n)
+ break ;
+ }
+ }
+ if (foundsec<=n) {
+ return NULL ;
+ }
+ return d->key[i] ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f)
+{
+ int i ;
+
+ if (d==NULL || f==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (d->val[i]!=NULL) {
+ fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
+ } else {
+ fprintf(f, "[%s]=UNDEF\n", d->key[i]);
+ }
+ }
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump_ini(dictionary * d, FILE * f)
+{
+ int i, j ;
+ char keym[ASCIILINESZ+1];
+ int nsec ;
+ char * secname ;
+ int seclen ;
+
+ if (d==NULL || f==NULL) return ;
+
+ nsec = iniparser_getnsec(d);
+ if (nsec<1) {
+ /* No section in file: dump all keys as they are */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
+ }
+ return ;
+ }
+ for (i=0 ; i<nsec ; i++) {
+ secname = iniparser_getsecname(d, i) ;
+ seclen = (int)strlen(secname);
+ fprintf(f, "\n[%s]\n", secname);
+ sprintf(keym, "%s:", secname);
+ for (j=0 ; j<d->size ; j++) {
+ if (d->key[j]==NULL)
+ continue ;
+ if (!strncmp(d->key[j], keym, seclen+1)) {
+ fprintf(f,
+ "%-30s = %s\n",
+ d->key[j]+seclen+1,
+ d->val[j] ? d->val[j] : "");
+ }
+ }
+ }
+ fprintf(f, "\n");
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def)
+{
+ char * lc_key ;
+ char * sval ;
+
+ if (d==NULL || key==NULL)
+ return def ;
+
+ lc_key = strlwc(key);
+ sval = dictionary_get(d, lc_key, def);
+ return sval ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to an int
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ Supported values for integers include the usual C notation
+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+ are supported. Examples:
+
+ "42" -> 42
+ "042" -> 34 (octal -> decimal)
+ "0x42" -> 66 (hexa -> decimal)
+
+ Warning: the conversion may overflow in various ways. Conversion is
+ totally outsourced to strtol(), see the associated man page for overflow
+ handling.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound)
+{
+ char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return (int)strtol(str, NULL, 0);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, char * key, double notfound)
+{
+ char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return atof(str);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound)
+{
+ char * c ;
+ int ret ;
+
+ c = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (c==INI_INVALID_KEY) return notfound ;
+ if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
+ ret = 1 ;
+ } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
+ ret = 0 ;
+ } else {
+ ret = notfound ;
+ }
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(
+ dictionary * ini,
+ char * entry
+)
+{
+ int found=0 ;
+ if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
+ found = 1 ;
+ }
+ return found ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ contain the provided value. If it cannot be found, -1 is returned.
+ It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_set(dictionary * ini, char * entry, char * val)
+{
+ return dictionary_set(ini, strlwc(entry), val) ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry)
+{
+ dictionary_unset(ini, strlwc(entry));
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Load a single line from an INI file
+ @param input_line Input line, may be concatenated multi-line input
+ @param section Output space to store section
+ @param key Output space to store key
+ @param value Output space to store value
+ @return line_status value
+ */
+/*--------------------------------------------------------------------------*/
+static line_status iniparser_line(
+ char * input_line,
+ char * section,
+ char * key,
+ char * value)
+{
+ line_status sta ;
+ char line[ASCIILINESZ+1];
+ int len ;
+
+ strcpy(line, strstrip(input_line));
+ len = (int)strlen(line);
+
+ sta = LINE_UNPROCESSED ;
+ if (len<1) {
+ /* Empty line */
+ sta = LINE_EMPTY ;
+ } else if (line[0]=='#') {
+ /* Comment line */
+ sta = LINE_COMMENT ;
+ } else if (line[0]=='[' && line[len-1]==']') {
+ /* Section name */
+ sscanf(line, "[%[^]]", section);
+ strcpy(section, strstrip(section));
+ strcpy(section, strlwc(section));
+ sta = LINE_SECTION ;
+ } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
+ || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
+ || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
+ /* Usual key=value, with or without comments */
+ strcpy(key, strstrip(key));
+ strcpy(key, strlwc(key));
+ strcpy(value, strstrip(value));
+ /*
+ * sscanf cannot handle '' or "" as empty values
+ * this is done here
+ */
+ if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
+ value[0]=0 ;
+ }
+ sta = LINE_VALUE ;
+ } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
+ || sscanf(line, "%[^=] %[=]", key, value) == 2) {
+ /*
+ * Special cases:
+ * key=
+ * key=;
+ * key=#
+ */
+ strcpy(key, strstrip(key));
+ strcpy(key, strlwc(key));
+ value[0]=0 ;
+ sta = LINE_VALUE ;
+ } else {
+ /* Generate syntax error */
+ sta = LINE_ERROR ;
+ }
+ return sta ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame)
+{
+ FILE * in ;
+
+ char line [ASCIILINESZ+1] ;
+ char section [ASCIILINESZ+1] ;
+ char key [ASCIILINESZ+1] ;
+ char tmp [ASCIILINESZ+1] ;
+ char val [ASCIILINESZ+1] ;
+
+ int last=0 ;
+ int len ;
+ int lineno=0 ;
+ int errs=0;
+
+ dictionary * dict ;
+
+ if ((in=fopen(ininame, "r"))==NULL) {
+ fprintf(stderr, "iniparser: cannot open %s\n", ininame);
+ return NULL ;
+ }
+
+ dict = dictionary_new(0) ;
+ if (!dict) {
+ fclose(in);
+ return NULL ;
+ }
+
+ memset(line, 0, ASCIILINESZ);
+ memset(section, 0, ASCIILINESZ);
+ memset(key, 0, ASCIILINESZ);
+ memset(val, 0, ASCIILINESZ);
+ last=0 ;
+
+ while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
+ lineno++ ;
+ len = (int)strlen(line)-1;
+ /* Safety check against buffer overflows */
+ if (line[len]!='\n') {
+ fprintf(stderr,
+ "iniparser: input line too long in %s (%d)\n",
+ ininame,
+ lineno);
+ dictionary_del(dict);
+ fclose(in);
+ return NULL ;
+ }
+ /* Get rid of \n and spaces at end of line */
+ while ((len>=0) &&
+ ((line[len]=='\n') || (isspace(line[len])))) {
+ line[len]=0 ;
+ len-- ;
+ }
+ /* Detect multi-line */
+ if (line[len]=='\\') {
+ /* Multi-line value */
+ last=len ;
+ continue ;
+ } else {
+ last=0 ;
+ }
+ switch (iniparser_line(line, section, key, val)) {
+ case LINE_EMPTY:
+ case LINE_COMMENT:
+ break ;
+
+ case LINE_SECTION:
+ errs = dictionary_set(dict, section, NULL);
+ break ;
+
+ case LINE_VALUE:
+ sprintf(tmp, "%s:%s", section, key);
+ errs = dictionary_set(dict, tmp, val) ;
+ break ;
+
+ case LINE_ERROR:
+ fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
+ ininame,
+ lineno);
+ fprintf(stderr, "-> %s\n", line);
+ errs++ ;
+ break;
+
+ default:
+ break ;
+ }
+ memset(line, 0, ASCIILINESZ);
+ last=0;
+ if (errs<0) {
+ fprintf(stderr, "iniparser: memory allocation failure\n");
+ break ;
+ }
+ }
+ if (errs) {
+ dictionary_del(dict);
+ dict = NULL ;
+ }
+ fclose(in);
+ return dict ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d)
+{
+ dictionary_del(d);
+}
+
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/ubi-utils/new-utils/src/libubi.c b/ubi-utils/new-utils/src/libubi.c
new file mode 100644
index 0000000..b53f18c
--- /dev/null
+++ b/ubi-utils/new-utils/src/libubi.c
@@ -0,0 +1,1143 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.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;
+ struct libubi *lib;
+
+ lib = calloc(1, sizeof(struct libubi));
+ if (!lib)
+ return NULL;
+
+ /* 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;
+
+ lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI);
+ if (!lib->sysfs_ubi)
+ goto out_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;
+ }
+
+ lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT);
+ if (!lib->ubi_dev)
+ goto out_error;
+
+ lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER);
+ if (!lib->ubi_version)
+ goto out_error;
+
+ lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV);
+ if (!lib->dev_dev)
+ goto out_error;
+
+ lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS);
+ if (!lib->dev_avail_ebs)
+ goto out_error;
+
+ lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS);
+ if (!lib->dev_total_ebs)
+ goto out_error;
+
+ lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT);
+ if (!lib->dev_bad_count)
+ goto out_error;
+
+ lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE);
+ if (!lib->dev_eb_size)
+ goto out_error;
+
+ lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC);
+ if (!lib->dev_max_ec)
+ goto out_error;
+
+ lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD);
+ if (!lib->dev_bad_rsvd)
+ goto out_error;
+
+ lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS);
+ if (!lib->dev_max_vols)
+ goto out_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;
+
+ lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT);
+ if (!lib->ubi_vol)
+ goto out_error;
+
+ lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE);
+ if (!lib->vol_type)
+ goto out_error;
+
+ lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV);
+ if (!lib->vol_dev)
+ goto out_error;
+
+ lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT);
+ if (!lib->vol_alignment)
+ goto out_error;
+
+ lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES);
+ if (!lib->vol_data_bytes)
+ goto out_error;
+
+ lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS);
+ if (!lib->vol_rsvd_ebs)
+ goto out_error;
+
+ lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE);
+ if (!lib->vol_eb_size)
+ goto out_error;
+
+ lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED);
+ if (!lib->vol_corrupted)
+ goto out_error;
+
+ lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
+ if (!lib->vol_name)
+ goto out_error;
+
+ if (read_positive_int(lib->ubi_version, &version))
+ goto out_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;
+ }
+
+ return lib;
+
+out_error:
+ libubi_close((libubi_t)lib);
+ return NULL;
+}
+
+void libubi_close(libubi_t desc)
+{
+ struct libubi *lib = (struct libubi *)desc;
+
+ free(lib->vol_name);
+ 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_mtd_num);
+ 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->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;
+ struct dirent *dirent;
+ struct libubi *lib = (struct libubi *)desc;
+
+ 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);
+
+ 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;
+
+ 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)
+ info->highest_dev_num = dev_num;
+ if (dev_num < info->lowest_dev_num)
+ info->lowest_dev_num = dev_num;
+ }
+ }
+
+ 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;
+
+ return 0;
+
+out_close:
+ closedir(sysfs_ubi);
+ return -1;
+}
+
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
+{
+ int fd, ret;
+ struct ubi_mkvol_req r;
+ size_t n;
+
+ memset(&r, sizeof(struct ubi_mkvol_req), '\0');
+
+ desc = desc;
+ r.vol_id = req->vol_id;
+ r.alignment = req->alignment;
+ r.bytes = req->bytes;
+ r.vol_type = req->vol_type;
+
+ n = strlen(req->name);
+ if (n > UBI_MAX_VOLUME_NAME)
+ return -1;
+
+ strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1);
+ r.name_len = n;
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ ret = ioctl(fd, UBI_IOCMKVOL, &r);
+ if (ret == -1)
+ goto out_close;
+
+ req->vol_id = r.vol_id;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+out_close:
+ close(fd);
+ return ret;
+}
+
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
+{
+ int fd, ret;
+
+ desc = desc;
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ 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;
+}
+
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
+{
+ int fd, ret;
+ struct ubi_rsvol_req req;
+
+ desc = desc;
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ req.bytes = bytes;
+ req.vol_id = vol_id;
+
+ ret = ioctl(fd, UBI_IOCRSVOL, &req);
+ close(fd);
+ return ret;
+}
+
+int ubi_update_start(libubi_t desc, int fd, long long bytes)
+{
+ desc = desc;
+ if (ioctl(fd, UBI_IOCVOLUP, &bytes))
+ return -1;
+ return 0;
+}
+
+int ubi_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;
+ struct dirent *dirent;
+ struct libubi *lib = (struct libubi *)desc;
+
+ memset(info, '\0', sizeof(struct ubi_dev_info));
+ info->dev_num = dev_num;
+
+ sysfs_ubi = opendir(lib->sysfs_ubi);
+ if (!sysfs_ubi)
+ return -1;
+
+ info->lowest_vol_num = INT_MAX;
+
+ while (1) {
+ 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);
+ if (ret == 2 && devno == dev_num) {
+ info->vol_count += 1;
+ if (vol_id > info->highest_vol_num)
+ info->highest_vol_num = vol_id;
+ if (vol_id < info->lowest_vol_num)
+ info->lowest_vol_num = vol_id;
+ }
+ }
+
+ 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_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))
+ return -1;
+ if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_lebs))
+ return -1;
+ if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
+ return -1;
+ if (dev_read_int(lib->dev_eb_size, dev_num, &info->leb_size))
+ return -1;
+ if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
+ return -1;
+ if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec))
+ return -1;
+ if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count))
+ return -1;
+ 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;
+
+ 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 dev_num;
+ struct libubi *lib = (struct libubi *)desc;
+
+ if (dev_node2num(lib, node, &dev_num))
+ return -1;
+
+ return ubi_get_dev_info1(desc, dev_num, info);
+}
+
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+ struct ubi_vol_info *info)
+{
+ int ret;
+ struct libubi *lib = (struct libubi *)desc;
+ char buf[50];
+
+ memset(info, '\0', sizeof(struct ubi_vol_info));
+ info->dev_num = dev_num;
+ info->vol_id = vol_id;
+
+ if (dev_get_major(lib, dev_num, &info->dev_major, &info->dev_minor))
+ return -1;
+ if (vol_get_major(lib, dev_num, vol_id, &info->major, &info->minor))
+ return -1;
+
+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50);
+ if (ret < 0)
+ return -1;
+
+ if (strncmp(buf, "static\n", ret) == 0)
+ info->type = UBI_STATIC_VOLUME;
+ else if (strncmp(buf, "dynamic\n", ret) == 0)
+ info->type = UBI_DYNAMIC_VOLUME;
+ else {
+ errmsg("bad value at \"%s\"", buf);
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = vol_read_int(lib->vol_alignment, dev_num, vol_id,
+ &info->alignment);
+ if (ret)
+ return -1;
+ ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id,
+ &info->data_bytes);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_lebs);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->leb_size);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
+ &info->corrupted);
+ if (ret)
+ return -1;
+ info->rsvd_bytes = info->leb_size * info->rsvd_lebs;
+
+ ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
+ UBI_VOL_NAME_MAX + 2);
+ if (ret < 0)
+ return -1;
+
+ info->name[ret - 1] = '\0';
+ return 0;
+}
+
+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
+{
+ int vol_id, dev_num;
+ struct libubi *lib = (struct libubi *)desc;
+
+ if (vol_node2nums(lib, node, &dev_num, &vol_id))
+ return -1;
+
+ return ubi_get_vol_info1(desc, dev_num, vol_id, info);
+}
diff --git a/ubi-utils/new-utils/src/libubi_int.h b/ubi-utils/new-utils/src/libubi_int.h
new file mode 100644
index 0000000..dab3e62
--- /dev/null
+++ b/ubi-utils/new-utils/src/libubi_int.h
@@ -0,0 +1,147 @@
+/*
+ * 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_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; \
+})
+
+/*
+ * 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 DEV_DEV "dev"
+#define DEV_AVAIL_EBS "avail_eraseblocks"
+#define DEV_TOTAL_EBS "total_eraseblocks"
+#define DEV_BAD_COUNT "bad_peb_count"
+#define DEV_EB_SIZE "eraseblock_size"
+#define DEV_MAX_EC "max_ec"
+#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"
+#define VOL_DATA_BYTES "data_bytes"
+#define VOL_RSVD_EBS "reserved_ebs"
+#define VOL_EB_SIZE "usable_eb_size"
+#define VOL_CORRUPTED "corrupted"
+#define VOL_NAME "name"
+
+/**
+ * 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
+ */
+struct libubi
+{
+ char *sysfs;
+ char *sysfs_ctrl;
+ char *ctrl_dev;
+ char *sysfs_ubi;
+ char *ubi_dev;
+ char *ubi_version;
+ char *dev_dev;
+ char *dev_avail_ebs;
+ char *dev_total_ebs;
+ char *dev_bad_count;
+ char *dev_eb_size;
+ char *dev_max_ec;
+ 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;
+ char *vol_alignment;
+ char *vol_data_bytes;
+ char *vol_rsvd_ebs;
+ char *vol_eb_size;
+ char *vol_corrupted;
+ char *vol_name;
+ char *vol_max_count;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_INT_H__ */
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/new-utils/src/ubi-attach.c b/ubi-utils/new-utils/src/ubi-attach.c
new file mode 100644
index 0000000..7b231a6
--- /dev/null
+++ b/ubi-utils/new-utils/src/ubi-attach.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * An utility to attach MTD devices to UBI.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#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-attach"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int mtdn;
+ int vidoffs;
+ const char *node;
+};
+
+static struct args args = {
+ .devn = UBI_DEV_NUM_AUTO,
+ .mtdn = -1,
+ .vidoffs = 0,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to attach MTD device to UBI.";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> the number to assign to the newly created UBI device\n"
+" (the number is assigned automatically if this is not\n"
+" specified\n"
+"-m, --mtdn=<MTD device number> MTD device number to attach\n"
+"-O, --vid-hdr-offset VID header offset (do not specify this unless you\n"
+" really know what you do and the optimal defaults will\n"
+" be used)\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME "<UBI control device node file name> [-m <MTD device number>] [-d <UBI device number>]\n"
+"\t\t[--mtdn=<MTD device number>] [--devn <UBI device number>]\n"
+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - attach MTD device 0 (mtd0) to UBI\n"
+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 -d 3 - attach MTD device 0 (mtd0) to UBI and\n"
+" and create UBI device number 3 (ubi3)";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "m:d:OhV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ break;
+
+ case 'm':
+ args.mtdn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.mtdn < 0)
+ return errmsg("bad MTD device number: \"%s\"", optarg);
+
+ break;
+
+ case 'o':
+ args.vidoffs = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vidoffs <= 0)
+ return errmsg("bad VID header offset: \"%s\"", optarg);
+
+ 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 ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("UBI control device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one UBI control device specified (use -h for help)");
+
+ if (args.mtdn == -1)
+ return errmsg("MTD device number was not specified (use -h for help)");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_info ubi_info;
+ struct ubi_dev_info dev_info;
+ struct ubi_attach_request req;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open();
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ /*
+ * Make sure the kernel is fresh enough and this feature is supported.
+ */
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err) {
+ sys_errmsg("cannot get UBI information");
+ goto out_libubi;
+ }
+
+ if (ubi_info.ctrl_major == -1) {
+ errmsg("MTD attach/detach feature is not supported by your kernel");
+ goto out_libubi;
+ }
+
+ req.dev_num = args.devn;
+ req.mtd_num = args.mtdn;
+ req.vid_hdr_offset = args.vidoffs;
+
+ err = ubi_attach_mtd(libubi, args.node, &req);
+ if (err) {
+ sys_errmsg("cannot attach mtd%d", args.mtdn);
+ goto out_libubi;
+ }
+
+ /* Print some information about the new UBI device */
+ err = ubi_get_dev_info1(libubi, req.dev_num, &dev_info);
+ if (err) {
+ sys_errmsg("cannot get information about newly created UBI device");
+ goto out_libubi;
+ }
+
+ printf("UBI device number %d, total %d LEBs (", dev_info.dev_num, dev_info.total_lebs);
+ ubiutils_print_bytes(dev_info.total_bytes, 0);
+ printf("), available %d LEBs (", dev_info.avail_lebs);
+ ubiutils_print_bytes(dev_info.avail_bytes, 0);
+ printf("), LEB size ");
+ ubiutils_print_bytes(dev_info.leb_size, 1);
+ printf("\n");
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
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/new-utils/src/ubi-detach.c b/ubi-utils/new-utils/src/ubi-detach.c
new file mode 100644
index 0000000..0ee7954
--- /dev/null
+++ b/ubi-utils/new-utils/src/ubi-detach.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * An utility to delete UBI devices (detach MTD devices from UBI).
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#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-detach"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int mtdn;
+ const char *node;
+};
+
+static struct args args = {
+ .devn = UBI_DEV_NUM_AUTO,
+ .mtdn = -1,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+" - a tool to remove UBI devices (detach MTD devices from UBI)";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> UBI device number to delete\n"
+"-m, --mtdn=<MTD device number> or altrnatively, MTD device number to detach -\n"
+" this will delete corresponding UBI device\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME "<UBI control device node file name> [-d <UBI device number>] [-m <MTD device number>]\n"
+"\t\t[--devn <UBI device number>] [--mtdn=<MTD device number>]\n"
+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -d 2 - delete UBI device 2 (ubi2)\n"
+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - detach MTD device 0 (mtd0)";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "m:d:hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ break;
+
+ case 'm':
+ args.mtdn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.mtdn < 0)
+ return errmsg("bad MTD device number: \"%s\"", optarg);
+
+ 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 ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("UBI control device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one UBI control device specified (use -h for help)");
+
+ if (args.mtdn == -1 && args.devn == -1)
+ return errmsg("neither MTD nor UBI devices were specified (use -h for help)");
+
+ if (args.mtdn != -1 && args.devn != -1)
+ return errmsg("specify either MTD or UBI device (use -h for help)");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_info ubi_info;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open();
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ /*
+ * Make sure the kernel is fresh enough and this feature is supported.
+ */
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err) {
+ sys_errmsg("cannot get UBI information");
+ goto out_libubi;
+ }
+
+ if (ubi_info.ctrl_major == -1) {
+ errmsg("MTD detach/detach feature is not supported by your kernel");
+ goto out_libubi;
+ }
+
+ if (args.devn != -1) {
+ err = ubi_remove_dev(libubi, args.node, args.devn);
+ if (err) {
+ sys_errmsg("cannot remove ubi%d", args.devn);
+ goto out_libubi;
+ }
+ } else {
+ err = ubi_detach_mtd(libubi, args.node, args.mtdn);
+ if (err) {
+ sys_errmsg("cannot detach mtd%d", args.mtdn);
+ goto out_libubi;
+ }
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
+
diff --git a/ubi-utils/new-utils/src/ubi-info.c b/ubi-utils/new-utils/src/ubi-info.c
new file mode 100644
index 0000000..d469a1a
--- /dev/null
+++ b/ubi-utils/new-utils/src/ubi-info.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * An utility to get UBI information.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#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-nfo"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int vol_id;
+ int all;
+ const char *node;
+};
+
+static struct args args = {
+ .vol_id = -1,
+ .devn = -1,
+ .all = 0,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to print UBI information.";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> UBI device number to get information about\n"
+"-n, --vol_id=<volume ID> ID of UBI volume to print information about\n"
+"-a, --all print information about all devices and volumes,\n"
+" or about all volumes if the UBI device was\n"
+" specified\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage 1: " PROGRAM_NAME " [-d <UBI device number>] [-n <volume ID>] [-a] [-h] [-V] [--vol_id=<volume ID>]\n"
+"\t\t[--devn <UBI device number>] [--all] [--help] [--version]\n"
+"Usage 2: " PROGRAM_NAME " <UBI device node file name> [-a] [-h] [-V] [--all] [--help] [--version]\n"
+"Usage 3: " PROGRAM_NAME " <UBI volume node file name> [-h] [-V] [--help] [--version]\n\n"
+"Example 1: " PROGRAM_NAME " - (no arguments) print general UBI information\n"
+"Example 2: " PROGRAM_NAME " -d 1 - print information about UBI device number 1\n"
+"Example 3: " PROGRAM_NAME " /dev/ubi0 -a - print information about all volumes of UBI\n"
+" device /dev/ubi0\n"
+"Example 4: " PROGRAM_NAME " /dev/ubi1_0 - print information about UBI volume /dev/ubi1_0\n"
+"Example 5: " PROGRAM_NAME " -a - print all information\n";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+ { .name = "all", .has_arg = 0, .flag = NULL, .val = 'a' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "an:d:hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'a':
+ args.all = 1;
+ 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 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ 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 ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc - 1)
+ args.node = argv[optind];
+ else if (optind < argc)
+ return errmsg("more then one UBI devices specified (use -h for help)");
+
+ return 0;
+}
+
+static int translate_dev(libubi_t libubi, const char *node)
+{
+ int err;
+
+ err = ubi_node_type(libubi, node);
+ if (err == -1) {
+ if (errno)
+ return errmsg("unrecognized device node \"%s\"", node);
+ return errmsg("\"%s\" does not correspond to any UBI device or volume", node);
+ }
+
+ if (err == 1) {
+ struct ubi_dev_info dev_info;
+
+ err = ubi_get_dev_info(libubi, node, &dev_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI device \"%s\"", node);
+
+ args.devn = dev_info.dev_num;
+ } else {
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_vol_info(libubi, node, &vol_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI volume \"%s\"", node);
+
+ if (args.vol_id != -1)
+ return errmsg("both volume character device node (\"%s\") and "
+ "volume ID (%d) are specify, use only one of them"
+ "(use -h for help)", node, args.vol_id);
+
+ args.devn = vol_info.dev_num;
+ args.vol_id = vol_info.vol_id;
+ }
+
+ return 0;
+}
+
+static int print_vol_info(libubi_t libubi, int dev_num, int vol_id)
+{
+ int err;
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_vol_info1(libubi, dev_num, vol_id, &vol_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI volume %d on ubi%d",
+ vol_id, dev_num);
+
+ printf("Volume ID: %d (on ubi%d)\n", vol_info.vol_id, vol_info.dev_num);
+ printf("Type: %s\n",
+ vol_info.type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static");
+ printf("Alignment: %d\n", vol_info.alignment);
+
+ printf("Size: %d LEBs (", vol_info.rsvd_lebs);
+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+ printf(")\n");
+
+ if (vol_info.type == UBI_STATIC_VOLUME) {
+ printf("Data bytes: ");
+ ubiutils_print_bytes(vol_info.data_bytes, 1);
+ }
+ printf("State: %s\n", vol_info.corrupted ? "corrupted" : "OK");
+ printf("Name: %s\n", vol_info.name);
+ printf("Character device major/minor: %d:%d\n",
+ vol_info.major, vol_info.minor);
+
+ return 0;
+}
+
+static int print_dev_info(libubi_t libubi, int dev_num, int all)
+{
+ int i, err, first = 1;
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_dev_info1(libubi, dev_num, &dev_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI device %d", dev_num);
+
+ printf("ubi%d:\n", dev_info.dev_num);
+ printf("Volumes count: %d\n", dev_info.vol_count);
+ printf("Logical eraseblock size: %d\n", dev_info.leb_size);
+
+ printf("Total amount of logical eraseblocks: %d (", dev_info.total_lebs);
+ ubiutils_print_bytes(dev_info.total_bytes, 0);
+ printf(")\n");
+
+ printf("Amount of available logical eraseblocks: %d (", dev_info.avail_lebs);
+ ubiutils_print_bytes(dev_info.avail_bytes, 0);
+ printf(")\n");
+
+ printf("Maximum count of volumes %d\n", dev_info.max_vol_count);
+ printf("Count of bad physical eraseblocks: %d\n", dev_info.bad_count);
+ printf("Count of reserved physical eraseblocks: %d\n", dev_info.bad_rsvd);
+ printf("Current maximum erase counter value: %lld\n", dev_info.max_ec);
+ printf("Minimum input/output unit size: %d bytes\n", dev_info.min_io_size);
+ printf("Character device major/minor: %d:%d\n",
+ dev_info.major, dev_info.minor);
+
+ if (dev_info.vol_count == 0)
+ return 0;
+
+ printf("Present volumes: ");
+ for (i = dev_info.lowest_vol_num;
+ i <= dev_info.highest_vol_num; i++) {
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe volume %d on ubi%d",
+ i, dev_info.dev_num);
+ }
+
+ if (!first)
+ printf(", %d", i);
+ else {
+ printf("%d", i);
+ first = 0;
+ }
+ }
+ printf("\n");
+
+ if (!all)
+ return 0;
+
+ first = 1;
+ printf("\n");
+
+ for (i = dev_info.lowest_vol_num;
+ i <= dev_info.highest_vol_num; i++) {
+ if(!first)
+ printf("-----------------------------------\n");
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe volume %d on ubi%d",
+ i, dev_info.dev_num);
+ }
+ first = 0;
+
+ err = print_vol_info(libubi, dev_info.dev_num, i);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int print_general_info(libubi_t libubi, int all)
+{
+ int i, err, first = 1;
+ struct ubi_info ubi_info;
+ struct ubi_dev_info dev_info;
+
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err)
+ return sys_errmsg("cannot get UBI information");
+
+ printf("UBI version: %d\n", ubi_info.version);
+ printf("Count of UBI devices: %d\n", ubi_info.dev_count);
+ if (ubi_info.ctrl_major != -1)
+ printf("UBI control device major/minor: %d:%d\n",
+ ubi_info.ctrl_major, ubi_info.ctrl_minor);
+ else
+ printf("UBI control device is not supported by this kernel\n");
+
+ if (ubi_info.dev_count == 0)
+ return 0;
+
+ printf("Present UBI devices: ");
+ for (i = ubi_info.lowest_dev_num;
+ i <= ubi_info.highest_dev_num; i++) {
+ err = ubi_get_dev_info1(libubi, i, &dev_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe UBI device %d", i);
+ }
+
+ if (!first)
+ printf(", ubi%d", i);
+ else {
+ printf("ubi%d", i);
+ first = 0;
+ }
+ }
+ printf("\n");
+
+ if (!all)
+ return 0;
+
+ first = 1;
+ printf("\n");
+
+ for (i = ubi_info.lowest_dev_num;
+ i <= ubi_info.highest_dev_num; i++) {
+ if(!first)
+ printf("\n===================================\n\n");
+ err = ubi_get_dev_info1(libubi, i, &dev_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe UBI device %d", i);
+ }
+ first = 0;
+
+ err = print_dev_info(libubi, i, all);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ if (!args.node && args.devn != -1)
+ return errmsg("specify either device number or node file (use -h for help)");
+
+ libubi = libubi_open();
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ if (args.node) {
+ /*
+ * A character device was specified, translate this into UBI
+ * device number and volume ID.
+ */
+ err = translate_dev(libubi, args.node);
+ if (err)
+ goto out_libubi;
+ }
+
+ if (args.vol_id != -1 && args.devn == -1) {
+ errmsg("volume ID is specified, but UBI device number is not "
+ "(use -h for help)\n");
+ goto out_libubi;
+ }
+
+ if (args.devn != -1 && args.vol_id != -1) {
+ print_vol_info(libubi, args.devn, args.vol_id);
+ goto out;
+ }
+
+ if (args.devn == -1 && args.vol_id == -1)
+ err = print_general_info(libubi, args.all);
+ else if (args.devn != -1 && args.vol_id == -1)
+ err = print_dev_info(libubi, args.devn, args.all);
+
+ if (err)
+ goto out_libubi;
+
+out:
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
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/new-utils/src/ubi-nize.c b/ubi-utils/new-utils/src/ubi-nize.c
new file mode 100644
index 0000000..8041df4
--- /dev/null
+++ b/ubi-utils/new-utils/src/ubi-nize.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Generate UBI images.
+ *
+ * Authors: Artem Bityutskiy
+ * Oliver Lohmann
+ */
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <mtd/ubi-header.h>
+#include <libubigen.h>
+#include <libiniparser.h>
+#include "common.h"
+
+#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 "
+"volumes which have to be defined in the input configuration ini-file. The "
+"ini file defines all the UBI volumes - their characteristics and the and the "
+"contents, but it does not define the characteristics of the flash the UBI "
+"image is generated for. Instead, the flash characteristics are defined via "
+"the command-line options. Note, if not sure about some of the command-line "
+"parameters, do not specify them and let the utility to use default values.";
+
+static const char *optionsstr =
+"-o, --output=<file name> output file name (default is stdout)\n"
+"-p, --peb-size=<bytes> size of the physical eraseblock of the flash\n"
+" this UBI image is created for in bytes,\n"
+" kilobytes (KiB), or megabytes (MiB)\n"
+" (mandatory parameter)\n"
+"-m, --min-io-size=<bytes> minimum input/output unit size of the flash\n"
+" in bytes\n"
+"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI\n"
+" headers, e.g. sub-page size in case of NAND\n"
+" flash (equivalent to the minimum input/output\n"
+" unit size by default)\n"
+"-O, --vid-hdr-offset=<num> offset if the VID header from start of the\n"
+" physical eraseblock (default is the second\n"
+" minimum I/O unit or sub-page, if it was\n"
+" specified)\n"
+"-e, --erase-counter=<num> the erase counter value to put to EC headers\n"
+" (default is 0)\n"
+"-x, --ubi-ver=<num> UBI version number to put to EC headers\n"
+" (default is 1)\n"
+"-v --verbose be verbose\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " [-o filename] [-h] [-V] [--output=<filename>] [--help]\n"
+"\t\t[--version] ini-file\n"
+"Example: " PROGRAM_NAME "-o fs.raw cfg.ini";
+
+static const char *ini_doc = "INI-file format.\n"
+"The input configuration ini-file describes all the volumes which have to\n"
+"be included to the output UBI image. Each volume is described in its own\n"
+"section which may be named arbitrarily. The section consists on\n"
+"\"key=value\" pairs, for example:\n\n"
+"[jffs2-volume]\n"
+"mode=ubi\n"
+"image=../jffs2.img\n"
+"vol_id=1\n"
+"vol_size=30MiB\n"
+"vol_type=dynamic\n"
+"vol_name=jffs2_volume\n"
+"vol_flags=autoresize\n"
+"vol_alignment=1\n\n"
+"This example configuration file tells the utility to create an UBI image\n"
+"with one volume with ID 1, volume size 30MiB, the volume is dynamic, has\n"
+"name \"jffs2_volume\", \"autoresize\" volume flag, and alignment 1. The\n"
+"\"image=../jffs2.img\" line tells the utility to take the contents of the\n"
+"volume from the \"../jffs2.img\" file. The size of the image file has to be\n"
+"less or equivalent to the volume size (30MiB). The \"mode=ubi\" line is\n"
+"mandatory and just tells that the section describes an UBI volume - other\n"
+"section modes may be added in the future.\n"
+"Notes:\n"
+" * size in vol_size might be specified kilobytes (KiB), megabytes (MiB),\n"
+" gigabytes (GiB) or bytes (no modifier);\n"
+" * if \"vol_size\" key is absent, the volume size is assumed to be\n"
+" equivalent to the size of the image file (defined by \"image\" key);\n"
+" * if the \"image\" is absent, the volume is assumed to be empty;\n"
+" * volume alignment must not be greater than the logical eraseblock size;\n"
+" * one ini file may contain arbitrary number of sections, the utility will\n"
+" put all the volumes which are described by these section to the output\n"
+" UBI image file.";
+
+struct option long_options[] = {
+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'p' },
+ { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' },
+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' },
+ { .name = "verbose", .has_arg = 1, .flag = NULL, .val = 'v' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+struct args {
+ const char *f_in;
+ const char *f_out;
+ FILE *fp_out;
+ int peb_size;
+ int min_io_size;
+ int subpage_size;
+ int vid_hdr_offs;
+ int ec;
+ int ubi_ver;
+ int verbose;
+ dictionary *dict;
+};
+
+static struct args args = {
+ .f_out = NULL,
+ .peb_size = -1,
+ .min_io_size = -1,
+ .subpage_size = -1,
+ .vid_hdr_offs = 0,
+ .ec = 0,
+ .ubi_ver = 1,
+ .verbose = 0,
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "o:p:m:s:O:e:x:vhV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'o':
+ args.fp_out = fopen(optarg, "wb");
+ if (!args.fp_out)
+ return errmsg("cannot open file \"%s\"", optarg);
+ args.f_out = optarg;
+ break;
+
+ case 'p':
+ args.peb_size = ubiutils_get_bytes(optarg);
+ if (args.peb_size <= 0)
+ return errmsg("bad physical eraseblock size: \"%s\"", optarg);
+ break;
+
+ case 'm':
+ args.min_io_size = ubiutils_get_bytes(optarg);
+ if (args.min_io_size <= 0)
+ return errmsg("bad min. I/O unit size: \"%s\"", optarg);
+ break;
+
+ case 's':
+ args.subpage_size = ubiutils_get_bytes(optarg);
+ if (args.subpage_size <= 0)
+ return errmsg("bad sub-page size: \"%s\"", optarg);
+ break;
+
+ case 'O':
+ args.vid_hdr_offs = strtoul(optarg, &endp, 0);
+ if (endp == optarg || args.vid_hdr_offs < 0)
+ return errmsg("bad VID header offset: \"%s\"", optarg);
+ break;
+
+ case 'e':
+ args.ec = strtoul(optarg, &endp, 0);
+ if (endp == optarg || args.ec < 0)
+ return errmsg("bad erase counter value: \"%s\"", optarg);
+ break;
+
+ case 'x':
+ args.ubi_ver = strtoul(optarg, &endp, 0);
+ if (endp == optarg || args.ubi_ver < 0)
+ return errmsg("bad UBI version: \"%s\"", optarg);
+ break;
+
+ case 'v':
+ args.verbose = 1;
+ break;
+
+ case 'h':
+ ubiutils_print_text(stderr, doc, 80);
+ fprintf(stderr, "\n%s\n\n", ini_doc);
+ fprintf(stderr, "%s\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("input PFI file was not specified (use -h for help)");
+
+ if (optind != argc - 1)
+ return errmsg("more then one input PFI file was specified (use -h for help)");
+
+ args.f_in = argv[optind];
+
+ if (args.peb_size < 0)
+ return errmsg("physical eraseblock size was not specified (use -h for help)");
+
+ if (args.min_io_size < 0)
+ return errmsg("min. I/O unit size was not specified (use -h for help)");
+
+ if (args.subpage_size < 0)
+ args.subpage_size = args.min_io_size;
+
+ if (!args.f_out) {
+ args.f_out = "stdout";
+ args.fp_out = stdout;
+ }
+
+ return 0;
+}
+
+int read_section(const char *sname, struct ubigen_vol_info *vi,
+ const char **img)
+{
+ char buf[256];
+ const char *p;
+
+ *img = NULL;
+
+ if (strlen(sname) > 128)
+ return errmsg("too long section name \"%s\"", sname);
+
+ /* Make sure mode is UBI, otherwise ignore this section */
+ sprintf(buf, "%s:mode", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p) {
+ errmsg("\"mode\" key not found in section \"%s\"", sname);
+ errmsg("the \"mode\" key is mandatory and has to be "
+ "\"mode=ubi\" if the section describes an UBI volume");
+ return -1;
+ }
+
+ /* If mode is not UBI, skip this section */
+ if (strcmp(p, "ubi")) {
+ verbose(args.verbose, "skip non-ubi section \"%s\"", sname);
+ return 1;
+ }
+
+ verbose(args.verbose, "mode=ubi, keep parsing");
+
+ /* Fetch the name of the volume image file */
+ sprintf(buf, "%s:image", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (p)
+ *img = p;
+
+ /* Fetch volume id */
+ sprintf(buf, "%s:vol_id", sname);
+ vi->id = iniparser_getint(args.dict, buf, -1);
+ if (vi->id == -1)
+ return errmsg("\"vol_id\" key not found in section \"%s\"", sname);
+
+ if (vi->id < 0)
+ return errmsg("negative volume ID %d", vi->id);
+
+ if (vi->id >= UBI_MAX_VOLUMES)
+ return errmsg("too high volume ID %d, max. is %d", vi->id, UBI_MAX_VOLUMES);
+
+ verbose(args.verbose, "volume ID: %d", vi->id);
+
+ /* Fetch volume size */
+ sprintf(buf, "%s:vol_size", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (p) {
+ vi->bytes = ubiutils_get_bytes(p);
+ if (vi->bytes <= 0)
+ return errmsg("bad \"vol_size\" key: \"%s\"", p);
+
+ verbose(args.verbose, "volume size: %lld bytes", vi->bytes);
+ } else {
+ struct stat st;
+
+ if (!*img)
+ return errmsg("neither image file (\"image=\") nor volume size (\"vol_size=\") specified");
+
+ if (stat(*img, &st))
+ return sys_errmsg("cannot stat \"%s\"", *img);
+
+ vi->bytes = st.st_size;
+
+ if (vi->bytes == 0)
+ return errmsg("file \"%s\" referred from section \"%s\" is empty", *img, sname);
+
+ printf(PROGRAM_NAME ": volume size was not specified in"
+ "section \"%s\", assume ", sname);
+ ubiutils_print_bytes(vi->bytes, 1);
+ printf("\n");
+ }
+
+ /* Fetch volume type */
+ sprintf(buf, "%s:vol_type", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p) {
+ normsg(": volume type was not specified in "
+ "section \"%s\", assume \"dynamic\"\n", sname);
+ vi->type = UBI_VID_DYNAMIC;
+ } else {
+ if (!strcmp(p, "static"))
+ vi->type = UBI_VID_STATIC;
+ else if (!strcmp(p, "dynamic"))
+ vi->type = UBI_VID_DYNAMIC;
+ else
+ return errmsg("invalid volume type \"%s\"", p);
+ }
+
+ verbose(args.verbose, "volume type: %s",
+ vi->type == UBI_VID_DYNAMIC ? "dynamic" : "static");
+
+ /* Fetch volume name */
+ sprintf(buf, "%s:vol_name", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p)
+ return errmsg("\"vol_name\" key not found in section \"%s\"", sname);
+
+ vi->name = p;
+ vi->name_len = strlen(p);
+ if (vi->name_len > UBI_VOL_NAME_MAX)
+ return errmsg("too long volume name in section \"%s\", max. is %d characters",
+ vi->name, UBI_VOL_NAME_MAX);
+
+ verbose(args.verbose, "volume name: %s", p);
+
+ /* Fetch volume alignment */
+ sprintf(buf, "%s:vol_alignment", sname);
+ vi->alignment = iniparser_getint(args.dict, buf, -1);
+ if (vi->alignment == -1) {
+ normsg("volume alignment was not specified in section "
+ "\"%s\", assume 1", sname);
+ vi->alignment = 1;
+ } else if (vi->id < 0)
+ return errmsg("negative volume alignement %d", vi->alignment);
+
+ verbose(args.verbose, "volume alignment: %d", vi->alignment);
+
+ /* Fetch volume flags */
+ sprintf(buf, "%s:vol_flags", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (p) {
+ if (!strcmp(p, "autoresize")) {
+ verbose(args.verbose, "autoresize flags found");
+ vi->flags |= UBI_VTBL_AUTORESIZE_FLG;
+ } else {
+ return errmsg("unknown flags \"%s\" in section \"%s\"", p, sname);
+ }
+ }
+
+ return 0;
+}
+
+static void init_vol_info(const struct ubigen_info *ui,
+ struct ubigen_vol_info *vi)
+{
+ vi->data_pad = ui->leb_size % vi->alignment;
+ vi->usable_leb_size = ui->leb_size - vi->data_pad;
+ vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size;
+ vi->compat = 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err = -1, sects, i, volumes;
+ struct ubigen_info ui;
+ struct ubi_vtbl_record *vtbl;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ ubigen_info_init(&ui, args.peb_size, args.min_io_size,
+ args.subpage_size, args.vid_hdr_offs,
+ args.ubi_ver, args.ec);
+
+ verbose(args.verbose, "LEB size: %d", ui.leb_size);
+ verbose(args.verbose, "PEB size: %d", ui.peb_size);
+ verbose(args.verbose, "min_io_size: %d", ui.min_io_size);
+ verbose(args.verbose, "VID offset: %d", ui.vid_hdr_offs);
+
+ vtbl = ubigen_create_empty_vtbl(&ui);
+ if (!vtbl)
+ goto out;
+
+ args.dict = iniparser_load(args.f_in);
+ if (!args.dict) {
+ errmsg("cannot load the input ini file \"%s\"", args.f_in);
+ goto out_vtbl;
+ }
+
+ verbose(args.verbose, "loaded the ini-file \"%s\"", args.f_in);
+
+ /* Each section describes one volume */
+ sects = iniparser_getnsec(args.dict);
+ if (sects == -1) {
+ errmsg("ini-file parsing error (iniparser_getnsec)");
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "count of sections: %d", sects);
+ if (sects == 0) {
+ errmsg("no sections found the ini-file \"%s\"", args.f_in);
+ goto out_dict;
+ }
+
+ /*
+ * Skip 2 PEBs at the beginning of the file for the volume table which
+ * will be written later.
+ */
+ if (fseek(args.fp_out, ui.peb_size * 2, SEEK_SET) == -1) {
+ errmsg("cannot seek file \"%s\"", args.f_out);
+ goto out_dict;
+ }
+
+ for (i = 0; i < sects; i++) {
+ const char *sname = iniparser_getsecname(args.dict, i);
+ struct ubigen_vol_info vi;
+ const char *img = NULL;
+ struct stat st;
+ FILE *f;
+
+ if (!sname) {
+ errmsg("ini-file parsing error (iniparser_getsecname)");
+ goto out_dict;
+ }
+
+ if (args.verbose)
+ printf("\n");
+ verbose(args.verbose, "parsing section \"%s\"", sname);
+
+ err = read_section(sname, &vi, &img);
+ if (err == -1)
+ goto out_dict;
+ if (!err)
+ volumes += 1;
+ init_vol_info(&ui, &vi);
+
+ verbose(args.verbose, "adding volume %d", vi.id);
+
+ err = ubigen_add_volume(&ui, &vi, vtbl);
+ if (err) {
+ errmsg("cannot add volume for section \"%s\"", sname);
+ goto out_dict;
+ }
+
+ if (!img)
+ continue;
+
+ if (stat(img, &st)) {
+ sys_errmsg("cannot stat \"%s\"", img);
+ goto out_dict;
+ }
+
+ /*
+ * Make sure the image size is not larger then the volume size.
+ */
+ if (st.st_size > vi.bytes) {
+ errmsg("error in section \"%s\": size of the image file \"%s\" "
+ "is %lld, which is larger then the volume size %lld",
+ sname, img, (long long)st.st_size, vi.bytes);
+ goto out_dict;
+ }
+
+ f = fopen(img, "r");
+ if (!f) {
+ sys_errmsg("cannot open \"%s\"", img);
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "writing volume %d", vi.id);
+ verbose(args.verbose, "image file: %s", img);
+
+ err = ubigen_write_volume(&ui, &vi, st.st_size, f, args.fp_out);
+ fclose(f);
+ if (err) {
+ errmsg("cannot write volume for section \"%s\"", sname);
+ goto out_dict;
+ }
+
+ if (args.verbose)
+ printf("\n");
+ }
+
+ verbose(args.verbose, "writing layout volume");
+
+ if (fseek(args.fp_out, 0, SEEK_SET) == -1) {
+ errmsg("cannot seek file \"%s\"", args.f_out);
+ goto out_dict;
+ }
+
+ err = ubigen_write_layout_vol(&ui, vtbl, args.fp_out);
+ if (err) {
+ errmsg("cannot write layout volume");
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "done");
+
+ iniparser_freedict(args.dict);
+ free(vtbl);
+ fclose(args.fp_out);
+ return 0;
+
+out_dict:
+ iniparser_freedict(args.dict);
+out_vtbl:
+ free(vtbl);
+out:
+ fclose(args.fp_out);
+ remove(args.f_out);
+ return err;
+}
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/new-utils/src/ubi-update.c b/ubi-utils/new-utils/src/ubi-update.c
new file mode 100644
index 0000000..bf548a9
--- /dev/null
+++ b/ubi-utils/new-utils/src/ubi-update.c
@@ -0,0 +1,295 @@
+/*
+ * 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 <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.0"
+#define PROGRAM_NAME "ubi-update"
+
+struct args {
+ int truncate;
+ const char *node;
+ const char *img;
+};
+
+static struct args args = {
+ .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':
+ args.truncate = 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 ':':
+ 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 - 2)
+ return errmsg("specify UBI device name and image file name as first 2 "
+ "parameters (use -h for help)");
+
+ args.node = argv[optind];
+ args.img = argv[optind + 1];
+
+ return 0;
+}
+
+static int truncate_volume(libubi_t libubi)
+{
+ int err, fd;
+
+ fd = open(args.node, O_RDWR);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", args.node);
+
+ err = ubi_update_start(libubi, fd, 0);
+ if (err) {
+ sys_errmsg("cannot truncate volume \"%s\"", args.node);
+ 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;
+ }
+ return sys_errmsg("cannot write %d bytes to volume \"%s\"",
+ len, args.node);
+ }
+
+ if (ret == 0)
+ return errmsg("cannot write %d bytes to volume \"%s\"", len, args.node);
+
+ 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)
+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size);
+
+ err = stat(args.img, &st);
+ if (err < 0) {
+ errmsg("stat failed on \"%s\"", args.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)",
+ args.img, bytes, args.node, vol_info->rsvd_bytes);
+ goto out_free;
+ }
+
+ fd = open(args.node, O_RDWR);
+ if (fd == -1) {
+ sys_errmsg("cannot open UBI volume \"%s\"", args.node);
+ goto out_free;
+ }
+
+ ifd = open(args.img, O_RDONLY);
+ if (ifd == -1) {
+ sys_errmsg("cannot open \"%s\"", args.img);
+ goto out_close1;
+ }
+
+ err = ubi_update_start(libubi, fd, bytes);
+ if (err) {
+ sys_errmsg("cannot start volume \"%s\" update", args.node);
+ 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 {
+ sys_errmsg("cannot read %d bytes from \"%s\"",
+ tocopy, args.img);
+ 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 (!args.img && !args.truncate)
+ return errmsg("incorrect arguments, use -h for help");
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ sys_errmsg("cannot open libubi");
+ goto out_libubi;
+ }
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 1) {
+ errmsg("\"%s\" is an UBI device node, not an UBI volume node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI volume node", args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_vol_info(libubi, args.node, &vol_info);
+ if (err) {
+ sys_errmsg("cannot get information about UBI volume \"%s\"",
+ args.node);
+ goto out_libubi;
+ }
+
+ if (args.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;
+}